feat: 恢复 ImGui OpenGL3 渲染链,剥离 Panda3D,实现 Filament 离屏渲染
This commit is contained in:
parent
3bf03f4b1f
commit
1d0377584c
@ -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()
|
||||
|
||||
@ -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();
|
||||
}
|
||||
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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_{};
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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
171
tests/FilamentImGuiDemo.cpp
Normal 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;
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user