752 lines
30 KiB
C++
752 lines
30 KiB
C++
#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 "MetaCoreFoundation/MetaCoreAssetRegistry.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;
|
||
|
||
// 【超级核心】:绑定顶级父 GameObject 标识到 Filament Asset 根 Entity,彻底打通顶级 Gizmo 的同步!
|
||
ObjectToFilamentEntity_[parentObject.GetId()] = { asset, asset->getRoot() };
|
||
|
||
// 预先收集并缓存 parentObject 子树下的所有已有 GameObject,用于高精度的三步复用匹配
|
||
std::vector<MetaCoreGameObject> subtreeObjects;
|
||
std::vector<MetaCoreId> subtreeIds = scene.GetSubtreeObjectIds(parentObject.GetId());
|
||
for (MetaCoreId subId : subtreeIds) {
|
||
auto subObj = scene.FindGameObject(subId);
|
||
if (subObj && subObj.GetId() != parentObject.GetId()) {
|
||
subtreeObjects.push_back(subObj);
|
||
}
|
||
}
|
||
|
||
// 第一遍:创建或复用所有对象
|
||
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;
|
||
bool isExisting = false;
|
||
|
||
// 1. 优先通过 ModelNodeIndex 进行精确匹配(针对带有网格的节点)
|
||
for (auto& sceneObj : subtreeObjects) {
|
||
if (sceneObj.HasComponent<MetaCoreMeshRendererComponent>()) {
|
||
auto& mesh = sceneObj.GetComponent<MetaCoreMeshRendererComponent>();
|
||
if (mesh.ModelNodeIndex == static_cast<std::int32_t>(i)) {
|
||
childObj = sceneObj;
|
||
isExisting = true;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
// 2. 如果没找到(针对没有网格的空节点),通过名字进行匹配复用
|
||
if (!isExisting) {
|
||
for (auto& sceneObj : subtreeObjects) {
|
||
if (sceneObj.GetName() == name) {
|
||
// 且该节点不能已经被其他实体映射占用
|
||
bool alreadyMapped = false;
|
||
for (auto& [ent, obj] : entityToObj) {
|
||
if (obj.GetId() == sceneObj.GetId()) {
|
||
alreadyMapped = true;
|
||
break;
|
||
}
|
||
}
|
||
if (!alreadyMapped) {
|
||
childObj = sceneObj;
|
||
isExisting = true;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// 3. 实在没有找到,才进行动态创建(仅作为降级兜底)
|
||
if (!isExisting) {
|
||
childObj = scene.CreateGameObject(name, parentObject.GetId());
|
||
auto& meshRenderer = childObj.AddComponent<MetaCoreMeshRendererComponent>();
|
||
meshRenderer.MeshSource = MetaCoreMeshSourceKind::Asset;
|
||
meshRenderer.ModelNodeIndex = static_cast<std::int32_t>(i);
|
||
}
|
||
|
||
entityToObj[entity] = childObj;
|
||
ObjectToFilamentEntity_[childObj.GetId()] = { asset, entity };
|
||
|
||
// 获取并设置 Transform
|
||
auto instance = tm.getInstance(entity);
|
||
if (instance) {
|
||
filament::math::mat4f localTransform = tm.getTransform(instance);
|
||
|
||
glm::mat4 filamentMatrix;
|
||
std::memcpy(glm::value_ptr(filamentMatrix), &localTransform[0][0], sizeof(float) * 16);
|
||
|
||
glm::mat4 R_minus90X = glm::rotate(glm::mat4(1.0f), glm::radians(-90.0f), {1, 0, 0});
|
||
glm::mat4 R_plus90X = glm::rotate(glm::mat4(1.0f), glm::radians(90.0f), {1, 0, 0});
|
||
glm::mat4 matrix = R_minus90X * filamentMatrix * R_plus90X;
|
||
|
||
// 拆解矩阵
|
||
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;
|
||
}
|
||
}
|
||
|
||
// 第二遍:修正父子关系
|
||
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());
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
static std::string NormalizePath(std::string path) {
|
||
std::replace(path.begin(), path.end(), '\\', '/');
|
||
return path;
|
||
}
|
||
|
||
void SyncScene(MetaCoreScene& scene, bool compatibilityMeshOnly) {
|
||
if (!AssetLoader_) return;
|
||
|
||
// 预处理:构建子树模型网格节点计数表,以支撑在没有 Tag 时的极速、完美 Fallback 回溯
|
||
std::unordered_map<MetaCoreId, std::unordered_map<std::string, int>> subtreeModelCounts;
|
||
for (const auto& obj : scene.GetGameObjects()) {
|
||
if (obj.HasComponent<MetaCoreMeshRendererComponent>()) {
|
||
auto& mesh = obj.GetComponent<MetaCoreMeshRendererComponent>();
|
||
if (mesh.ModelNodeIndex >= 0 && !mesh.SourceModelPath.empty()) {
|
||
std::string normPath = NormalizePath(mesh.SourceModelPath);
|
||
MetaCoreId currentId = obj.GetId();
|
||
while (currentId != 0) {
|
||
auto currentObj = scene.FindGameObject(currentId);
|
||
if (!currentObj) break;
|
||
subtreeModelCounts[currentId][normPath]++;
|
||
currentId = currentObj.GetParentId();
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
for (const auto& gameObject : scene.GetGameObjects()) {
|
||
if (!gameObject.HasComponent<MetaCoreMeshRendererComponent>()) {
|
||
continue;
|
||
}
|
||
|
||
const auto& meshRenderer = gameObject.GetComponent<MetaCoreMeshRendererComponent>();
|
||
|
||
if (meshRenderer.MeshSource != MetaCoreMeshSourceKind::Asset &&
|
||
meshRenderer.MeshSource != MetaCoreMeshSourceKind::Builtin) {
|
||
continue;
|
||
}
|
||
|
||
std::string modelPath;
|
||
if (meshRenderer.SourceModelAssetGuid.IsValid()) {
|
||
modelPath = MetaCoreAssetRegistry::Get().ResolveGuidToPath(meshRenderer.SourceModelAssetGuid).generic_string();
|
||
}
|
||
if (modelPath.empty() && !meshRenderer.SourceModelPath.empty()) {
|
||
modelPath = meshRenderer.SourceModelPath;
|
||
}
|
||
if (modelPath.empty() && meshRenderer.MeshSource == MetaCoreMeshSourceKind::Builtin && meshRenderer.BuiltinMesh == MetaCoreBuiltinMeshType::Cube) {
|
||
modelPath = "Assets/Models/box1.glb";
|
||
}
|
||
if (modelPath.empty()) {
|
||
continue;
|
||
}
|
||
|
||
std::filesystem::path absolutePath = ProjectRootPath_ / modelPath;
|
||
|
||
// 【黄金算法】:溯源确定唯一的模型根加载主体
|
||
MetaCoreGameObject hostRoot = gameObject;
|
||
if (meshRenderer.ModelNodeIndex >= 0) {
|
||
const std::string& currentModelPath = meshRenderer.SourceModelPath;
|
||
std::string normCurrentPath = NormalizePath(currentModelPath);
|
||
MetaCoreGameObject current = gameObject;
|
||
MetaCoreGameObject foundRoot = {};
|
||
|
||
// 1. 优先通过运行时 MetaCoreModelRootTag 快速寻找顶级根
|
||
while (current.GetParentId() != 0) {
|
||
auto parentObj = scene.FindGameObject(current.GetParentId());
|
||
if (!parentObj) break;
|
||
|
||
if (parentObj.HasComponent<MetaCoreModelRootTag>()) {
|
||
auto& tag = parentObj.GetComponent<MetaCoreModelRootTag>();
|
||
if (NormalizePath(tag.SourceModelPath) == normCurrentPath) {
|
||
foundRoot = parentObj;
|
||
break;
|
||
}
|
||
}
|
||
current = parentObj;
|
||
}
|
||
|
||
if (foundRoot) {
|
||
hostRoot = foundRoot;
|
||
} else {
|
||
// 2. Fallback:若无明确 Tag(例如反序列化后),使用转折点判定算法(匹配包含模型网格数最大的、最深的祖先)
|
||
current = gameObject;
|
||
MetaCoreGameObject bestCandidate = gameObject;
|
||
int maxCount = subtreeModelCounts[gameObject.GetId()][normCurrentPath];
|
||
|
||
while (current) {
|
||
int count = subtreeModelCounts[current.GetId()][normCurrentPath];
|
||
if (count > maxCount) {
|
||
maxCount = count;
|
||
bestCandidate = current;
|
||
}
|
||
if (current.GetParentId() == 0) break;
|
||
current = scene.FindGameObject(current.GetParentId());
|
||
}
|
||
hostRoot = bestCandidate;
|
||
}
|
||
}
|
||
|
||
// 如果该模型的顶级根宿主已经被加载过,我们只需更新当前游戏对象的位置即可
|
||
if (LoadedAssets_.contains(hostRoot.GetId())) {
|
||
UpdateTransform(gameObject);
|
||
continue;
|
||
}
|
||
|
||
// 加载新模型,以顶级根宿主 hostRoot 的 ID 进行注册存储
|
||
std::cout << "FilamentSceneBridge: Loading GLTF: " << absolutePath << " (Host: " << hostRoot.GetName() << ")" << 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_[hostRoot.GetId()] = asset;
|
||
|
||
// 同步层级结构到场景树并自动进行展开子节点的复用映射
|
||
MetaCoreGameObject nonConstHostRoot = hostRoot;
|
||
|
||
// 现场补挂 Tag,确保后续帧和拖拽时 100% 命中 Tag 快速通道,绝不走 Fallback
|
||
if (!nonConstHostRoot.HasComponent<MetaCoreModelRootTag>()) {
|
||
nonConstHostRoot.AddComponent<MetaCoreModelRootTag>(MetaCoreModelRootTag{ modelPath });
|
||
}
|
||
|
||
// 如果名字是默认的 "Cube",自动改为模型文件名
|
||
if (nonConstHostRoot.GetName() == "Cube") {
|
||
std::string filename = std::filesystem::path(modelPath).filename().string();
|
||
nonConstHostRoot.GetName() = filename;
|
||
}
|
||
|
||
ParseModelHierarchyToEcs(scene, nonConstHostRoot, 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)));
|
||
|
||
// 【关键一步】:注册 hostRoot(顶级根宿主)的 ID 与 pivotEntity,彻底打通顶级宿主的 Gizmo 坐标变换!
|
||
ObjectToFilamentEntity_[hostRoot.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);
|
||
|
||
// 【关键修复】:如果当前 entity 是子节点(即不是顶级映射的 pivotEntity)
|
||
// 由于它的父级(assetRoot)带有了 -90X 旋转,我们必须对子节点应用基变换来抵消这个旋转。
|
||
// 公式:L_filament = R(90X) * L_ecs * R(-90X)
|
||
if (LoadedAssets_.count(gameObject.GetId()) == 0) {
|
||
glm::mat4 R_plus90X = glm::rotate(glm::mat4(1.0f), glm::radians(90.0f), {1, 0, 0});
|
||
glm::mat4 R_minus90X = glm::rotate(glm::mat4(1.0f), glm::radians(-90.0f), {1, 0, 0});
|
||
matrix = R_plus90X * matrix * R_minus90X;
|
||
}
|
||
|
||
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
|