fix: fixed transform updating and scale transformation
This commit is contained in:
parent
0661622b9c
commit
86e64f82ed
|
@ -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)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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 };\
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in a new issue