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,
.position = global_transform.translation,
.projection = CAMERA_PERSPECTIVE,
.target = Vector3Add(global_transform.translation, Vector3Scale(forward, 1000.f)),
.up = (Vector3){mat.m4, mat.m5, mat.m6}
.target = Vector3Add(global_transform.translation, forward),
.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.
static
void Internal_SceneRemoveNode(Scene *self, SceneNode *node) {
@ -73,14 +90,6 @@ void Internal_SceneAddNode(Scene *self, SceneNode *node) {
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) {
// initialize memory
SceneNode *self = new(SceneNode);
@ -173,5 +182,5 @@ void DestroyScene(Scene *self) {
void SceneTick(Scene* self, double 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() {
TransformNode *self = new(TransformNode);
self->dirty_bit = 0x0;
self->dirty_bit = 1;
self->node = NULL;
self->parent_transformable = tc_null(Transformable);
self->global_transform = TransformIdentity();

View file

@ -25,7 +25,7 @@ Vector3 TransformDirection(Transform self, Vector3 local_direction) {
}
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) {
@ -54,11 +54,11 @@ Vector3 InverseTransformDirection(Transform self, Vector3 global_direction) {
}
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) {
return QuaternionDivide(self.rotation, global_rotation);
return QuaternionMultiply(QuaternionInvert(self.rotation), global_rotation);
}
Transform InverseTransformTransform(Transform self, Transform other) {

View file

@ -17,6 +17,7 @@ typedef struct ITransformable {
void (*const set_global_transform)(void*, Transform);
void (*const force_update)(void*);
unsigned char (*const get_dirty_bit)(void*);
void (*const clear_dirty_bit)(void*);
struct Transformable (*const get_parent_transformable)(void*);
} ITransformable;
@ -58,26 +59,29 @@ extern Transform InverseTransformTransform(Transform self, Transform other);
//! Macro implements the interface functions itself to ensure consistent behaviour.
#define impl_Transformable_for(T)\
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 void T##_set_global_transform_GEN_(T* self, Transform value) {\
self->global_transform = value;\
if(tc_is_null(self->parent_transformable)) {\
self->transform = value;\
} 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);\
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) {\
if(tc_is_null(self->parent_transformable)) {\
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 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; }\
Transformable T##_as_Transformable(T *x) {\
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_,\
.force_update = (void (*const)(void*)) T##_force_update_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_\
};\
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() {
SceneNode *root = CreateTransformNode();
SceneNode *model_parent = CreateTransformNode();
SceneNodeAddChild(root, model_parent);
SceneNode *camera_parent = CreateTransformNode();
SceneNodeAddChild(model_parent, camera_parent);
// set camera parent location
Transformable transformable = TC_CAST(camera_parent->entity, Transformable);
Transform transform = transformable.tc->get_transform(transformable.data);
transform.translation = (Vector3){0.f, 10.f, -10.f};
transform.rotation = QuaternionFromEuler(45.f * DEG2RAD, 0.f, 0.f);
transformable.tc->set_transform(transformable.data, transform);
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, CreateTestObject());
return CreateScene(root);