feat: scene graph - node tree + transform inheritance
- SceneNode: position/rotation(scale) + parent/child hierarchy - World matrix: local = translate * rotate * scale, world = parent.world * local - Euler/Quaternion rotation support - Dirty flag propagation for efficient updates - Scene init/find/create/destroy operations
This commit is contained in:
1 parent
2947ca3b9d
commit
d15a3947ab
3 files changed
+304
No files matched your search
@@ -24,6 +24,7 @@ set(ENGINE_SOURCES
|
||||
Engine/Rendering/mesh.c
|
||||
Engine/Rendering/texture.c
|
||||
Engine/Rendering/camera.c
|
||||
Engine/Scene/scene_graph.c
|
||||
Engine/ECS/world.c
|
||||
Engine/Input/input.c
|
||||
Engine/Physics/physics.c
|
||||
|
||||
@@ -0,0 +1,226 @@
|
||||
// ============================================================================
|
||||
// scene_graph.c - 场景图实现
|
||||
// ============================================================================
|
||||
|
||||
#include "scene_graph.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
void scene_init(Scene* scene) {
|
||||
memset(scene, 0, sizeof(Scene));
|
||||
scene->next_id = 1;
|
||||
// 创建根节点
|
||||
scene->root = &scene->nodes[0];
|
||||
memset(scene->root, 0, sizeof(SceneNode));
|
||||
scene->root->id = scene->next_id++;
|
||||
strcpy(scene->root->name, "Root");
|
||||
scene->root->scale = (Vec3){1, 1, 1};
|
||||
scene->root->visible = 1;
|
||||
scene->root->dirty = 1;
|
||||
scene->node_count = 1;
|
||||
}
|
||||
|
||||
void scene_destroy(Scene* scene) {
|
||||
// 清空子节点引用 (不释放静态数组)
|
||||
for (int i = 0; i < scene->node_count; i++) {
|
||||
scene->nodes[i].parent = NULL;
|
||||
scene->nodes[i].child_count = 0;
|
||||
}
|
||||
scene->node_count = 0;
|
||||
}
|
||||
|
||||
SceneNode* scene_create_node(Scene* scene, const char* name) {
|
||||
if (scene->node_count >= MAX_NODES) return NULL;
|
||||
SceneNode* node = &scene->nodes[scene->node_count++];
|
||||
memset(node, 0, sizeof(SceneNode));
|
||||
node->id = scene->next_id++;
|
||||
strncpy(node->name, name, 63);
|
||||
node->scale = (Vec3){1, 1, 1};
|
||||
node->visible = 1;
|
||||
node->dirty = 1;
|
||||
return node;
|
||||
}
|
||||
|
||||
void scene_destroy_node(Scene* scene, SceneNode* node) {
|
||||
if (!node || node == scene->root) return;
|
||||
// 移除子引用
|
||||
if (node->parent) {
|
||||
scene_remove_child(node->parent, node);
|
||||
}
|
||||
// 递归销毁子节点
|
||||
while (node->child_count > 0) {
|
||||
scene_destroy_node(scene, node->children[0]);
|
||||
}
|
||||
node->id = 0; // 标记为空
|
||||
}
|
||||
|
||||
SceneNode* scene_find_node(Scene* scene, int id) {
|
||||
for (int i = 0; i < scene->node_count; i++) {
|
||||
if (scene->nodes[i].id == id) return &scene->nodes[i];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SceneNode* scene_find_by_name(Scene* scene, const char* name) {
|
||||
for (int i = 0; i < scene->node_count; i++) {
|
||||
if (strcmp(scene->nodes[i].name, name) == 0) return &scene->nodes[i];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void scene_set_parent(SceneNode* child, SceneNode* parent) {
|
||||
if (!child || !parent || child == parent) return;
|
||||
if (child->parent) scene_remove_child(child->parent, child);
|
||||
child->parent = parent;
|
||||
if (parent->child_count < MAX_CHILDREN) {
|
||||
parent->children[parent->child_count++] = child;
|
||||
}
|
||||
child->dirty = 1;
|
||||
}
|
||||
|
||||
void scene_add_child(SceneNode* parent, SceneNode* child) {
|
||||
scene_set_parent(child, parent);
|
||||
}
|
||||
|
||||
void scene_remove_child(SceneNode* parent, SceneNode* child) {
|
||||
if (!parent || !child) return;
|
||||
for (int i = 0; i < parent->child_count; i++) {
|
||||
if (parent->children[i] == child) {
|
||||
parent->children[i] = parent->children[parent->child_count - 1];
|
||||
parent->child_count--;
|
||||
child->parent = NULL;
|
||||
child->dirty = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void scene_set_position(SceneNode* node, float x, float y, float z) {
|
||||
node->position = (Vec3){x, y, z};
|
||||
node->dirty = 1;
|
||||
}
|
||||
|
||||
void scene_set_rotation_euler(SceneNode* node, float rx, float ry, float rz) {
|
||||
// 欧拉角转四元数 (YXZ 顺序)
|
||||
float cr = cosf(rx * 0.5f), sr = sinf(rx * 0.5f);
|
||||
float cp = cosf(ry * 0.5f), sp = sinf(ry * 0.5f);
|
||||
float cy = cosf(rz * 0.5f), sy = sinf(rz * 0.5f);
|
||||
node->rotation = (Quat){
|
||||
sr * cp * cy - cr * sp * sy,
|
||||
cr * sp * cy + sr * cp * sy,
|
||||
cr * cp * sy - sr * sp * cy,
|
||||
cr * cp * cy + sr * sp * sy
|
||||
};
|
||||
node->dirty = 1;
|
||||
}
|
||||
|
||||
void scene_set_scale(SceneNode* node, float sx, float sy, float sz) {
|
||||
node->scale = (Vec3){sx, sy, sz};
|
||||
node->dirty = 1;
|
||||
}
|
||||
|
||||
void scene_set_rotation_quat(SceneNode* node, const Quat* q) {
|
||||
node->rotation = *q;
|
||||
node->dirty = 1;
|
||||
}
|
||||
|
||||
void scene_mark_dirty(SceneNode* node) {
|
||||
node->dirty = 1;
|
||||
for (int i = 0; i < node->child_count; i++) {
|
||||
scene_mark_dirty(node->children[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static void update_local_matrix(SceneNode* node) {
|
||||
// 旋转矩阵
|
||||
Mat4 rot;
|
||||
quat_to_matrix(&node->rotation, &rot);
|
||||
|
||||
// 缩放矩阵
|
||||
Mat4 scl;
|
||||
mat4_identity(&scl);
|
||||
scl.m[0][0] = node->scale.x;
|
||||
scl.m[1][1] = node->scale.y;
|
||||
scl.m[2][2] = node->scale.z;
|
||||
|
||||
// 平移矩阵
|
||||
Mat4 trl;
|
||||
mat4_translate(node->position.x, node->position.y, node->position.z, &trl);
|
||||
|
||||
// local = trl * rot * scl
|
||||
Mat4 tmp;
|
||||
mat4_multiply(&rot, &scl, &tmp);
|
||||
mat4_multiply(&trl, &tmp, &node->local_matrix);
|
||||
}
|
||||
|
||||
static void update_world_matrices(SceneNode* node) {
|
||||
if (node->dirty) {
|
||||
update_local_matrix(node);
|
||||
if (node->parent) {
|
||||
mat4_multiply(&node->parent->world_matrix, &node->local_matrix, &node->world_matrix);
|
||||
} else {
|
||||
node->world_matrix = node->local_matrix;
|
||||
}
|
||||
node->dirty = 0;
|
||||
}
|
||||
for (int i = 0; i < node->child_count; i++) {
|
||||
update_world_matrices(node->children[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void scene_update(Scene* scene) {
|
||||
if (scene->root) {
|
||||
update_world_matrices(scene->root);
|
||||
}
|
||||
}
|
||||
|
||||
void scene_get_world_position(SceneNode* node, Vec3* out) {
|
||||
out->x = node->world_matrix.m[3][0];
|
||||
out->y = node->world_matrix.m[3][1];
|
||||
out->z = node->world_matrix.m[3][2];
|
||||
}
|
||||
|
||||
void scene_get_world_rotation(SceneNode* node, Quat* out) {
|
||||
// 从世界矩阵提取四元数
|
||||
Mat4 m = node->world_matrix;
|
||||
float tr = m.m[0][0] + m.m[1][1] + m.m[2][2];
|
||||
if (tr > 0) {
|
||||
float s = 0.5f / sqrtf(tr + 1.0f);
|
||||
out->w = 0.25f / s;
|
||||
out->x = (m.m[2][1] - m.m[1][2]) * s;
|
||||
out->y = (m.m[0][2] - m.m[2][0]) * s;
|
||||
out->z = (m.m[1][0] - m.m[0][1]) * s;
|
||||
} else if (m.m[0][0] > m.m[1][1] && m.m[0][0] > m.m[2][2]) {
|
||||
float s = 2.0f * sqrtf(1.0f + m.m[0][0] - m.m[1][1] - m.m[2][2]);
|
||||
out->w = (m.m[2][1] - m.m[1][2]) / s;
|
||||
out->x = 0.25f * s;
|
||||
out->y = (m.m[0][1] + m.m[1][0]) / s;
|
||||
out->z = (m.m[0][2] + m.m[2][0]) / s;
|
||||
} else if (m.m[1][1] > m.m[2][2]) {
|
||||
float s = 2.0f * sqrtf(1.0f + m.m[1][1] - m.m[0][0] - m.m[2][2]);
|
||||
out->w = (m.m[0][2] - m.m[2][0]) / s;
|
||||
out->x = (m.m[0][1] + m.m[1][0]) / s;
|
||||
out->y = 0.25f * s;
|
||||
out->z = (m.m[1][2] + m.m[2][1]) / s;
|
||||
} else {
|
||||
float s = 2.0f * sqrtf(1.0f + m.m[2][2] - m.m[0][0] - m.m[1][1]);
|
||||
out->w = (m.m[1][0] - m.m[0][1]) / s;
|
||||
out->x = (m.m[0][2] + m.m[2][0]) / s;
|
||||
out->y = (m.m[1][2] + m.m[2][1]) / s;
|
||||
out->z = 0.25f * s;
|
||||
}
|
||||
}
|
||||
|
||||
void scene_get_world_scale(SceneNode* node, Vec3* out) {
|
||||
// 从世界矩阵提取缩放 (各列向量的长度)
|
||||
out->x = sqrtf(node->world_matrix.m[0][0] * node->world_matrix.m[0][0] +
|
||||
node->world_matrix.m[0][1] * node->world_matrix.m[0][1] +
|
||||
node->world_matrix.m[0][2] * node->world_matrix.m[0][2]);
|
||||
out->y = sqrtf(node->world_matrix.m[1][0] * node->world_matrix.m[1][0] +
|
||||
node->world_matrix.m[1][1] * node->world_matrix.m[1][1] +
|
||||
node->world_matrix.m[1][2] * node->world_matrix.m[1][2]);
|
||||
out->z = sqrtf(node->world_matrix.m[2][0] * node->world_matrix.m[2][0] +
|
||||
node->world_matrix.m[2][1] * node->world_matrix.m[2][1] +
|
||||
node->world_matrix.m[2][2] * node->world_matrix.m[2][2]);
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
#pragma once
|
||||
|
||||
// ============================================================================
|
||||
// scene_graph.h - 场景图: 节点树 + 变换继承
|
||||
// ============================================================================
|
||||
|
||||
#include "../ASM/math_c_fallback.h"
|
||||
#include <stdint.h>
|
||||
|
||||
#define MAX_CHILDREN 64
|
||||
#define MAX_NODES 1024
|
||||
|
||||
// 场景节点
|
||||
typedef struct SceneNode {
|
||||
int id;
|
||||
char name[64];
|
||||
|
||||
// 本地变换
|
||||
Vec3 position;
|
||||
Quat rotation;
|
||||
Vec3 scale;
|
||||
|
||||
// 世界矩阵 (每帧由 scene_update 计算)
|
||||
Mat4 world_matrix;
|
||||
Mat4 local_matrix;
|
||||
|
||||
// 层级
|
||||
struct SceneNode* parent;
|
||||
struct SceneNode* children[MAX_CHILDREN];
|
||||
int child_count;
|
||||
|
||||
// 标志
|
||||
int visible;
|
||||
int dirty; // 需要重新计算矩阵
|
||||
|
||||
// 用户数据
|
||||
void* user_data;
|
||||
int user_type;
|
||||
} SceneNode;
|
||||
|
||||
// 场景
|
||||
typedef struct Scene {
|
||||
SceneNode nodes[MAX_NODES];
|
||||
int node_count;
|
||||
SceneNode* root;
|
||||
int next_id;
|
||||
} Scene;
|
||||
|
||||
// 初始化/销毁
|
||||
void scene_init(Scene* scene);
|
||||
void scene_destroy(Scene* scene);
|
||||
|
||||
// 节点管理
|
||||
SceneNode* scene_create_node(Scene* scene, const char* name);
|
||||
void scene_destroy_node(Scene* scene, SceneNode* node);
|
||||
SceneNode* scene_find_node(Scene* scene, int id);
|
||||
SceneNode* scene_find_by_name(Scene* scene, const char* name);
|
||||
|
||||
// 层级
|
||||
void scene_set_parent(SceneNode* child, SceneNode* parent);
|
||||
void scene_add_child(SceneNode* parent, SceneNode* child);
|
||||
void scene_remove_child(SceneNode* parent, SceneNode* child);
|
||||
|
||||
// 变换
|
||||
void scene_set_position(SceneNode* node, float x, float y, float z);
|
||||
void scene_set_rotation_euler(SceneNode* node, float rx, float ry, float rz);
|
||||
void scene_set_scale(SceneNode* node, float sx, float sy, float sz);
|
||||
void scene_set_rotation_quat(SceneNode* node, const Quat* q);
|
||||
void scene_mark_dirty(SceneNode* node);
|
||||
|
||||
// 每帧更新
|
||||
void scene_update(Scene* scene);
|
||||
|
||||
// 获取世界变换
|
||||
void scene_get_world_position(SceneNode* node, Vec3* out);
|
||||
void scene_get_world_rotation(SceneNode* node, Quat* out);
|
||||
void scene_get_world_scale(SceneNode* node, Vec3* out);
|
||||
Reference in new issue
Block a user