Skip to main content

CameraSceneNode.ixx File

Camera scene node adapter providing view and projection matrices within a scene graph. More...

Included Headers

#include <cassert> #include <iostream> #include <memory> #include <stdexcept> #include <helios.scene.SceneNode> #include <helios.scene.Camera> #include <helios.math.TransformType> #include <helios.math.types>

Namespaces Index

namespacehelios
namespacescene

Scene graph and camera management. More...

Classes Index

classCameraSceneNode

Represents an adapter for cameras, allowing spatial positioning and transformation within the scene graph. More...

Description

Camera scene node adapter providing view and projection matrices within a scene graph.

File Listing

The file content with the documentation metadata removed is:

1/**
2 * @file CameraSceneNode.ixx
3 * @brief Camera scene node adapter providing view and projection matrices within a scene graph.
4 */
5module;
6
7#include <cassert>
8#include <iostream>
9#include <memory>
10#include <stdexcept>
11
12export module helios.scene.CameraSceneNode;
13
14import helios.math.types;
15import helios.math.TransformType;
16import helios.scene.SceneNode;
17import helios.scene.Camera;
18
19export namespace helios::scene {
20
21 /**
22 * @brief Represents an adapter for cameras, allowing spatial positioning and transformation within the scene graph.
23 *
24 * A CameraSceneNode behaves just like a (non-renderable) SceneNode, except that
25 * it does not accept child nodes.
26 *
27 * An instance of `CameraSceneNode` can be added as a direct descendant of the scene's root node
28 * for free transform, or it can be a child of a model hierarchy to inherit the
29 * corresponding positioning in the world.
30 */
31 class CameraSceneNode : public SceneNode {
32
33
34
35 protected:
36 /**
37 * @brief Unique pointer to the camera instance owned by this scene node.
38 */
39 std::unique_ptr<helios::scene::Camera> camera_;
40
41 public:
42 /**
43 * @brief Constructs a CameraSceneNode that takes ownership of the given camera.
44 *
45 * The CameraSceneNode becomes the sole owner of the Camera instance. The camera's
46 * view matrix is automatically updated when `worldTransform()` is called.
47 *
48 * @param camera A unique pointer to the camera to be owned by this scene node.
49 *
50 * @throws std::invalid_argument if camera is a nullptr.
51 */
52 explicit CameraSceneNode(std::unique_ptr<helios::scene::Camera> camera) :
53 camera_(std::move(camera)) {
54 if (!camera_) {
55 throw std::invalid_argument("CameraSceneNode received a Camera nullptr.");
56 }
57 }
58
59 /**
60 * @brief Prevents adding child nodes to a camera scene node.
61 *
62 * This method does nothing and returns `nullptr`, indicating that a `CameraSceneNode`
63 * must not have child nodes.
64 *
65 * @param sceneNode The attempted child node to add (ignored).
66 *
67 * @return Always returns `nullptr`.
68 *
69 * @see https://stackoverflow.com/questions/24609872/delete-virtual-function-from-a-derived-class
70 */
71 [[nodiscard]] SceneNode* addNode(std::unique_ptr<SceneNode> sceneNode) override {
72 assert(false && "CameraSceneNode does not accept child nodes.");
73 return nullptr;
74 }
75
76 /**
77 * @brief Gets the camera associated with this scene node.
78 *
79 * @return A const ref to the associated camera instance.
80 */
81 [[nodiscard]] const helios::scene::Camera& camera() const noexcept {
82 return *camera_;
83 }
84
85 /**
86 * @brief Gets the camera associated with this scene node.
87 *
88 * @return A ref to the associated camera instance.
89 */
90 [[nodiscard]] helios::scene::Camera& camera() noexcept {
91 return *camera_;
92 }
93
94
95 /**
96 * @brief Orients this camera node to look at a target position in world space.
97 *
98 * Computes the rotation matrix required to align this scene node's forward direction
99 * with the specified target position. The rotation is computed in world space and then
100 * converted to local space by factoring out the parent's rotation.
101 *
102 * @param target The world-space coordinates of the target to look at.
103 * @param up The up vector defining the camera's vertical orientation in world space.
104 *
105 * @pre The camera node must have a valid parent (i.e., must be added to a scene graph).
106 *
107 * @note The up vector should typically be `(0, 1, 0)` for standard upright orientation.
108 *
109 * @see lookAtLocal()
110 * @see helios::scene::SceneNode::setRotation()
111 */
113 // We treat up as a vector in world-space for now.
114 const auto wt = worldTransform();
115 const auto worldPos = helios::math::vec3f(
116 wt(0, 3), wt(1, 3), wt(2, 3)
117 );
118
119 auto z = (target - worldPos).normalize();
120 auto y = up.normalize();
121 auto x = helios::math::cross(y, z).normalize();
122 y = helios::math::cross(z, x).normalize();
123
124 const helios::math::mat4f worldRotation = helios::math::mat4f{
125 x[0], x[1], x[2], 0.0f,
126 y[0], y[1], y[2], 0.0f,
127 z[0], z[1], z[2], 0.0f,
128 0.0f, 0.0f, 0.0f, 1.0f
129 };
130
133 /**
134 * @todo add support for different rotations
135 */
136 setRotation(worldRotation);
137 return;
138 }
139
140 // ParentTransform
141 assert(parent() && "parent() of CameraSceneNode returned null, are you sure the node was added properly to the scenegraph?");
143
144 const helios::math::mat4f parentRotInv = pT.decompose(helios::math::TransformType::Rotation).transpose();
145
146 // Apply rotation in local space by undoing the parent rotation
147 setRotation(parentRotInv * worldRotation);
148 }
149
150 /**
151 * @brief Orients this camera node to look at a target position in local space.
152 *
153 * Similar to `lookAt()`, but the target and up vector are interpreted relative
154 * to this node's local coordinate system rather than world space. Useful when
155 * the camera should track objects within the same local hierarchy.
156 *
157 * @param targetLocal The local-space coordinates of the target to look at.
158 * @param upLocal The up vector defining the camera's vertical orientation in local space.
159 *
160 * @see lookAt()
161 */
163 // We treat up as a vector in world-space for now.
164 const auto lt = localTransform().transform();
165 const auto localPos = helios::math::vec3f(
166 lt(0, 3), lt(1, 3), lt(2, 3)
167 );
168
169 auto z = (targetLocal - localPos).normalize();
170 auto y = upLocal.normalize();
171 auto x = helios::math::cross(y, z).normalize();
172 y = helios::math::cross(z, x).normalize();
173
174 const helios::math::mat4f localRotation = helios::math::mat4f{
175 x[0], x[1], x[2], 0.0f,
176 y[0], y[1], y[2], 0.0f,
177 z[0], z[1], z[2], 0.0f,
178 0.0f, 0.0f, 0.0f, 1.0f
179 };
180
181 setRotation(localRotation);
182 }
183
184 /**
185 * @brief Callback invoked when the world transform of this node changes.
186 *
187 * Overrides the base class implementation to update the camera's view matrix
188 * whenever the node's position or orientation in the scene graph changes.
189 * This ensures the camera always reflects the current world-space transform.
190 *
191 * @see SceneNode::onWorldTransformUpdate()
192 */
193 void onWorldTransformUpdate() noexcept override {
194
196
197 // Updates this SceneNode's worldTransform_
199
200 const auto x = helios::math::vec3f{wt(0, 0), wt(1, 0), wt(2, 0)};
201 const auto y = helios::math::vec3f{wt(0, 1), wt(1, 1), wt(2, 1)};
202 const auto z = helios::math::vec3f{wt(0, 2), wt(1, 2), wt(2, 2)};
203
204 const auto eye = helios::math::vec3f{wt(0, 3), wt(1, 3), wt(2, 3)};
205
206 // Compute view matrix: inverse of world transform with Z-negation for OpenGL RHS
207 auto inv = helios::math::mat4f{
208 x[0], y[0], -z[0], 0.0f,
209 x[1], y[1], -z[1], 0.0f,
210 x[2], y[2], -z[2], 0.0f,
211 -dot(x, eye), -dot(y, eye), dot(z, eye), 1.0f
212 };
213
214 camera_->setViewMatrix(inv);
215 }
216 };
217
218}

Generated via doxygen2docusaurus 2.0.0 by Doxygen 1.15.0.