diff --git a/examples/grass.cpp b/examples/grass.cpp index 2293d322..a66fc304 100644 --- a/examples/grass.cpp +++ b/examples/grass.cpp @@ -205,8 +205,7 @@ struct grass_app camera.near_clip = 0.1f; camera.far_clip = 1000.f; camera.pos = {0.5f, 0.5f, 1.5f}; - camera.elevation_angle = geom::rad(15.f); - camera.azimuthal_angle = geom::rad(-90.f); + camera.rotateYZ(geom::rad(-90.f)); init_ground(); init_grass(); @@ -474,8 +473,8 @@ struct grass_app if (is_middle_button_down()) { - camera.azimuthal_angle -= dx * 0.01f; - camera.elevation_angle += dy * 0.01f; + camera.rotateZX(0.01f * dx); + camera.rotateYZ(0.01f * dy); } } diff --git a/libs/geom/include/psemek/geom/camera.hpp b/libs/geom/include/psemek/geom/camera.hpp index 3fc5142e..8651a4ec 100644 --- a/libs/geom/include/psemek/geom/camera.hpp +++ b/libs/geom/include/psemek/geom/camera.hpp @@ -128,22 +128,28 @@ namespace psemek::geom struct free_camera : perspective_camera { - // assumes up is +Z - // azimuthal angle is in XY plane - // both angles zero gives X right, Y forward, and Z up - - float azimuthal_angle; - float elevation_angle; point pos; + vector axes[3]; - free_camera() = default; + free_camera() + { + axes[0] = {1.f, 0.f, 0.f}; + axes[1] = {0.f, 1.f, 0.f}; + axes[2] = {0.f, 0.f, 1.f}; + } - free_camera(float fov_x, float fov_y, float near_clip, float far_clip, float azimuthal_angle, float elevation_angle, point const & pos) + free_camera(float fov_x, float fov_y, float near_clip, float far_clip, point const & pos) : perspective_camera(fov_x, fov_y, near_clip, far_clip) - , azimuthal_angle{azimuthal_angle} - , elevation_angle{elevation_angle} , pos{pos} - {} + { + axes[0] = {1.f, 0.f, 0.f}; + axes[1] = {0.f, 1.f, 0.f}; + axes[2] = {0.f, 0.f, 1.f}; + } + + void rotateXY(float angle); + void rotateYZ(float angle); + void rotateZX(float angle); matrix view() const override; }; diff --git a/libs/geom/source/camera.cpp b/libs/geom/source/camera.cpp index f3311cce..5bb3710c 100644 --- a/libs/geom/source/camera.cpp +++ b/libs/geom/source/camera.cpp @@ -120,17 +120,35 @@ namespace psemek::geom 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 { - auto tr = - 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({ -pos[0], -pos[1], -pos[2] }).transform() - ; - - return tr.homogeneous_matrix(); + return homogeneous(by_rows(axes[0], axes[1], axes[2])) * translation{geom::point::zero() - pos}.homogeneous_matrix(); } }