#include #include #include #include #include #include #include #include #include namespace psemek::geom { matrix camera::transform() const { return projection() * view(); } point camera::position() const { vector b{ 0.f, 0.f, 0.f, 1.f }; gauss(view(), b); return { b[0], b[1], b[2] }; } vector camera::axis_x() const { vector b{ 1.f, 0.f, 0.f, 0.f }; gauss(view(), b); return { b[0], b[1], b[2] }; } vector camera::axis_y() const { vector b{ 0.f, 1.f, 0.f, 0.f }; gauss(view(), b); return { b[0], b[1], b[2] }; } vector camera::axis_z() const { vector b{ 0.f, 0.f, 1.f, 0.f }; gauss(view(), b); return { b[0], b[1], b[2] }; } vector camera::direction() const { return -axis_z(); } vector camera::direction(float x, float y) const { vector b{ x, y, -1.f, 1.f}; gauss(transform(), b); point p{ b[0] / b[3], b[1] / b[3], b[2] / b[3] }; return p - position(); } std::array, 6> camera::clip_planes() const { auto const m = transpose(transform()); std::array, 6> p; p[0] = m * vector{1.f, 0.f, 0.f, 1.f}; p[1] = m * vector{-1.f, 0.f, 0.f, 1.f}; p[2] = m * vector{0.f, 1.f, 0.f, 1.f}; p[3] = m * vector{0.f, -1.f, 0.f, 1.f}; p[4] = m * vector{0.f, 0.f, 1.f, 1.f}; p[5] = m * vector{0.f, 0.f, -1.f, 1.f}; return p; } matrix window_camera::view() const { return matrix::identity(); } matrix window_camera::projection() const { return orthographic({{ {0.f, width}, {height, 0.f}, {-1.f, 1.f} }}).homogeneous_matrix(); } matrix orthographic_camera::view() const { return matrix::identity(); } matrix orthographic_camera::projection() const { return orthographic(box).homogeneous_matrix(); } matrix perspective_camera::projection() const { return perspective(fov_x, fov_y, near_clip, far_clip).homogeneous_matrix(); } void perspective_camera::set_fov(float fov_y, float aspect_ratio) { this->fov_y = fov_y; fov_x = 2.f * std::atan(aspect_ratio * std::tan(fov_y / 2.f)); } matrix spherical_camera::view() const { auto tr = translation({0.f, 0.f, -distance}).transform() * swap(1, 2).transform() * scale({1.f, -1.f, 1.f}).transform() * plane_rotation(1, 2, elevation_angle).transform() * plane_rotation(1, 0, azimuthal_angle).transform() * translation({ -target[0], -target[1], -target[2] }).transform() ; return tr.homogeneous_matrix(); } static void rotate(geom::vector & a, geom::vector & b, float angle) { auto s = std::sin(angle); auto c = std::cos(angle); auto aa = a * c - b * s; auto bb = a * s + b * c; a = aa; b = bb; } void free_camera::rotateXY(float angle) { rotate(axes[0], axes[1], angle); } void free_camera::rotateYZ(float angle) { rotate(axes[1], axes[2], angle); } void free_camera::rotateZX(float angle) { rotate(axes[2], axes[0], angle); } matrix free_camera::view() const { return homogeneous(by_rows(axes[0], axes[1], axes[2])) * translation{geom::point::zero() - pos}.homogeneous_matrix(); } }