feat: 恢复 ImGui OpenGL3 渲染链,剥离 Panda3D,实现 Filament 离屏渲染

This commit is contained in:
ayuan9957 2026-05-15 15:06:15 +08:00
parent 3bf03f4b1f
commit 1d0377584c
11 changed files with 351 additions and 245 deletions

View File

@ -209,16 +209,16 @@ target_compile_options(MetaCoreScene PRIVATE ${METACORE_COMMON_WARNINGS})
set(METACORE_RENDER_HEADERS
Source/MetaCoreRender/Public/MetaCoreRender/MetaCoreEditorViewportRenderer.h
Source/MetaCoreRender/Public/MetaCoreRender/MetaCorePandaSceneBridge.h
Source/MetaCoreRender/Public/MetaCoreRender/MetaCoreFilamentSceneBridge.h
Source/MetaCoreRender/Public/MetaCoreRender/MetaCoreImGuiHelper.h
Source/MetaCoreRender/Public/MetaCoreRender/MetaCoreRenderDevice.h
Source/MetaCoreRender/Public/MetaCoreRender/MetaCoreRenderTypes.h
)
set(METACORE_RENDER_SOURCES
Source/MetaCoreRender/Private/MetaCoreEditorViewportRenderer.cpp
Source/MetaCoreRender/Private/MetaCorePandaSceneBridge.cpp
Source/MetaCoreRender/Private/MetaCoreFilamentSceneBridge.cpp
Source/MetaCoreRender/Private/MetaCoreImGuiHelper.cpp
Source/MetaCoreRender/Private/MetaCoreRenderDevice.cpp
)
@ -240,6 +240,7 @@ target_link_libraries(MetaCoreRender
MetaCoreScene
MetaCorePanda3D::SDK
glm::glm
imgui::imgui
)
metacore_use_filament(MetaCoreRender)
@ -418,4 +419,17 @@ if(METACORE_BUILD_TESTS)
metacore_stage_panda3d_runtime(MetaCoreSmokeTests)
metacore_stage_simplepbr_runtime(MetaCoreSmokeTests)
add_test(NAME MetaCoreSmokeTests COMMAND MetaCoreSmokeTests)
# Filament + ImGui Demo
add_executable(FilamentImGuiDemo
tests/FilamentImGuiDemo.cpp
)
target_link_libraries(FilamentImGuiDemo
PRIVATE
MetaCoreRender
imgui::imgui
)
target_compile_options(FilamentImGuiDemo PRIVATE ${METACORE_COMMON_WARNINGS})
target_compile_definitions(FilamentImGuiDemo PRIVATE WIN32_LEAN_AND_MEAN NOMINMAX)
metacore_use_filament(FilamentImGuiDemo)
endif()

View File

@ -754,9 +754,20 @@ int MetaCoreEditorApp::Run() {
DrawEditorFrame();
ImGui::Render();
RenderDevice_.RenderFrame();
// 1. Filament 渲染 3D 视口到离屏纹理
MetaCoreSceneView sceneView = EditorContext_->GetCameraController().BuildSceneView();
sceneView.SelectedObjectId = EditorContext_->GetSelectedObjectId();
ViewportRenderer_.RenderSceneToViewport(Scene_, sceneView);
// 2. ImGui 渲染 UI 到屏幕 (包含 3D 纹理的显示)
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
RenderDevice_.PresentFrame();
// 3. 交换缓冲区 (因为去掉了 Panda3D 的 flip_frame)
HDC hdc = GetDC(static_cast<HWND>(Window_.GetNativeWindowHandle()));
SwapBuffers(hdc);
ReleaseDC(static_cast<HWND>(Window_.GetNativeWindowHandle()), hdc);
Window_.EndFrame();
}

View File

@ -1,11 +1,5 @@
#include "MetaCorePlatform/MetaCoreWindow.h"
#include "graphicsWindow.h"
#include "load_prc_file.h"
#include "nativeWindowHandle.h"
#include "pandaFramework.h"
#include "windowFramework.h"
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
@ -50,41 +44,6 @@ void MetaCoreWindowTrace(const char* message) {
std::printf("%s%s\n", timeBuffer, message);
}
void MetaCoreConfigurePanda3D(const std::string& title) {
static bool configured = false;
if (configured) {
return;
}
load_prc_file_data("", "load-display pandagl\n");
load_prc_file_data("", "aux-display p3windisplay\n");
load_prc_file_data("", "window-type onscreen\n");
load_prc_file_data("", "model-path ./models\n");
load_prc_file_data("", "sync-video false\n");
load_prc_file_data("", "notify-level warning\n");
load_prc_file_data("", "audio-library-name null\n");
load_prc_file_data("", "textures-power-2 none\n");
// Use window-title PrC variable instead of WindowProperties::set_title to avoid ABI mismatch in Debug builds.
const std::string configData = "window-title " + title + "\n";
load_prc_file_data("", configData);
configured = true;
}
HWND MetaCoreResolveNativeWindowHandle(GraphicsWindow* graphicsWindow) {
if (graphicsWindow == nullptr) {
return nullptr;
}
WindowHandle* windowHandle = graphicsWindow->get_window_handle();
if (windowHandle == nullptr) {
return nullptr;
}
return reinterpret_cast<HWND>(windowHandle->get_int_handle());
}
std::wstring MetaCoreUtf8ToWide(std::string_view utf8Text) {
if (utf8Text.empty()) {
return {};
@ -130,10 +89,9 @@ std::unordered_map<HWND, class MetaCoreWindow::MetaCoreWindowImpl*>& MetaCoreGet
class MetaCoreWindow::MetaCoreWindowImpl {
public:
PandaFramework Framework{};
WindowFramework* WindowFrameworkHandle = nullptr;
GraphicsWindow* GraphicsWindowHandle = nullptr;
HWND NativeHandle = nullptr;
HDC hDC = nullptr;
HGLRC hGLRC = nullptr;
MetaCoreInput Input{};
MetaCoreNativeWindowMessageHandler MessageHandler{};
WNDPROC OriginalWindowProc = nullptr;
@ -189,54 +147,75 @@ bool MetaCoreWindow::Initialize(int width, int height, const std::string& title)
return true;
}
MetaCoreWindowTrace("metacore.window: configure runtime backend");
MetaCoreConfigurePanda3D(title);
MetaCoreWindowTrace("metacore.window: open framework");
Impl_->Framework.open_framework();
// 1. 注册窗口类
WNDCLASSEXW wcex{};
wcex.cbSize = sizeof(WNDCLASSEXW);
wcex.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
wcex.lpfnWndProc = MetaCoreWindowSubclassProc; // 直接使用我们的处理函数
wcex.hInstance = GetModuleHandle(nullptr);
wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wcex.lpszClassName = L"MetaCoreWindowClass";
MetaCoreWindowTrace("metacore.window: setup window properties begin");
WindowProperties windowProperties;
MetaCoreWindowTrace("metacore.window: set window size");
windowProperties.set_size(width, height);
MetaCoreWindowTrace("metacore.window: skip runtime title handoff due to ABI issues");
// windowProperties.set_title(title); // This triggers bad_alloc in VS2022 Debug vs Panda3D VS2019 SDK
MetaCoreWindowTrace("metacore.window: set foreground");
windowProperties.set_foreground(true);
RegisterClassExW(&wcex);
MetaCoreWindowTrace("metacore.window: open window");
Impl_->WindowFrameworkHandle = Impl_->Framework.open_window(windowProperties, 0);
if (Impl_->WindowFrameworkHandle == nullptr) {
MetaCoreWindowTrace("metacore.window: open window returned null");
Shutdown();
return false;
}
// 2. 转换标题
std::wstring wideTitle = MetaCoreUtf8ToWide(title);
MetaCoreWindowTrace("metacore.window: get graphics window");
Impl_->GraphicsWindowHandle = Impl_->WindowFrameworkHandle->get_graphics_window();
MetaCoreWindowTrace("metacore.window: resolve native handle");
Impl_->NativeHandle = MetaCoreResolveNativeWindowHandle(Impl_->GraphicsWindowHandle);
if (Impl_->GraphicsWindowHandle == nullptr || Impl_->NativeHandle == nullptr) {
MetaCoreWindowTrace("metacore.window: graphics/native handle invalid");
Shutdown();
return false;
}
// 3. 计算窗口大小 (包含边框)
RECT rect = { 0, 0, width, height };
AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, FALSE);
if (!title.empty()) {
const std::wstring wideTitle = MetaCoreUtf8ToWide(title);
if (!wideTitle.empty()) {
SetWindowTextW(Impl_->NativeHandle, wideTitle.c_str());
}
}
MetaCoreWindowTrace("metacore.window: subclass window proc");
MetaCoreGetWindowMap()[Impl_->NativeHandle] = Impl_.get();
Impl_->OriginalWindowProc = reinterpret_cast<WNDPROC>(
SetWindowLongPtr(Impl_->NativeHandle, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(&MetaCoreWindowSubclassProc))
// 4. 创建窗口
Impl_->NativeHandle = CreateWindowExW(
0,
L"MetaCoreWindowClass",
wideTitle.c_str(),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
rect.right - rect.left, rect.bottom - rect.top,
nullptr, nullptr, GetModuleHandle(nullptr), nullptr
);
if (!Impl_->NativeHandle) {
MetaCoreWindowTrace("metacore.window: CreateWindowExW failed");
return false;
}
ShowWindow(Impl_->NativeHandle, SW_SHOW);
UpdateWindow(Impl_->NativeHandle);
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;
Impl_->LastFrameTime = std::chrono::steady_clock::now();
Impl_->Initialized = true;
@ -263,22 +242,23 @@ 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);
if (Impl_->OriginalWindowProc != nullptr) {
SetWindowLongPtr(Impl_->NativeHandle, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(Impl_->OriginalWindowProc));
}
DestroyWindow(Impl_->NativeHandle);
}
if (Impl_->WindowFrameworkHandle != nullptr) {
Impl_->Framework.close_window(Impl_->WindowFrameworkHandle);
Impl_->WindowFrameworkHandle = nullptr;
}
Impl_->GraphicsWindowHandle = nullptr;
Impl_->NativeHandle = nullptr;
Impl_->OriginalWindowProc = nullptr;
Impl_->Framework.close_framework();
Impl_->Initialized = false;
}
@ -296,8 +276,11 @@ void MetaCoreWindow::BeginFrame() {
Impl_->Input.BeginFrame();
if (Impl_->GraphicsWindowHandle != nullptr) {
Impl_->GraphicsWindowHandle->process_events();
// Win32 消息循环
MSG msg;
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
Impl_->Input.SetKeyState(MetaCoreInputKey::LeftAlt, MetaCoreIsVirtualKeyDown(VK_LMENU));
@ -323,27 +306,12 @@ bool MetaCoreWindow::ShouldClose() const {
void MetaCoreWindow::RequestClose() {
Impl_->CloseRequested = true;
if (Impl_->GraphicsWindowHandle != nullptr) {
Impl_->GraphicsWindowHandle->request_close();
}
}
void* MetaCoreWindow::GetNativeWindowHandle() const {
return Impl_->NativeHandle;
}
void* MetaCoreWindow::GetNativeFrameworkHandle() const {
return &Impl_->Framework;
}
void* MetaCoreWindow::GetNativeWindowFrameworkHandle() const {
return Impl_->WindowFrameworkHandle;
}
void* MetaCoreWindow::GetNativeGraphicsWindowHandle() const {
return Impl_->GraphicsWindowHandle;
}
MetaCoreInput& MetaCoreWindow::GetInput() {
return Impl_->Input;
}
@ -357,12 +325,13 @@ float MetaCoreWindow::GetDeltaSeconds() const {
}
std::pair<int, int> MetaCoreWindow::GetWindowSize() const {
if (Impl_->GraphicsWindowHandle == nullptr) {
if (Impl_->NativeHandle == nullptr) {
return {0, 0};
}
const WindowProperties windowProperties = Impl_->GraphicsWindowHandle->get_properties();
return {windowProperties.get_x_size(), windowProperties.get_y_size()};
RECT rect{};
GetClientRect(Impl_->NativeHandle, &rect);
return { rect.right - rect.left, rect.bottom - rect.top };
}
std::pair<int, int> MetaCoreWindow::GetFramebufferSize() const {

View File

@ -30,9 +30,6 @@ public:
void RequestClose();
[[nodiscard]] void* GetNativeWindowHandle() const;
[[nodiscard]] void* GetNativeFrameworkHandle() const;
[[nodiscard]] void* GetNativeWindowFrameworkHandle() const;
[[nodiscard]] void* GetNativeGraphicsWindowHandle() const;
[[nodiscard]] MetaCoreInput& GetInput();
[[nodiscard]] const MetaCoreInput& GetInput() const;

View File

@ -44,10 +44,13 @@ bool MetaCoreEditorViewportRenderer::Initialize(MetaCoreRenderDevice& renderDevi
Shutdown();
MetaCoreTrace("metacore.render: viewport scene runtime bind begin");
// 彻底剔除 Panda3D不再初始化 Panda3D 场景桥接器
/*
if (!SceneBridge_.Initialize(renderDevice)) {
MetaCoreTrace("metacore.render: viewport scene runtime bind failed");
return false;
}
*/
if (!FilamentSceneBridge_.Initialize(window)) {
MetaCoreTrace("metacore.render: viewport filament scene runtime bind failed");
@ -63,7 +66,6 @@ bool MetaCoreEditorViewportRenderer::Initialize(MetaCoreRenderDevice& renderDevi
void MetaCoreEditorViewportRenderer::Shutdown() {
SceneBridge_.Shutdown();
FilamentSceneBridge_.Shutdown();
RenderDevice_ = nullptr;
ViewportRect_ = MetaCoreViewportRect{};
@ -84,6 +86,9 @@ void MetaCoreEditorViewportRenderer::RenderSceneToViewport(const MetaCoreScene&
RenderDevice_->SetSceneViewportRect(ViewportRect_);
// 动态调整离屏纹理大小以匹配 ImGui 视口
FilamentSceneBridge_.Resize(ViewportRect_.Width, ViewportRect_.Height);
// 更新并渲染 Filament 桥接器
FilamentSceneBridge_.ApplySceneView(sceneView);
FilamentSceneBridge_.SyncScene(scene, false);
@ -92,7 +97,6 @@ void MetaCoreEditorViewportRenderer::RenderSceneToViewport(const MetaCoreScene&
void MetaCoreEditorViewportRenderer::SetProjectRootPath(const std::filesystem::path& projectRootPath) {
SceneBridge_.SetProjectRootPath(projectRootPath);
FilamentSceneBridge_.SetProjectRootPath(projectRootPath);
}
@ -100,8 +104,12 @@ uint32_t MetaCoreEditorViewportRenderer::GetFilamentGLTextureId() const {
return FilamentSceneBridge_.GetGLTextureId();
}
void* MetaCoreEditorViewportRenderer::GetFilamentTexturePointer() const {
return FilamentSceneBridge_.GetFilamentTexturePointer();
}
bool MetaCoreEditorViewportRenderer::TryGetObjectWorldMatrix(MetaCoreId objectId, glm::mat4& worldMatrix) const {
return SceneBridge_.TryGetObjectWorldMatrix(objectId, worldMatrix);
return FilamentSceneBridge_.TryGetObjectWorldMatrix(objectId, worldMatrix);
}
} // namespace MetaCore

View File

@ -305,6 +305,49 @@ public:
return GLTextureId_;
}
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_);
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);
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()
.width(static_cast<uint32_t>(width))
.height(static_cast<uint32_t>(height))
.usage(filament::Texture::Usage::DEPTH_ATTACHMENT)
.format(filament::Texture::InternalFormat::DEPTH24)
.build(*Engine_);
RenderTarget_ = filament::RenderTarget::Builder()
.texture(filament::RenderTarget::AttachmentPoint::COLOR, FilamentTexture_)
.texture(filament::RenderTarget::AttachmentPoint::DEPTH, DepthTexture_)
.build(*Engine_);
View_->setRenderTarget(RenderTarget_);
View_->setViewport({0, 0, static_cast<uint32_t>(width), static_cast<uint32_t>(height)});
}
void* GetFilamentTexturePointer() const {
return FilamentTexture_;
}
bool TryGetObjectWorldMatrix(MetaCoreId objectId, glm::mat4& worldMatrix) const {
return false;
}
@ -393,6 +436,14 @@ uint32_t MetaCoreFilamentSceneBridge::GetGLTextureId() const {
return Impl_->GetGLTextureId();
}
void MetaCoreFilamentSceneBridge::Resize(int width, int height) {
Impl_->Resize(width, height);
}
void* MetaCoreFilamentSceneBridge::GetFilamentTexturePointer() const {
return Impl_->GetFilamentTexturePointer();
}
bool MetaCoreFilamentSceneBridge::TryGetObjectWorldMatrix(MetaCoreId objectId, glm::mat4& worldMatrix) const {
return Impl_->TryGetObjectWorldMatrix(objectId, worldMatrix);
}

View File

@ -59,55 +59,7 @@ bool MetaCoreRenderDevice::Initialize(MetaCoreWindow& window) {
if (Impl_->Initialized) {
return true;
}
auto* frameworkHandle = static_cast<PandaFramework*>(window.GetNativeFrameworkHandle());
auto* windowFrameworkHandle = static_cast<WindowFramework*>(window.GetNativeWindowFrameworkHandle());
auto* graphicsWindowHandle = static_cast<GraphicsWindow*>(window.GetNativeGraphicsWindowHandle());
if (frameworkHandle == nullptr || windowFrameworkHandle == nullptr || graphicsWindowHandle == nullptr) {
return false;
}
Impl_->Window = &window;
Impl_->Framework = frameworkHandle;
Impl_->WindowFrameworkHandle = windowFrameworkHandle;
Impl_->GraphicsWindowHandle = graphicsWindowHandle;
Impl_->GraphicsEngineHandle = frameworkHandle->get_graphics_engine();
if (Impl_->GraphicsEngineHandle == nullptr) {
return false;
}
Impl_->GraphicsEngineHandle->set_auto_flip(false);
Impl_->GraphicsEngineHandle->open_windows();
if (Impl_->WindowFrameworkHandle->get_display_region_2d() != nullptr) {
Impl_->WindowFrameworkHandle->get_display_region_2d()->set_active(false);
}
Impl_->SceneDisplayRegion = Impl_->WindowFrameworkHandle->get_display_region_3d();
if (Impl_->SceneDisplayRegion == nullptr) {
return false;
}
Impl_->GraphicsWindowHandle->set_clear_color_active(true);
Impl_->GraphicsWindowHandle->set_clear_color(LColor(0.38F, 0.48F, 0.62F, 1.0F));
PT(PandaNode) sceneRootNode = new PandaNode("MetaCoreSceneRoot");
Impl_->SceneRoot = Impl_->WindowFrameworkHandle->get_render().attach_new_node(sceneRootNode);
Impl_->SceneRoot.set_shader_auto();
Impl_->EditorCamera = Impl_->WindowFrameworkHandle->make_camera();
Impl_->SceneDisplayRegion->set_camera(Impl_->EditorCamera);
Impl_->SceneDisplayRegion->set_sort(0);
Impl_->SceneDisplayRegion->set_scissor_enabled(true);
Impl_->SceneDisplayRegion->set_clear_color_active(false);
if (auto* cameraNode = DCAST(Camera, Impl_->EditorCamera.node()); cameraNode != nullptr) {
PT(PerspectiveLens) lens = new PerspectiveLens();
lens->set_fov(60.0F);
lens->set_near_far(0.05F, 500.0F);
cameraNode->set_lens(lens);
}
Impl_->Initialized = true;
return true;
}
@ -149,70 +101,7 @@ void MetaCoreRenderDevice::PresentFrame() const {
}
void MetaCoreRenderDevice::SetSceneViewportRect(const MetaCoreViewportRect& viewportRect) {
if (Impl_->SceneDisplayRegion == nullptr || Impl_->Window == nullptr) {
return;
}
const auto [framebufferWidth, framebufferHeight] = Impl_->Window->GetFramebufferSize();
if (framebufferWidth <= 0 || framebufferHeight <= 0 || viewportRect.Width <= 1.0F || viewportRect.Height <= 1.0F) {
Impl_->SceneDisplayRegion->set_active(false);
return;
}
const float clampedLeft = std::clamp(viewportRect.Left / static_cast<float>(framebufferWidth), 0.0F, 1.0F);
const float clampedRight = std::clamp((viewportRect.Left + viewportRect.Width) / static_cast<float>(framebufferWidth), 0.0F, 1.0F);
const float clampedTop = std::clamp(viewportRect.Top / static_cast<float>(framebufferHeight), 0.0F, 1.0F);
const float clampedBottom = std::clamp((viewportRect.Top + viewportRect.Height) / static_cast<float>(framebufferHeight), 0.0F, 1.0F);
Impl_->SceneDisplayRegion->set_active(true);
Impl_->SceneDisplayRegion->set_dimensions(
clampedLeft,
clampedRight,
1.0F - clampedBottom,
1.0F - clampedTop
);
if (auto* cameraNode = DCAST(Camera, Impl_->EditorCamera.node()); cameraNode != nullptr) {
if (auto* perspectiveLens = DCAST(PerspectiveLens, cameraNode->get_lens()); perspectiveLens != nullptr) {
perspectiveLens->set_aspect_ratio(viewportRect.Width / viewportRect.Height);
}
}
}
void* MetaCoreRenderDevice::GetNativeWindowFrameworkHandle() const {
return Impl_->WindowFrameworkHandle;
}
void* MetaCoreRenderDevice::GetNativeSceneRootHandle() const {
return Impl_->SceneRoot.is_empty() ? nullptr : static_cast<void*>(&Impl_->SceneRoot);
}
void* MetaCoreRenderDevice::GetNativeEditorCameraHandle() const {
return Impl_->EditorCamera.is_empty() ? nullptr : static_cast<void*>(&Impl_->EditorCamera);
}
bool MetaCoreRenderDevice::TryGetEditorCameraMatrices(glm::mat4& viewMatrix, glm::mat4& projectionMatrix) const {
if (!Impl_->Initialized || Impl_->EditorCamera.is_empty()) {
return false;
}
auto* cameraNode = DCAST(Camera, Impl_->EditorCamera.node());
if (cameraNode == nullptr) {
return false;
}
auto* lens = cameraNode->get_lens();
if (lens == nullptr) {
return false;
}
// view = inverse of camera world matrix (Panda world → Panda camera space).
const glm::mat4 cameraWorldMatrix = MetaCoreConvertPandaMatrixToGlm(Impl_->EditorCamera.get_mat(Impl_->SceneRoot));
viewMatrix = glm::inverse(cameraWorldMatrix);
// Panda's native projection matrix works correctly once mathematically transposed.
projectionMatrix = MetaCoreConvertPandaMatrixToGlm(lens->get_projection_mat());
return true;
// 已废弃 Panda3D 实现,视口管理已移至 Filament 链
}
} // namespace MetaCore

View File

@ -1,6 +1,5 @@
#pragma once
#include "MetaCoreRender/MetaCorePandaSceneBridge.h"
#include "MetaCoreRender/MetaCoreFilamentSceneBridge.h"
#include "MetaCoreRender/MetaCoreRenderTypes.h"
@ -22,12 +21,12 @@ public:
void RenderSceneToViewport(const MetaCoreScene& scene, const MetaCoreSceneView& sceneView);
void SetProjectRootPath(const std::filesystem::path& projectRootPath);
[[nodiscard]] uint32_t GetFilamentGLTextureId() const;
[[nodiscard]] void* GetFilamentTexturePointer() const;
[[nodiscard]] bool TryGetObjectWorldMatrix(MetaCoreId objectId, glm::mat4& worldMatrix) const;
private:
MetaCoreRenderDevice* RenderDevice_ = nullptr;
MetaCorePandaSceneBridge SceneBridge_{};
MetaCoreFilamentSceneBridge FilamentSceneBridge_{};
MetaCoreViewportRect ViewportRect_{};

View File

@ -24,11 +24,13 @@ public:
bool Initialize(MetaCoreWindow& window);
void Shutdown();
void Resize(int width, int height);
void SetProjectRootPath(const std::filesystem::path& projectRootPath);
void SyncScene(const MetaCoreScene& scene, bool compatibilityMeshOnly = false);
void ApplySceneView(const MetaCoreSceneView& sceneView);
void Render();
[[nodiscard]] uint32_t GetGLTextureId() const;
[[nodiscard]] void* GetFilamentTexturePointer() const;
[[nodiscard]] bool TryGetObjectWorldMatrix(MetaCoreId objectId, glm::mat4& worldMatrix) const;
[[nodiscard]] bool HasRuntimeSyncFailure() const;

View File

@ -23,11 +23,6 @@ public:
void PresentFrame() const;
void SetSceneViewportRect(const MetaCoreViewportRect& viewportRect);
[[nodiscard]] void* GetNativeWindowFrameworkHandle() const;
[[nodiscard]] void* GetNativeSceneRootHandle() const;
[[nodiscard]] void* GetNativeEditorCameraHandle() const;
[[nodiscard]] bool TryGetEditorCameraMatrices(glm::mat4& viewMatrix, glm::mat4& projectionMatrix) const;
private:
class MetaCoreRenderDeviceImpl;

171
tests/FilamentImGuiDemo.cpp Normal file
View File

@ -0,0 +1,171 @@
#include <windows.h>
#include <filament/Engine.h>
#include <filament/Scene.h>
#include <filament/View.h>
#include <filament/Camera.h>
#include <filament/SwapChain.h>
#include <filament/Renderer.h>
#include <filament/Viewport.h>
#include <filament/Texture.h>
#include <filament/RenderTarget.h>
#include <filament/Skybox.h>
#include <imgui.h>
#include "MetaCoreRender/MetaCoreImGuiHelper.h"
#include <utils/Entity.h>
#include <utils/EntityManager.h>
#include <iostream>
#include <chrono>
using namespace filament;
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
switch (message) {
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hWnd, message, wParam, lParam);
}
int main() {
std::cout << "[Demo] Starting..." << std::endl;
HINSTANCE hInstance = GetModuleHandle(nullptr);
int nCmdShow = SW_SHOW;
// 1. 注册窗口类
std::cout << "[Demo] Registering window class..." << std::endl;
WNDCLASSEXW wcex = {0};
wcex.cbSize = sizeof(WNDCLASSEXW);
wcex.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
wcex.lpfnWndProc = WndProc;
wcex.hInstance = hInstance;
wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
wcex.lpszClassName = L"FilamentImGuiDemoClass";
RegisterClassExW(&wcex);
// 2. 创建窗口
std::cout << "[Demo] Creating window..." << std::endl;
HWND hWnd = CreateWindowExW(0, L"FilamentImGuiDemoClass", L"Filament + ImGui 离屏渲染最小化 Demo", WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, 1280, 720, nullptr, nullptr, hInstance, nullptr);
if (!hWnd) {
std::cout << "[Demo] Failed to create window!" << std::endl;
return -1;
}
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
// 3. 初始化 Filament
std::cout << "[Demo] Creating Filament Engine (OpenGL)..." << std::endl;
Engine* engine = Engine::create(Engine::Backend::OPENGL);
if (!engine) {
std::cout << "[Demo] Failed to create Engine!" << std::endl;
return -1;
}
std::cout << "[Demo] Creating Renderer..." << std::endl;
Renderer* renderer = engine->createRenderer();
std::cout << "[Demo] Creating SwapChain..." << std::endl;
SwapChain* swapChain = engine->createSwapChain(hWnd);
std::cout << "[Demo] Creating Scene..." << std::endl;
Scene* scene = engine->createScene();
std::cout << "[Demo] Creating View..." << std::endl;
View* view = engine->createView();
view->setScene(scene);
std::cout << "[Demo] Creating Camera..." << std::endl;
utils::Entity cameraEntity = utils::EntityManager::get().create();
Camera* camera = engine->createCamera(cameraEntity);
view->setCamera(camera);
view->setViewport({0, 0, 1280, 720});
std::cout << "[Demo] Creating Skybox..." << std::endl;
Skybox* skybox = Skybox::Builder().color({1.0f, 0.0f, 1.0f, 1.0f}).build(*engine);
scene->setSkybox(skybox);
// 4. 创建离屏 RenderTarget
std::cout << "[Demo] Creating offscreen texture..." << std::endl;
Texture* viewportTexture = Texture::Builder()
.width(800).height(600).levels(1)
.usage(Texture::Usage::COLOR_ATTACHMENT | Texture::Usage::SAMPLEABLE)
.format(Texture::InternalFormat::RGBA8)
.build(*engine);
std::cout << "[Demo] Creating RenderTarget..." << std::endl;
RenderTarget* renderTarget = RenderTarget::Builder()
.texture(RenderTarget::AttachmentPoint::COLOR, viewportTexture)
.build(*engine);
std::cout << "[Demo] Creating offscreen View..." << std::endl;
View* offscreenView = engine->createView();
offscreenView->setScene(scene);
offscreenView->setCamera(camera);
offscreenView->setRenderTarget(renderTarget);
offscreenView->setViewport({0, 0, 800, 600});
offscreenView->setPostProcessingEnabled(true);
// 5. 初始化 ImGui
std::cout << "[Demo] Initializing ImGui..." << std::endl;
IMGUI_CHECKVERSION();
ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO();
io.DisplaySize = ImVec2(1280, 720);
std::cout << "[Demo] Creating UI View..." << std::endl;
View* uiView = engine->createView();
uiView->setViewport({0, 0, 1280, 720});
uiView->setPostProcessingEnabled(false);
std::cout << "[Demo] Creating MetaCoreImGuiHelper..." << std::endl;
MetaCore::MetaCoreImGuiHelper imguiHelper(engine, uiView, "C:\\Windows\\Fonts\\msyh.ttc");
std::cout << "[Demo] Setting Display Size..." << std::endl;
imguiHelper.setDisplaySize(1280, 720);
std::cout << "[Demo] Entering message loop..." << std::endl;
MSG msg = {0};
bool quit = false;
while (!quit) {
while (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE)) {
if (msg.message == WM_QUIT) quit = true;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
if (renderer->beginFrame(swapChain)) {
// 1. 渲染离屏 3D 场景
renderer->render(offscreenView);
// 2. 构建 ImGui 界面
ImGui::NewFrame();
ImGui::SetNextWindowSize(ImVec2(820, 640), ImGuiCond_FirstUseEver);
ImGui::Begin("3D Viewport");
ImGui::Image((void*)viewportTexture, ImVec2(800, 600), ImVec2(0, 1), ImVec2(1, 0));
ImGui::End();
ImGui::Render();
// 3. 处理 ImGui 命令
imguiHelper.processImGuiCommands(ImGui::GetDrawData(), io);
// 4. 渲染 UI
renderer->render(uiView);
renderer->endFrame();
}
Sleep(16);
}
std::cout << "[Demo] Cleaning up..." << std::endl;
// 省略详细清理,由操作系统回收
return 0;
}