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:
@@ -55,11 +55,10 @@ namespace Engine::ECS {
|
||||
|
||||
void Scene::UpdateTransforms()
|
||||
{
|
||||
// 全量重算:分量允许直接写字段(无法可靠 dirty 追踪),
|
||||
// 无条件 Compose 保证任何写法下 world 都新鲜。
|
||||
// 实测万级实体内成本可忽略;更大规模再引入 dirty+封装优化
|
||||
// 只重算脏的:UE transform-update 阶段模式。
|
||||
// 静止实体(绝大多数)零成本;层级传播在此扩展
|
||||
m_Registry.view<TransformComponent>().each([](TransformComponent& t) {
|
||||
t.Compose();
|
||||
if (t.IsDirty()) t.Compose();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -185,7 +185,7 @@ namespace Engine
|
||||
ubo.lights[i].color = glm::vec4(0.0f);
|
||||
}
|
||||
ComputeCascades(shadowDir);
|
||||
ubo.cameraPos = glm::vec4(camTransform->position, 1.0f);
|
||||
ubo.cameraPos = glm::vec4(camTransform->GetPosition(), 1.0f);
|
||||
|
||||
// ---- 3. GPUDriven:单趟收集 + 多视图剔除 ----
|
||||
// 每个实例的包围球对 4 个视锥分别测试:
|
||||
@@ -218,22 +218,22 @@ namespace Engine
|
||||
// TAA velocity:本实例的上一帧世界矩阵(首帧/新实体 = 当前
|
||||
// 矩阵 → 速度为 0,不产生假运动)
|
||||
const u32 entKey = static_cast<u32>(entt::to_integral(entity));
|
||||
glm::mat4 prevWorld = t.world;
|
||||
glm::mat4 prevWorld = t.World();
|
||||
if (auto it = m_PrevWorlds.find(entKey); it != m_PrevWorlds.end()) {
|
||||
prevWorld = it->second;
|
||||
}
|
||||
m_CurWorlds.emplace(entKey, t.world);
|
||||
m_CurWorlds.emplace(entKey, t.World());
|
||||
|
||||
// 实例世界缩放(矩阵列向量最大长度,包围球半径随缩放)
|
||||
const f32 worldScale = glm::max(
|
||||
glm::length(glm::vec3(t.world[0])),
|
||||
glm::max(glm::length(glm::vec3(t.world[1])),
|
||||
glm::length(glm::vec3(t.world[2]))));
|
||||
glm::length(glm::vec3(t.World()[0])),
|
||||
glm::max(glm::length(glm::vec3(t.World()[1])),
|
||||
glm::length(glm::vec3(t.World()[2]))));
|
||||
|
||||
for (auto& mesh : model->GetMeshes()) {
|
||||
const auto& bounds = mesh->GetBounds();
|
||||
const glm::vec3 worldCenter =
|
||||
glm::vec3(t.world * glm::vec4(bounds.center, 1.0f));
|
||||
glm::vec3(t.World() * glm::vec4(bounds.center, 1.0f));
|
||||
const f32 worldRadius = bounds.radius * worldScale;
|
||||
|
||||
auto tryAppend = [&](ViewScratch& s, const Frustum& frustum) {
|
||||
@@ -252,7 +252,7 @@ namespace Engine
|
||||
}
|
||||
s.result.batches[it->second].count++;
|
||||
s.result.instanceCount++;
|
||||
s.worlds.push_back(t.world);
|
||||
s.worlds.push_back(t.World());
|
||||
s.prevWorlds.push_back(prevWorld);
|
||||
++totalInstances;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user