refactor: Camera 位姿统一到 TransformComponent(单一事实源)
- Camera 删除内部 position/yaw/pitch 状态:Update 把鼠标旋转与 WASD 移动直接写回实体 Transform(rotation.y=yaw / rotation.x=pitch, 移动基向量由实体旋转推导,有变更才 Compose) - GetView(transform) = 实体世界矩阵的逆——相机即实体,视图矩阵无 第二来源;Scene::GetPrimaryCamera 可选带出实体 Transform - 默认朝向约定变化:rotation.y=0 = 看向 -Z(与旧 yaw=-90 等价) - 消除 CameraComponent 位置与 Transform 脱节的遗留债
This commit is contained in:
+9
-5
@@ -63,14 +63,16 @@ protected:
|
||||
.Compose();
|
||||
m_Ground.AddComponent<MeshRendererComponent>(MeshRendererComponent{ground});
|
||||
|
||||
// 相机实体(primary = 当前渲染视角)
|
||||
// 相机实体(primary = 当前渲染视角;位姿存实体 Transform)
|
||||
m_Camera = scene.CreateEntity("MainCamera");
|
||||
auto& camera = m_Camera.AddComponent<CameraComponent>();
|
||||
camera.primary = true;
|
||||
camera.camera.SetPosition(glm::vec3(0.0f, 0.0f, 7.0f));
|
||||
m_Camera.GetComponent<TransformComponent>()
|
||||
.SetPosition(glm::vec3(0.0f, 0.0f, 7.0f))
|
||||
.Compose();
|
||||
|
||||
// 神庙实体 × 1( FBX 单位较大,缩放到场景尺度)
|
||||
if (0){
|
||||
{
|
||||
auto e = scene.CreateEntity("SunTemple");
|
||||
e.GetComponent<TransformComponent>()
|
||||
.SetScale(glm::vec3(0.05f))
|
||||
@@ -103,9 +105,11 @@ protected:
|
||||
m_Time += deltaTime;
|
||||
}
|
||||
|
||||
// 相机(WASD/Space/Shift 移动)
|
||||
// 相机(WASD/Space/Shift 移动;位姿读写实体 Transform)
|
||||
m_Camera.GetComponent<CameraComponent>()
|
||||
.camera.Update(GetWindow(), deltaTime);
|
||||
.camera.Update(GetWindow(),
|
||||
m_Camera.GetComponent<TransformComponent>(),
|
||||
deltaTime);
|
||||
|
||||
// 旋转动画:编辑 Transform 分量后 Compose 重算 world
|
||||
for (size_t i = 0; i < m_Spinners.size(); ++i)
|
||||
|
||||
@@ -86,8 +86,10 @@ namespace Engine::ECS {
|
||||
|
||||
// ---- 常用查询 ----
|
||||
|
||||
// primary 相机(渲染视角来源);无则返回 nullptr
|
||||
CameraComponent* GetPrimaryCamera();
|
||||
// 主相机(primary=true,渲染视角来源);无则返回 nullptr。
|
||||
// outTransform 可选:带出该实体的 TransformComponent
|
||||
//(相机位姿的单一事实源)
|
||||
CameraComponent* GetPrimaryCamera(TransformComponent** outTransform = nullptr);
|
||||
|
||||
private:
|
||||
Registry m_Registry;
|
||||
|
||||
@@ -2,8 +2,11 @@
|
||||
// Created by atdunbg on 2026/9/22.
|
||||
//
|
||||
// Camera:独立的相机模块。
|
||||
// 职责:输入驱动的运动更新 + 视图/投影矩阵计算。
|
||||
// 不再依赖具体渲染器——Renderer/RenderGraph 只消费它的矩阵输出。
|
||||
//
|
||||
// 设计(Transform 单一事实源):相机的位置与朝向完全由实体上的
|
||||
// TransformComponent 承载——Update 把输入直接写回 transform(末尾
|
||||
// Compose),视图矩阵 = 实体世界矩阵的逆(本地 -Z 为视线方向)。
|
||||
// 相机类自身不保存任何位姿状态,杜绝"位置两套来源"的脱节。
|
||||
//
|
||||
|
||||
#ifndef HELLOVULKAN_CAMERA_H
|
||||
@@ -15,25 +18,20 @@
|
||||
namespace Engine {
|
||||
|
||||
class Window;
|
||||
namespace ECS { struct TransformComponent; }
|
||||
|
||||
class Camera {
|
||||
public:
|
||||
// 每帧调用:读取窗口输入,更新位置与朝向
|
||||
void Update(Window& window, f32 deltaTime);
|
||||
// 输入驱动:WASD/Space/Shift 移动 + 鼠标视角(需 SetMouseLookEnabled)。
|
||||
// 全部写回传入的 transform,有变更才 Compose。
|
||||
void Update(Window& window, ECS::TransformComponent& transform, f32 deltaTime);
|
||||
|
||||
glm::mat4 GetView() const;
|
||||
// 相机视图 = 实体世界矩阵的逆(要求 transform 已 Compose)
|
||||
glm::mat4 GetView(const ECS::TransformComponent& transform) const;
|
||||
|
||||
// Vulkan 投影:内部完成 Y 翻转(clip space Y 向下)和 [0,1] 深度
|
||||
glm::mat4 GetProjection(f32 aspect, f32 nearZ, f32 farZ) const;
|
||||
|
||||
glm::vec3 GetPosition() const { return m_Position; }
|
||||
void SetPosition(const glm::vec3& pos) { m_Position = pos; }
|
||||
|
||||
void SetYaw(f32 yaw) { m_Yaw = yaw; }
|
||||
void SetPitch(f32 pitch) { m_Pitch = pitch; }
|
||||
f32 GetYaw() const { return m_Yaw; }
|
||||
f32 GetPitch() const { return m_Pitch; }
|
||||
|
||||
void SetMoveSpeed(f32 speed) { m_MoveSpeed = speed; }
|
||||
void SetMouseSensitivity(f32 sens) { m_MouseSensitivity = sens; }
|
||||
|
||||
@@ -41,24 +39,10 @@ namespace Engine {
|
||||
void SetMouseLookEnabled(bool enabled) { m_MouseLookEnabled = enabled; }
|
||||
bool IsMouseLookEnabled() const { return m_MouseLookEnabled; }
|
||||
|
||||
glm::vec3 GetForward() const { return m_Forward; }
|
||||
glm::vec3 GetRight() const { return m_Right; }
|
||||
glm::vec3 GetUp() const { return m_Up; }
|
||||
|
||||
private:
|
||||
void UpdateBasis();
|
||||
|
||||
glm::vec3 m_Position{0.0f, 0.0f, 7.0f};
|
||||
f32 m_Yaw = -90.0f; // 朝向 -Z
|
||||
f32 m_Pitch = 0.0f;
|
||||
f32 m_MoveSpeed = 2.5f;
|
||||
f32 m_MouseSensitivity = 0.1f;
|
||||
bool m_MouseLookEnabled = false;
|
||||
|
||||
// 缓存的方向基向量,Update 时刷新,避免每帧三角函数重复计算
|
||||
glm::vec3 m_Forward{0.0f, 0.0f, -1.0f};
|
||||
glm::vec3 m_Right{1.0f, 0.0f, 0.0f};
|
||||
glm::vec3 m_Up{0.0f, 1.0f, 0.0f};
|
||||
};
|
||||
|
||||
} // namespace Engine
|
||||
|
||||
@@ -53,12 +53,20 @@ namespace Engine::ECS {
|
||||
m_PendingDestroy.clear();
|
||||
}
|
||||
|
||||
CameraComponent* Scene::GetPrimaryCamera()
|
||||
CameraComponent* Scene::GetPrimaryCamera(TransformComponent** outTransform)
|
||||
{
|
||||
CameraComponent* found = nullptr;
|
||||
m_Registry.view<CameraComponent>().each([&](Entity, CameraComponent& cc) {
|
||||
if (!found && cc.primary) found = &cc;
|
||||
Entity foundEntity = entt::null;
|
||||
m_Registry.view<CameraComponent>().each([&](Entity e, CameraComponent& cc) {
|
||||
if (!found && cc.primary) {
|
||||
found = &cc;
|
||||
foundEntity = e;
|
||||
}
|
||||
});
|
||||
if (outTransform) {
|
||||
*outTransform = (found && foundEntity != entt::null)
|
||||
? &m_Registry.get<TransformComponent>(foundEntity) : nullptr;
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#include <Engine/Renderer/Camera.h>
|
||||
#include <Engine/Core/Window.h>
|
||||
#include <Engine/ECS/Components.h>
|
||||
|
||||
#include <glm/gtc/matrix_transform.hpp>
|
||||
|
||||
@@ -11,9 +12,11 @@
|
||||
|
||||
namespace Engine {
|
||||
|
||||
void Camera::Update(Window& window, f32 deltaTime)
|
||||
void Camera::Update(Window& window, ECS::TransformComponent& t, f32 deltaTime)
|
||||
{
|
||||
// 鼠标旋转(需显式启用,配合 cursor capture 使用)
|
||||
bool dirty = false;
|
||||
|
||||
// 鼠标旋转:直接写实体旋转(yaw → rotation.y,pitch → rotation.x)
|
||||
if (m_MouseLookEnabled)
|
||||
{
|
||||
f32 mouseDX = 0, mouseDY = 0;
|
||||
@@ -21,37 +24,39 @@ namespace Engine {
|
||||
|
||||
if (mouseDX != 0 || mouseDY != 0)
|
||||
{
|
||||
m_Yaw += mouseDX * m_MouseSensitivity;
|
||||
m_Pitch -= mouseDY * m_MouseSensitivity;
|
||||
m_Pitch = glm::clamp(m_Pitch, -89.0f, 89.0f);
|
||||
t.rotation.y += mouseDX * m_MouseSensitivity;
|
||||
t.rotation.x = glm::clamp(
|
||||
t.rotation.x - mouseDY * m_MouseSensitivity, -89.0f, 89.0f);
|
||||
dirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
UpdateBasis();
|
||||
// 基向量由实体旋转决定(本地 -Z 为视线方向;应用顺序 Y→X,
|
||||
// 与 TransformComponent::Compose 一致;roll 不参与 FPS 相机)
|
||||
const glm::mat3 r = static_cast<glm::mat3>(
|
||||
glm::rotate(glm::mat4(1.0f), glm::radians(t.rotation.y),
|
||||
glm::vec3(0, 1, 0)) *
|
||||
glm::rotate(glm::mat4(1.0f), glm::radians(t.rotation.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)) m_Position += m_Forward * speed;
|
||||
if (window.IsKeyPressed(GLFW_KEY_S)) m_Position -= m_Forward * speed;
|
||||
if (window.IsKeyPressed(GLFW_KEY_A)) m_Position -= m_Right * speed;
|
||||
if (window.IsKeyPressed(GLFW_KEY_D)) m_Position += m_Right * speed;
|
||||
if (window.IsKeyPressed(GLFW_KEY_SPACE)) m_Position.y += speed;
|
||||
if (window.IsKeyPressed(GLFW_KEY_LEFT_SHIFT)) m_Position.y -= speed;
|
||||
if (window.IsKeyPressed(GLFW_KEY_W)) { t.position += forward * speed; dirty = true; }
|
||||
if (window.IsKeyPressed(GLFW_KEY_S)) { t.position -= forward * speed; dirty = true; }
|
||||
if (window.IsKeyPressed(GLFW_KEY_A)) { t.position -= right * speed; dirty = true; }
|
||||
if (window.IsKeyPressed(GLFW_KEY_D)) { t.position += right * speed; dirty = true; }
|
||||
if (window.IsKeyPressed(GLFW_KEY_SPACE)) { t.position.y += speed; dirty = true; }
|
||||
if (window.IsKeyPressed(GLFW_KEY_LEFT_SHIFT)) { t.position.y -= speed; dirty = true; }
|
||||
|
||||
// 世界矩阵供 GetView(inverse)与渲染消费
|
||||
if (dirty) t.Compose();
|
||||
}
|
||||
|
||||
void Camera::UpdateBasis()
|
||||
glm::mat4 Camera::GetView(const ECS::TransformComponent& t) const
|
||||
{
|
||||
m_Forward.x = cosf(glm::radians(m_Yaw)) * cosf(glm::radians(m_Pitch));
|
||||
m_Forward.y = sinf(glm::radians(m_Pitch));
|
||||
m_Forward.z = sinf(glm::radians(m_Yaw)) * cosf(glm::radians(m_Pitch));
|
||||
m_Forward = glm::normalize(m_Forward);
|
||||
|
||||
m_Right = glm::normalize(glm::cross(m_Forward, glm::vec3(0, 1, 0)));
|
||||
m_Up = glm::normalize(glm::cross(m_Right, m_Forward));
|
||||
}
|
||||
|
||||
glm::mat4 Camera::GetView() const
|
||||
{
|
||||
return glm::lookAt(m_Position, m_Position + m_Forward, m_Up);
|
||||
// 相机作为实体:视图 = 世界矩阵的逆(无重复位姿状态)
|
||||
return glm::inverse(t.world);
|
||||
}
|
||||
|
||||
glm::mat4 Camera::GetProjection(f32 aspect, f32 nearZ, f32 farZ) const
|
||||
|
||||
@@ -136,9 +136,10 @@ namespace Engine
|
||||
ubo.prevView = m_LastView;
|
||||
ubo.prevProj = m_LastProjNoJitter;
|
||||
|
||||
// ---- 1. 相机 ----
|
||||
auto* cameraComp = scene.GetPrimaryCamera();
|
||||
if (!cameraComp) {
|
||||
// ---- 1. 相机(位姿单一事实源 = 相机实体的 Transform)----
|
||||
TransformComponent* camTransform = nullptr;
|
||||
auto* cameraComp = scene.GetPrimaryCamera(&camTransform);
|
||||
if (!cameraComp || !camTransform) {
|
||||
// 无相机:本帧跳过(正常场景必有相机,安全网)
|
||||
return false;
|
||||
}
|
||||
@@ -146,7 +147,7 @@ namespace Engine
|
||||
|
||||
const f32 aspect = static_cast<f32>(targetExtent.width) /
|
||||
static_cast<f32>(targetExtent.height);
|
||||
ubo.view = camera.GetView();
|
||||
ubo.view = camera.GetView(*camTransform);
|
||||
ubo.proj = camera.GetProjection(aspect, 0.1f, 100.0f);
|
||||
|
||||
// 未抖动投影:velocity 的当前帧 clip 位置用它(抖动不能进 velocity)
|
||||
@@ -184,7 +185,7 @@ namespace Engine
|
||||
ubo.lights[i].color = glm::vec4(0.0f);
|
||||
}
|
||||
ComputeCascades(shadowDir);
|
||||
ubo.cameraPos = glm::vec4(camera.GetPosition(), 1.0f);
|
||||
ubo.cameraPos = glm::vec4(camTransform->position, 1.0f);
|
||||
|
||||
// ---- 3. GPUDriven:单趟收集 + 多视图剔除 ----
|
||||
// 每个实例的包围球对 4 个视锥分别测试:
|
||||
|
||||
Reference in New Issue
Block a user