mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-07-12 09:17:52 -06:00
Six degrees of freedom camera - 1st installment
This commit is contained in:
parent
536514ff03
commit
62e60bcb43
8 changed files with 245 additions and 2 deletions
|
@ -34,18 +34,27 @@ double Camera::FrustrumZMargin = 10.0;
|
|||
double Camera::MaxFovDeg = 60.0;
|
||||
|
||||
Camera::Camera()
|
||||
#if ENABLE_6DOF_CAMERA
|
||||
: requires_zoom_to_bed(false)
|
||||
#else
|
||||
: phi(45.0f)
|
||||
, requires_zoom_to_bed(false)
|
||||
, inverted_phi(false)
|
||||
#endif // ENABLE_6DOF_CAMERA
|
||||
, m_type(Perspective)
|
||||
, m_target(Vec3d::Zero())
|
||||
#if !ENABLE_6DOF_CAMERA
|
||||
, m_theta(45.0f)
|
||||
#endif // !ENABLE_6DOF_CAMERA
|
||||
, m_zoom(1.0)
|
||||
, m_distance(DefaultDistance)
|
||||
, m_gui_scale(1.0)
|
||||
, m_view_matrix(Transform3d::Identity())
|
||||
, m_projection_matrix(Transform3d::Identity())
|
||||
{
|
||||
#if ENABLE_6DOF_CAMERA
|
||||
set_default_orientation();
|
||||
#endif // ENABLE_6DOF_CAMERA
|
||||
}
|
||||
|
||||
std::string Camera::get_type_as_string() const
|
||||
|
@ -91,6 +100,9 @@ void Camera::select_next_type()
|
|||
|
||||
void Camera::set_target(const Vec3d& target)
|
||||
{
|
||||
#if ENABLE_6DOF_CAMERA
|
||||
translate_world(target - m_target);
|
||||
#else
|
||||
BoundingBoxf3 test_box = m_scene_box;
|
||||
test_box.translate(-m_scene_box.center());
|
||||
// We may let this factor be customizable
|
||||
|
@ -101,8 +113,10 @@ void Camera::set_target(const Vec3d& target)
|
|||
m_target(0) = clamp(test_box.min(0), test_box.max(0), target(0));
|
||||
m_target(1) = clamp(test_box.min(1), test_box.max(1), target(1));
|
||||
m_target(2) = clamp(test_box.min(2), test_box.max(2), target(2));
|
||||
#endif // ENABLE_6DOF_CAMERA
|
||||
}
|
||||
|
||||
#if !ENABLE_6DOF_CAMERA
|
||||
void Camera::set_theta(float theta, bool apply_limit)
|
||||
{
|
||||
if (apply_limit)
|
||||
|
@ -114,6 +128,7 @@ void Camera::set_theta(float theta, bool apply_limit)
|
|||
m_theta += 360.0f;
|
||||
}
|
||||
}
|
||||
#endif // !ENABLE_6DOF_CAMERA
|
||||
|
||||
void Camera::update_zoom(double delta_zoom)
|
||||
{
|
||||
|
@ -130,7 +145,25 @@ void Camera::set_zoom(double zoom)
|
|||
// Don't allow to zoom too close to the scene.
|
||||
m_zoom = std::min(zoom, 100.0);
|
||||
}
|
||||
|
||||
#if ENABLE_6DOF_CAMERA
|
||||
void Camera::select_view(const std::string& direction)
|
||||
{
|
||||
if (direction == "iso")
|
||||
set_default_orientation();
|
||||
else if (direction == "left")
|
||||
m_view_matrix = look_at(m_target - m_distance * Vec3d::UnitX(), m_target, Vec3d::UnitZ());
|
||||
else if (direction == "right")
|
||||
m_view_matrix = look_at(m_target + m_distance * Vec3d::UnitX(), m_target, Vec3d::UnitZ());
|
||||
else if (direction == "top")
|
||||
m_view_matrix = look_at(m_target + m_distance * Vec3d::UnitZ(), m_target, Vec3d::UnitY());
|
||||
else if (direction == "bottom")
|
||||
m_view_matrix = look_at(m_target - m_distance * Vec3d::UnitZ(), m_target, -Vec3d::UnitY());
|
||||
else if (direction == "front")
|
||||
m_view_matrix = look_at(m_target - m_distance * Vec3d::UnitY(), m_target, Vec3d::UnitZ());
|
||||
else if (direction == "rear")
|
||||
m_view_matrix = look_at(m_target + m_distance * Vec3d::UnitY(), m_target, Vec3d::UnitZ());
|
||||
}
|
||||
#else
|
||||
bool Camera::select_view(const std::string& direction)
|
||||
{
|
||||
const float* dir_vec = nullptr;
|
||||
|
@ -159,6 +192,7 @@ bool Camera::select_view(const std::string& direction)
|
|||
else
|
||||
return false;
|
||||
}
|
||||
#endif // ENABLE_6DOF_CAMERA
|
||||
|
||||
double Camera::get_fov() const
|
||||
{
|
||||
|
@ -180,20 +214,26 @@ void Camera::apply_viewport(int x, int y, unsigned int w, unsigned int h) const
|
|||
|
||||
void Camera::apply_view_matrix() const
|
||||
{
|
||||
#if !ENABLE_6DOF_CAMERA
|
||||
double theta_rad = Geometry::deg2rad(-(double)m_theta);
|
||||
double phi_rad = Geometry::deg2rad((double)phi);
|
||||
double sin_theta = ::sin(theta_rad);
|
||||
Vec3d camera_pos = m_target + m_distance * Vec3d(sin_theta * ::sin(phi_rad), sin_theta * ::cos(phi_rad), ::cos(theta_rad));
|
||||
#endif // !ENABLE_6DOF_CAMERA
|
||||
|
||||
glsafe(::glMatrixMode(GL_MODELVIEW));
|
||||
glsafe(::glLoadIdentity());
|
||||
|
||||
#if ENABLE_6DOF_CAMERA
|
||||
glsafe(::glMultMatrixd(m_view_matrix.data()));
|
||||
#else
|
||||
glsafe(::glRotatef(-m_theta, 1.0f, 0.0f, 0.0f)); // pitch
|
||||
glsafe(::glRotatef(phi, 0.0f, 0.0f, 1.0f)); // yaw
|
||||
|
||||
glsafe(::glTranslated(-camera_pos(0), -camera_pos(1), -camera_pos(2)));
|
||||
|
||||
glsafe(::glGetDoublev(GL_MODELVIEW_MATRIX, m_view_matrix.data()));
|
||||
#endif // ENABLE_6DOF_CAMERA
|
||||
}
|
||||
|
||||
void Camera::apply_projection(const BoundingBoxf3& box, double near_z, double far_z) const
|
||||
|
@ -300,7 +340,11 @@ void Camera::zoom_to_box(const BoundingBoxf3& box, int canvas_w, int canvas_h)
|
|||
{
|
||||
m_zoom = zoom;
|
||||
// center view around box center
|
||||
#if ENABLE_6DOF_CAMERA
|
||||
set_target(box.center());
|
||||
#else
|
||||
m_target = box.center();
|
||||
#endif // ENABLE_6DOF_CAMERA
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -313,7 +357,11 @@ void Camera::zoom_to_volumes(const GLVolumePtrs& volumes, int canvas_w, int canv
|
|||
{
|
||||
m_zoom = zoom;
|
||||
// center view around the calculated center
|
||||
#if ENABLE_6DOF_CAMERA
|
||||
set_target(center);
|
||||
#else
|
||||
m_target = center;
|
||||
#endif // ENABLE_6DOF_CAMERA
|
||||
}
|
||||
}
|
||||
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||
|
@ -360,6 +408,43 @@ void Camera::debug_render() const
|
|||
}
|
||||
#endif // ENABLE_CAMERA_STATISTICS
|
||||
|
||||
#if ENABLE_6DOF_CAMERA
|
||||
void Camera::translate_world(const Vec3d& displacement)
|
||||
{
|
||||
Vec3d new_target = validate_target(m_target + displacement);
|
||||
Vec3d new_displacement = new_target - m_target;
|
||||
if (!new_displacement.isApprox(Vec3d::Zero()))
|
||||
{
|
||||
m_target += new_displacement;
|
||||
m_view_matrix.translate(-new_displacement);
|
||||
}
|
||||
}
|
||||
|
||||
void Camera::rotate_on_sphere(double delta_azimut_rad, double delta_zenit_rad, bool apply_limit)
|
||||
{
|
||||
Vec3d target = m_target;
|
||||
translate_world(-target);
|
||||
m_view_matrix.rotate(Eigen::AngleAxisd(delta_zenit_rad, get_dir_right()));
|
||||
m_view_matrix.rotate(Eigen::AngleAxisd(delta_azimut_rad, Vec3d::UnitZ()));
|
||||
translate_world(target);
|
||||
}
|
||||
|
||||
void Camera::rotate_local_around_target(const Vec3d& rotation_rad)
|
||||
{
|
||||
Vec3d target = m_target;
|
||||
translate_world(-target);
|
||||
m_view_matrix.rotate(Eigen::AngleAxisd(rotation_rad(0), get_dir_right()));
|
||||
m_view_matrix.rotate(Eigen::AngleAxisd(rotation_rad(1), get_dir_up()));
|
||||
m_view_matrix.rotate(Eigen::AngleAxisd(rotation_rad(2), get_dir_forward()));
|
||||
translate_world(target);
|
||||
}
|
||||
|
||||
bool Camera::is_looking_downward() const
|
||||
{
|
||||
return get_dir_forward().dot(Vec3d::UnitZ()) < 0.0;
|
||||
}
|
||||
#endif // ENABLE_6DOF_CAMERA
|
||||
|
||||
std::pair<double, double> Camera::calc_tight_frustrum_zs_around(const BoundingBoxf3& box) const
|
||||
{
|
||||
std::pair<double, double> ret;
|
||||
|
@ -540,6 +625,63 @@ void Camera::set_distance(double distance) const
|
|||
apply_view_matrix();
|
||||
}
|
||||
|
||||
#if ENABLE_6DOF_CAMERA
|
||||
Transform3d Camera::look_at(const Vec3d& position, const Vec3d& target, const Vec3d& up) const
|
||||
{
|
||||
Vec3d unit_z = (position - target).normalized();
|
||||
Vec3d unit_x = up.cross(unit_z).normalized();
|
||||
Vec3d unit_y = unit_z.cross(unit_x).normalized();
|
||||
|
||||
Transform3d matrix;
|
||||
|
||||
matrix(0, 0) = unit_x(0);
|
||||
matrix(0, 1) = unit_x(1);
|
||||
matrix(0, 2) = unit_x(2);
|
||||
matrix(0, 3) = -unit_x.dot(position);
|
||||
|
||||
matrix(1, 0) = unit_y(0);
|
||||
matrix(1, 1) = unit_y(1);
|
||||
matrix(1, 2) = unit_y(2);
|
||||
matrix(1, 3) = -unit_y.dot(position);
|
||||
|
||||
matrix(2, 0) = unit_z(0);
|
||||
matrix(2, 1) = unit_z(1);
|
||||
matrix(2, 2) = unit_z(2);
|
||||
matrix(2, 3) = -unit_z.dot(position);
|
||||
|
||||
matrix(3, 0) = 0.0;
|
||||
matrix(3, 1) = 0.0;
|
||||
matrix(3, 2) = 0.0;
|
||||
matrix(3, 3) = 1.0;
|
||||
|
||||
return matrix;
|
||||
}
|
||||
|
||||
void Camera::set_default_orientation()
|
||||
{
|
||||
double theta_rad = Geometry::deg2rad(-45.0);
|
||||
double phi_rad = Geometry::deg2rad(45.0);
|
||||
double sin_theta = ::sin(theta_rad);
|
||||
Vec3d camera_pos = m_target + m_distance * Vec3d(sin_theta * ::sin(phi_rad), sin_theta * ::cos(phi_rad), ::cos(theta_rad));
|
||||
m_view_matrix = Transform3d::Identity();
|
||||
m_view_matrix.rotate(Eigen::AngleAxisd(theta_rad, Vec3d::UnitX())).rotate(Eigen::AngleAxisd(phi_rad, Vec3d::UnitZ())).translate(-camera_pos);
|
||||
}
|
||||
|
||||
Vec3d Camera::validate_target(const Vec3d& target) const
|
||||
{
|
||||
BoundingBoxf3 test_box = m_scene_box;
|
||||
test_box.translate(-m_scene_box.center());
|
||||
// We may let this factor be customizable
|
||||
static const double ScaleFactor = 1.5;
|
||||
test_box.scale(ScaleFactor);
|
||||
test_box.translate(m_scene_box.center());
|
||||
|
||||
return Vec3d(std::clamp(target(0), test_box.min(0), test_box.max(0)),
|
||||
std::clamp(target(1), test_box.min(1), test_box.max(1)),
|
||||
std::clamp(target(2), test_box.min(2), test_box.max(2)));
|
||||
}
|
||||
#endif // ENABLE_6DOF_CAMERA
|
||||
|
||||
} // GUI
|
||||
} // Slic3r
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue