editor camera: dedicated Scene-view camera decoupled from camera entities
EditorCamera (UE FEditorViewportClient semantics) owned by SceneRenderer:
own TransformComponent + reused Camera controller. BuildFrame dispatches
render source by display mode — editor form always renders from the
editor camera (usable in empty scenes), game form renders from the
scene's primary camera entity. AlignTo copies an entity pose into the
editor camera ("Align Viewport to Camera" button in Inspector). F focus
and viewport gizmo now follow the same dispatch. main.cpp stripped of
dangling sandbox camera/spinner state; onSceneLoaded hook removed.
This commit is contained in:
@@ -54,6 +54,10 @@ namespace Engine {
|
||||
void SetMouseLookEnabled(const bool enabled) { m_MouseLookEnabled = enabled; }
|
||||
bool IsMouseLookEnabled() const { return m_MouseLookEnabled; }
|
||||
|
||||
// 清除环绕 pivot(位姿被外部整体改写后 pivot 已失效——下一次
|
||||
// MMB 环绕按新视线自动重建)
|
||||
void ResetOrbit() { m_HasPivot = false; }
|
||||
|
||||
private:
|
||||
f32 m_MoveSpeed = 2.5f;
|
||||
f32 m_MouseSensitivity = 0.1f;
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
//
|
||||
// Created by atdunbg on 2026/10/3.
|
||||
//
|
||||
// EditorCamera:Scene view 专用相机(UE FEditorViewportClient 语义)。
|
||||
//
|
||||
// 与场景相机实体是两个东西——它是视口 UI 状态,不属于场景:
|
||||
// - 位姿自有(内嵌 TransformComponent,无父层级),空场景/无相机
|
||||
// 实体也可用,永在不可删
|
||||
// - 交互复用 Camera 控制器(RMB 飞行 / MMB 环绕 / 滚轮推拉),输入
|
||||
// 直接写回自有 transform——位姿单一事实源不变(transform 即位姿)
|
||||
// - 渲染源分派在 SceneRenderer::BuildFrame:编辑器形态恒用本类,
|
||||
// 游戏形态用场景 primary 相机实体(游戏逻辑所有,本类不参与,
|
||||
// 不 Update 即静止)
|
||||
//
|
||||
|
||||
#ifndef HELLOVULKAN_EDITORCAMERA_H
|
||||
#define HELLOVULKAN_EDITORCAMERA_H
|
||||
|
||||
#include <Engine/Renderer/Camera.h>
|
||||
#include <Engine/ECS/Components.h>
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
namespace Engine {
|
||||
|
||||
class Window;
|
||||
|
||||
class EditorCamera {
|
||||
public:
|
||||
EditorCamera()
|
||||
{
|
||||
// 出场位姿:俯视场中央(与旧沙盒 MainCamera 出场一致,
|
||||
// 空场景也有可看的初始视角)
|
||||
m_Transform.SetPosition({0.0f, 12.0f, 22.0f});
|
||||
m_Transform.SetRotation({-25.0f, 0.0f, 0.0f});
|
||||
m_Transform.Compose();
|
||||
}
|
||||
|
||||
// 每帧输入驱动(编辑器形态由 Application 调用;游戏形态不调
|
||||
// 即静止)。flyRequiresRMB 恒 true:编辑器移动键只在 RMB 按住
|
||||
// 时生效(W/E/R 归 Gizmo,UE 语义)。暂停(timeScale=0)时
|
||||
// 仍可飞行——调用方传 unscaled dt
|
||||
void Update(Window& window, f32 deltaTime)
|
||||
{
|
||||
m_Controller.Update(window, m_Transform, deltaTime,
|
||||
/*flyRequiresRMB=*/true);
|
||||
m_Transform.Compose(); // World() 是渲染/Gizmo 读源,随写随算
|
||||
}
|
||||
|
||||
// 跳转(对齐视口):把相机实体(或任意实体)位姿复制过来,
|
||||
// Scene view 立即从该位置观看(UE "Pilot This Camera" 的
|
||||
// 一次性对齐版)。环绕 pivot 已失效,清除待 MMB 重建
|
||||
void AlignTo(const ECS::TransformComponent& target)
|
||||
{
|
||||
m_Transform.SetPosition(target.GetPosition());
|
||||
m_Transform.SetRotationQuat(target.GetRotationQuat());
|
||||
m_Transform.Compose();
|
||||
m_Controller.ResetOrbit();
|
||||
}
|
||||
|
||||
// 焦点选中(F 键):pivot 设为 point,沿当前视线平移对准
|
||||
void FocusOn(const glm::vec3& point)
|
||||
{
|
||||
m_Controller.FocusOn(m_Transform, point);
|
||||
}
|
||||
|
||||
// 视图 = 自有 transform 世界矩阵的逆(要求已 Compose——
|
||||
// Update/AlignTo/ctor 三个写入口都收尾 Compose)
|
||||
glm::mat4 GetView() const { return m_Controller.GetView(m_Transform); }
|
||||
|
||||
ECS::TransformComponent& GetTransform() { return m_Transform; }
|
||||
Camera& GetController() { return m_Controller; }
|
||||
|
||||
private:
|
||||
ECS::TransformComponent m_Transform; // 自有位姿(非场景实体)
|
||||
Camera m_Controller; // 交互控制器(环绕状态在此)
|
||||
};
|
||||
|
||||
} // namespace Engine
|
||||
|
||||
#endif //HELLOVULKAN_EDITORCAMERA_H
|
||||
@@ -41,6 +41,7 @@ namespace Engine {
|
||||
class CommandManager;
|
||||
class UniformBuffer;
|
||||
class SceneRenderer;
|
||||
class EditorCamera;
|
||||
class VulkanAssetUploader;
|
||||
class Cubemap;
|
||||
class IblGenerator;
|
||||
@@ -141,6 +142,9 @@ namespace Engine {
|
||||
// ---- 显示模式(Editor 视口 ↔ 全屏直出;帧首同步生效)----
|
||||
int GetDisplayMode() const { return m_DesiredDisplayMode; }
|
||||
void SetDisplayMode(int mode); // cpp 内定义(SceneRenderer 前置声明)
|
||||
// 编辑器相机(Scene view 恒用,与场景相机实体无关)。转发
|
||||
// SceneRenderer 持有的实例:Application 驱动 Update,面板读写位姿
|
||||
EditorCamera& GetEditorCamera(); // cpp 内定义(SceneRenderer 完整类型)
|
||||
// 当帧场景数据(只读直通)。CPU 消费如视口拾取:反投影矩阵必须
|
||||
// 与渲染同一台相机同一投影(含 [0,1] 深度语义),禁止自行重算
|
||||
const FrameSceneData& GetFrameSceneData() const; // cpp 内定义
|
||||
|
||||
@@ -28,6 +28,8 @@
|
||||
#include <array>
|
||||
#include <unordered_map>
|
||||
|
||||
#include <Engine/Renderer/EditorCamera.h>
|
||||
|
||||
namespace Engine {
|
||||
|
||||
namespace ECS { class Scene; }
|
||||
@@ -35,7 +37,8 @@ namespace Engine {
|
||||
|
||||
class SceneRenderer {
|
||||
public:
|
||||
// 从场景构建当帧渲染数据。无 primary 相机返回 false(渲染跳帧)。
|
||||
// 从场景构建当帧渲染数据。游戏形态无 primary 相机返回 false
|
||||
//(渲染跳帧;编辑器形态恒用编辑器相机,不跳)。
|
||||
// targetExtent 用于 TAA 子像素抖动的 NDC 偏移折算。
|
||||
// dt 驱动骨骼动画采样推进(crossfade 计时)。
|
||||
bool BuildFrame(ECS::Scene& scene, Assets::AssetManager& assets,
|
||||
@@ -62,6 +65,9 @@ namespace Engine {
|
||||
void SetLodEnabled(bool b) { m_LodEnabled = b; }
|
||||
void SetDebugView(int v) { m_DebugView = v; }
|
||||
void SetDisplayMode(int m) { m_DisplayMode = m; } // kDisplayDirect / kDisplayViewport
|
||||
// 编辑器相机(视口 UI 状态,SceneRenderer 持有 = 渲染源在此分派);
|
||||
// Application 驱动 Update,ViewportPanel/Inspector 经 Renderer 门面访问
|
||||
EditorCamera& GetEditorCamera() { return m_EditorCamera; }
|
||||
// Editor 视口拾取请求(UI 段写入,下一次 BuildFrame 落帧后清除)
|
||||
void SetPickRequest(const glm::vec2& ndc)
|
||||
{
|
||||
@@ -83,6 +89,7 @@ namespace Engine {
|
||||
static void PackIndirect(CullResult& view, bool byMaterial);
|
||||
|
||||
FrameSceneData m_Frame;
|
||||
EditorCamera m_EditorCamera; // 编辑器相机(视口 UI 状态,见 GetEditorCamera)
|
||||
PickRequest m_PendingPick{}; // 拾取请求缓冲(BuildFrame 落帧后清除)
|
||||
u32 m_PendingSelected = 0; // 选中实体缓冲(描边)
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#include <Engine/Renderer/Renderer.h>
|
||||
#include <Engine/Renderer/SceneRenderer.h>
|
||||
#include <Engine/Renderer/EditorCamera.h>
|
||||
#include <Engine/Renderer/VulkanAssetUploader.h>
|
||||
#include <Engine/Renderer/Passes/SceneGpu.h>
|
||||
#include <Engine/Renderer/Passes/FullscreenGpu.h>
|
||||
@@ -233,6 +234,11 @@ namespace Engine
|
||||
m_SceneRenderer->SetDisplayMode(mode);
|
||||
}
|
||||
|
||||
EditorCamera& Renderer::GetEditorCamera()
|
||||
{
|
||||
return m_SceneRenderer->GetEditorCamera();
|
||||
}
|
||||
|
||||
const FrameSceneData &Renderer::GetFrameSceneData() const
|
||||
{
|
||||
return m_SceneRenderer->Frame();
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <Engine/ECS/Scene.h>
|
||||
#include <Engine/ECS/Components.h>
|
||||
#include <Engine/Renderer/Camera.h>
|
||||
#include <Engine/Renderer/EditorCamera.h>
|
||||
#include <Engine/Renderer/Frustum.h>
|
||||
#include <Engine/Renderer/Model.h>
|
||||
#include <Engine/Renderer/Mesh.h>
|
||||
@@ -258,14 +259,21 @@ namespace Engine
|
||||
ubo.prevView = m_LastView;
|
||||
ubo.prevProj = m_LastProjNoJitter;
|
||||
|
||||
// ---- 1. 相机(位姿单一事实源 = 相机实体的 Transform)----
|
||||
TransformComponent* camTransform = nullptr;
|
||||
auto* cameraComp = scene.GetPrimaryCamera(&camTransform);
|
||||
if (!cameraComp || !camTransform) {
|
||||
// 无相机:本帧跳过(正常场景必有相机,安全网)
|
||||
// ---- 1. 相机:渲染源按显示模式分派(UE 语义)。编辑器形态
|
||||
// Scene view 恒用编辑器相机(视口 UI 状态,空场景可用);
|
||||
// 游戏形态用场景 primary 相机实体(游戏逻辑所有)----
|
||||
ECS::TransformComponent* camTransform = nullptr;
|
||||
const Camera* camera = nullptr;
|
||||
if (m_DisplayMode == kDisplayViewport) {
|
||||
camTransform = &m_EditorCamera.GetTransform();
|
||||
camera = &m_EditorCamera.GetController();
|
||||
} else if (auto* cameraComp = scene.GetPrimaryCamera(&camTransform)) {
|
||||
camera = &cameraComp->camera;
|
||||
}
|
||||
if (!camera || !camTransform) {
|
||||
// 游戏形态无 primary 相机:本帧跳过(安全网)
|
||||
return false; // 拾取请求未消费,留待下一帧重试
|
||||
}
|
||||
const Camera& camera = cameraComp->camera;
|
||||
|
||||
// 拾取请求落帧(一次性消费:本帧 HitProxy 渲染 + 像素拷贝)。
|
||||
// 放在相机校验之后:跳帧时请求保留,不丢点击
|
||||
@@ -276,8 +284,8 @@ namespace Engine
|
||||
|
||||
const f32 aspect = static_cast<f32>(targetExtent.width) /
|
||||
static_cast<f32>(targetExtent.height);
|
||||
ubo.view = camera.GetView(*camTransform);
|
||||
ubo.proj = camera.GetProjection(aspect, 0.1f, 100.0f);
|
||||
ubo.view = camera->GetView(*camTransform);
|
||||
ubo.proj = camera->GetProjection(aspect, 0.1f, 100.0f);
|
||||
|
||||
// 未抖动投影:velocity 的当前帧 clip 位置用它(抖动不能进 velocity)
|
||||
ubo.projNoJitter = ubo.proj;
|
||||
|
||||
Reference in New Issue
Block a user