Skip to main content

Scene.ixx File

Represents a hierarchical SceneGraph that organizes all renderable and non-renderable objects within a scene. More...

Included Headers

#include <cassert> #include <format> #include <memory> #include <optional> #include <vector> #include <helios.core.types> #include <helios.engine.modules.scene.types.SceneId> #include <helios.util.log.Logger> #include <helios.scene.SnapshotItem> #include <helios.util.log.LogManager> #include <helios.scene.FrustumCullingStrategy> #include <helios.scene.SceneNode> #include <helios.rendering.Viewport> #include <helios.math.types> #include <helios.scene.Camera> #include <helios.scene.CameraSceneNode> #include <helios.scene.Snapshot>

Namespaces Index

namespacehelios
namespacescene

Scene graph and camera management. More...

Classes Index

classScene

Represents a hierarchical SceneGraph that organizes all renderable and non-renderable objects within a scene. More...

Macro Definitions Index

#defineHELIOS_LOG_SCOPE   "helios::scene::Scene"

Description

Represents a hierarchical SceneGraph that organizes all renderable and non-renderable objects within a scene.

Macro Definitions

HELIOS_LOG_SCOPE

#define HELIOS_LOG_SCOPE   "helios::scene::Scene"

Definition at line 32 of file Scene.ixx.

32#define HELIOS_LOG_SCOPE "helios::scene::Scene"

File Listing

The file content with the documentation metadata removed is:

