MetaCore/Source/MetaCoreRender/Private/MetaCoreFilamentSceneBridge.cpp

606 lines
23 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>
#include <utils/NameComponentManager.h>
#include "MetaCoreScene/MetaCoreTransformUtils.h"
#define GLM_ENABLE_EXPERIMENTAL
#include <glm/gtc/type_ptr.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtx/matrix_decompose.hpp>
#include <glm/gtc/quaternion.hpp>
#include <iostream>
#include <fstream>
#include <unordered_map>
#include <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, 0.5f, -1.0f }) // Z-up 下 Z 向下
.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
MaterialProvider_ = filament::gltfio::createJitShaderProvider(Engine_);
NameManager_ = new utils::NameComponentManager(utils::EntityManager::get());
AssetLoader_ = filament::gltfio::AssetLoader::create({ Engine_, MaterialProvider_, NameManager_ });
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_);
delete NameManager_;
NameManager_ = nullptr;
// 最后销毁 Engine
filament::Engine::destroy(&Engine_);
Engine_ = nullptr;
}
}
void SetProjectRootPath(const std::filesystem::path& projectRootPath) {
ProjectRootPath_ = projectRootPath;
}
void ParseModelHierarchyToEcs(MetaCoreScene& scene, MetaCoreGameObject& parentObject, filament::gltfio::FilamentAsset* asset) {
if (!asset) return;
const utils::Entity* entities = asset->getEntities();
size_t entityCount = asset->getEntityCount();
auto& tm = Engine_->getTransformManager();
// 建立 Filament Entity 到 MetaCore GameObject 的映射
std::map<utils::Entity, MetaCoreGameObject> entityToObj;
entityToObj[asset->getRoot()] = parentObject;
// 第一遍:创建所有对象
for (size_t i = 0; i < entityCount; i++) {
utils::Entity entity = entities[i];
if (entity == asset->getRoot()) continue;
const char* nodeName = asset->getName(entity);
std::string name = nodeName ? nodeName : ("Node_" + std::to_string(i));
// 初始先挂在根部,第二遍再调整
MetaCoreGameObject childObj = scene.CreateGameObject(name, parentObject.GetId());
entityToObj[entity] = childObj;
ObjectToFilamentEntity_[childObj.GetId()] = { asset, entity };
// 获取并设置 Transform
auto instance = tm.getInstance(entity);
if (instance) {
filament::math::mat4f localTransform = tm.getTransform(instance);
// 转换为 GLM 矩阵
glm::mat4 matrix;
std::memcpy(glm::value_ptr(matrix), &localTransform[0][0], sizeof(float) * 16);
// 拆解矩阵
glm::vec3 scale;
glm::quat rotation;
glm::vec3 translation;
glm::vec3 skew;
glm::vec4 perspective;
glm::decompose(matrix, scale, rotation, translation, skew, perspective);
auto& transform = childObj.GetComponent<MetaCoreTransformComponent>();
transform.Position = translation;
transform.RotationEulerDegrees = glm::degrees(glm::eulerAngles(rotation));
transform.Scale = scale;
}
// 记录节点索引
auto& meshRenderer = childObj.AddComponent<MetaCoreMeshRendererComponent>();
meshRenderer.MeshSource = MetaCoreMeshSourceKind::Asset;
meshRenderer.ModelNodeIndex = static_cast<std::int32_t>(i);
}
// 第二遍:修正父子关系
for (size_t i = 0; i < entityCount; i++) {
utils::Entity entity = entities[i];
if (entity == asset->getRoot()) continue;
auto instance = tm.getInstance(entity);
if (instance) {
utils::Entity parentEntity = tm.getParent(instance);
if (parentEntity && entityToObj.count(parentEntity)) {
MetaCoreGameObject currentObj = entityToObj[entity];
MetaCoreGameObject parentObj = entityToObj[parentEntity];
currentObj.SetParentId(parentObj.GetId());
}
}
}
}
void SyncScene(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;
// 同步层级结构到场景树
MetaCoreGameObject nonConstObj = gameObject;
// 如果名字是默认的 "Cube",自动改为模型文件名
if (nonConstObj.GetName() == "Cube") {
std::string filename = std::filesystem::path(meshRenderer.SourceModelPath).filename().string();
nonConstObj.GetName() = filename;
}
ParseModelHierarchyToEcs(scene, nonConstObj, asset);
// 创建中间 Pivot 实体用于坐标系转换 (glTF Y-up -> MetaCore Z-up)
utils::Entity pivotEntity = utils::EntityManager::get().create();
auto& tm = Engine_->getTransformManager();
tm.create(pivotEntity);
// 将资产根节点挂载到 Pivot 下
utils::Entity assetRoot = asset->getRoot();
tm.setParent(tm.getInstance(assetRoot), tm.getInstance(pivotEntity));
// 获取原始局部变换并叠加旋转补偿
filament::math::mat4f originalLocalTransform = tm.getTransform(tm.getInstance(assetRoot));
glm::mat4 originalMatrix;
std::memcpy(glm::value_ptr(originalMatrix), &originalLocalTransform[0][0], sizeof(float) * 16);
glm::mat4 compensationMatrix = glm::rotate(glm::mat4(1.0f), glm::radians(-90.0f), {1, 0, 0});
glm::mat4 finalRootMatrix = compensationMatrix * originalMatrix;
tm.setTransform(tm.getInstance(assetRoot), *reinterpret_cast<const filament::math::mat4f*>(glm::value_ptr(finalRootMatrix)));
// 将 MetaCore 对象映射到 Pivot 实体,这样 Gizmo 操作的就是正确的坐标空间
ObjectToFilamentEntity_[gameObject.GetId()] = { asset, pivotEntity };
Scene_->addEntity(pivotEntity);
// 更新初始位置
UpdateTransform(gameObject);
}
// 全量同步所有已映射对象的 Transform
for (const auto& gameObject : scene.GetGameObjects()) {
if (ObjectToFilamentEntity_.count(gameObject.GetId())) {
UpdateTransform(gameObject);
}
}
}
void ApplySceneView(const MetaCoreSceneView& sceneView) {
if (!Camera_ || !View_) return;
// 1. 视图矩阵同步
const glm::mat4 viewMatrix = glm::lookAt(sceneView.CameraPosition, sceneView.CameraTarget, sceneView.CameraUp);
const glm::mat4 cameraModelMatrix = glm::inverse(viewMatrix);
Camera_->setModelMatrix(*reinterpret_cast<const filament::math::mat4f*>(glm::value_ptr(cameraModelMatrix)));
// 2. 投影矩阵:回归 Filament 原生设置
const auto& viewport = View_->getViewport();
float aspect = (viewport.height > 0) ? (static_cast<float>(viewport.width) / static_cast<float>(viewport.height)) : 1.0f;
Camera_->setProjection(
sceneView.VerticalFieldOfViewDegrees,
aspect,
0.1,
1000.0,
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 = ObjectToFilamentEntity_.find(gameObject.GetId());
if (it == ObjectToFilamentEntity_.end()) return;
filament::gltfio::FilamentAsset* asset = it->second.first;
utils::Entity entity = it->second.second;
auto& tm = Engine_->getTransformManager();
auto instance = tm.getInstance(entity);
if (instance) {
if (!gameObject.HasComponent<MetaCoreTransformComponent>()) return;
const auto& transform = gameObject.GetComponent<MetaCoreTransformComponent>();
glm::mat4 matrix = MetaCoreBuildTransformMatrix(transform);
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;
utils::NameComponentManager* NameManager_ = nullptr;
std::unordered_map<MetaCoreId, std::pair<filament::gltfio::FilamentAsset*, utils::Entity>> ObjectToFilamentEntity_;
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(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