Vulkan Schnee 0.0.1
High-performance rendering engine
Loading...
Searching...
No Matches
SceneGraph.cpp
Go to the documentation of this file.
2
6
7#include <glm/gtc/matrix_transform.hpp>
8#include <glm/gtc/quaternion.hpp>
9
10namespace EngineCore {
15 SceneNode::SceneNode( entt::registry & reg, bool disableCaching ) :
16 entity( reg.create() )
17 , registry( &reg )
18 , worldMatrix( 1.0f )
20 {
21 reg.emplace<Ecs::LocalTransform>(entity, glm::mat4(1.f));
22 reg.emplace<Ecs::TransformDirty>(entity);
24 }
25
27 if (registry && registry->valid(entity)) {
28 registry->destroy(entity);
29 }
30 }
31
39
43
45 {
46 registry->emplace<Ecs::SceneNodeRef>(entity, weak_from_this());
47 }
48
49 entt::entity SceneNode::getEntity() const {
50 return entity;
51 }
52
57 void SceneNode::setWorldPosition(const glm::vec3 &newLocation) {
58 if (parent == nullptr) {
61 return;
62 }
63
64 // Get current world transform components
65 const glm::mat4& world = getWorldMatrix();
66 glm::vec3 currentScale = Ecs::TransformOperators::getScale(world);
67 glm::quat currentRotation = Ecs::TransformOperators::getRotation(world);
68
69 // Build desired world matrix
70 glm::mat4 desiredWorld = glm::translate(glm::mat4(1.f), newLocation)
71 * glm::mat4_cast(currentRotation)
72 * glm::scale(glm::mat4(1.f), currentScale);
73
74 // Convert to local space
75 glm::mat4 parentInverse = glm::inverse(parent->getWorldMatrix());
76 getLocalTransform().matrix = parentInverse * desiredWorld;
77
79 }
80
81 void SceneNode::setWorldRotation(const glm::vec3 &newRotation) {
82 setWorldRotation(glm::quat(glm::radians(newRotation)));
83 }
84
85 void SceneNode::setWorldRotation(const glm::quat &newRotation) {
86 if (parent == nullptr) {
89 return;
90 }
91
92 const glm::mat4& world = getWorldMatrix();
93 glm::vec3 currentPosition = Ecs::TransformOperators::getPosition(world);
94 glm::vec3 currentScale = Ecs::TransformOperators::getScale(world);
95
96 glm::mat4 desiredWorld = glm::translate(glm::mat4(1.f), currentPosition)
97 * glm::mat4_cast(newRotation)
98 * glm::scale(glm::mat4(1.f), currentScale);
99
100 glm::mat4 parentInverse = glm::inverse(parent->getWorldMatrix());
101 getLocalTransform().matrix = parentInverse * desiredWorld;
102
104 }
105
106 void SceneNode::rotateWorld(const glm::vec3 &deltaRotation) {
107 rotateWorld(glm::quat(glm::radians(deltaRotation)));
108 }
109
110 void SceneNode::rotateWorld(const glm::quat &deltaRotation) {
111 const glm::mat4& world = getWorldMatrix();
112 glm::quat currentRotation = Ecs::TransformOperators::getRotation(world);
113 glm::quat newRotation = deltaRotation * currentRotation;
114 setWorldRotation(newRotation);
115 }
116
117 void SceneNode::setWorldScale(const glm::vec3 &newScale) {
118 if (parent == nullptr) {
121 return;
122 }
123
124 const glm::mat4& world = getWorldMatrix();
125 glm::vec3 currentPosition = Ecs::TransformOperators::getPosition(world);
126 glm::quat currentRotation = Ecs::TransformOperators::getRotation(world);
127
128 glm::mat4 desiredWorld = glm::translate(glm::mat4(1.f), currentPosition)
129 * glm::mat4_cast(currentRotation)
130 * glm::scale(glm::mat4(1.f), newScale);
131
132 glm::mat4 parentInverse = glm::inverse(parent->getWorldMatrix());
133 getLocalTransform().matrix = parentInverse * desiredWorld;
134
136 }
137
138 void SceneNode::setLocalModelMatrix( const glm::mat4 & newModelMatrix )
139 {
140 getLocalTransform().matrix = newModelMatrix;
142 }
143
144 void SceneNode::setWorldModelMatrix( const glm::mat4 & newModelMatrix )
145 {
146 if (parent == nullptr) {
147 getLocalTransform().matrix = newModelMatrix;
149 return;
150 }
151
152 glm::mat4 parentInverse = glm::inverse(parent->getWorldMatrix());
153 getLocalTransform().matrix = parentInverse * newModelMatrix;
155 }
156
157 void SceneNode::addChild(const std::shared_ptr<SceneNode> &newChild) {
158 newChild->indexInParent = children.size();
159 children.push_back(newChild);
160 newChild->parent = shared_from_this();
161 }
162
163 void SceneNode::addChildren(std::vector<std::shared_ptr<SceneNode>> newChildren) {
164 size_t startIndex = children.size();
165 children.insert(children.end(), newChildren.begin(), newChildren.end());
166 for (size_t i = 0; i < newChildren.size(); ++i) {
167 newChildren[i]->indexInParent = startIndex + i;
168 newChildren[i]->parent = shared_from_this();
169 }
170 }
171
173 for (const auto child : children) {
174 child->parent = nullptr;
175 }
176 children.clear();
177 }
178
179 void SceneNode::removeChild(const std::shared_ptr<SceneNode> &child) {
180 size_t idx = child->indexInParent;
181 if (idx < children.size() - 1) {
182 children[idx] = std::move(children.back());
183 children[idx]->indexInParent = idx;
184 }
185 children.pop_back();
186 child->parent = nullptr;
187 }
188
190 if (parent != nullptr) {
191 worldMatrix = parent->getWorldMatrix() * getLocalTransform().matrix;
192 } else {
194 }
195
196 // Sync to ECS for cache-friendly rendering reads
197 registry->get_or_emplace<Ecs::WorldTransform>(entity).matrix = worldMatrix;
198
199 if (!disableCaching) {
201 }
202 }
203
204 const glm::mat4 & SceneNode::getWorldMatrix() const {
207 } else if (disableCaching) {
209 }
210 return worldMatrix;
211 }
212
213 bool SceneNode::isRoot() const {
214 return parent == nullptr;
215 }
216
217 std::vector<std::weak_ptr<SceneNode>> SceneNode::getChildren() const {
218 std::vector<std::weak_ptr<SceneNode>> weakChildren;
219 weakChildren.reserve(children.size());
220 for (const auto& child : children) {
221 weakChildren.push_back(child);
222 }
223 return weakChildren;
224 }
225
227 return registry->any_of<Ecs::TransformDirty>( entity );
228 }
229
231 registry->emplace_or_replace<Ecs::TransformDirty>( entity );
232 registry->emplace_or_replace<Ecs::TransformDirtyRenderer>( entity );
233 for (const auto& child : children) {
234 child->markDirtyRecursive();
235 }
236 }
237
238 RootNode::RootNode(entt::registry& registry) : SceneNode(registry, false) {
239 }
240
241 SceneGraph::SceneGraph(const std::shared_ptr<SceneNode> &root) : root(root) {
242
243 }
244
245 std::shared_ptr<SceneNode> SceneGraph::createNode(const Ecs::LocalTransform& transform, std::shared_ptr<SceneNode> parent,
246 bool disableCaching) {
247 const std::shared_ptr<SceneNode> node = NodeFactory::createNode( parent, disableCaching );
248 node->setWorldModelMatrix(transform.matrix);
249 return node;
250 }
251
252 std::shared_ptr<SceneNode> NodeFactory::createNode(const std::shared_ptr<SceneNode> &parent,
253 const bool disableCaching) {
254 if (!parent) {
255 throw std::invalid_argument("Parent node cannot be null when creating a new node");
256 }
257 auto& registry = Ecs::RegistryManager::get();
258 auto node = std::shared_ptr<SceneNode>(new SceneNode(registry, disableCaching));
259 parent->addChild(node);
260 node->registerWithEcs();
261 return node;
262 }
263
264 std::vector<std::shared_ptr<SceneNode>> NodeFactory::createNodes(const std::shared_ptr<SceneNode> &parent,
265 size_t count, bool disableCaching) {
266 if (!parent) {
267 throw std::invalid_argument("Parent node cannot be null when creating nodes");
268 }
269 std::vector<std::shared_ptr<SceneNode>> nodes;
270 nodes.reserve(count);
271 auto& registry = Ecs::RegistryManager::get();
272 for (size_t i = 0; i < count; ++i) {
273 nodes.push_back(std::shared_ptr<SceneNode>(new SceneNode(registry, disableCaching)));
274 }
275 parent->addChildren(nodes);
276 return nodes;
277 }
278}
static entt::registry & get()
Gets the registry for all components.
static void setScale(Ecs::LocalTransform &transform, const glm::vec3 &newScale)
static glm::vec3 getPosition(const glm::mat4 &matrix)
static void setPosition(Ecs::LocalTransform &transform, const glm::vec3 &newPosition)
static glm::quat getRotation(const glm::mat4 &matrix)
static glm::vec3 getScale(const glm::mat4 &matrix)
static void setRotation(Ecs::LocalTransform &transform, const glm::vec3 &newRotation)
static std::shared_ptr< SceneNode > createNode(const std::shared_ptr< SceneNode > &parent, const bool disableCaching=false)
Creates a new SceneNode with the specified parent.
static std::vector< std::shared_ptr< SceneNode > > createNodes(const std::shared_ptr< SceneNode > &parent, size_t count, bool disableCaching=false)
Creates multiple nodes under the same parent.
RootNode(entt::registry &registry)
SceneGraph(const std::shared_ptr< SceneNode > &root)
Constructs a new Scene Graph object, initializing the root node.
std::shared_ptr< SceneNode > createNode(const Ecs::LocalTransform &transform, std::shared_ptr< SceneNode > parent, bool disableCaching=false)
Creates a node which tells you where an object is in the scene.
std::shared_ptr< SceneNode > root
Definition SceneGraph.h:268
Represents a node in the scene graph, containing information about its position, rotation,...
Definition SceneGraph.h:24
entt::entity entity
Definition SceneGraph.h:240
std::vector< std::shared_ptr< SceneNode > > children
Definition SceneGraph.h:237
void removeChild(const std::shared_ptr< SceneNode > &child)
Removes a single child from this node.
std::vector< std::weak_ptr< SceneNode > > getChildren() const
Get a list of all children of this node.
void setWorldScale(const glm::vec3 &newScale)
sets the scale for this node
void setWorldPosition(const glm::vec3 &newLocation)
Sets the world position of the scene node. This will calculate the corresponding local position based...
bool isWorldMatrixDirty() const
Checks if the world matrix has to be recalculated.
void setWorldRotation(const glm::vec3 &newRotation)
Sets the world rotation of this node with euler angles.
void addChild(const std::shared_ptr< SceneNode > &newChild)
Adds a child node to this node.
void clearChildren()
Removes all children from this node.
bool isRoot() const
Checks if this node is the root node.
const glm::mat4 & getWorldMatrix() const
get the world matrix as a raw glm matrix
void updateWorldMatrix() const
void rotateWorld(const glm::vec3 &deltaRotation)
Applies an incremental rotation to the current world rotation using quaternion multiplication....
void markDirtyRecursive()
Marks this node and its children as dirty.
void setLocalModelMatrix(const glm::mat4 &newModelMatrix)
Overwrites all components of the transform.
SceneNode(entt::registry &registry, bool disableCaching=false)
Constructs a new Scene Node object.
entt::registry * registry
Definition SceneGraph.h:241
Ecs::LocalTransform & getLocalTransform()
Gets the local transform of the scene node. The local transform is relative to the parent node.
std::shared_ptr< SceneNode > parent
Definition SceneGraph.h:236
void setWorldModelMatrix(const glm::mat4 &newModelMatrix)
Overwrites all components of this transform.
void addChildren(std::vector< std::shared_ptr< SceneNode > > newChildren)
adds new children to this node
entt::entity getEntity() const
Gets the entity associated with this scene node.
Log category system implementation.
glm::mat4 matrix
Definition EcsData.h:303
A struct which allows the engine to find out which SceneNode needs to propagate a dirty flag down the...
Definition EcsData.h:130
Tag for transforms that need GPU upload. Separate from TransformDirty because the renderer clears thi...
Definition EcsData.h:123
Tag for dirty transforms (used by scene graph synchronization)
Definition EcsData.h:113