MetaCore/Source/MetaCoreRender/Private/MetaCoreFilamentSceneBridge.cpp

1171 lines
49 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 "MetaCoreRender/MetaCoreSceneRenderSync.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/geometric.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtx/matrix_decompose.hpp>
#include <glm/gtc/quaternion.hpp>
#include <iostream>
#include <fstream>
#include <algorithm>
#include <unordered_map>
#include <unordered_set>
#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();
}
// 提供公有接口用于构建渲染同步快照
MetaCoreSceneRenderSyncSnapshot BuildSnapshot(const MetaCoreScene& scene) const {
return RenderSync_.BuildSnapshot(scene);
}
bool Initialize(MetaCoreWindow& window, bool offscreen = true) {
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_);
EntitiesInScene_.insert(Light_);
// 创建相机
utils::Entity cameraEntity = utils::EntityManager::get().create();
Camera_ = Engine_->createCamera(cameraEntity);
// 创建视图
View_ = Engine_->createView();
View_->setScene(Scene_);
View_->setCamera(Camera_);
if (offscreen) {
// 创建 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)});
} else {
auto [width, height] = window.GetFramebufferSize();
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=" << (offscreen ? "true" : "false") << std::endl;
return true;
}
void Shutdown() {
if (Engine_) {
std::cout << "FilamentSceneBridge: Shutting down..." << std::endl;
// 销毁所有加载的资产
std::cout << "[DEBUG] LoadedAssets_ size: " << LoadedAssets_.size() << std::endl;
for (auto& [id, asset] : LoadedAssets_) {
std::cout << "[DEBUG] Destroying asset for ID: " << id << ", asset pointer: " << asset << std::endl;
if (asset) {
AssetLoader_->destroyAsset(asset);
}
std::cout << "[DEBUG] Destroyed asset for ID: " << id << std::endl;
}
LoadedAssets_.clear();
ObjectToFilamentEntity_.clear();
ObjectWorldMatrices_.clear();
for (auto& [id, entity] : SceneLightEntities_) {
if (Scene_) {
Scene_->remove(entity);
EntitiesInScene_.erase(entity);
}
Engine_->destroy(entity);
utils::EntityManager::get().destroy(entity);
}
SceneLightEntities_.clear();
EntitiesInScene_.clear();
// 销毁 gltfio 资源
std::cout << "[DEBUG] Destroying gltfio resources..." << std::endl;
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 (UIView_) {
Engine_->destroy(UIView_);
UIView_ = nullptr;
}
if (ImGuiHelper_) {
delete ImGuiHelper_;
ImGuiHelper_ = nullptr;
}
// 销毁相机组件和实体
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(const MetaCoreSceneRenderSyncSnapshot& snapshot, MetaCoreScene* scene, bool compatibilityMeshOnly, bool useScenePrimaryCamera) {
if (!AssetLoader_) return;
(void)compatibilityMeshOnly;
LastSyncSnapshot_ = snapshot;
ObjectWorldMatrices_ = LastSyncSnapshot_.WorldMatrices;
SyncSceneLights(LastSyncSnapshot_);
if (useScenePrimaryCamera) {
MetaCoreSceneView primarySceneView;
if (MetaCoreSceneRenderSync::TryBuildSceneViewFromPrimaryCamera(LastSyncSnapshot_, primarySceneView)) {
ApplySceneView(primarySceneView);
}
}
// 1. 收集当前 snapshot 中所有存在的模型 Root ID
std::unordered_set<MetaCoreId> activeHostRootIds;
for (const auto& renderable : snapshot.Renderables) {
if (renderable.MeshSource == MetaCoreMeshSourceKind::Asset ||
(renderable.MeshSource == MetaCoreMeshSourceKind::Builtin &&
(renderable.BuiltinMesh == MetaCoreBuiltinMeshType::Cube || renderable.BuiltinMesh == MetaCoreBuiltinMeshType::Plane))) {
if (renderable.HostRootId != 0) {
activeHostRootIds.insert(renderable.HostRootId);
}
}
}
// 2. 检查所有已加载的资产,若其 Root ID 不在 activeHostRootIds 中,则说明已被删除,执行清理
for (auto it = LoadedAssets_.begin(); it != LoadedAssets_.end(); ) {
MetaCoreId hostRootId = it->first;
filament::gltfio::FilamentAsset* asset = it->second;
if (!activeHostRootIds.contains(hostRootId)) {
std::cout << "FilamentSceneBridge: Unloading deleted asset: " << hostRootId << std::endl;
// 从场景中移除该资产关联的所有实体
if (Scene_ && asset) {
const utils::Entity* entities = asset->getEntities();
size_t entityCount = asset->getEntityCount();
for (size_t i = 0; i < entityCount; ++i) {
Scene_->remove(entities[i]);
EntitiesInScene_.erase(entities[i]);
}
}
// 查找并清理对应的 pivotEntity
auto pivotIt = ObjectToFilamentEntity_.find(hostRootId);
if (pivotIt != ObjectToFilamentEntity_.end()) {
utils::Entity pivotEntity = pivotIt->second.second;
bool isPivotNode = (asset == nullptr || pivotEntity != asset->getRoot());
if (Scene_ && pivotEntity) {
Scene_->remove(pivotEntity);
EntitiesInScene_.erase(pivotEntity);
}
if (isPivotNode && pivotEntity) {
utils::EntityManager::get().destroy(pivotEntity);
}
}
// 销毁资产本身
if (asset) {
AssetLoader_->destroyAsset(asset);
}
// 从 ObjectToFilamentEntity_ 和 ObjectWorldMatrices_ 中清除所有指向该 asset 的映射
if (asset != nullptr) {
for (auto entIt = ObjectToFilamentEntity_.begin(); entIt != ObjectToFilamentEntity_.end(); ) {
if (entIt->second.first == asset) {
ObjectWorldMatrices_.erase(entIt->first);
entIt = ObjectToFilamentEntity_.erase(entIt);
} else {
++entIt;
}
}
}
// 确保顶级父 ID 的变换缓存也被清除
ObjectWorldMatrices_.erase(hostRootId);
// 从 LoadedAssets_ 中移除
it = LoadedAssets_.erase(it);
} else {
++it;
}
}
for (const auto& renderable : snapshot.Renderables) {
if (renderable.MeshSource != MetaCoreMeshSourceKind::Asset &&
renderable.MeshSource != MetaCoreMeshSourceKind::Builtin) {
continue;
}
std::string modelPath;
if (renderable.SourceModelAssetGuid.IsValid()) {
modelPath = MetaCoreAssetRegistry::Get().ResolveGuidToPath(renderable.SourceModelAssetGuid).generic_string();
}
if (modelPath.empty() && !renderable.SourceModelPath.empty()) {
modelPath = renderable.SourceModelPath;
}
if (modelPath.empty() && renderable.MeshSource == MetaCoreMeshSourceKind::Builtin) {
if (renderable.BuiltinMesh == MetaCoreBuiltinMeshType::Cube) {
modelPath = "Assets/Models/Cube.glb";
} else if (renderable.BuiltinMesh == MetaCoreBuiltinMeshType::Plane) {
modelPath = "Assets/Models/Plane.glb";
}
}
if (modelPath.empty()) {
continue;
}
std::filesystem::path absolutePath = ProjectRootPath_ / modelPath;
MetaCoreId hostRootId = renderable.HostRootId;
std::string hostRootName = renderable.HostRootName;
// 如果该模型的顶级根宿主已经被加载过,则不需要重复加载,直接更新变换
if (LoadedAssets_.contains(hostRootId)) {
continue;
}
// 加载新模型,以顶级根宿主 hostRootId 进行注册存储
std::cout << "FilamentSceneBridge: Loading GLTF: " << absolutePath << " (Host: " << hostRootName << ")" << 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());
{
const utils::Entity* entities = asset->getEntities();
size_t entityCount = asset->getEntityCount();
for (size_t i = 0; i < entityCount; ++i) {
EntitiesInScene_.insert(entities[i]);
}
}
LoadedAssets_[hostRootId] = asset;
if (scene != nullptr) {
// 有 ECS 实例模式下同步层级结构并补挂 Tag
auto hostRootObj = scene->FindGameObject(hostRootId);
if (hostRootObj) {
MetaCoreGameObject nonConstHostRoot = hostRootObj;
// 现场补挂 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);
}
} else {
// 如果 scene 为 nullptr代表纯快照渲染模式。我们需要直接在 ObjectToFilamentEntity_ 中建立子实体的映射。
// 顶级父 ID 对应 asset->getRoot()
ObjectToFilamentEntity_[hostRootId] = { asset, asset->getRoot() };
// 遍历新资产中的 entities 映射到 snapshot 中的 renderable 节点
const utils::Entity* entities = asset->getEntities();
size_t entityCount = asset->getEntityCount();
std::vector<MetaCoreRenderSyncRenderable> candidates;
for (const auto& r : snapshot.Renderables) {
if (r.HostRootId == hostRootId && r.ObjectId != hostRootId) {
candidates.push_back(r);
}
}
std::map<utils::Entity, MetaCoreId> entityToId;
entityToId[asset->getRoot()] = hostRootId;
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));
MetaCoreId childObjectId = 0;
bool isExisting = false;
// 1. 优先通过 ModelNodeIndex 进行匹配
for (const auto& cand : candidates) {
if (cand.ModelNodeIndex == static_cast<std::int32_t>(i)) {
childObjectId = cand.ObjectId;
isExisting = true;
break;
}
}
// 2. 其次通过名字匹配
if (!isExisting) {
for (const auto& cand : candidates) {
if (cand.Name == name) {
bool alreadyMapped = false;
for (auto& [ent, id] : entityToId) {
if (id == cand.ObjectId) {
alreadyMapped = true;
break;
}
}
if (!alreadyMapped) {
childObjectId = cand.ObjectId;
isExisting = true;
break;
}
}
}
}
if (isExisting && childObjectId != 0) {
entityToId[entity] = childObjectId;
ObjectToFilamentEntity_[childObjectId] = { asset, entity };
}
}
}
// 创建中间 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)));
// 【关键一步】:注册 hostRootId顶级根宿主的 ID 与 pivotEntity彻底打通顶级宿主的 Gizmo 坐标变换!
ObjectToFilamentEntity_[hostRootId] = { asset, pivotEntity };
Scene_->addEntity(pivotEntity);
EntitiesInScene_.insert(pivotEntity);
// 更新初始位置
glm::mat4 initLocalMat{1.0f};
auto itMat = snapshot.LocalMatrices.find(renderable.ObjectId);
if (itMat != snapshot.LocalMatrices.end()) {
initLocalMat = itMat->second;
}
UpdateTransform(renderable.ObjectId, initLocalMat);
}
// 1. 构建反向查找映射,方便反查 entity 对应的 objectId
std::unordered_map<utils::Entity, MetaCoreId, utils::Entity::Hasher> entityToObjectId;
for (const auto& [objectId, assetEntity] : ObjectToFilamentEntity_) {
entityToObjectId[assetEntity.second] = objectId;
}
// 2. 控制所有已加载 glTF 资产内部所有实体(包括无直接映射的内部渲染实体)的可见性
auto& tm = Engine_->getTransformManager();
for (const auto& [hostRootId, asset] : LoadedAssets_) {
if (!asset) continue;
const utils::Entity* entities = asset->getEntities();
size_t entityCount = asset->getEntityCount();
for (size_t i = 0; i < entityCount; ++i) {
utils::Entity entity = entities[i];
if (!entity) continue;
bool shouldBeInScene = false;
auto it = entityToObjectId.find(entity);
if (it != entityToObjectId.end()) {
// 若是直接映射节点,其可见性由快照决定
shouldBeInScene = snapshot.WorldMatrices.contains(it->second);
} else {
// 若是没有直接映射关系的内部渲染/辅助实体,上溯其在 Filament 层级树中的父节点链,
// 找到最近的具有映射关系的祖先节点,并继承其可见性状态。
utils::Entity current = entity;
utils::Entity mappedAncestor;
while (current) {
auto instance = tm.getInstance(current);
if (!instance) break;
utils::Entity parent = tm.getParent(instance);
if (!parent) break;
if (entityToObjectId.contains(parent)) {
mappedAncestor = parent;
break;
}
current = parent;
}
if (mappedAncestor) {
shouldBeInScene = snapshot.WorldMatrices.contains(entityToObjectId[mappedAncestor]);
} else {
// 回退保护:如果没有找到,则与该资产对应的顶级根宿主保持状态一致
shouldBeInScene = snapshot.WorldMatrices.contains(hostRootId);
}
}
// 同步可见性状态到 Filament Scene
if (shouldBeInScene) {
if (Scene_ && !EntitiesInScene_.contains(entity)) {
Scene_->addEntity(entity);
EntitiesInScene_.insert(entity);
}
} else {
if (Scene_ && EntitiesInScene_.contains(entity)) {
Scene_->remove(entity);
EntitiesInScene_.erase(entity);
}
}
}
}
// 3. 控制 ObjectToFilamentEntity_ 中所有非资产实体(如 pivotEntity 辅助实体)的可见性
for (const auto& [objectId, assetEntity] : ObjectToFilamentEntity_) {
utils::Entity entity = assetEntity.second;
if (!entity) continue;
// 检查该实体是否为资产内部实体,如果不是(例如 pivotEntity则直接控制可见性
bool isAssetEntity = false;
if (assetEntity.first) {
const utils::Entity* entities = assetEntity.first->getEntities();
size_t entityCount = assetEntity.first->getEntityCount();
for (size_t i = 0; i < entityCount; ++i) {
if (entities[i] == entity) {
isAssetEntity = true;
break;
}
}
}
if (!isAssetEntity) {
bool shouldBeInScene = snapshot.WorldMatrices.contains(objectId);
if (shouldBeInScene) {
if (Scene_ && !EntitiesInScene_.contains(entity)) {
Scene_->addEntity(entity);
EntitiesInScene_.insert(entity);
}
} else {
if (Scene_ && EntitiesInScene_.contains(entity)) {
Scene_->remove(entity);
EntitiesInScene_.erase(entity);
}
}
}
}
// 4. 同步所有存活实体的本地和全局变换矩阵
for (const auto& [objectId, assetEntity] : ObjectToFilamentEntity_) {
if (snapshot.WorldMatrices.contains(objectId)) {
auto itMat = snapshot.LocalMatrices.find(objectId);
if (itMat != snapshot.LocalMatrices.end()) {
UpdateTransform(objectId, itMat->second);
}
}
}
}
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,
sceneView.NearClip,
sceneView.FarClip,
filament::Camera::Fov::VERTICAL
);
}
void RenderAll() {
if (!Renderer_ || !SwapChain_ || !View_) {
return;
}
if (Renderer_->beginFrame(SwapChain_)) {
if (RenderTarget_) {
// 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_);
if (UIView_ && ImGuiHelper_) {
// 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_);
}
} else {
// 3. 直接上屏渲染
filament::Renderer::ClearOptions options;
options.clearColor = { 0.11f, 0.12f, 0.14f, 1.0f }; // 深灰色
options.clear = true;
Renderer_->setClearOptions(options);
Renderer_->render(View_);
}
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;
if (!RenderTarget_) {
View_->setViewport({0, 0, static_cast<uint32_t>(width), static_cast<uint32_t>(height)});
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 {
const auto worldIt = ObjectWorldMatrices_.find(objectId);
if (worldIt == ObjectWorldMatrices_.end()) {
return false;
}
worldMatrix = worldIt->second;
return true;
}
bool HasRuntimeSyncFailure() const { return false; }
const std::string& GetLastRuntimeSyncFailure() const { return EmptyString_; }
bool VerifyTransformForTesting(MetaCoreId objectId, const glm::mat4& expectedMatrix) const {
auto it = ObjectToFilamentEntity_.find(objectId);
if (it == ObjectToFilamentEntity_.end()) return false;
utils::Entity entity = it->second.second;
auto& tm = Engine_->getTransformManager();
auto instance = tm.getInstance(entity);
if (!instance) return false;
filament::math::mat4f currentMat = tm.getTransform(instance);
glm::mat4 actualMatrix;
std::memcpy(glm::value_ptr(actualMatrix), &currentMat[0][0], sizeof(float) * 16);
glm::mat4 targetMatrix = expectedMatrix;
if (LoadedAssets_.count(objectId) == 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});
targetMatrix = R_plus90X * targetMatrix * R_minus90X;
}
// 浮点数比对,精度 0.0001
for (int c = 0; c < 4; ++c) {
for (int r = 0; r < 4; ++r) {
if (std::abs(actualMatrix[c][r] - targetMatrix[c][r]) > 0.0001f) {
return false;
}
}
}
return true;
}
bool VerifyLightExistsForTesting(MetaCoreId objectId) const {
return SceneLightEntities_.contains(objectId);
}
float GetDefaultLightIntensityForTesting() const {
if (!Engine_) return 0.0F;
auto& lightManager = Engine_->getLightManager();
const auto defaultLightInstance = lightManager.getInstance(Light_);
if (defaultLightInstance) {
return lightManager.getIntensity(defaultLightInstance);
}
return 0.0F;
}
bool VerifyEntityInSceneForTesting(MetaCoreId objectId) const {
auto it = ObjectToFilamentEntity_.find(objectId);
if (it == ObjectToFilamentEntity_.end()) return false;
return EntitiesInScene_.contains(it->second.second);
}
private:
static filament::math::float3 ToFilamentFloat3(const glm::vec3& value) {
return filament::math::float3{ value.x, value.y, value.z };
}
static filament::math::float3 BuildFilamentLightDirection(const glm::mat4& worldMatrix) {
glm::vec3 direction = glm::vec3(worldMatrix * glm::vec4(0.0F, 0.0F, -1.0F, 0.0F));
if (glm::length(direction) <= 0.0001F) {
direction = glm::vec3(0.5F, 0.5F, -1.0F);
}
direction = glm::normalize(direction);
return ToFilamentFloat3(direction);
}
static filament::LinearColor BuildFilamentLightColor(const glm::vec3& color) {
return filament::Color::toLinear<filament::ACCURATE>({ color.x, color.y, color.z });
}
static float BuildFilamentLightIntensity(float intensity) {
return (intensity > 0.0F ? intensity : 0.0F) * 10000.0F;
}
void SyncSceneLights(const MetaCoreSceneRenderSyncSnapshot& snapshot) {
if (!Engine_ || !Scene_) {
return;
}
std::unordered_set<MetaCoreId> activeLightIds;
auto& lightManager = Engine_->getLightManager();
const auto defaultLightInstance = lightManager.getInstance(Light_);
// 统计当前是否有处于启用状态的光源
bool hasActiveLight = false;
for (const auto& light : snapshot.Lights) {
if (light.Enabled) {
hasActiveLight = true;
break;
}
}
if (defaultLightInstance) {
// 如果场景中没有任何起作用的灯光,则自动亮起默认灯光作为兜底
lightManager.setIntensity(defaultLightInstance, hasActiveLight ? 0.0F : 100000.0F);
}
for (const MetaCoreRenderSyncLight& light : snapshot.Lights) {
if (!light.Enabled) {
continue;
}
activeLightIds.insert(light.ObjectId);
auto lightIt = SceneLightEntities_.find(light.ObjectId);
if (lightIt == SceneLightEntities_.end()) {
utils::Entity lightEntity = utils::EntityManager::get().create();
filament::LightManager::Builder(filament::LightManager::Type::DIRECTIONAL)
.color(BuildFilamentLightColor(light.Color))
.intensity(BuildFilamentLightIntensity(light.Intensity))
.direction(BuildFilamentLightDirection(light.WorldMatrix))
.castShadows(true)
.build(*Engine_, lightEntity);
Scene_->addEntity(lightEntity);
EntitiesInScene_.insert(lightEntity);
lightIt = SceneLightEntities_.emplace(light.ObjectId, lightEntity).first;
}
const auto lightInstance = lightManager.getInstance(lightIt->second);
if (lightInstance) {
lightManager.setColor(lightInstance, BuildFilamentLightColor(light.Color));
lightManager.setIntensity(lightInstance, BuildFilamentLightIntensity(light.Intensity));
lightManager.setDirection(lightInstance, BuildFilamentLightDirection(light.WorldMatrix));
}
}
for (auto it = SceneLightEntities_.begin(); it != SceneLightEntities_.end();) {
if (activeLightIds.contains(it->first)) {
++it;
continue;
}
Scene_->remove(it->second);
EntitiesInScene_.erase(it->second);
Engine_->destroy(it->second);
utils::EntityManager::get().destroy(it->second);
it = SceneLightEntities_.erase(it);
}
}
void UpdateTransform(MetaCoreId objectId, const glm::mat4& localMatrix) {
auto it = ObjectToFilamentEntity_.find(objectId);
if (it == ObjectToFilamentEntity_.end()) return;
utils::Entity entity = it->second.second;
auto& tm = Engine_->getTransformManager();
auto instance = tm.getInstance(entity);
if (instance) {
glm::mat4 matrix = localMatrix;
// 【关键修复】:如果当前 entity 是子节点(即不是顶级映射的 pivotEntity
// 由于它的父级assetRoot带有了 -90X 旋转,我们必须对子节点应用基变换来抵消这个旋转。
// 公式L_filament = R(90X) * L_ecs * R(-90X)
if (LoadedAssets_.count(objectId) == 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;
MetaCoreSceneRenderSync RenderSync_{};
MetaCoreSceneRenderSyncSnapshot LastSyncSnapshot_{};
std::unordered_map<MetaCoreId, glm::mat4> ObjectWorldMatrices_{};
std::unordered_map<MetaCoreId, std::pair<filament::gltfio::FilamentAsset*, utils::Entity>> ObjectToFilamentEntity_;
std::unordered_map<MetaCoreId, filament::gltfio::FilamentAsset*> LoadedAssets_;
std::unordered_map<MetaCoreId, utils::Entity> SceneLightEntities_;
std::unordered_set<utils::Entity, utils::Entity::Hasher> EntitiesInScene_;
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, bool offscreen) {
return Impl_->Initialize(window, offscreen);
}
void MetaCoreFilamentSceneBridge::Shutdown() {
Impl_->Shutdown();
}
void MetaCoreFilamentSceneBridge::SetProjectRootPath(const std::filesystem::path& projectRootPath) {
Impl_->SetProjectRootPath(projectRootPath);
}
void MetaCoreFilamentSceneBridge::SyncScene(MetaCoreScene& scene, bool compatibilityMeshOnly, bool useScenePrimaryCamera) {
auto snapshot = Impl_->BuildSnapshot(scene);
Impl_->SyncScene(snapshot, &scene, compatibilityMeshOnly, useScenePrimaryCamera);
}
void MetaCoreFilamentSceneBridge::SyncScene(const MetaCoreSceneRenderSyncSnapshot& snapshot, MetaCoreScene* scene, bool compatibilityMeshOnly, bool useScenePrimaryCamera) {
Impl_->SyncScene(snapshot, scene, compatibilityMeshOnly, useScenePrimaryCamera);
}
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();
}
bool MetaCoreFilamentSceneBridge::VerifyTransformForTesting(MetaCoreId objectId, const glm::mat4& expectedMatrix) const {
return Impl_->VerifyTransformForTesting(objectId, expectedMatrix);
}
bool MetaCoreFilamentSceneBridge::VerifyLightExistsForTesting(MetaCoreId objectId) const {
return Impl_->VerifyLightExistsForTesting(objectId);
}
float MetaCoreFilamentSceneBridge::GetDefaultLightIntensityForTesting() const {
return Impl_->GetDefaultLightIntensityForTesting();
}
bool MetaCoreFilamentSceneBridge::VerifyEntityInSceneForTesting(MetaCoreId objectId) const {
return Impl_->VerifyEntityInSceneForTesting(objectId);
}
} // namespace MetaCore