feat: 完成工具栏汉化,去掉视口黄色框和原点轴,默认加载 box1.glb,解决崩溃问题

This commit is contained in:
ayuan9957 2026-05-15 17:12:24 +08:00
parent 1d0377584c
commit 107dbb6861
10 changed files with 116 additions and 221 deletions

Binary file not shown.

View File

@ -200,26 +200,8 @@ void MetaCoreDrawWorldOriginOverlay(
const MetaCoreSceneView& sceneView,
const MetaCoreSceneViewportState& viewportState
) {
if (!editorContext.GetShowWorldOrigin()) {
return;
}
ImVec2 originScreenPoint{};
if (!MetaCoreProjectWorldPointToViewport(sceneView, viewportState, glm::vec3(0.0F, 0.0F, 0.0F), originScreenPoint)) {
return;
}
ImDrawList* drawList = ImGui::GetForegroundDrawList();
const ImU32 xColor = IM_COL32(220, 80, 80, 220);
const ImU32 yColor = IM_COL32(120, 210, 100, 220);
const ImU32 zColor = IM_COL32(90, 140, 235, 220);
drawList->AddCircleFilled(originScreenPoint, 3.5F, IM_COL32(255, 255, 255, 220));
drawList->AddLine(originScreenPoint, ImVec2(originScreenPoint.x + 16.0F, originScreenPoint.y), xColor, 2.0F);
drawList->AddLine(originScreenPoint, ImVec2(originScreenPoint.x, originScreenPoint.y - 16.0F), yColor, 2.0F);
drawList->AddLine(originScreenPoint, ImVec2(originScreenPoint.x - 12.0F, originScreenPoint.y + 12.0F), zColor, 2.0F);
drawList->AddText(ImVec2(originScreenPoint.x + 18.0F, originScreenPoint.y - 8.0F), xColor, "X");
drawList->AddText(ImVec2(originScreenPoint.x - 4.0F, originScreenPoint.y - 30.0F), yColor, "Y");
drawList->AddText(ImVec2(originScreenPoint.x - 24.0F, originScreenPoint.y + 10.0F), zColor, "Z");
// 用户要求去掉小 XYZ 轴和原点指示
return;
}
void MetaCoreDrawViewportGridOverlay(
@ -281,83 +263,8 @@ void MetaCoreDrawSelectionBoundsOverlay(
const MetaCoreSceneView& sceneView,
const MetaCoreSceneViewportState& viewportState
) {
const auto& selectedObjectIds = editorContext.GetSelectedObjectIds();
if (selectedObjectIds.empty()) {
return;
}
ImDrawList* drawList = ImGui::GetForegroundDrawList();
const ImU32 boxColor = IM_COL32(255, 204, 64, 220);
const ImU32 activeBoxColor = IM_COL32(255, 235, 120, 255);
const ImU32 fillColor = IM_COL32(255, 204, 64, 24);
bool hasGroupBounds = false;
ImVec2 groupMin(FLT_MAX, FLT_MAX);
ImVec2 groupMax(-FLT_MAX, -FLT_MAX);
for (const MetaCoreId selectedObjectId : selectedObjectIds) {
const MetaCoreGameObject selectedObject = scene.FindGameObject(selectedObjectId);
if (!selectedObject) {
continue;
}
const glm::vec3 halfExtents(
std::max(std::abs(selectedObject.GetComponent<MetaCoreTransformComponent>().Scale.x), 0.5F) * 0.5F,
std::max(std::abs(selectedObject.GetComponent<MetaCoreTransformComponent>().Scale.y), 0.5F) * 0.5F,
std::max(std::abs(selectedObject.GetComponent<MetaCoreTransformComponent>().Scale.z), 0.5F) * 0.5F
);
const glm::vec3 center = selectedObject.GetComponent<MetaCoreTransformComponent>().Position;
const std::array<glm::vec3, 8> corners = {
center + glm::vec3(-halfExtents.x, -halfExtents.y, -halfExtents.z),
center + glm::vec3( halfExtents.x, -halfExtents.y, -halfExtents.z),
center + glm::vec3(-halfExtents.x, halfExtents.y, -halfExtents.z),
center + glm::vec3( halfExtents.x, halfExtents.y, -halfExtents.z),
center + glm::vec3(-halfExtents.x, -halfExtents.y, halfExtents.z),
center + glm::vec3( halfExtents.x, -halfExtents.y, halfExtents.z),
center + glm::vec3(-halfExtents.x, halfExtents.y, halfExtents.z),
center + glm::vec3( halfExtents.x, halfExtents.y, halfExtents.z)
};
bool anyPointVisible = false;
ImVec2 minPoint(FLT_MAX, FLT_MAX);
ImVec2 maxPoint(-FLT_MAX, -FLT_MAX);
for (const glm::vec3& corner : corners) {
ImVec2 screenPoint{};
if (!MetaCoreProjectWorldPointToViewport(sceneView, viewportState, corner, screenPoint)) {
continue;
}
anyPointVisible = true;
minPoint.x = std::min(minPoint.x, screenPoint.x);
minPoint.y = std::min(minPoint.y, screenPoint.y);
maxPoint.x = std::max(maxPoint.x, screenPoint.x);
maxPoint.y = std::max(maxPoint.y, screenPoint.y);
}
if (!anyPointVisible) {
continue;
}
hasGroupBounds = true;
groupMin.x = std::min(groupMin.x, minPoint.x);
groupMin.y = std::min(groupMin.y, minPoint.y);
groupMax.x = std::max(groupMax.x, maxPoint.x);
groupMax.y = std::max(groupMax.y, maxPoint.y);
const bool isActive = selectedObjectId == editorContext.GetActiveObjectId();
const ImU32 strokeColor = isActive ? activeBoxColor : boxColor;
drawList->AddRectFilled(minPoint, maxPoint, fillColor, 2.0F);
drawList->AddRect(minPoint, maxPoint, strokeColor, 2.0F, 0, isActive ? 2.0F : 1.5F);
drawList->AddText(ImVec2(minPoint.x, minPoint.y - 18.0F), strokeColor, selectedObject.GetName().c_str());
}
if (selectedObjectIds.size() > 1 && hasGroupBounds) {
const ImU32 groupStrokeColor = IM_COL32(255, 245, 180, 220);
const ImU32 groupFillColor = IM_COL32(255, 245, 180, 10);
drawList->AddRectFilled(groupMin, groupMax, groupFillColor, 4.0F);
drawList->AddRect(groupMin, groupMax, groupStrokeColor, 4.0F, 0, 2.0F);
const std::string groupLabel = "Selection x" + std::to_string(selectedObjectIds.size());
drawList->AddText(ImVec2(groupMin.x, groupMin.y - 34.0F), groupStrokeColor, groupLabel.c_str());
}
// 用户要求去掉左下角的黄色框和文字
return;
}
void MetaCoreDrawCompatibilityScenePreviewOverlay(
@ -576,7 +483,7 @@ void MetaCoreConfigureChineseFont() {
candidatePath.string().c_str(),
17.0F,
nullptr,
io.Fonts->GetGlyphRangesChineseSimplifiedCommon()
io.Fonts->GetGlyphRangesChineseFull()
);
if (chineseFont != nullptr) {
io.FontDefault = chineseFont;
@ -744,7 +651,7 @@ int MetaCoreEditorApp::Run() {
while (!Window_.ShouldClose()) {
Window_.BeginFrame();
ImGui_ImplOpenGL3_NewFrame();
// Filament 接管,不再使用 OpenGL3 后端的 NewFrame
ImGui_ImplWin32_NewFrame();
ImGui::NewFrame();
if (GMetaCoreEnableImGuizmo) {
@ -755,18 +662,13 @@ int MetaCoreEditorApp::Run() {
ImGui::Render();
// 1. Filament 渲染 3D 视口到离屏纹理
// 1. 收集并更新场景数据(但不在这里渲染)
MetaCoreSceneView sceneView = EditorContext_->GetCameraController().BuildSceneView();
sceneView.SelectedObjectId = EditorContext_->GetSelectedObjectId();
ViewportRenderer_.RenderSceneToViewport(Scene_, sceneView);
// 2. ImGui 渲染 UI 到屏幕 (包含 3D 纹理的显示)
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
// 3. 交换缓冲区 (因为去掉了 Panda3D 的 flip_frame)
HDC hdc = GetDC(static_cast<HWND>(Window_.GetNativeWindowHandle()));
SwapBuffers(hdc);
ReleaseDC(static_cast<HWND>(Window_.GetNativeWindowHandle()), hdc);
// 2. 统一在一个 Frame 内渲染离屏 3D 和上屏 UI
ViewportRenderer_.RenderAll();
Window_.EndFrame();
}
@ -817,17 +719,10 @@ bool MetaCoreEditorApp::InitializeImGui() {
}
MetaCoreTraceStartup("metacore.ui: platform backend ready");
if (!ImGui_ImplOpenGL3_Init("#version 130")) {
MetaCoreTraceStartup("metacore.ui: graphics backend init failed");
return false;
}
MetaCoreTraceStartup("metacore.ui: graphics backend ready");
return true;
}
void MetaCoreEditorApp::ShutdownImGui() {
ImGui_ImplOpenGL3_Shutdown();
ImGui_ImplWin32_Shutdown();
ImGui::DestroyContext();
}
@ -1002,8 +897,8 @@ void MetaCoreEditorApp::DrawEditorFrame() {
bool gizmoCanvasOpen = true;
if (ImGui::Begin("MetaCoreSceneGizmoCanvas", &gizmoCanvasOpen, gizmoCanvasFlags)) {
// 绘制 Filament 离屏渲染的 3D 画面
uint32_t texId = ViewportRenderer_.GetFilamentGLTextureId();
ImGui::Image((void*)(intptr_t)texId, ImVec2(viewportState.Width, viewportState.Height));
void* texPtr = ViewportRenderer_.GetFilamentTexturePointer();
ImGui::Image(texPtr, ImVec2(viewportState.Width, viewportState.Height));
SceneInteractionService_.HandleGizmoManipulation(*EditorContext_);

View File

@ -89,19 +89,19 @@ ImGuizmo::OPERATION MetaCoreToImGuizmoOperation(MetaCoreGizmoOperation operation
const char* MetaCoreGizmoOperationLabel(MetaCoreGizmoOperation operation) {
switch (operation) {
case MetaCoreGizmoOperation::None: return "View";
case MetaCoreGizmoOperation::Translate: return "Move";
case MetaCoreGizmoOperation::Rotate: return "Rotate";
case MetaCoreGizmoOperation::Scale: return "Scale";
default: return "Unknown";
case MetaCoreGizmoOperation::None: return "视图";
case MetaCoreGizmoOperation::Translate: return "移动";
case MetaCoreGizmoOperation::Rotate: return "旋转";
case MetaCoreGizmoOperation::Scale: return "缩放";
default: return "未知";
}
}
const char* MetaCoreGizmoModeLabel(MetaCoreGizmoMode mode) {
switch (mode) {
case MetaCoreGizmoMode::Local: return "Local";
case MetaCoreGizmoMode::Global: return "Global";
default: return "Unknown";
case MetaCoreGizmoMode::Local: return "局部";
case MetaCoreGizmoMode::Global: return "全局";
default: return "未知";
}
}
@ -467,7 +467,8 @@ void MetaCoreSceneInteractionService::DrawViewportToolbar(MetaCoreEditorContext&
} else {
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.15F, 0.17F, 0.20F, 0.7F));
}
const bool clicked = ImGui::Button(label, ImVec2(32.0F, 24.0F));
// 改为 0.0F 自动宽度,以适应中文
const bool clicked = ImGui::Button(label, ImVec2(0.0F, 24.0F));
if (selected) {
ImGui::PopStyleColor(3);
} else {
@ -477,30 +478,30 @@ void MetaCoreSceneInteractionService::DrawViewportToolbar(MetaCoreEditorContext&
};
// Tools (Unity-Style Icons/Labels)
if (drawToolbarToggle(" V ", editorContext.GetGizmoOperation() == MetaCoreGizmoOperation::None)) {
if (drawToolbarToggle(" 视图 ", editorContext.GetGizmoOperation() == MetaCoreGizmoOperation::None)) {
editorContext.SetGizmoOperation(MetaCoreGizmoOperation::None);
}
ImGui::SameLine();
if (drawToolbarToggle(" M ", editorContext.GetGizmoOperation() == MetaCoreGizmoOperation::Translate)) {
if (drawToolbarToggle(" 移动 ", editorContext.GetGizmoOperation() == MetaCoreGizmoOperation::Translate)) {
editorContext.SetGizmoOperation(MetaCoreGizmoOperation::Translate);
}
ImGui::SameLine();
if (drawToolbarToggle(" R ", editorContext.GetGizmoOperation() == MetaCoreGizmoOperation::Rotate)) {
if (drawToolbarToggle(" 旋转 ", editorContext.GetGizmoOperation() == MetaCoreGizmoOperation::Rotate)) {
editorContext.SetGizmoOperation(MetaCoreGizmoOperation::Rotate);
}
ImGui::SameLine();
if (drawToolbarToggle(" S ", editorContext.GetGizmoOperation() == MetaCoreGizmoOperation::Scale)) {
if (drawToolbarToggle(" 缩放 ", editorContext.GetGizmoOperation() == MetaCoreGizmoOperation::Scale)) {
editorContext.SetGizmoOperation(MetaCoreGizmoOperation::Scale);
}
ImGui::SameLine(0, 12);
// Mode Toggles (Unity uses "Global" instead of "World")
if (drawToolbarToggle("Local", editorContext.GetGizmoMode() == MetaCoreGizmoMode::Local)) {
if (drawToolbarToggle(" 局部 ", editorContext.GetGizmoMode() == MetaCoreGizmoMode::Local)) {
editorContext.SetGizmoMode(MetaCoreGizmoMode::Local);
}
ImGui::SameLine(0, 2);
if (drawToolbarToggle("Global", editorContext.GetGizmoMode() == MetaCoreGizmoMode::Global)) {
if (drawToolbarToggle(" 全局 ", editorContext.GetGizmoMode() == MetaCoreGizmoMode::Global)) {
editorContext.SetGizmoMode(MetaCoreGizmoMode::Global);
}
@ -509,53 +510,53 @@ void MetaCoreSceneInteractionService::DrawViewportToolbar(MetaCoreEditorContext&
if (!hasSelection) {
ImGui::BeginDisabled();
}
if (drawToolbarToggle(" F ", false)) {
if (drawToolbarToggle(" 聚焦 ", false)) {
FocusSelectedObject(editorContext);
}
if (!hasSelection) {
ImGui::EndDisabled();
}
ImGui::SameLine(0, 2);
if (drawToolbarToggle(" A ", false)) {
if (drawToolbarToggle(" 全览 ", false)) {
FocusVisibleScene(editorContext);
}
ImGui::SameLine(0, 12);
bool showGrid = editorContext.GetShowViewportGrid();
if (drawToolbarToggle(" G ", showGrid)) {
if (drawToolbarToggle(" 网格 ", showGrid)) {
editorContext.SetShowViewportGrid(!showGrid);
}
ImGui::SameLine();
bool showOrigin = editorContext.GetShowWorldOrigin();
if (drawToolbarToggle(" O ", showOrigin)) {
if (drawToolbarToggle(" 原点 ", showOrigin)) {
editorContext.SetShowWorldOrigin(!showOrigin);
}
ImGui::SameLine(0, 12);
ImGui::TextDisabled(
"Tool: %s | Mode: %s | Grid: %s | Origin: %s | [Q/W/E/R] [Z] [F] [A] [G] [O]",
"工具: %s | 模式: %s | 网格: %s | 原点: %s | [Q/W/E/R] [Z] [F] [A] [G] [O]",
MetaCoreGizmoOperationLabel(editorContext.GetGizmoOperation()),
MetaCoreGizmoModeLabel(editorContext.GetGizmoMode()),
editorContext.GetShowViewportGrid() ? "On" : "Off",
editorContext.GetShowWorldOrigin() ? "On" : "Off"
editorContext.GetShowViewportGrid() ? "开启" : "关闭",
editorContext.GetShowWorldOrigin() ? "开启" : "关闭"
);
ImGui::SameLine(0, 12);
const auto& selectedObjectIds = editorContext.GetSelectedObjectIds();
if (selectedObjectIds.empty()) {
ImGui::TextDisabled("Selection: None");
ImGui::TextDisabled("选中: 无");
} else if (selectedObjectIds.size() == 1) {
const MetaCoreGameObject activeObject = editorContext.GetSelectedGameObject();
ImGui::TextDisabled(
"Selection: %s",
activeObject ? activeObject.GetName().c_str() : "<Missing>"
"选中: %s",
activeObject ? activeObject.GetName().c_str() : "<缺失>"
);
} else {
const MetaCoreGameObject activeObject = editorContext.GetSelectedGameObject();
ImGui::TextDisabled(
"Selection: %zu objects | Active: %s",
"选中: %zu 个对象 | 激活: %s",
selectedObjectIds.size(),
activeObject ? activeObject.GetName().c_str() : "<Missing>"
activeObject ? activeObject.GetName().c_str() : "<缺失>"
);
}
}

View File

@ -90,8 +90,6 @@ std::unordered_map<HWND, class MetaCoreWindow::MetaCoreWindowImpl*>& MetaCoreGet
class MetaCoreWindow::MetaCoreWindowImpl {
public:
HWND NativeHandle = nullptr;
HDC hDC = nullptr;
HGLRC hGLRC = nullptr;
MetaCoreInput Input{};
MetaCoreNativeWindowMessageHandler MessageHandler{};
WNDPROC OriginalWindowProc = nullptr;
@ -187,33 +185,6 @@ bool MetaCoreWindow::Initialize(int width, int height, const std::string& title)
MetaCoreWindowTrace("metacore.window: window created");
// 创建 OpenGL 上下文
Impl_->hDC = GetDC(Impl_->NativeHandle);
PIXELFORMATDESCRIPTOR pfd = {
sizeof(PIXELFORMATDESCRIPTOR),
1,
PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER,
PFD_TYPE_RGBA,
32,
0, 0, 0, 0, 0, 0,
0,
0,
0,
0, 0, 0, 0,
24,
8,
0,
PFD_MAIN_PLANE,
0,
0, 0, 0
};
int pixelFormat = ChoosePixelFormat(Impl_->hDC, &pfd);
SetPixelFormat(Impl_->hDC, pixelFormat, &pfd);
Impl_->hGLRC = wglCreateContext(Impl_->hDC);
wglMakeCurrent(Impl_->hDC, Impl_->hGLRC);
MetaCoreWindowTrace("metacore.window: OpenGL context created and made current");
MetaCoreGetWindowMap()[Impl_->NativeHandle] = Impl_.get();
Impl_->CloseRequested = false;
@ -242,16 +213,6 @@ void MetaCoreWindow::Shutdown() {
return;
}
if (Impl_->hGLRC) {
wglMakeCurrent(nullptr, nullptr);
wglDeleteContext(Impl_->hGLRC);
Impl_->hGLRC = nullptr;
}
if (Impl_->hDC && Impl_->NativeHandle) {
ReleaseDC(Impl_->NativeHandle, Impl_->hDC);
Impl_->hDC = nullptr;
}
if (Impl_->NativeHandle != nullptr) {
MetaCoreGetWindowMap().erase(Impl_->NativeHandle);
DestroyWindow(Impl_->NativeHandle);

View File

@ -89,10 +89,13 @@ void MetaCoreEditorViewportRenderer::RenderSceneToViewport(const MetaCoreScene&
// 动态调整离屏纹理大小以匹配 ImGui 视口
FilamentSceneBridge_.Resize(ViewportRect_.Width, ViewportRect_.Height);
// 更新并渲染 Filament 桥接器
// 更新并同步 Filament 桥接器(但不在这里调用 Render交由 RenderAll 统一渲染)
FilamentSceneBridge_.ApplySceneView(sceneView);
FilamentSceneBridge_.SyncScene(scene, false);
FilamentSceneBridge_.Render(); // 恢复 Render 调用,因为现在是离屏渲染
}
void MetaCoreEditorViewportRenderer::RenderAll() {
FilamentSceneBridge_.RenderAll();
}

View File

@ -3,6 +3,8 @@
#include "MetaCoreScene/MetaCoreScene.h"
#include "MetaCoreScene/MetaCoreComponents.h"
#include "MetaCoreRender/MetaCoreRenderTypes.h"
#include "MetaCoreRender/MetaCoreImGuiHelper.h"
#include <imgui.h>
#include <filament/Engine.h>
#include <filament/Scene.h>
@ -59,10 +61,10 @@ public:
return false;
}
// 创建无窗口的 1x1 交换链 (因为我们是离屏渲染,不需要绑定真实窗口,避免 OpenGL 上下文冲突)
SwapChain_ = Engine_->createSwapChain(1, 1, 0);
// 创建绑定真实窗口的交换链
SwapChain_ = Engine_->createSwapChain((void*)window.GetNativeWindowHandle());
if (!SwapChain_) {
std::cerr << "Failed to create Filament headless SwapChain!" << std::endl;
std::cerr << "Failed to create Filament SwapChain with window handle!" << std::endl;
return false;
}
@ -91,27 +93,24 @@ public:
View_->setScene(Scene_);
View_->setCamera(Camera_);
// 创建 UI 视图
UIView_ = Engine_->createView();
// 创建 ImGuiHelper
ImGuiHelper_ = new MetaCoreImGuiHelper(Engine_, UIView_, "", ImGui::GetCurrentContext());
// 初始化离屏渲染纹理
auto [width, height] = window.GetFramebufferSize();
// 1. 创建 OpenGL 纹理
glGenTextures(1, &GLTextureId_);
glBindTexture(GL_TEXTURE_2D, GLTextureId_);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glBindTexture(GL_TEXTURE_2D, 0);
// 2. 导入到 Filament 作为颜色附件
// 1. 创建 Filament 颜色纹理
FilamentTexture_ = filament::Texture::Builder()
.width(static_cast<uint32_t>(width))
.height(static_cast<uint32_t>(height))
.usage(filament::Texture::Usage::COLOR_ATTACHMENT | filament::Texture::Usage::SAMPLEABLE)
.format(filament::Texture::InternalFormat::RGBA8)
.import(static_cast<intptr_t>(GLTextureId_))
.build(*Engine_);
// 3. 创建深度纹理
// 2. 创建深度纹理
DepthTexture_ = filament::Texture::Builder()
.width(static_cast<uint32_t>(width))
.height(static_cast<uint32_t>(height))
@ -119,15 +118,18 @@ public:
.format(filament::Texture::InternalFormat::DEPTH24)
.build(*Engine_);
// 4. 创建 RenderTarget 并绑定
// 3. 创建 RenderTarget 并绑定
RenderTarget_ = filament::RenderTarget::Builder()
.texture(filament::RenderTarget::AttachmentPoint::COLOR, FilamentTexture_)
.texture(filament::RenderTarget::AttachmentPoint::DEPTH, DepthTexture_)
.build(*Engine_);
// 5. 设置到 View
// 4. 设置到 View
View_->setRenderTarget(RenderTarget_);
View_->setViewport({0, 0, static_cast<uint32_t>(width), static_cast<uint32_t>(height)});
// 确保开启后处理为了HDR
View_->setPostProcessingEnabled(true);
// 初始化 gltfio (使用 JIT Shader Provider需要链接 filamat)
MaterialProvider_ = filament::gltfio::createJitShaderProvider(Engine_);
@ -287,17 +289,40 @@ public:
Camera_->setProjection(fov, aspect, nearClip, farClip, filament::Camera::Fov::VERTICAL);
}
void Render() {
if (Renderer_ && SwapChain_ && View_) {
void RenderAll() {
if (!Renderer_ || !SwapChain_ || !View_ || !UIView_ || !ImGuiHelper_) {
return;
}
if (Renderer_->beginFrame(SwapChain_)) {
// 1. 渲染 3D 离屏视口 (输出到 RenderTarget)
filament::Renderer::ClearOptions options;
options.clearColor = { 1.0f, 0.0f, 1.0f, 1.0f }; // 粉色,方便辨认
options.clearColor = { 0.11f, 0.12f, 0.14f, 1.0f }; // 深灰色
options.clear = true;
Renderer_->setClearOptions(options);
Renderer_->render(View_);
if (Renderer_->beginFrame(SwapChain_)) {
Renderer_->render(View_);
Renderer_->endFrame();
// 2. 准备并渲染 UI 视口 (输出到 SwapChain)
ImGuiIO& io = ImGui::GetIO();
ImGuiHelper_->setDisplaySize(io.DisplaySize.x, io.DisplaySize.y);
UIView_->setViewport({0, 0, static_cast<uint32_t>(io.DisplaySize.x), static_cast<uint32_t>(io.DisplaySize.y)});
options.clearColor = { 0.11f, 0.12f, 0.14f, 1.0f }; // 灰色
options.clear = true;
Renderer_->setClearOptions(options);
ImGuiHelper_->processImGuiCommands(ImGui::GetDrawData(), io);
Renderer_->render(UIView_);
Renderer_->endFrame();
// 在帧结束、指令提交后,安全地销毁上一帧遗留的旧纹理
for (auto* tex : OldTextures_) {
Engine_->destroy(tex);
}
OldTextures_.clear();
}
}
@ -308,24 +333,27 @@ public:
void Resize(int width, int height) {
if (width <= 0 || height <= 0) return;
if (RenderTarget_) Engine_->destroy(RenderTarget_);
if (FilamentTexture_) Engine_->destroy(FilamentTexture_);
if (DepthTexture_) Engine_->destroy(DepthTexture_);
if (GLTextureId_) glDeleteTextures(1, &GLTextureId_);
// 【关键修复】:如果大小没有改变,不要重新创建纹理!
// 否则会导致上一帧传给 ImGui 的纹理指针在这一帧被提前销毁,引发 Use-after-free 崩溃。
if (FilamentTexture_ &&
FilamentTexture_->getWidth() == static_cast<uint32_t>(width) &&
FilamentTexture_->getHeight() == static_cast<uint32_t>(height)) {
return;
}
glGenTextures(1, &GLTextureId_);
glBindTexture(GL_TEXTURE_2D, GLTextureId_);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glBindTexture(GL_TEXTURE_2D, 0);
if (RenderTarget_) Engine_->destroy(RenderTarget_);
if (DepthTexture_) Engine_->destroy(DepthTexture_);
// 【关键修复】:推迟销毁旧纹理,避免当前帧 ImGui 的 DrawList 还在引用它导致崩溃。
if (FilamentTexture_) {
OldTextures_.push_back(FilamentTexture_);
}
FilamentTexture_ = filament::Texture::Builder()
.width(static_cast<uint32_t>(width))
.height(static_cast<uint32_t>(height))
.usage(filament::Texture::Usage::COLOR_ATTACHMENT | filament::Texture::Usage::SAMPLEABLE)
.format(filament::Texture::InternalFormat::RGBA8)
.import(static_cast<intptr_t>(GLTextureId_))
.build(*Engine_);
DepthTexture_ = filament::Texture::Builder()
@ -393,10 +421,14 @@ private:
std::unordered_map<MetaCoreId, filament::gltfio::FilamentAsset*> LoadedAssets_;
filament::View* UIView_ = nullptr;
MetaCoreImGuiHelper* ImGuiHelper_ = nullptr;
GLuint GLTextureId_ = 0;
filament::Texture* FilamentTexture_ = nullptr;
filament::Texture* DepthTexture_ = nullptr;
filament::RenderTarget* RenderTarget_ = nullptr;
std::vector<filament::Texture*> OldTextures_;
utils::Entity Light_;
std::filesystem::path ProjectRootPath_{};
@ -428,8 +460,8 @@ void MetaCoreFilamentSceneBridge::ApplySceneView(const MetaCoreSceneView& sceneV
Impl_->ApplySceneView(sceneView);
}
void MetaCoreFilamentSceneBridge::Render() {
Impl_->Render();
void MetaCoreFilamentSceneBridge::RenderAll() {
Impl_->RenderAll();
}
uint32_t MetaCoreFilamentSceneBridge::GetGLTextureId() const {

View File

@ -19,6 +19,7 @@ public:
void Shutdown();
void SetViewportRect(const MetaCoreViewportRect& viewportRect);
void RenderSceneToViewport(const MetaCoreScene& scene, const MetaCoreSceneView& sceneView);
void RenderAll();
void SetProjectRootPath(const std::filesystem::path& projectRootPath);
[[nodiscard]] uint32_t GetFilamentGLTextureId() const;
[[nodiscard]] void* GetFilamentTexturePointer() const;

View File

@ -28,7 +28,7 @@ public:
void SetProjectRootPath(const std::filesystem::path& projectRootPath);
void SyncScene(const MetaCoreScene& scene, bool compatibilityMeshOnly = false);
void ApplySceneView(const MetaCoreSceneView& sceneView);
void Render();
void RenderAll();
[[nodiscard]] uint32_t GetGLTextureId() const;
[[nodiscard]] void* GetFilamentTexturePointer() const;

View File

@ -460,7 +460,9 @@ MetaCoreScene MetaCoreCreateDefaultScene() {
directionalLight.GetComponent<MetaCoreTransformComponent>().RotationEulerDegrees = glm::vec3(-45.0F, 30.0F, 0.0F);
MetaCoreGameObject cube = scene.CreateGameObject("Cube");
cube.AddComponent<MetaCoreMeshRendererComponent>();
auto& meshRenderer = cube.AddComponent<MetaCoreMeshRendererComponent>();
meshRenderer.MeshSource = MetaCoreMeshSourceKind::Asset;
meshRenderer.SourceModelPath = "Assets/Models/box1.glb";
cube.GetComponent<MetaCoreTransformComponent>().Position = glm::vec3(0.0F, 0.5F, 0.0F);
MetaCoreGameObject valve = scene.CreateGameObject("Valve");