Vulkan Schnee 0.0.1
High-performance rendering engine
Loading...
Searching...
No Matches
Transform.cpp
Go to the documentation of this file.
2
4
5#include <glm/ext/matrix_transform.hpp>
6#include <glm/glm.hpp>
7#include <glm/gtc/quaternion.hpp>
8#include <glm/gtx/matrix_decompose.hpp>
9#include <glm/gtx/quaternion.hpp>
10#include <iostream>
11#include <tiny_gltf.h>
12
13#include "Engine/Ecs/EcsData.h"
15
16namespace EngineCore {
17 Transform::Transform() = default;
18
19 Transform::Transform(glm::vec3 location)
20 {
21 setLocation(location);
22 }
23
24 Transform::Transform(glm::vec3 location, glm::vec3 rotation) {
25 setLocation(location);
26 setRotation(rotation);
27 }
28
29 Transform::Transform(glm::vec3 location, glm::vec3 rotation, glm::vec3 scale)
30 {
31 setLocation(location);
32 setRotation(rotation);
33 setScale(scale);
34 }
35
36 Transform::Transform(glm::mat4 matrix)
37 {
38 overrideMatrix(matrix);
39 markDirty();
40 }
41
42 Transform::Transform(nlohmann::json object) {
44 }
45
46 Transform::~Transform() = default;
47
48 /*
49 * TODO: implement instead of generateTransformComponentsFromMatrix
50 Max Sander
51 // taken from https://stackoverflow.com/a/68323550 :
52 static void decomposeMatrix(const glm::mat4& m, glm::vec3& pos, glm::quat& rot, glm::vec3& scale)
53 {
54 pos = m[3];
55 for(int i = 0; i < 3; i++)
56 scale[i] = glm::length(glm::vec3(m[i]));
57 const glm::mat3 rotMtx(
58 glm::vec3(m[0]) / scale[0],
59 glm::vec3(m[1]) / scale[1],
60 glm::vec3(m[2]) / scale[2]);
61 rot = glm::quat_cast(rotMtx);
62 }
63 */
64
66 Transform::MatrixTransformComponent transform_component = {};
67 const bool success = glm::decompose(matrix,
68 transform_component.scale,
69 transform_component.rotation,
70 transform_component.translation,
71 transform_component.skew,
72 transform_component.perspective);
73 if (!success) {
74 std::cerr << "Failed to decompose transformation matrix.\n";
75 // Handle decomposition failure as needed
76 }
77 return transform_component;
78 }
79
84
85 glm::mat4 Transform::getInverse() const {
87 cachedInverse = glm::inverse(transform);
88 inverseNeedsUpdate = false;
89 }
90 return cachedInverse;
91 }
92
101
102
103
104 glm::vec3 Transform::getLocation() const {
105 return getComponents().translation;
106 }
107
108 // Set Location
109 void Transform::setLocation(const glm::vec3& newLocation) {
110 // Directly set the translation part of the matrix (last column)
111 transform[3] = glm::vec4(newLocation, 1.0f);
112 markDirty();
113 }
114
115 glm::vec3 Transform::getRotation() const {
116 return degrees(glm::eulerAngles(getComponents().rotation));
117 }
118
119 // Set Rotation using Quaternion
120 void Transform::setRotationQuat(glm::quat newQuaternion) {
121 // Extract current translation and scale
122 const MatrixTransformComponent currentComponents = getComponents();
123 const glm::vec3 currentTranslation = currentComponents.translation;
124 const glm::vec3 currentScale = currentComponents.scale;
125
126 // Create rotation matrix from quaternion
127 const glm::mat4 rotationMatrix = glm::toMat4(newQuaternion);
128
129 // Recompose the transformation matrix
130 transform = glm::mat4(1.0f);
131 transform = glm::translate(transform, currentTranslation);
132 transform *= rotationMatrix;
133 transform = glm::scale(transform, currentScale);
134
135 markDirty();
136 }
137
138 glm::quat Transform::getRotationQuat() const {
139 return getComponents().rotation;
140 }
141
142 // Set Rotation using Euler Angles (Degrees)
143 void Transform::setRotation(const glm::vec3& newRotationEuler) {
144 // Convert Euler angles (in degrees) to radians and then to a quaternion
145 glm::quat rotationQuat = glm::quat(glm::radians(newRotationEuler));
146
147 // Extract current translation and scale
148 MatrixTransformComponent currentComponents = getComponents();
149 glm::vec3 currentTranslation = currentComponents.translation;
150 glm::vec3 currentScale = currentComponents.scale;
151
152 // Create rotation matrix from quaternion
153 glm::mat4 rotationMatrix = glm::toMat4(rotationQuat);
154
155 // Recompose the transformation matrix
156 transform = glm::mat4(1.0f);
157 transform = glm::translate(transform, currentTranslation);
158 transform *= rotationMatrix;
159 transform = glm::scale(transform, currentScale);
160
161 markDirty();
162 }
163
164 glm::vec3 Transform::getScale() const {
165 return getComponents().scale;
166 }
167
168 // Set Scale
169 void Transform::setScale(const glm::vec3& newScale) {
170 // Extract current translation and rotation
171 MatrixTransformComponent currentComponents = getComponents();
172 glm::vec3 currentTranslation = currentComponents.translation;
173 glm::quat currentRotation = currentComponents.rotation;
174
175 // Create rotation matrix from quaternion
176 glm::mat4 rotationMatrix = glm::toMat4(currentRotation);
177
178 // Recompose the transformation matrix with the new scale
179 transform = glm::mat4(1.0f);
180 transform = glm::translate(transform, currentTranslation);
181 transform *= rotationMatrix;
182 transform = glm::scale(transform, newScale);
183
184 markDirty();
185 }
186
187 glm::mat4 Transform::toMatrix() const {
188#ifdef ENABLE_TRACY
190#endif
191 if (isTransformDirty()) {
193 }
194 return transform;
195 }
196
198
199 // first apply the parent transform
200 const glm::mat4 parentMatrix = parent.toMatrix();
201 const glm::mat4 localMatrix = this->toMatrix();
202
203 // calculate world matrix
204 const glm::mat4 worldMatrix = parentMatrix * localMatrix;
205
206 return matrixToTransform(worldMatrix);
207 }
208
209 Transform Transform::matrixToTransform(glm::mat4 matrix) const {
211
213 transform.setLocation(transform_component.translation);
214 transform.setRotation(glm::degrees(glm::eulerAngles(transform_component.rotation)));
215 transform.setScale(transform_component.scale);
216
217 return transform;
218 }
219
220 void Transform::overrideMatrix(glm::mat4 matrix) {
221 transform = matrix;
222 }
223
224 std::string Transform::toString() const {
225 return "((x:" + std::to_string(getLocation().x) + ",y:" + std::to_string(getLocation().y) + ",z:" + std::to_string(getLocation().z) + ")" + "," +
226 "(x:" + std::to_string(getRotation().x) + ",y:" + std::to_string(getRotation().y) + ",z:" + std::to_string(getRotation().z) + ")" + "," +
227 "(x:" + std::to_string(getScale().x) + ",y:" + std::to_string(getScale().y) + ",z:" + std::to_string(getScale().z) + "))";
228 }
229
230 void Transform::Serialize(nlohmann::json &archive) {
232 GlmSerialize::Serialize(archive[serial::LOCATION], this->getComponents().translation);
233 GlmSerialize::Serialize(archive[serial::ROTATION], this->getComponents().rotation);
234 GlmSerialize::Serialize(archive[serial::SCALE], this->getComponents().scale);
235 }
236
237 void Transform::Deserialize(nlohmann::json &archive) {
238
239 glm::vec3 location;
241 setLocation(location);
242
243 glm::quat rotation;
245 setRotationQuat(rotation);
246
247 glm::vec3 scale;
249 setScale(scale);
250
252 }
253
254 std::string Transform::getClassName() const {
255 return typeid(*this).name();
256 }
257
259 {
260 return isDirty;
261 }
262
264 {
265 return Transform(this->toMatrix() * other.toMatrix());
266 }
267
268 void Transform::markDirty() const {
270 isDirty = true;
271 inverseNeedsUpdate = true;
272 }
273
274 void Transform::markClean() const {
275 isDirty = false;
276 }
277} // namespace EngineCore
278
279namespace Ecs
280{
282 {
283 MatrixTransformComponent transform_component = {};
284 const bool success = glm::decompose(matrix,
285 transform_component.scale,
286 transform_component.rotation,
287 transform_component.translation,
288 transform_component.skew,
289 transform_component.perspective);
290 if (!success) {
291 std::cerr << "Failed to decompose transformation matrix.\n";
292 // Handle decomposition failure as needed
293 }
294 return transform_component;
295 }
296
297 glm::vec3 TransformOperators::getPosition(const glm::mat4& matrix)
298 {
299 return glm::vec3(matrix[3]);
300 }
301
302 glm::quat TransformOperators::getRotation(const glm::mat4& matrix)
303 {
304 glm::mat3 rotMat(
305 glm::normalize(glm::vec3(matrix[0])),
306 glm::normalize(glm::vec3(matrix[1])),
307 glm::normalize(glm::vec3(matrix[2]))
308 );
309 return glm::quat_cast(rotMat);
310 }
311
312 glm::vec3 TransformOperators::getRotationEuler( const glm::mat4 & matrix )
313 {
314 return glm::degrees(glm::eulerAngles(getRotation(matrix)));
315 }
316
317 glm::vec3 TransformOperators::getScale(const glm::mat4& matrix)
318 {
319 return glm::vec3(
320 glm::length(glm::vec3(matrix[0])),
321 glm::length(glm::vec3(matrix[1])),
322 glm::length(glm::vec3(matrix[2]))
323 );
324 }
325
326 void TransformOperators::setPosition( Ecs::LocalTransform & transform, const glm::vec3 & newPosition )
327 {
328 transform.matrix[3] = glm::vec4(newPosition, 1.0f);
329 }
330
331 void TransformOperators::setRotation( Ecs::LocalTransform & transform, const glm::vec3 & newRotation )
332 {
333 setRotation(transform, glm::quat(glm::radians(newRotation)));
334 }
335
336 void TransformOperators::setRotation( Ecs::LocalTransform & transform, const glm::quat & newQuaternion )
337 {
338 // Extract current scale from column lengths
339 glm::vec3 currentScale;
340 currentScale.x = glm::length(glm::vec3(transform.matrix[0]));
341 currentScale.y = glm::length(glm::vec3(transform.matrix[1]));
342 currentScale.z = glm::length(glm::vec3(transform.matrix[2]));
343
344 // Get rotation as mat3, apply scale to each column
345 glm::mat3 rotMat = glm::mat3_cast(newQuaternion);
346
347 transform.matrix[0] = glm::vec4(rotMat[0] * currentScale.x, 0.f);
348 transform.matrix[1] = glm::vec4(rotMat[1] * currentScale.y, 0.f);
349 transform.matrix[2] = glm::vec4(rotMat[2] * currentScale.z, 0.f);
350 // column 3 (translation) remains untouched
351 }
352
353 void TransformOperators::setScale( Ecs::LocalTransform & transform, const glm::vec3 & newScale )
354 {
355 transform.matrix[0] = glm::vec4(glm::normalize(glm::vec3(transform.matrix[0])) * newScale.x, 0.f);
356 transform.matrix[1] = glm::vec4(glm::normalize(glm::vec3(transform.matrix[1])) * newScale.y, 0.f);
357 transform.matrix[2] = glm::vec4(glm::normalize(glm::vec3(transform.matrix[2])) * newScale.z, 0.f);
358 }
359} // namespace Ecs
360
#define TRACY_ZONE_SCOPED_FUNCTION
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 MatrixTransformComponent extractComponents(const glm::mat4 &matrix)
static glm::vec3 getRotationEuler(const glm::mat4 &matrix)
static void deserialize(nlohmann::json &archive, glm::vec3 &vector)
static void Serialize(nlohmann::json &archive, const glm::vec3 &vector)
virtual void Serialize(nlohmann::json &archive)
static std::string LOCATION
Definition Transform.h:114
static std::string SCALE
Definition Transform.h:116
static std::string ROTATION
Definition Transform.h:115
std::string getClassName() const override
glm::quat getRotationQuat() const
glm::vec3 getRotation() const
glm::mat4 toMatrix() const
bool isTransformDirty() const
void setLocation(const glm::vec3 &newLocation)
Transform matrixToTransform(glm::mat4 matrix) const
void setScale(const glm::vec3 &newScale)
std::string toString() const
Transform operator*(const Transform &other) const
void Serialize(nlohmann::json &archive) override
void regenerateTransformComponents() const
Definition Transform.cpp:80
void markDirty() const
void overrideMatrix(glm::mat4 matrix)
glm::mat4 getInverse() const
Definition Transform.cpp:85
void setRotation(const glm::vec3 &newRotationEuler)
Transform combine(const Transform &parent) const
MatrixTransformComponent getComponents() const
Definition Transform.cpp:93
glm::mat4 cachedInverse
Definition Transform.h:74
void setRotationQuat(glm::quat newQuaternion)
Transform::MatrixTransformComponent transform_components
Definition Transform.h:66
void Deserialize(nlohmann::json &archive) override
glm::vec3 getScale() const
MatrixTransformComponent generateTransformComponentsFromMatrix(const glm::mat4 &matrix) const
Definition Transform.cpp:65
glm::vec3 getLocation() const
void markClean() const
Data structs for the Entity Component System.
Log category system implementation.
glm::mat4 matrix
Definition EcsData.h:303