MetaCore/Source/MetaCoreRender/Private/MetaCoreFilamentSceneBridge.cpp

492 lines
18 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "MetaCoreRender/MetaCoreFilamentSceneBridge.h"
#include "MetaCorePlatform/MetaCoreWindow.h"
#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>
#include <filament/View.h>
#include <filament/Camera.h>
#include <filament/SwapChain.h>
#include <filament/Renderer.h>
#include <filament/Viewport.h>
#include <filament/TransformManager.h>
#include <filament/Texture.h>
#include <filament/RenderTarget.h>
#include <filament/LightManager.h>
#include <gltfio/AssetLoader.h>
#include <gltfio/FilamentAsset.h>
#include <gltfio/ResourceLoader.h>
#include <gltfio/MaterialProvider.h>
#include <utils/Entity.h>
#include <utils/EntityManager.h>
#define GLM_ENABLE_EXPERIMENTAL
#include <glm/gtc/type_ptr.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <iostream>
#include <fstream>
#include <unordered_map>
#include <vector>
// 引入 Windows 和 OpenGL 头文件以创建纹理
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <GL/gl.h>
namespace MetaCore {
class MetaCoreFilamentSceneBridge::MetaCoreFilamentSceneBridgeImpl {
public:
MetaCoreFilamentSceneBridgeImpl() = default;
~MetaCoreFilamentSceneBridgeImpl() {
Shutdown();
}
bool Initialize(MetaCoreWindow& window) {
std::cout << "FilamentSceneBridge: Initializing..." << std::endl;
// 创建 Filament Engine (不共享上下文,避免闪退)
Engine_ = filament::Engine::create();
if (!Engine_) {
std::cerr << "Failed to create Filament Engine with shared context!" << std::endl;
return false;
}
// 创建绑定真实窗口的交换链
SwapChain_ = Engine_->createSwapChain((void*)window.GetNativeWindowHandle());
if (!SwapChain_) {
std::cerr << "Failed to create Filament SwapChain with window handle!" << std::endl;
return false;
}
// 创建渲染器
Renderer_ = Engine_->createRenderer();
// 创建场景
Scene_ = Engine_->createScene();
// 创建默认灯光
Light_ = utils::EntityManager::get().create();
filament::LightManager::Builder(filament::LightManager::Type::DIRECTIONAL)
.color(filament::Color::toLinear<filament::ACCURATE>({ 1.0f, 1.0f, 1.0f }))
.intensity(100000.0f)
.direction({ 0.5f, -1.0f, -0.5f })
.castShadows(true)
.build(*Engine_, Light_);
Scene_->addEntity(Light_);
// 创建相机
utils::Entity cameraEntity = utils::EntityManager::get().create();
Camera_ = Engine_->createCamera(cameraEntity);
// 创建视图
View_ = Engine_->createView();
View_->setScene(Scene_);
View_->setCamera(Camera_);
// 创建 UI 视图
UIView_ = Engine_->createView();
// 创建 ImGuiHelper
ImGuiHelper_ = new MetaCoreImGuiHelper(Engine_, UIView_, "", ImGui::GetCurrentContext());
// 初始化离屏渲染纹理
auto [width, height] = window.GetFramebufferSize();
// 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)
.build(*Engine_);
// 2. 创建深度纹理
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_);
// 3. 创建 RenderTarget 并绑定
RenderTarget_ = filament::RenderTarget::Builder()
.texture(filament::RenderTarget::AttachmentPoint::COLOR, FilamentTexture_)
.texture(filament::RenderTarget::AttachmentPoint::DEPTH, DepthTexture_)
.build(*Engine_);
// 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_);
AssetLoader_ = filament::gltfio::AssetLoader::create({ Engine_, MaterialProvider_, nullptr });
std::cout << "FilamentSceneBridge: Initialized with Offscreen Texture ID: " << GLTextureId_ << std::endl;
return true;
}
void Shutdown() {
if (Engine_) {
std::cout << "FilamentSceneBridge: Shutting down..." << std::endl;
// 销毁所有加载的资产
for (auto& [id, asset] : LoadedAssets_) {
AssetLoader_->destroyAsset(asset);
}
LoadedAssets_.clear();
// 销毁 gltfio 资源
if (AssetLoader_) {
filament::gltfio::AssetLoader::destroy(&AssetLoader_);
AssetLoader_ = nullptr;
}
if (MaterialProvider_) {
MaterialProvider_->destroyMaterials();
delete MaterialProvider_;
MaterialProvider_ = nullptr;
}
// 销毁离屏渲染资源
if (RenderTarget_) {
Engine_->destroy(RenderTarget_);
RenderTarget_ = nullptr;
}
if (FilamentTexture_) {
Engine_->destroy(FilamentTexture_);
FilamentTexture_ = nullptr;
}
if (DepthTexture_) {
Engine_->destroy(DepthTexture_);
DepthTexture_ = nullptr;
}
if (GLTextureId_) {
glDeleteTextures(1, &GLTextureId_);
GLTextureId_ = 0;
}
// 销毁 View
Engine_->destroy(View_);
// 销毁相机组件和实体
if (Camera_) {
utils::Entity cameraEntity = Camera_->getEntity();
Engine_->destroyCameraComponent(cameraEntity);
utils::EntityManager::get().destroy(cameraEntity);
}
// 销毁其他资源
Engine_->destroy(Scene_);
Engine_->destroy(Renderer_);
Engine_->destroy(SwapChain_);
// 最后销毁 Engine
filament::Engine::destroy(&Engine_);
Engine_ = nullptr;
}
}
void SetProjectRootPath(const std::filesystem::path& projectRootPath) {
ProjectRootPath_ = projectRootPath;
}
void SyncScene(const MetaCoreScene& scene, bool compatibilityMeshOnly) {
if (!AssetLoader_) return;
for (const auto& gameObject : scene.GetGameObjects()) {
if (!gameObject.HasComponent<MetaCoreMeshRendererComponent>()) {
continue;
}
const auto& meshRenderer = gameObject.GetComponent<MetaCoreMeshRendererComponent>();
if (meshRenderer.MeshSource != MetaCoreMeshSourceKind::Asset) {
continue;
}
std::string modelPath = meshRenderer.SourceModelPath;
if (modelPath.empty()) {
continue;
}
std::filesystem::path absolutePath = ProjectRootPath_ / modelPath;
// 如果已经加载过,更新位置即可
if (LoadedAssets_.contains(gameObject.GetId())) {
UpdateTransform(gameObject);
continue;
}
// 加载新模型
std::cout << "FilamentSceneBridge: Loading GLTF: " << absolutePath << std::endl;
std::ifstream file(absolutePath, std::ios::binary);
if (!file.is_open()) {
std::cerr << "Failed to open file: " << absolutePath << std::endl;
continue;
}
std::vector<char> buffer((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
filament::gltfio::FilamentAsset* asset = AssetLoader_->createAsset(
reinterpret_cast<const uint8_t*>(buffer.data()),
static_cast<uint32_t>(buffer.size())
);
if (!asset) {
std::cerr << "Failed to create asset!" << std::endl;
continue;
}
// 加载贴图等资源
filament::gltfio::ResourceLoader resourceLoader({ Engine_ });
resourceLoader.loadResources(asset);
// 添加到场景
Scene_->addEntities(asset->getEntities(), asset->getEntityCount());
LoadedAssets_[gameObject.GetId()] = asset;
// 更新初始位置
UpdateTransform(gameObject);
}
}
void ApplySceneView(const MetaCoreSceneView& sceneView) {
if (!Camera_ || !View_) return;
// 设置相机位置和朝向
Camera_->lookAt(
{ sceneView.CameraPosition.x, sceneView.CameraPosition.y, sceneView.CameraPosition.z },
{ sceneView.CameraTarget.x, sceneView.CameraTarget.y, sceneView.CameraTarget.z },
{ sceneView.CameraUp.x, sceneView.CameraUp.y, sceneView.CameraUp.z }
);
// 获取当前视口大小计算宽高比
const auto& viewport = View_->getViewport();
double aspect = 1.0;
if (viewport.height > 0) {
aspect = static_cast<double>(viewport.width) / static_cast<double>(viewport.height);
}
// 设置透视投影
double fov = sceneView.VerticalFieldOfViewDegrees;
double nearClip = 0.1;
double farClip = 1000.0;
Camera_->setProjection(fov, aspect, nearClip, farClip, filament::Camera::Fov::VERTICAL);
}
void RenderAll() {
if (!Renderer_ || !SwapChain_ || !View_ || !UIView_ || !ImGuiHelper_) {
return;
}
if (Renderer_->beginFrame(SwapChain_)) {
// 1. 渲染 3D 离屏视口 (输出到 RenderTarget)
filament::Renderer::ClearOptions options;
options.clearColor = { 0.11f, 0.12f, 0.14f, 1.0f }; // 深灰色
options.clear = true;
Renderer_->setClearOptions(options);
Renderer_->render(View_);
// 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();
}
}
uint32_t GetGLTextureId() const {
return GLTextureId_;
}
void Resize(int width, int height) {
if (width <= 0 || height <= 0) return;
// 【关键修复】:如果大小没有改变,不要重新创建纹理!
// 否则会导致上一帧传给 ImGui 的纹理指针在这一帧被提前销毁,引发 Use-after-free 崩溃。
if (FilamentTexture_ &&
FilamentTexture_->getWidth() == static_cast<uint32_t>(width) &&
FilamentTexture_->getHeight() == static_cast<uint32_t>(height)) {
return;
}
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)
.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;
}
bool HasRuntimeSyncFailure() const { return false; }
const std::string& GetLastRuntimeSyncFailure() const { return EmptyString_; }
private:
void UpdateTransform(const MetaCoreGameObject& gameObject) {
auto it = LoadedAssets_.find(gameObject.GetId());
if (it == LoadedAssets_.end()) return;
filament::gltfio::FilamentAsset* asset = it->second;
utils::Entity rootEntity = asset->getRoot();
auto& tm = Engine_->getTransformManager();
auto instance = tm.getInstance(rootEntity);
if (instance) {
if (!gameObject.HasComponent<MetaCoreTransformComponent>()) return;
const auto& transform = gameObject.GetComponent<MetaCoreTransformComponent>();
glm::mat4 matrix = glm::mat4(1.0f);
matrix = glm::translate(matrix, transform.Position);
matrix = glm::rotate(matrix, glm::radians(transform.RotationEulerDegrees.x), {1, 0, 0});
matrix = glm::rotate(matrix, glm::radians(transform.RotationEulerDegrees.y), {0, 1, 0});
matrix = glm::rotate(matrix, glm::radians(transform.RotationEulerDegrees.z), {0, 0, 1});
matrix = glm::scale(matrix, transform.Scale);
tm.setTransform(instance, *reinterpret_cast<const filament::math::mat4f*>(glm::value_ptr(matrix)));
}
}
filament::Engine* Engine_ = nullptr;
filament::SwapChain* SwapChain_ = nullptr;
filament::Renderer* Renderer_ = nullptr;
filament::Scene* Scene_ = nullptr;
filament::Camera* Camera_ = nullptr;
filament::View* View_ = nullptr;
filament::gltfio::AssetLoader* AssetLoader_ = nullptr;
filament::gltfio::MaterialProvider* MaterialProvider_ = nullptr;
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_{};
std::string EmptyString_{};
};
MetaCoreFilamentSceneBridge::MetaCoreFilamentSceneBridge()
: Impl_(std::make_unique<MetaCoreFilamentSceneBridgeImpl>()) {}
MetaCoreFilamentSceneBridge::~MetaCoreFilamentSceneBridge() = default;
bool MetaCoreFilamentSceneBridge::Initialize(MetaCoreWindow& window) {
return Impl_->Initialize(window);
}
void MetaCoreFilamentSceneBridge::Shutdown() {
Impl_->Shutdown();
}
void MetaCoreFilamentSceneBridge::SetProjectRootPath(const std::filesystem::path& projectRootPath) {
Impl_->SetProjectRootPath(projectRootPath);
}
void MetaCoreFilamentSceneBridge::SyncScene(const MetaCoreScene& scene, bool compatibilityMeshOnly) {
Impl_->SyncScene(scene, compatibilityMeshOnly);
}
void MetaCoreFilamentSceneBridge::ApplySceneView(const MetaCoreSceneView& sceneView) {
Impl_->ApplySceneView(sceneView);
}
void MetaCoreFilamentSceneBridge::RenderAll() {
Impl_->RenderAll();
}
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);
}
bool MetaCoreFilamentSceneBridge::HasRuntimeSyncFailure() const {
return Impl_->HasRuntimeSyncFailure();
}
const std::string& MetaCoreFilamentSceneBridge::GetLastRuntimeSyncFailure() const {
return Impl_->GetLastRuntimeSyncFailure();
}
} // namespace MetaCore