fix: fixed transform updating and scale transformation

This commit is contained in:
Sara 2024-09-17 14:10:30 +02:00
parent 0661622b9c
commit 86e64f82ed
6 changed files with 39 additions and 23 deletions

View file

@ -54,7 +54,7 @@ Camera3D CameraNodeGetCamera(CameraNode *self) {
.fovy = 90, .fovy = 90,
.position = global_transform.translation, .position = global_transform.translation,
.projection = CAMERA_PERSPECTIVE, .projection = CAMERA_PERSPECTIVE,
.target = Vector3Add(global_transform.translation, Vector3Scale(forward, 1000.f)), .target = Vector3Add(global_transform.translation, forward),
.up = (Vector3){mat.m4, mat.m5, mat.m6} .up = MATRIX_UP(mat)
}; };
} }

View file

@ -28,6 +28,23 @@ void Internal_SceneNodeUpdateTransform(SceneNode *self) {
} }
} }
//! Update global transforms of all children recursively
static
void Internal_SceneNodeUpdateTransformRecursive(SceneNode *self, bool is_dirty) {
if(TC_MIRRORS(self->entity, Transformable)) {
Transformable transformable = TC_CAST(self->entity, Transformable);
is_dirty = is_dirty || transformable.tc->get_dirty_bit(transformable.data);
if(is_dirty) {
transformable.tc->force_update(transformable.data);
transformable.tc->clear_dirty_bit(transformable.data);
}
} else {
is_dirty = false;
}
list_foreach(SceneNode **,child, &self->children)
Internal_SceneNodeUpdateTransformRecursive(*child, is_dirty);
}
//! Remove a single node (does NOT recurse to children children) from this scene. //! Remove a single node (does NOT recurse to children children) from this scene.
static static
void Internal_SceneRemoveNode(Scene *self, SceneNode *node) { void Internal_SceneRemoveNode(Scene *self, SceneNode *node) {
@ -73,14 +90,6 @@ void Internal_SceneAddNode(Scene *self, SceneNode *node) {
Internal_SceneAddNode(self, *child); Internal_SceneAddNode(self, *child);
} }
//! Update global transforms of all children recursively
static
void Internal_SceneNodeUpdateTransformRecursive(SceneNode *self) {
Internal_SceneNodeUpdateTransform(self);
list_foreach(SceneNode **,child, &self->children)
Internal_SceneNodeUpdateTransformRecursive(*child);
}
SceneNode *CreateSceneNode(SceneNodeEntity entity) { SceneNode *CreateSceneNode(SceneNodeEntity entity) {
// initialize memory // initialize memory
SceneNode *self = new(SceneNode); SceneNode *self = new(SceneNode);
@ -173,5 +182,5 @@ void DestroyScene(Scene *self) {
void SceneTick(Scene* self, double delta_time) { void SceneTick(Scene* self, double delta_time) {
Internal_SceneNodeTick(self->root, delta_time); Internal_SceneNodeTick(self->root, delta_time);
Internal_SceneNodeUpdateTransformRecursive(self->root); Internal_SceneNodeUpdateTransformRecursive(self->root, false);
} }

View file

@ -20,7 +20,7 @@ impl_SceneNodeEntity_for(TransformNode,
SceneNode *CreateTransformNode() { SceneNode *CreateTransformNode() {
TransformNode *self = new(TransformNode); TransformNode *self = new(TransformNode);
self->dirty_bit = 0x0; self->dirty_bit = 1;
self->node = NULL; self->node = NULL;
self->parent_transformable = tc_null(Transformable); self->parent_transformable = tc_null(Transformable);
self->global_transform = TransformIdentity(); self->global_transform = TransformIdentity();

View file

@ -25,7 +25,7 @@ Vector3 TransformDirection(Transform self, Vector3 local_direction) {
} }
Vector3 TransformScale(Transform self, Vector3 local_scale) { Vector3 TransformScale(Transform self, Vector3 local_scale) {
return Vector3Multiply(self.scale, TransformDirection(self, local_scale)); return Vector3Multiply(local_scale, self.scale);
} }
Quaternion TransformRotation(Transform self, Quaternion local_rotation) { Quaternion TransformRotation(Transform self, Quaternion local_rotation) {
@ -54,11 +54,11 @@ Vector3 InverseTransformDirection(Transform self, Vector3 global_direction) {
} }
Vector3 InverseTransformScale(Transform self, Vector3 global_scale) { Vector3 InverseTransformScale(Transform self, Vector3 global_scale) {
return Vector3Multiply(Vector3Invert(self.scale), InverseTransformDirection(self, global_scale)); return Vector3Multiply(global_scale, Vector3Invert(self.scale));
} }
Quaternion InverseTransformRotation(Transform self, Quaternion global_rotation) { Quaternion InverseTransformRotation(Transform self, Quaternion global_rotation) {
return QuaternionDivide(self.rotation, global_rotation); return QuaternionMultiply(QuaternionInvert(self.rotation), global_rotation);
} }
Transform InverseTransformTransform(Transform self, Transform other) { Transform InverseTransformTransform(Transform self, Transform other) {

View file

@ -17,6 +17,7 @@ typedef struct ITransformable {
void (*const set_global_transform)(void*, Transform); void (*const set_global_transform)(void*, Transform);
void (*const force_update)(void*); void (*const force_update)(void*);
unsigned char (*const get_dirty_bit)(void*); unsigned char (*const get_dirty_bit)(void*);
void (*const clear_dirty_bit)(void*);
struct Transformable (*const get_parent_transformable)(void*); struct Transformable (*const get_parent_transformable)(void*);
} ITransformable; } ITransformable;
@ -58,26 +59,29 @@ extern Transform InverseTransformTransform(Transform self, Transform other);
//! Macro implements the interface functions itself to ensure consistent behaviour. //! Macro implements the interface functions itself to ensure consistent behaviour.
#define impl_Transformable_for(T)\ #define impl_Transformable_for(T)\
static Transform T##_get_transform_GEN_(T* self) { return self->transform; }\ static Transform T##_get_transform_GEN_(T* self) { return self->transform; }\
static void T##_set_transform_GEN_(T* self, Transform value) { self->transform = value; self->dirty_bit |= 1u; } /*!< sets dirty bit */\ static void T##_set_transform_GEN_(T* self, Transform value) { self->transform = value; self->dirty_bit = 1; } /*!< sets dirty bit */\
static Transform T##_get_global_transform_GEN_(T* self) { return self->global_transform; }\ static Transform T##_get_global_transform_GEN_(T* self) { return self->global_transform; }\
static void T##_set_global_transform_GEN_(T* self, Transform value) {\ static void T##_set_global_transform_GEN_(T* self, Transform value) {\
self->global_transform = value;\
if(tc_is_null(self->parent_transformable)) {\ if(tc_is_null(self->parent_transformable)) {\
self->transform = value;\ self->transform = value;\
} else {\ } else {\
if(self->parent_transformable.tc->get_dirty_bit(self->parent_transformable.data))\
self->parent_transformable.tc->force_update(self->parent_transformable.data);\
Transform parent_global = self->parent_transformable.tc->get_global_transform(self->parent_transformable.data);\ Transform parent_global = self->parent_transformable.tc->get_global_transform(self->parent_transformable.data);\
self->transform = InverseTransformTransform(parent_global, value); /* Use parent transform to transform the local transform to the new global transform */\ self->transform = InverseTransformTransform(parent_global, value); /* Use parent transform to transform the local transform to the new global transform */\
self->dirty_bit = 1;\
}\ }\
}\ }\
static void T##_force_update_GEN_(T *self) {\ static void T##_force_update_GEN_(T *self) {\
if(tc_is_null(self->parent_transformable)) {\ if(tc_is_null(self->parent_transformable)) {\
self->global_transform = self->transform;\ self->global_transform = self->transform;\
return;\ } else {\
Transform parent_global = self->parent_transformable.tc->get_global_transform(self->parent_transformable.data);\
self->global_transform = TransformTransform(parent_global, self->transform);\
}\ }\
Transform parent_global = self->parent_transformable.tc->get_global_transform(self->parent_transformable.data);\
self->global_transform = TransformTransform(parent_global, self->transform);\
}\ }\
static unsigned char T##_get_dirty_bit_GEN_(T *self) { return self->dirty_bit; }\ static unsigned char T##_get_dirty_bit_GEN_(T *self) { return self->dirty_bit; }\
static void T##_clear_dirty_bit_GEN_(T *self) { self->dirty_bit = 0; }\
static Transformable T##_get_parent_transformable_GEN_(T *self) { return self->parent_transformable; }\ static Transformable T##_get_parent_transformable_GEN_(T *self) { return self->parent_transformable; }\
Transformable T##_as_Transformable(T *x) {\ Transformable T##_as_Transformable(T *x) {\
static ITransformable const tc = {\ static ITransformable const tc = {\
@ -87,6 +91,7 @@ Transformable T##_as_Transformable(T *x) {\
.set_global_transform = (void (*const)(void*,Transform)) T##_set_global_transform_GEN_,\ .set_global_transform = (void (*const)(void*,Transform)) T##_set_global_transform_GEN_,\
.force_update = (void (*const)(void*)) T##_force_update_GEN_,\ .force_update = (void (*const)(void*)) T##_force_update_GEN_,\
.get_dirty_bit = (unsigned char (*const)(void*)) T##_get_dirty_bit_GEN_,\ .get_dirty_bit = (unsigned char (*const)(void*)) T##_get_dirty_bit_GEN_,\
.clear_dirty_bit = (void (*const)(void*)) T##_clear_dirty_bit_GEN_,\
.get_parent_transformable = (Transformable (*const)(void*)) T##_get_parent_transformable_GEN_\ .get_parent_transformable = (Transformable (*const)(void*)) T##_get_parent_transformable_GEN_\
};\ };\
return (Transformable){ .tc = &tc, .data = x, .scene_node_entity = T##_as_SceneNodeEntity(x).tc, .mirror = T##_as_Mirror(x).tc };\ return (Transformable){ .tc = &tc, .data = x, .scene_node_entity = T##_as_SceneNodeEntity(x).tc, .mirror = T##_as_Mirror(x).tc };\

View file

@ -10,17 +10,19 @@
Scene *CreateInitialScene() { Scene *CreateInitialScene() {
SceneNode *root = CreateTransformNode(); SceneNode *root = CreateTransformNode();
SceneNode *model_parent = CreateTransformNode();
SceneNodeAddChild(root, model_parent);
SceneNode *camera_parent = CreateTransformNode(); SceneNode *camera_parent = CreateTransformNode();
SceneNodeAddChild(model_parent, camera_parent);
// set camera parent location // set camera parent location
Transformable transformable = TC_CAST(camera_parent->entity, Transformable); Transformable transformable = TC_CAST(camera_parent->entity, Transformable);
Transform transform = transformable.tc->get_transform(transformable.data); Transform transform = transformable.tc->get_transform(transformable.data);
transform.translation = (Vector3){0.f, 10.f, -10.f}; transform.translation = (Vector3){0.f, 10.f, -10.f};
transform.rotation = QuaternionFromEuler(45.f * DEG2RAD, 0.f, 0.f); transform.rotation = QuaternionFromEuler(45.f * DEG2RAD, 0.f, 0.f);
transformable.tc->set_transform(transformable.data, transform); transformable.tc->set_transform(transformable.data, transform);
SceneNodeAddChild(camera_parent, CreateCameraNode()); SceneNodeAddChild(camera_parent, CreateCameraNode());
SceneNode *model_parent = CreateTransformNode();
SceneNodeAddChild(root, model_parent);
SceneNodeAddChild(model_parent, camera_parent);
SceneNodeAddChild(model_parent, CreateMeshRenderEntity("spacefighter.glb")); SceneNodeAddChild(model_parent, CreateMeshRenderEntity("spacefighter.glb"));
SceneNodeAddChild(model_parent, CreateTestObject()); SceneNodeAddChild(model_parent, CreateTestObject());
return CreateScene(root); return CreateScene(root);