- 更正: Engine 核心已有完整组件系统,Editor Inspector 只是未完善 - 补充: Editor 和 Engine 使用两套不同的 GameObject/Component 系统 (重大架构问题) - 补充: Scene 序列化依赖描述修正 - 补充: 架构问题中新增 Editor/Engine 系统差异分析
26 KiB
XCEngine Editor 设计分析与改进计划
1. 项目概述
1.1 当前状态
XCEngine Editor 是一个基于 ImGui 的 Unity 风格编辑器 UI,目前具备以下基础功能:
- 渲染基础: DirectX 12 + ImGui 对接
- 面板框架: Docking 布局系统
- UI 主题: Unity 风格深色主题
1.2 对比参考
参考项目 Fermion Boson Editor 是一个功能完整的游戏引擎编辑器,具有:
- 完整的 3D Viewport
- 场景层级系统
- 组件检查器
- 资源浏览器
- 材质编辑器
- Play/Edit/Simulate 模式切换
2. 整体架构对比
2.1 架构图
Fermion 架构:
Fermion::Application
└── LayerStack
├── ImGuiLayer (overlay)
└── BosonLayer (editor layer)
├── ViewportPanel (3D viewport + gizmos)
├── SceneHierarchyPanel (entity tree)
│ └── InspectorPanel (embedded, component editor)
├── ContentBrowserPanel (asset browser)
├── MaterialEditorPanel (node-based material)
├── SettingsPanel (editor settings)
├── OverlayRenderPanel (physics debug)
└── MenuBarPanel (menu bar)
XCEngine 架构:
UI::Application
└── Panels (独立 Panel 类)
├── MenuBar
├── HierarchyPanel
├── InspectorPanel
├── SceneViewPanel (占位符)
├── GameViewPanel (占位符)
├── ProjectPanel
└── ConsolePanel
2.2 关键差异
| 方面 | Fermion | XCEngine |
|---|---|---|
| Layer 系统 | Application → LayerStack → BosonLayer | Application 直接管理 Panels |
| Panel 集成 | SceneHierarchy 内嵌 InspectorPanel | 各 Panel 独立 |
| Scene 管理 | BosonLayer 持有 Scene/SceneRenderer | SceneManager 单例 |
| 渲染集成 | BosonLayer → SceneRenderer → Framebuffer | 无对接 |
| 事件系统 | Layer::onEvent 统一分发 | 各 Panel 独立处理 |
3. 各面板详细分析
3.1 SceneHierarchyPanel / HierarchyPanel
功能对比
| 功能 | Fermion | XCEngine | 状态 |
|---|---|---|---|
| 树节点渲染 | ✅ TreeNodeEx + UUID |
✅ TreeNodeEx + EntityID |
完成 |
| 选中高亮 | ✅ | ✅ | 完成 |
| 展开/折叠 | ✅ 自动记忆状态 | ✅ isOpen 状态 |
完成 |
| 重命名 | ✅ 双击触发 | ⚠️ 有 bug | 需修复 |
| 拖拽重排 | ✅ 完整 + 循环检测 | ⚠️ 基本实现 | 需完善 |
| 右键菜单 | ✅ Create Child, Detach, Delete | ✅ Create, Rename, Delete, Copy/Paste, Duplicate | 需补充 |
| 空区域点击 | ✅ 取消选中 | ✅ 取消选中 | 完成 |
| 嵌入 Inspector | ✅ Panel 内嵌 InspectorPanel | ❌ 分离 | 架构差异 |
XCEngine 问题详解
问题 1: 重命名逻辑 bug
HierarchyPanel.cpp lines 106-113:
if (!ImGui::IsItemActive() && ImGui::IsMouseClicked(0)) {
if (strlen(m_renameBuffer) > 0) {
sceneManager.RenameEntity(id, m_renameBuffer);
}
m_renaming = false;
m_renamingEntity = INVALID_ENTITY_ID;
}
问题:点击 InputText 外部时,IsItemActive() 已经变为 false,此时 IsMouseClicked(0) 也已经错过。
问题 2: 缺少 "Create Child" 选项
右键菜单只有:
- Create → Empty Object, Camera, Light, Cube, Sphere, Plane
- Rename, Delete
- Copy, Paste, Duplicate
缺少 "Create Child" 选项来在选中物体下创建子物体。
问题 3: 没有 "Detach from Parent" 选项
无法将子物体脱离父物体,直接变为根层级。
3.2 InspectorPanel
功能对比
| 功能 | Fermion (1173 行) | XCEngine (94 行) | 状态 |
|---|---|---|---|
| 组件显示 | ✅ 模板系统 | ⚠️ 只实现 2 种组件 (Engine 有完整组件库) | 需完善 |
| 动态增删组件 | ✅ 分类菜单 | ❌ 无 | 需实现 |
| 删除组件 | ✅ 右键 Remove | ❌ 无 | 需实现 |
| Transform 编辑 | ✅ drawVec3Control |
⚠️ DragFloat3 简陋 |
需改进 |
| Mesh 编辑 | ✅ Drag-drop + popup | ⚠️ 只有 InputText | 需改进 |
| 材质预览 | ✅ 缩略图渲染 | ❌ 无 | 需实现 |
| Camera 编辑 | ✅ 完整 | ❌ 无 | 需实现 |
| Light 编辑 | ✅ D/P/S Light | ❌ 无 | 需实现 |
| Physics 编辑 | ✅ 完整 | ❌ 无 | 需实现 |
| Script 编辑 | ✅ 字段编辑 | ❌ 无 | 需实现 |
| Entity Picking | ✅ 关节连接 | ❌ 无 | 需实现 |
XCEngine 实现现状
InspectorPanel.cpp lines 44-92:
void InspectorPanel::RenderComponent(Component* component) {
if (auto* transform = dynamic_cast<TransformComponent*>(component)) {
ImGui::DragFloat3("##Position", transform->position, 0.1f);
ImGui::DragFloat3("##Rotation", transform->rotation, 1.0f);
ImGui::DragFloat3("##Scale", transform->scale, 0.1f);
}
else if (auto* meshRenderer = dynamic_cast<MeshRendererComponent*>(component)) {
// 只有 InputText,没有预览,没有拖拽
}
}
主要问题:
- Editor Inspector 面板只实现了 Transform 和 MeshRenderer 显示编辑,但 Engine 核心已有完整组件系统
- 没有 Add Component 菜单
- 没有 Remove Component 功能
- 没有 CollapsingHeader 折叠
- 布局简陋,没有缩进和对齐
3.3 ProjectPanel / ContentBrowserPanel
功能对比
| 功能 | Fermion | XCEngine | 状态 |
|---|---|---|---|
| 布局 | ✅ 两列 (树 + 网格) | ⚠️ 只有网格 | 需补充 |
| 文件夹树 | ✅ 左侧导航树 | ❌ 无 | 需实现 |
| 缩略图 | ✅ 加载 Texture | ⚠️ 彩色方块 | 需改进 |
| 材质预览 | ✅ 缩略图渲染 | ❌ 无 | 需实现 |
| 拖拽移动 | ✅ 完整实现 | ⚠️ stubbed | 需修复 |
| 双击打开 | ✅ 打开文件夹 | ✅ 实现 | 完成 |
| 面包屑导航 | ✅ 路径按钮 | ✅ 实现 | 完成 |
| 搜索过滤 | ✅ 实现 | ✅ 实现 | 完成 |
XCEngine 问题详解
问题: HandleDrop() 返回 false
ProjectPanel.cpp line 294:
bool ProjectPanel::HandleDrop(const AssetItemPtr& targetFolder) {
return false; // STUBBED OUT - 拖拽移动功能不工作
}
虽然 RenderAssetItem() 中有拖拽目标代码,但实际上 HandleDrop() 从未被调用,拖拽移动功能完全失效。
3.4 MenuBar
功能对比
| 功能 | Fermion (271 行) | XCEngine (55 行) | 状态 |
|---|---|---|---|
| 实现方式 | ✅ 自定义窗口边框 | ✅ BeginMainMenuBar |
完成 |
| 菜单项 | ✅ 实际回调 | ❌ 全部 stubbed | 需实现 |
| 项目操作 | ✅ new/open/save | ❌ 无 | 需实现 |
| 创建菜单 | ✅ Material/Texture | ❌ 无 | 需实现 |
| 窗口控制 | ✅ 有 (已注释) | ❌ 无 | 可选 |
XCEngine 问题详解
所有菜单项都是空的:
// MenuBar.cpp
if (ImGui::MenuItem("New Scene", "Ctrl+N")) {} // 空
if (ImGui::MenuItem("Open Scene", "Ctrl+O")) {} // 空
if (ImGui::MenuItem("Save Scene", "Ctrl+S")) {} // 空
// ... 所有项都是空的
3.5 ConsolePanel
功能对比
| 功能 | Fermion (84 行) | XCEngine (70 行) | 状态 |
|---|---|---|---|
| 日志显示 | ✅ 彩色 + 前缀 | ✅ 彩色 + 前缀 | 完成 |
| 命令输入 | ✅ 底部输入框 | ❌ 无 | 需补充 |
| 命令处理 | ✅ clear/help | ❌ 无 | 需实现 |
| 自动滚动 | ✅ 新日志时滚动 | ⚠️ flag 设置但逻辑不完整 | 需改进 |
XCEngine 优点
- 测试按钮注入日志功能完善
- 日志级别颜色区分正确
- 基本显示功能正常
3.6 SceneViewPanel / ViewportPanel
功能对比
| 功能 | Fermion (356 行) | XCEngine (54 行) | 状态 |
|---|---|---|---|
| 3D 渲染 | ✅ Framebuffer | ❌ 只有网格 | 需重构 |
| 相机 | ✅ EditorCamera | ❌ 无 | 需实现 |
| 鼠标拾取 | ✅ readPixel | ❌ 无 | 需实现 |
| Gizmo | ✅ ImGuizmo | ❌ 无 | 需实现 |
| 工具栏 | ✅ Q/W/E/R | ❌ 无 | 需实现 |
| Play 控制 | ✅ Play/Stop/Pause/Step | ❌ 无 | 需实现 |
| 状态切换 | ✅ Edit/Play/Simulate | ❌ 无 | 需实现 |
XCEngine 实现现状
// SceneViewPanel.cpp
void SceneViewPanel::RenderGrid() {
// 只画了 50px 网格背景
for (float x = 0; x < canvasSize.x; x += gridSize) {
drawList->AddLine(...);
}
// 没有任何 3D 渲染
}
问题: 完全没有任何 3D 渲染能力,只是占位符。
3.7 GameViewPanel
| 功能 | Fermion | XCEngine | 状态 |
|---|---|---|---|
| 游戏视图 | ✅ Framebuffer 渲染 | ❌ 纯占位符 | 需重构 |
| 状态栏 | ✅ Play/Simulate 指示 | ❌ 无 | 需实现 |
4. XCEngine 缺失的面板
XCEngine Editor 只有 7 个面板,而 Fermion 有 10 个。以下是缺失的面板:
4.1 SettingsPanel - 编辑器设置
Fermion 功能:
- Renderer Info: 相机设置、设备信息、帧时间统计
- Environment Settings: Skybox、阴影、IBL、HDR 加载、环境光强度、法线强度
- Debug Settings: 渲染模式 (Forward/Deferred Hybrid)、GBuffer 调试、深度视图、物理调试开关、无限网格、轮廓设置
- Project Settings: 项目信息、默认字体配置
XCEngine 状态: 无此面板
实现建议: 可以作为 InspectorPanel 的扩展,或者单独的设置浮窗
4.2 OverlayRenderPanel - 调试可视化
Fermion 功能:
class OverlayRenderPanel {
void render(const Context &ctx) const;
void renderPhysicsColliders(); // 物理碰撞体可视化
void renderPhysics2DColliders(); // 2D 碰撞体
void renderPhysics3DColliders(); // 3D 碰撞体
void renderJoints(); // 关节连接可视化
void renderSelectedEntityOutline(); // 选中物体轮廓
};
功能说明:
- 在 Viewport 上叠加渲染物理调试信息
- 2D 碰撞体: Box、Circle、BoxSensor、CircleSensor
- 3D 碰撞体: Box、Sphere、Capsule、Mesh (三角形线框)
- 关节: RevoluteJoint (锚点圆)、DistanceJoint (锚点圆 + 线段)
- 选中物体白色轮廓
XCEngine 状态: 无此面板,但可以在 SceneViewPanel 完善后添加
4.3 MaterialEditorPanel - 材质编辑器
Fermion 功能:
- 基于
ax::NodeEditor(imnodes) 的节点式材质编辑器 - PBR Output 节点 (ID=1) 固定在右侧
- Texture 节点可动态创建
- 引脚连接系统 (Pin ID 约定:
nodeID*100 + pinIndex) - 材质预览渲染 (
MaterialPreviewRenderer) - 材质编译 (
compileMaterial())
节点系统:
// PBR Output 节点输入引脚
enum PBRInputPin {
Albedo = 1, // 引脚 ID = 101
Normal = 2, // 引脚 ID = 102
Metallic = 3, // 引脚 ID = 103
Roughness = 4,// 引脚 ID = 104
AO = 5 // 引脚 ID = 105
};
// Texture 节点输出引脚
// 引脚 ID = nodeID * 100 + 1
UI 布局:
┌─────────────────────────────────────────────────────┐
│ [Texture Node] ──────→ [Albedo] │
│ [Texture Node] ──────→ [Normal] │
│ [Texture Node] ──────→ [PBR Output] → [Material] │
│ → [Metallic] │
│ → [Roughness] │
│ → [AO] │
└─────────────────────────────────────────────────────┘
XCEngine 状态: 无此面板,需要独立开发
实现难度: 高,需要 imnodes 库集成和材质编译系统
4.4 TextureConfigPanel - 纹理配置
Fermion 功能:
class TextureConfigPanel {
void loadTexture(const std::filesystem::path &ftexPath);
void loadTextures(const vector<path> &ftexPaths);
void saveTexture(TextureConfigData &data);
void saveAllTextures();
struct TextureConfigData {
std::filesystem::path FtexPath;
std::string Name;
TextureAssetSpecification Spec;
bool Modified = false;
};
bool m_BatchMode = false; // 批量配置模式
TextureAssetSpecification m_BatchSpec;
};
功能:
- 批量纹理加载
- 纹理规格编辑 (格式、过滤器、Mipmaps 等)
- 保存/导出功能
XCEngine 状态: 无此面板,ProjectPanel 只做文件浏览
4.5 AssetManagerPanel - 资源注册表
Fermion 功能:
class AssetManagerPanel {
void onImGuiRender();
// 显示所有注册的资源
// 可搜索、可过滤
// Asset 类型过滤
// Load/Unload 按钮
// 显示: asset path, type, handle ID, loading status
};
功能:
- 查看所有已注册资产
- 按类型过滤 (Texture, Mesh, Material, etc.)
- 搜索功能
- 手动加载/卸载资产
- 显示资源路径、类型、句柄 ID、加载状态
XCEngine 状态: 无此面板,ProjectPanel 只做文件系统浏览
5. 核心系统差异分析
5.1 Application 架构对比
Fermion Application:
class Application {
std::unique_ptr<IWindow> m_window;
std::unique_ptr<ImGuiLayer> m_imGuiLayer;
std::unique_ptr<LayerStack> m_layerStack;
void pushLayer(std::unique_ptr<Layer> layer); // 在 ImGui 之前更新
void pushOverlay(std::unique_ptr<Layer> overlay); // 在 ImGui 之后更新
};
XCEngine Application:
class Application {
HWND m_hwnd;
ID3D12Device* m_device;
// 直接管理所有 Panels
std::unique_ptr<MenuBar> m_menuBar;
std::unique_ptr<HierarchyPanel> m_hierarchyPanel;
// ...
};
关键差异:
- Fermion 使用 Layer/Overlay 模式,事件按倒序传播
- XCEngine 直接管理 Panels,缺乏层次化设计
- Fermion 有 ImGuiLayer 专门处理 ImGui 事件阻塞
- XCEngine 需要手动在 Panel 内部处理焦点判断
5.2 SceneManager vs Scene/EntityManager
XCEngine SceneManager:
class SceneManager {
std::unordered_map<EntityID, GameObject> m_entities;
std::vector<EntityID> m_rootEntities;
EntityID CreateEntity(name, parent);
void DeleteEntity(id);
void MoveEntity(id, newParent);
EntityID CopyEntity(id);
EntityID PasteEntity(parent);
};
Fermion Scene + EntityManager:
class Scene {
std::unique_ptr<EntityManager> m_entityManager;
std::unique_ptr<Physics2DWorld> m_physicsWorld2D;
std::unique_ptr<Physics3DWorld> m_physicsWorld3D;
};
class EntityManager {
entt::registry m_registry; // EnTT ECS
std::unordered_map<UUID, entt::entity> m_entityMap;
};
XCEngine 实际情况:
- ✅ 有 Scene 类和 SceneManager (见 engine/include/XCEngine/Scene/)
- ❌ 没有物理世界集成
- ✅ 有 Component/GameObject 系统,但非 EnTT ECS (使用 dynamic_cast)
- ✅ EntityID 是 uint64_t 递增整数,不是 UUID
- ❌ Editor 没有场景状态 (Edit/Play/Simulate) 切换机制
5.3 BosonUI 自定义控件
Fermion 定义了 ui 命名空间的自定义控件,XCEngine 没有:
Fermion ui 控件:
namespace ui {
// 向量编辑器 (带 XYZ 标签和 reset 按钮)
void drawVec3Control(const char* label, glm::vec3& values,
float resetValue = 0.0f, float columnWidth = 120.0f);
// 浮点数编辑器
bool drawFloatControl(const char* label, float& value,
float columnWidth = 120.0f, float speed = 0.1f);
// 复选框
void drawCheckboxControl(const char* label, bool& value, float width = 120.0f);
// 自定义 Popup 包装
bool BeginPopup(const char* name);
void EndPopup();
}
XCEngine: 直接使用原生 ImGui API,没有封装
5.4 选择系统差异
Fermion 选择 + Entity Picking:
// InspectorPanel 实体拾取用于关节连接
bool m_entityPickingActive = false;
Entity m_pickingTargetEntity;
// 当用户在 Viewport 点击时
void deliverPickedEntity(Entity pickedEntity) {
if (m_pickingTargetEntity.hasComponent<RevoluteJoint2DComponent>()) {
m_pickingTargetEntity.getComponent<RevoluteJoint2DComponent>()
.connectedBodyID = pickedEntity.getUUID();
}
}
XCEngine SelectionManager:
class SelectionManager {
Event<EntityID> OnSelectionChanged;
EntityID GetSelectedEntity();
void SetSelectedEntity(EntityID entity);
};
XCEngine 问题: 没有 Entity Picking 机制,无法在编辑关节时拾取场景中的物体
5.5 资源系统对比
Fermion 资源系统:
AssetManager (抽象基类)
├── EditorAssetManager (编辑器资源管理)
│ └── importAsset() 导入资源
└── RuntimeAssetManager (运行时资源管理)
└── getAsset<T>() 获取资源
AssetRegistry (资源注册表)
AssetHandle (资源句柄)
XCEngine 资源系统:
ProjectManager (文件系统浏览)
└── GetCurrentItems() 返回 AssetItem 列表
AssetItem (只包含文件信息)
├── name
├── type
├── isFolder
└── fullPath
XCEngine 问题:
- 没有真正的资源导入流程
- 没有 AssetRegistry 资源注册表
- 没有 AssetHandle 统一资源句柄
- 没有资源缓存和加载/卸载管理
7. 核心问题总结
7.1 已完成功能
| 面板 | 完成度 | 说明 |
|---|---|---|
| HierarchyPanel | 70% | 基本树视图、选中、重命名、复制、拖拽 |
| ProjectPanel | 60% | 文件浏览、网格显示、导航,但拖拽移动失效 |
| ConsolePanel | 60% | 日志显示,缺少命令输入 |
| MenuBar | 30% | 菜单结构存在,但所有项 stubbed |
| InspectorPanel | 20% | 只实现 Transform 和 MeshRenderer 编辑,但 Engine 核心有完整组件库 |
| SceneViewPanel | 5% | 纯占位符 |
| GameViewPanel | 5% | 纯占位符 |
7.2 高优先级问题
- MenuBar 所有菜单项 stubbed - 无法进行任何 Scene/Project 操作
- Inspector 没有 Add/Remove Component - 无法添加/删除组件
- SceneViewPanel 完全是占位符 - 无法预览场景
- Project 拖拽移动失效 - HandleDrop() 返回 false
- 缺少 5 个重要面板 - SettingsPanel, OverlayRenderPanel, MaterialEditorPanel, TextureConfigPanel, AssetManagerPanel
7.3 RHI 限制
当前 RHI 模块状态:
- D3D12: PipelineState 返回 nullptr,无法创建 3D 渲染 Pipeline
- OpenGL: Framebuffer、PipelineState、Shader 正常工作
影响: 在 RHI 重构完成前,3D Viewport 无法实现。
8. 改进计划
8.1 第一阶段: 完善现有面板功能
目标: 不依赖 RHI,完善 Editor UI 功能
8.1.1 MenuBar 菜单功能对接
优先级: 高
预计工作量: 1-2 天
依赖: 无
需要实现:
- File 菜单: New Scene, Open Scene, Save Scene, Exit
- Edit 菜单: Undo, Redo (需要命令历史系统), Cut, Copy, Paste
- View 菜单: Reset Layout
- Help 菜单: About
实现方案:
// MenuBar.cpp
if (ImGui::MenuItem("New Scene", "Ctrl+N")) {
m_onNewSceneCallback(); // 通过回调连接到 BosonLayer
}
8.1.2 Inspector Add/Remove Component
优先级: 高
预计工作量: 2-3 天
依赖: 组件系统完善
需要实现:
- 添加 "Add Component" 按钮
- 分类组件菜单 (2D, 3D, Other)
- 右键 "Remove Component" 选项
实现方案:
// InspectorPanel.cpp
void InspectorPanel::drawComponent<T>(Entity entity, UIFunction uiFunction) {
// 右键菜单
if (ImGui::BeginPopupContextItem("ComponentSettings")) {
if (ImGui::MenuItem("Remove Component"))
entity.removeComponent<T>();
ImGui::EndPopup();
}
}
// Add Component 按钮
if (ImGui::Button("Add Component")) {
ImGui::OpenPopup("AddComponentMenu");
}
// 分类显示组件列表
8.1.3 修复 Project 拖拽移动
优先级: 中
预计工作量: 0.5 天
依赖: 无
问题: HandleDrop() 返回 false,从未被调用
修复方案: 在双击打开文件夹时,检查是否正在拖拽,如果是则执行移动操作。
8.2 第二阶段: Inspector 组件系统完善
目标: 实现完整的组件编辑功能
8.2.1 Inspector 组件编辑支持
Engine 核心已有完整组件系统,Editor Inspector 需要添加对这些组件的编辑支持:
| 组件 | Engine 状态 | Inspector 编辑复杂度 | 说明 |
|---|---|---|---|
| TransformComponent | ✅ | 低 | 需改进 UI (drawVec3Control) |
| MeshRendererComponent | ✅ | 中 | 需添加拖拽、预览 |
| CameraComponent | ✅ | 中 | 投影、FOV、近远裁剪 |
| DirectionalLightComponent | ✅ | 低 | 颜色、强度 |
| PointLightComponent | ✅ | 低 | 颜色、强度、范围 |
| SpotLightComponent | ✅ | 中 | 颜色、强度、范围、角度 |
| Rigidbody2DComponent | ✅ | 高 | 物理引擎对接 |
| Rigidbody3DComponent | ✅ | 高 | 物理引擎对接 |
| Collider2D/3D | ✅ | 高 | 碰撞体 |
| SpriteRendererComponent | ✅ | 中 | 2D 精灵 |
| CircleRendererComponent | ✅ | 低 | 圆形渲染 |
| TextComponent | ✅ | 中 | 文本渲染 |
| ScriptComponent | ✅ | 高 | 脚本字段编辑 |
8.2.2 Transform UI 改进
当前:
ImGui::DragFloat3("##Position", transform->position, 0.1f);
改进方案 (参考 Fermion ui::drawVec3Control):
- 添加 XYZ 标签
- 添加 Per-axis reset 按钮
- 统一对齐和缩进
- 添加合适的刻度 (speed)
8.3 第三阶段: 场景序列化
目标: 实现 Scene Save/Load
优先级: 中
预计工作量: 2-3 天
依赖: Scene 序列化框架 (Engine Scene 类已有基础 Serialize/Deserialize)
需要实现:
- Scene 序列化到文件 (Engine 核心已有基础)
- Scene 反序列化
- 资源路径管理
- Editor/Runtime 场景分离
8.4 第四阶段: 3D Viewport (依赖 RHI)
目标: 实现完整的 3D Viewport
优先级: 高 (但依赖 RHI)
预计工作量: 2-4 周
依赖: RHI 重构完成
8.4.1 OpenGL Backend 优先方案
由于 D3D12 PipelineState 当前 broken,可以先用 OpenGL Backend 实现 Viewport:
优势:
- OpenGL Framebuffer 正常工作
- OpenGL PipelineState 正常工作
- Shader uniform 设置正常工作
需要工作:
- EditorCamera 实现 (Orbit/Pan/Zoom)
- SceneRenderer 中间层
- ViewportPanel Framebuffer 渲染
- 鼠标拾取 (readPixel from entity ID attachment)
- ImGuizmo 集成
8.4.2 实现步骤
Step 1: EditorCamera (3-5 天)
class EditorCamera {
// Orbit 模式
void orbit(float deltaX, float deltaY);
void pan(float deltaX, float deltaY);
void zoom(float delta);
// FPS 模式
void moveForward(float delta);
void moveRight(float delta);
};
Step 2: SceneRenderer 中间层 (1 周)
class ViewportRenderer {
std::shared_ptr<Framebuffer> m_framebuffer;
std::shared_ptr<Scene> m_scene;
void beginScene(const EditorCamera& camera);
void submitMesh(MeshComponent& mesh, glm::mat4 transform);
void endScene();
};
Step 3: ViewportPanel 集成 (3-5 天)
void ViewportPanel::onImGuiRender() {
// 渲染到 framebuffer
m_framebuffer->bind();
m_viewportRenderer->beginScene(m_editorCamera);
// ... 提交场景物体
m_viewportRenderer->endScene();
m_framebuffer->unbind();
// 显示到 ImGui
ImGui::Image(m_framebuffer->getColorTexture(), ...);
// 鼠标拾取
int entityID = m_framebuffer->readPixel(1, pixelX, pixelY);
}
Step 4: ImGuizmo 集成 (2-3 天)
ImGuizmo::SetOrthographic(isOrthographic);
ImGuizmo::SetRect(viewportBounds);
ImGuizmo::Manipulate(
cameraView, cameraProjection,
operation, LOCAL,
glm::value_ptr(worldTransform)
);
8.5 第五阶段: Play/Edit 模式
目标: 实现场景状态切换
优先级: 中
预计工作量: 1-2 周
依赖: 3D Viewport + 组件系统
状态机:
enum class SceneState { Edit, Play, Simulate };
void BosonLayer::onScenePlay() {
m_runtimeScene = Scene::copy(m_editorScene);
m_activeScene = m_runtimeScene;
m_activeScene->onRuntimeStart();
}
void BosonLayer::onSceneStop() {
m_activeScene->onRuntimeStop();
m_activeScene = m_editorScene;
}
9. 技术债务
9.1 架构问题
-
Editor 和 Engine 使用两套不同的 GameObject/Component 系统
- Editor (
editor/src/Core/GameObject.h): 简化版,使用float position[3]数组存储变换 - Engine (
engine/include/XCEngine/Components/): 完整 ECS,使用TransformComponent组件 - 后果: Editor 无法直接使用 Engine 的组件系统,需要重新实现
- 建议: Editor 应复用 Engine 的 Components::GameObject/Scene 系统
- Editor (
-
Panel 独立设计 vs Layer 组合
- Fermion: BosonLayer 组合所有面板,共享 Context
- XCEngine: 各 Panel 独立,通过 SceneManager 单例通信
-
SceneManager 单例 vs Scene 指针传递
- Editor 使用简化版 SceneManager,与 Engine 的 Scene 类不兼容
- 建议: 考虑使用 Context 模式传递 Scene 引用
-
缺少 BosonUI 自定义控件封装
- Fermion 有 ui::drawVec3Control, ui::drawFloatControl 等
- XCEngine 直接使用原生 ImGui API,代码重复
9.2 代码质量问题
- 注释掉的代码 - 建议清理
- TODO/FIXME - 建议跟踪
- Magic numbers - 建议定义常量
10. 建议实施路线
短期 (1-2 周)
□ MenuBar 菜单功能对接
□ Inspector Add/Remove Component
□ 修复 Project 拖拽移动
□ Transform UI 改进
□ Console 命令输入
中期 (1-2 月,RHI 完成后)
□ EditorCamera 实现
□ SceneRenderer 中间层
□ ViewportPanel 3D 渲染
□ 鼠标拾取
□ ImGuizmo 集成
□ Play/Edit/Simulate 模式
长期
□ 完整的 Inspector 组件编辑界面 (Engine 核心组件已有)
□ 场景序列化
□ 资源导入系统
□ 材质编辑器
□ 动画编辑器
□ OverlayRenderPanel (物理调试可视化)
□ TextureConfigPanel (纹理配置)
□ AssetManagerPanel (资源注册表)
□ SettingsPanel (编辑器设置)
□ Play/Edit/Simulate 模式切换
11. 参考资料
- Fermion Boson Editor 源码:
参考/Fermion/Boson/ - XCEngine Editor 源码:
editor/ - RHI 模块:
engine/include/XCEngine/RHI/
文档生成时间: 2026-03-24 最后更新: 2026-03-24 (更正 Component 系统描述,补充 Editor/Engine 架构问题)