refactor: Transform 字段封装 + dirty 标记(对齐 UE USceneComponent 真实现)

- 修正上一版"全量暴力重算":UE 实为 dirty 标记 + 惰性计算,前提是
  字段私有(SetRelativeLocation 等 setter 标脏 + 子级传播)
- TransformComponent:SRT 字段私有化,Set/Get/World()/IsDirty 访问器;
  Set* 变更才标脏;AddRotationY 便捷接口
- Scene::UpdateTransforms 只重算脏实体——静止实体零成本;
  层级(父子)传播在脏标记基础上扩展
- 迁移 Camera/SceneRenderer/main.cpp 到封装 API
This commit is contained in:
2026-09-23 15:35:20 +08:00
parent 57ab8901a9
commit 7d137fa9b1
5 changed files with 63 additions and 47 deletions
+16 -14
View File
@@ -14,8 +14,7 @@ namespace Engine {
void Camera::Update(Window& window, ECS::TransformComponent& t, f32 deltaTime)
{
// 鼠标旋转:直接写实体旋转(yaw → rotation.y,pitch → rotation.x)。
// Set*/成员写后由帧循环的 UpdateTransforms 统一 Compose
// 鼠标旋转:直接写实体旋转(yaw → rotation.y,pitch → rotation.x)
if (m_MouseLookEnabled)
{
f32 mouseDX = 0, mouseDY = 0;
@@ -23,35 +22,38 @@ namespace Engine {
if (mouseDX != 0 || mouseDY != 0)
{
t.rotation.y += mouseDX * m_MouseSensitivity;
t.rotation.x = glm::clamp(
t.rotation.x - mouseDY * m_MouseSensitivity, -89.0f, 89.0f);
glm::vec3 rot = t.GetRotation();
rot.y += mouseDX * m_MouseSensitivity;
rot.x = glm::clamp(
rot.x - mouseDY * m_MouseSensitivity, -89.0f, 89.0f);
t.SetRotation(rot);
}
}
// 基向量由实体旋转决定(本地 -Z 为视线方向;应用顺序 Y→X,
// 与 TransformComponent::Compose 一致;roll 不参与 FPS 相机)
const glm::vec3& rot = t.GetRotation();
const glm::mat3 r = static_cast<glm::mat3>(
glm::rotate(glm::mat4(1.0f), glm::radians(t.rotation.y),
glm::rotate(glm::mat4(1.0f), glm::radians(rot.y),
glm::vec3(0, 1, 0)) *
glm::rotate(glm::mat4(1.0f), glm::radians(t.rotation.x),
glm::rotate(glm::mat4(1.0f), glm::radians(rot.x),
glm::vec3(1, 0, 0)));
const glm::vec3 forward = r * glm::vec3(0, 0, -1);
const glm::vec3 right = r * glm::vec3(1, 0, 0);
f32 speed = m_MoveSpeed * deltaTime;
if (window.IsKeyPressed(GLFW_KEY_W)) { t.position += forward * speed; }
if (window.IsKeyPressed(GLFW_KEY_S)) { t.position -= forward * speed; }
if (window.IsKeyPressed(GLFW_KEY_A)) { t.position -= right * speed; }
if (window.IsKeyPressed(GLFW_KEY_D)) { t.position += right * speed; }
if (window.IsKeyPressed(GLFW_KEY_SPACE)) { t.position.y += speed; }
if (window.IsKeyPressed(GLFW_KEY_LEFT_SHIFT)) { t.position.y -= speed; }
if (window.IsKeyPressed(GLFW_KEY_W)) { t.SetPosition(t.GetPosition() + forward * speed); }
if (window.IsKeyPressed(GLFW_KEY_S)) { t.SetPosition(t.GetPosition() - forward * speed); }
if (window.IsKeyPressed(GLFW_KEY_A)) { t.SetPosition(t.GetPosition() - right * speed); }
if (window.IsKeyPressed(GLFW_KEY_D)) { t.SetPosition(t.GetPosition() + right * speed); }
if (window.IsKeyPressed(GLFW_KEY_SPACE)) { t.SetPosition(t.GetPosition() + glm::vec3(0, speed, 0)); }
if (window.IsKeyPressed(GLFW_KEY_LEFT_SHIFT)) { t.SetPosition(t.GetPosition() - glm::vec3(0, speed, 0)); }
}
glm::mat4 Camera::GetView(const ECS::TransformComponent& t) const
{
// 相机作为实体:视图 = 世界矩阵的逆(无重复位姿状态)
return glm::inverse(t.world);
return glm::inverse(t.World());
}
glm::mat4 Camera::GetProjection(f32 aspect, f32 nearZ, f32 farZ) const