1/**
2 * @file Scene.ixx
3 * @brief Represents a hierarchical SceneGraph that organizes all renderable
4 * and non-renderable objects within a scene.
5 */
6module;
7
8#include <cassert>
9#include <format>
10#include <memory>
11#include <optional>
12#include <vector>
13
14export module helios.scene.Scene;
15
16import helios.scene.Snapshot;
17import helios.scene.SceneNode;
18import helios.scene.CameraSceneNode;
19import helios.scene.Camera;
20import helios.math.types;
21
22import helios.rendering.Viewport;
23import helios.scene.FrustumCullingStrategy;
24import helios.scene.SnapshotItem;
25
26import helios.util.log.Logger;
27import helios.util.log.LogManager;
28
29import helios.engine.modules.scene.types.SceneId;
30import helios.core.types;
31
32#define HELIOS_LOG_SCOPE "helios::scene::Scene"
33export namespace helios::scene {
34
35
36 /**
37 * @brief Represents a hierarchical SceneGraph that organizes all renderable
38 * and non-renderable objects within a scene.
39 *
40 * Every scene has one implicit root node all nodes are appended to when
41 * `addNode` is called.
42 *
43 * A Scene is responsible for managing the SceneGraph, consisting of SceneNodes;
44 * it provides methods to frustum cull SceneNodes based on a specific `FrustumCullingStrategy`
45 * and a particular `CameraSceneNode` and also allows for propagating world transformations
46 * through the contained subtrees.
47 *
48 * @see [RTR, pp. 828]
49 * @see [Gre19, pp. 693]
50 * @see [HDMS+14, pp. 138]
51 *
52 * @note By default, we're not allowing copying/moving Scenes.
53 * These constraints may be relaxed in the future, depending on valid use cases.
54 */
55 class Scene {
56
57 private:
58
59 /**
60 * @brief SceneGraphKey for internal use.
61 *
62 * @see helios::scene::SceneNode::setWorldTransform()
63 */
64 SceneGraphKey sceneGraphKey_{};
65
66 /**
67 * @brief 4x4 identity matrix for internal use.
68 */
70
71 /**
72 * @brief The root node of this scene.
73 *
74 * All other SceneNodes are (in)direct children of this node.
75 */
76 std::unique_ptr<SceneNode> root_;
77
78 /**
79 * @brief Unique identifier for this scene.
80 */
82
83 /**
84 * @brief Internal helper function to force-propagate the worldTransformation of SceneNodes to their child nodes.
85 *
86 * Propagation is cancelled for this node if the resulting world transform
87 * is considered equal to the current world transform of the SceneNode.
88 *
89 * @param node The current SceneNode for which to propagate the world transformation.
90 * @param parentWorldTransform The world transformation from the parent node.
91 *
92 * @see updateNodes()
93 */
94 void propagateWorldTransform(SceneNode& node, const math::mat4f& parentWorldTransform) const {
95
96 // if the worldTransform was not updated,
97 // branch back into selective updates
98 if (!node.applyWorldTransform(parentWorldTransform, sceneGraphKey_)) {
99 for (auto& child: node.children()) {
100 updateNodes(*child, node.cachedWorldTransform());
101 }
102 } else {
103 for (auto& child: node.children()) {
104 propagateWorldTransform(*child, node.cachedWorldTransform());
105 }
106 }
107 }
108
109 /**
110 * @brief Selectively updates the world transformation of SceneNodes in the scene graph.
111 *
112 * A SceneNode is forced to update its own world transformation and the
113 * world transformation of its children as soon as a check for the dirty-state of the
114 * node is true.
115 *
116 * @param node The current SceneNode processed.
117 * @param wt The world transform to apply.
118 *
119 * @note It is important that this method is called before the next render pass, or before
120 * the scene graph is culled. This method must also consider CameraSceneNodes, making sure the
121 * associated `Camera` is updated with the view matrix.
122 */
123 void updateNodes(SceneNode& node, const math::mat4f& wt) const {
124
125 if (node.needsUpdate()) {
126 propagateWorldTransform(node, wt);
127 } else {
128 const auto& parentWt = node.worldTransform();
129 for (auto& child: node.children()) {
130 updateNodes(*child, parentWt);
131 }
132 }
133 }
134
135 /**
136 * @brief The FrustumCullingStrategy used with this Scene.
137 */
138 std::unique_ptr<helios::scene::FrustumCullingStrategy> frustumCullingStrategy_;
139
140 /**
141 * @brief The logger used with this Scene instance.
142 *
143 * Defaults to HELIOS_LOG_SCOPE.
144 *
145 * @todo constructor injection
146 */
149 );
150
151 public:
152 /**
153 * @brief Prevent copying.
154 *
155 * A Scene is not intended to be copied.
156 */
157 Scene(const Scene&) = delete;
158
159 /**
160 * @brief Prevent copy assignment.
161 *
162 * A Scene is not intended to be copied.
163 */
164 Scene& operator=(const Scene&) = delete;
165
166 /**
167 * @brief Move constructor.
168 */
169 Scene(Scene&&) noexcept = default;
170
171 /**
172 * @brief Move assignment operator.
173 */
174 Scene& operator=(Scene&&) noexcept = default;
175
176 /**
177 * @brief Destructor.
178 */
179 ~Scene() = default;
180
181 /**
182 * @brief Constructs a new Scene.
183 *
184 * The root node for this scene is automatically created.
185 *
186 * @param frustumCullingStrategy The frustum culling strategy to use with this Scene.
187 */
188 explicit Scene(std::unique_ptr<helios::scene::FrustumCullingStrategy> frustumCullingStrategy) :
189 frustumCullingStrategy_(std::move(frustumCullingStrategy)), root_(std::make_unique<SceneNode>()) {
190
191 root_->setIsRoot(sceneGraphKey_);
192 }
193
194 /**
195 * @brief Constructs a new Scene with a specific scene ID.
196 *
197 * @param frustumCullingStrategy The frustum culling strategy to use with this Scene.
198 * @param sceneId Unique identifier for this scene.
199 */
200 explicit Scene(
201 std::unique_ptr<helios::scene::FrustumCullingStrategy> frustumCullingStrategy,
203 Scene(std::move(frustumCullingStrategy))
204 {
205 sceneId_ = sceneId;
206 }
207
208 /**
209 * @brief Adds a new SceneNode to this scene.
210 *
211 * The SceneNode becomes a direct descendant of this scene's root.
212 *
213 * @param node The SceneNode to add to this Scene.
214 *
215 * @return The raw pointer to the newly added node, or `nullptr` if the node was not added.
216 */
217 [[nodiscard]] SceneNode* addNode(std::unique_ptr<SceneNode> node) const {
218 assert(root_ && "Unexpected null-root");
219 if (!root_) {
220 logger_.error("Unexpected nullptr for this Scene's root.");
221 }
222 return root_->addNode(std::move(node));
223 }
224
225 /**
226 * @brief Updates the world transformations of SceneNodes in the graph.
227 *
228 * The method traverses the Scene and propagates updated world transformations
229 * to their respective child nodes if the processed node is considered to be dirty.
230 */
231 void updateNodes() const {
232 updateNodes(*root_, mat4fid);
233 }
234
235 /**
236 * @brief Returns the unique identifier for this scene.
237 *
238 * @return The SceneId for this scene.
239 */
241 return sceneId_;
242 }
243
244 /**
245 * @brief Applies this Scene's frustumCullingStrategy and returns all nodes visible for the specified
246 * CameraSceneNode and its associated `Camera`.
247 *
248 * This method ensures that all nodes' world geometry is properly updated
249 * before culling is applied.
250 *
251 * @param cameraSceneNode The cameraSceneNode used to determine the view frustum for culling.
252 *
253 * @return A list of currently visible nodes (const pointers into the scene graph).
254 */
255 [[nodiscard]] std::vector<const helios::scene::SceneNode*> findVisibleNodes(
256 const helios::scene::CameraSceneNode* cameraSceneNode
257 ) const {
258 assert(root_ && "Unexpected null-root");
259 if (!root_) {
260 logger_.error("Unexpected nullptr for this Scene's root.");
261 }
262
264
265 return frustumCullingStrategy_->cull(cameraSceneNode, *root_);
266 }
267
268 /**
269 * @brief Returns the root node of this Scene.
270 *
271 * The root node is guaranteed to exist.
272 *
273 * @return The root node of this Scene.
274 */
275 [[nodiscard]] helios::scene::SceneNode& root() const noexcept {
276 assert(root_ && "Unexpected null-root");
277 if (!root_) {
278 logger_.error("Unexpected nullptr for this Scene's root.");
279 }
280 return *root_;
281 }
282
283 /**
284 * @brief Creates a Snapshot of the Scene and returns it.
285 *
286 * Taking a snapshot will frustum cull the SceneNodes and place their Renderables
287 * along with the current matrices of this scene into the Snapshot object.
288 * Only those SceneNodes are considered that were configured with a Renderable and
289 * have their `isActive`-flag set to true.
290 *
291 * @param viewport The viewport for which the Snapshot is created.
292 *
293 * @return An optional Snapshot created for this Scene, or `std::nullopt` if creation failed.
294 *
295 * @todo This should be refactored into a factory to prevent domain leakage between Scene and Rendering.
296 */
297 [[nodiscard]] std::optional<Snapshot>
298 createSnapshot(const rendering::Viewport& viewport) const {
299
300 const auto* cameraSceneNode = viewport.cameraSceneNode();
301
302 if (!cameraSceneNode) {
303 logger_.warn("Viewport was not configured with a camera, skipping createSnapshot()...");
304 return std::nullopt;
305 }
306
307 const auto nodes = findVisibleNodes(cameraSceneNode);
308
309 std::vector<SnapshotItem> renderables;
310 renderables.reserve(nodes.size());
311 for (const auto& node: nodes) {
312 if (node->isActive() && node->hasRenderable()) {
313 renderables.emplace_back(
314 node->renderable(),
316 );
317 }
318 }
319
320 return std::make_optional<Snapshot>(
321 viewport,
322 cameraSceneNode->camera().projectionMatrix(),
323 cameraSceneNode->camera().viewMatrix(),
324 std::move(renderables)
325 );
326 }
327
328 };
329
330} // namespace helios::scene
331

Generated via doxygen2docusaurus 2.0.0 by Doxygen 1.15.0.