#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 #include "MetaCoreFoundation/MetaCoreAssetRegistry.h" #include "MetaCoreFoundation/MetaCoreRuntimeAssetRegistry.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "MetaCoreScene/MetaCoreTransformUtils.h" #define GLM_ENABLE_EXPERIMENTAL #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // 引入平台和 OpenGL 头文件以创建纹理 #if defined(_WIN32) #define WIN32_LEAN_AND_MEAN #include #endif #include #if !defined(_WIN32) #define GLFW_EXPOSE_NATIVE_X11 #include #include #endif namespace MetaCore { namespace { void* MetaCoreGetFilamentNativeWindowHandle(MetaCoreWindow& window) { #if defined(_WIN32) return window.GetNativeWindowHandle(); #else auto* glfwWindow = static_cast(window.GetNativeWindowHandle()); if (glfwWindow == nullptr) { return nullptr; } const Window x11Window = glfwGetX11Window(glfwWindow); return reinterpret_cast(static_cast(x11Window)); #endif } filament::Engine::Backend MetaCoreResolveFilamentBackend() { const char* backend = std::getenv("METACORE_FILAMENT_BACKEND"); if (backend == nullptr) { return filament::Engine::Backend::DEFAULT; } const std::string_view backendName(backend); if (backendName == "opengl") { return filament::Engine::Backend::OPENGL; } if (backendName == "vulkan") { return filament::Engine::Backend::VULKAN; } return filament::Engine::Backend::DEFAULT; } template [[nodiscard]] std::string MetaCoreDebugPointer(T* pointer) { std::ostringstream stream; stream << static_cast(pointer); return stream.str(); } void MetaCoreFilamentDebugLog(const std::string& message) { std::cerr << "[MetaCoreDebug][Filament] " << message << std::endl; } } // namespace 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(MetaCoreResolveFilamentBackend()); if (!Engine_) { std::cerr << "Failed to create Filament Engine with shared context!" << std::endl; return false; } // 创建绑定真实窗口的交换链 SwapChain_ = Engine_->createSwapChain(MetaCoreGetFilamentNativeWindowHandle(window)); 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({ 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(width)) .height(static_cast(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(width)) .height(static_cast(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_); ++RenderTargetGeneration_; DebugRenderTargetState("Initialize offscreen render target"); // 4. 设置到 View View_->setRenderTarget(RenderTarget_); View_->setViewport({0, 0, static_cast(width), static_cast(height)}); } else { auto [width, height] = window.GetFramebufferSize(); View_->setViewport({0, 0, static_cast(width), static_cast(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_ }); RuntimeAssetSubscriptionId_ = MetaCoreRuntimeAssetRegistry::Get().Subscribe( [this](const MetaCoreAssetChangeEvent& event) { if (event.AssetGuid.IsValid()) { InvalidatedModelGuids_.insert(event.AssetGuid); } if (event.SourceAssetGuid.IsValid()) { InvalidatedModelGuids_.insert(event.SourceAssetGuid); } } ); std::cout << "FilamentSceneBridge: Initialized with Offscreen=" << (offscreen ? "true" : "false") << std::endl; return true; } void Shutdown() { if (RuntimeAssetSubscriptionId_ != 0) { MetaCoreRuntimeAssetRegistry::Get().Unsubscribe(RuntimeAssetSubscriptionId_); RuntimeAssetSubscriptionId_ = 0; } if (Engine_) { std::cout << "FilamentSceneBridge: Shutting down..." << std::endl; DebugRenderTargetState("Shutdown begin"); // 1. 销毁所有加载的资产,切断其内部 Renderable 对克隆材质实例的占用引用 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; MetaCoreFilamentDebugLog( "Shutdown destroyAsset begin hostRootId=" + std::to_string(id) + " asset=" + MetaCoreDebugPointer(asset) ); if (asset) { Engine_->flushAndWait(); AssetLoader_->destroyAsset(asset); } MetaCoreFilamentDebugLog( "Shutdown destroyAsset end hostRootId=" + std::to_string(id) + " asset=" + MetaCoreDebugPointer(asset) ); std::cout << "[DEBUG] Destroyed asset for ID: " << id << std::endl; } LoadedAssets_.clear(); HostRootSourceModelGuids_.clear(); InvalidatedModelGuids_.clear(); // 2. 销毁所有 pivotEntity 中间辅助坐标变换实体 for (auto& [objectId, assetEntity] : ObjectToFilamentEntity_) { utils::Entity entity = assetEntity.second; if (!entity) continue; 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) { if (Scene_) { Scene_->remove(entity); EntitiesInScene_.erase(entity); } Engine_->destroy(entity); utils::EntityManager::get().destroy(entity); } } ObjectToFilamentEntity_.clear(); ObjectWorldMatrices_.clear(); // 3. 销毁所有克隆的材质实例,由于引用的实体都已被销毁,此时可安全释放 for (auto& [id, mats] : AssetDuplicatedMaterials_) { MetaCoreFilamentDebugLog( "Shutdown destroy duplicated materials hostRootId=" + std::to_string(id) + " count=" + std::to_string(mats.size()) ); Engine_->flushAndWait(); for (auto* mat : mats) { if (mat) { Engine_->destroy(mat); } } } AssetDuplicatedMaterials_.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; } DestroyDeferredRenderTargetResources(true); // 销毁离屏渲染资源 if (RenderTarget_) { DebugRenderTargetState("Shutdown destroy current render target begin"); Engine_->flushAndWait(); Engine_->destroy(RenderTarget_); RenderTarget_ = nullptr; } if (FilamentTexture_) { MetaCoreFilamentDebugLog( "Shutdown destroy current colorTexture=" + MetaCoreDebugPointer(FilamentTexture_) ); Engine_->destroy(FilamentTexture_); FilamentTexture_ = nullptr; } if (DepthTexture_) { MetaCoreFilamentDebugLog( "Shutdown destroy current depthTexture=" + MetaCoreDebugPointer(DepthTexture_) ); Engine_->destroy(DepthTexture_); DepthTexture_ = nullptr; } DebugRenderTargetState("Shutdown after current render target destroy"); 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; auto& tm = Engine_->getTransformManager(); // 绑定顶级父 GameObject 标识到 Filament Asset 根 Entity,彻底打通顶级 Gizmo 的同步! ObjectToFilamentEntity_[parentObject.GetId()] = { asset, asset->getRoot() }; // 1. 自底向上建立完整的 Filament 父子关系映射,解决隐藏过渡节点导致的层级断裂问题 std::unordered_map, utils::Entity::Hasher> parentToChildren = BuildFullParentToChildrenMap(asset); // 2. 建立 ECS 的父子关系映射 std::unordered_map> ecsParentToChildren; std::vector subtreeIds = scene.GetSubtreeObjectIds(parentObject.GetId()); for (MetaCoreId subId : subtreeIds) { auto subObj = scene.FindGameObject(subId); if (subObj) { ecsParentToChildren[subObj.GetParentId()].push_back(subObj); } } // 3. 递归 DFS 精确结构匹配并初始化 Transform 属性,穿透所有过渡节点 std::function matchRecursive = [&](MetaCoreGameObject currentObj, utils::Entity currentEntity) { ObjectToFilamentEntity_[currentObj.GetId()] = { asset, currentEntity }; if (currentEntity != asset->getRoot()) { auto instance = tm.getInstance(currentEntity); 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 = currentObj.GetComponent(); transform.Position = translation; transform.RotationEulerDegrees = glm::degrees(glm::eulerAngles(rotation)); transform.Scale = scale; } } // 穿透过渡节点获取当前实体的有效 Filament 子实体列表 std::vector fChildren; GetEffectiveFilamentChildren(currentEntity, asset, parentToChildren, fChildren); auto& eChildren = ecsParentToChildren[currentObj.GetId()]; for (utils::Entity fChild : fChildren) { const char* nodeName = asset->getName(fChild); std::string name = nodeName ? nodeName : ""; MetaCoreGameObject matchedEObj; for (auto it = eChildren.begin(); it != eChildren.end(); ++it) { if (it->GetName() == name) { matchedEObj = *it; eChildren.erase(it); break; } } // 模糊/降级匹配 if (!matchedEObj && name.empty() && !eChildren.empty()) { matchedEObj = eChildren.front(); eChildren.erase(eChildren.begin()); } if (matchedEObj) { matchRecursive(matchedEObj, fChild); } } }; // 从根开始执行递归层级树匹配 matchRecursive(parentObject, asset->getRoot()); } 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; // 构建物体ID到网格快照的快速映射,方便后续查询可见性及材质属性 std::unordered_map renderableMap; for (const auto& r : snapshot.Renderables) { renderableMap[r.ObjectId] = &r; } // 定义用于检测场景中某个对象及其所有祖先节点当前在快照里是否应为可见状态的辅助方法 std::unordered_map visibilityCache; std::function isObjectVisible = [&](MetaCoreId objectId) -> bool { if (objectId == 0) { return true; } auto cacheIt = visibilityCache.find(objectId); if (cacheIt != visibilityCache.end()) { return cacheIt->second; } if (!snapshot.WorldMatrices.contains(objectId)) { visibilityCache[objectId] = false; return false; } bool selfVisible = true; MetaCoreId parentId = 0; auto rIt = renderableMap.find(objectId); if (rIt != renderableMap.end()) { selfVisible = rIt->second->Visible; parentId = rIt->second->ParentId; } else if (scene != nullptr) { auto obj = scene->FindGameObject(objectId); if (obj) { parentId = obj.GetParentId(); } } if (!selfVisible) { visibilityCache[objectId] = false; return false; } bool parentVisible = isObjectVisible(parentId); visibilityCache[objectId] = parentVisible; return parentVisible; }; SyncSceneLights(LastSyncSnapshot_); if (useScenePrimaryCamera) { MetaCoreSceneView primarySceneView; if (MetaCoreSceneRenderSync::TryBuildSceneViewFromPrimaryCamera(LastSyncSnapshot_, primarySceneView)) { ApplySceneView(primarySceneView); } } // 1. 收集当前 snapshot 中所有存在的模型 Root ID std::unordered_set 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; const auto sourceGuid = HostRootSourceModelGuids_.find(hostRootId); const bool invalidated = sourceGuid != HostRootSourceModelGuids_.end() && InvalidatedModelGuids_.contains(sourceGuid->second); if (!activeHostRootIds.contains(hostRootId) || invalidated) { std::cout << "FilamentSceneBridge: Unloading deleted asset: " << hostRootId << std::endl; const size_t assetEntityCount = asset != nullptr ? asset->getEntityCount() : 0; const auto materialIt = AssetDuplicatedMaterials_.find(hostRootId); const size_t duplicatedMaterialCount = materialIt != AssetDuplicatedMaterials_.end() ? materialIt->second.size() : 0; MetaCoreFilamentDebugLog( "Unload begin hostRootId=" + std::to_string(hostRootId) + " asset=" + MetaCoreDebugPointer(asset) + " active=" + (activeHostRootIds.contains(hostRootId) ? std::string("true") : std::string("false")) + " invalidated=" + (invalidated ? std::string("true") : std::string("false")) + " entities=" + std::to_string(assetEntityCount) + " duplicatedMaterials=" + std::to_string(duplicatedMaterialCount) ); // 从场景中移除该资产关联的所有实体 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); } } // 等待后台渲染线程消费完上一帧命令,再销毁 GLTF 资产持有的纹理/材质。 // 脚本播放会每帧推进 Transform,暂停/热更新等操作可能和渲染同步落在相邻帧, // 不等待会让 OpenGL descriptor 绑定已释放的 FTexture。 if (Engine_) { MetaCoreFilamentDebugLog( "Unload flush before destroyAsset hostRootId=" + std::to_string(hostRootId) ); Engine_->flushAndWait(); } // 销毁资产本身 if (asset) { MetaCoreFilamentDebugLog( "Unload destroyAsset begin hostRootId=" + std::to_string(hostRootId) + " asset=" + MetaCoreDebugPointer(asset) ); AssetLoader_->destroyAsset(asset); MetaCoreFilamentDebugLog( "Unload destroyAsset end hostRootId=" + std::to_string(hostRootId) + " asset=" + MetaCoreDebugPointer(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); // 销毁克隆的材质 auto matIt = AssetDuplicatedMaterials_.find(hostRootId); if (matIt != AssetDuplicatedMaterials_.end()) { MetaCoreFilamentDebugLog( "Unload destroy duplicated materials begin hostRootId=" + std::to_string(hostRootId) + " count=" + std::to_string(matIt->second.size()) ); if (Engine_) { Engine_->flushAndWait(); } for (auto* mat : matIt->second) { if (mat) { Engine_->destroy(mat); } } MetaCoreFilamentDebugLog( "Unload destroy duplicated materials end hostRootId=" + std::to_string(hostRootId) ); AssetDuplicatedMaterials_.erase(matIt); } // 从 LoadedAssets_ 中移除 HostRootSourceModelGuids_.erase(hostRootId); it = LoadedAssets_.erase(it); MetaCoreFilamentDebugLog( "Unload end hostRootId=" + std::to_string(hostRootId) + " loadedAssets=" + std::to_string(LoadedAssets_.size()) + " objectMappings=" + std::to_string(ObjectToFilamentEntity_.size()) ); } else { ++it; } } InvalidatedModelGuids_.clear(); 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; MetaCoreFilamentDebugLog( "Load begin hostRootId=" + std::to_string(hostRootId) + " host=\"" + hostRootName + "\"" + " modelPath=\"" + modelPath + "\"" + " loadedAssets=" + std::to_string(LoadedAssets_.size()) ); std::ifstream file(absolutePath, std::ios::binary); if (!file.is_open()) { std::cerr << "Failed to open file: " << absolutePath << std::endl; continue; } std::vector buffer((std::istreambuf_iterator(file)), std::istreambuf_iterator()); filament::gltfio::FilamentAsset* asset = AssetLoader_->createAsset( reinterpret_cast(buffer.data()), static_cast(buffer.size()) ); if (!asset) { std::cerr << "Failed to create asset!" << std::endl; continue; } MetaCoreFilamentDebugLog( "Load createAsset hostRootId=" + std::to_string(hostRootId) + " asset=" + MetaCoreDebugPointer(asset) + " entities=" + std::to_string(asset->getEntityCount()) ); // 加载贴图等资源 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 (renderable.SourceModelAssetGuid.IsValid()) { HostRootSourceModelGuids_[hostRootId] = renderable.SourceModelAssetGuid; } // 复制材质实例防止共享干扰,放在加载好资源后 { auto& rm = Engine_->getRenderableManager(); std::vector& dupList = AssetDuplicatedMaterials_[hostRootId]; const utils::Entity* assetEntities = asset->getEntities(); size_t assetEntityCount = asset->getEntityCount(); for (size_t i = 0; i < assetEntityCount; ++i) { utils::Entity ent = assetEntities[i]; if (!ent) continue; auto rmInst = rm.getInstance(ent); if (rmInst) { size_t primCount = rm.getPrimitiveCount(rmInst); for (size_t primIndex = 0; primIndex < primCount; ++primIndex) { filament::MaterialInstance* originalMat = rm.getMaterialInstanceAt(rmInst, primIndex); if (originalMat) { filament::MaterialInstance* dupMat = filament::MaterialInstance::duplicate(originalMat); if (dupMat) { rm.setMaterialInstanceAt(rmInst, primIndex, dupMat); dupList.push_back(dupMat); } } } } } MetaCoreFilamentDebugLog( "Load duplicated materials hostRootId=" + std::to_string(hostRootId) + " count=" + std::to_string(dupList.size()) ); } if (scene != nullptr) { // 有 ECS 实例模式下同步层级结构并补挂 Tag auto hostRootObj = scene->FindGameObject(hostRootId); if (hostRootObj) { MetaCoreGameObject nonConstHostRoot = hostRootObj; // 现场补挂 Tag,确保后续帧和拖拽时 100% 命中 Tag 快速通道,绝不走 Fallback if (!nonConstHostRoot.HasComponent()) { nonConstHostRoot.AddComponent(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() }; // 1. 自底向上建立完整的 Filament 父子关系映射,解决隐藏过渡节点导致的层级断裂问题 std::unordered_map, utils::Entity::Hasher> parentToChildren = BuildFullParentToChildrenMap(asset); // 2. 建立快照中的父子关系映射 std::unordered_map> snapParentToChildren; for (const auto& r : snapshot.Renderables) { if (r.HostRootId == hostRootId && r.ObjectId != hostRootId) { snapParentToChildren[r.ParentId].push_back(r); } } // 3. 递归 DFS 进行精确层级树结构匹配,穿透所有过渡节点 std::function matchRecursive = [&](MetaCoreId currentId, utils::Entity currentEntity) { ObjectToFilamentEntity_[currentId] = { asset, currentEntity }; // 穿透过渡节点获取当前实体的有效 Filament 子实体列表 std::vector fChildren; GetEffectiveFilamentChildren(currentEntity, asset, parentToChildren, fChildren); auto& sChildren = snapParentToChildren[currentId]; for (utils::Entity fChild : fChildren) { const char* nodeName = asset->getName(fChild); std::string name = nodeName ? nodeName : ""; MetaCoreId matchedChildId = 0; for (auto it = sChildren.begin(); it != sChildren.end(); ++it) { if (it->Name == name) { matchedChildId = it->ObjectId; sChildren.erase(it); break; } } // 兜底匹配 if (matchedChildId == 0 && name.empty() && !sChildren.empty()) { matchedChildId = sChildren.front().ObjectId; sChildren.erase(sChildren.begin()); } if (matchedChildId != 0) { matchRecursive(matchedChildId, fChild); } } }; // 从根开始执行递归层级树匹配 matchRecursive(hostRootId, asset->getRoot()); } // 创建中间 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(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; } glm::mat4 initWorldMat = initLocalMat; auto itWorldMat = snapshot.WorldMatrices.find(renderable.ObjectId); if (itWorldMat != snapshot.WorldMatrices.end()) { initWorldMat = itWorldMat->second; } UpdateTransform(renderable.ObjectId, initLocalMat, initWorldMat); } // 1. 构建反向查找映射,方便反查 entity 对应的 objectId std::unordered_map 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 = isObjectVisible(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 = isObjectVisible(entityToObjectId[mappedAncestor]); } else { // 回退保护:如果没有找到,则与该资产对应的顶级根宿主保持状态一致 shouldBeInScene = isObjectVisible(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 = isObjectVisible(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_) { auto itWorld = snapshot.WorldMatrices.find(objectId); if (itWorld != snapshot.WorldMatrices.end()) { auto itLocal = snapshot.LocalMatrices.find(objectId); if (itLocal != snapshot.LocalMatrices.end()) { UpdateTransform(objectId, itLocal->second, itWorld->second); } } } // 5. 同步所有存活网格的材质属性,例如 BaseColor auto& rm = Engine_->getRenderableManager(); for (const auto& renderable : snapshot.Renderables) { auto itEntity = ObjectToFilamentEntity_.find(renderable.ObjectId); if (itEntity == ObjectToFilamentEntity_.end()) { continue; } utils::Entity entity = itEntity->second.second; if (!entity) { continue; } auto instance = rm.getInstance(entity); if (!instance) { continue; } // 遍历所有 primitive,获取材质实例,并设置其 baseColorFactor 属性 size_t primCount = rm.getPrimitiveCount(instance); for (size_t primIndex = 0; primIndex < primCount; ++primIndex) { filament::MaterialInstance* matInst = rm.getMaterialInstanceAt(instance, primIndex); if (matInst) { // BaseColor 包含 RGB,以 float4 传递,Alpha 设为 1.0 filament::math::float4 baseColorVec{ renderable.BaseColor.x, renderable.BaseColor.y, renderable.BaseColor.z, 1.0f }; matInst->setParameter("baseColorFactor", baseColorVec); } } } } 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(glm::value_ptr(cameraModelMatrix))); // 2. 投影矩阵:回归 Filament 原生设置 const auto& viewport = View_->getViewport(); float aspect = (viewport.height > 0) ? (static_cast(viewport.width) / static_cast(viewport.height)) : 1.0f; Camera_->setProjection( sceneView.VerticalFieldOfViewDegrees, aspect, sceneView.NearClip, sceneView.FarClip, filament::Camera::Fov::VERTICAL ); } void RenderAll() { if (!Renderer_ || !SwapChain_ || !View_) { return; } ++RenderFrameIndex_; if (!PendingRenderTargetResources_.empty()) { DebugRenderTargetState("RenderAll before beginFrame with pending destroy"); } // ImGui draw data -> Filament renderable 的同步会修改 Renderable、VertexBuffer、 // MaterialInstance 参数和 descriptor 绑定。必须在 beginFrame/render pass 之前完成, // 否则 Filament 会警告 descriptor set 在 begin/endRenderPass 中被修改,并可能在 // 后续句柄校验中触发 FTexture use-after-free/Postcondition 崩溃。 const bool hasUiPass = UIView_ != nullptr && ImGuiHelper_ != nullptr; if (hasUiPass) { ImGuiIO& io = ImGui::GetIO(); ImGuiHelper_->setDisplaySize(io.DisplaySize.x, io.DisplaySize.y); UIView_->setViewport({0, 0, static_cast(io.DisplaySize.x), static_cast(io.DisplaySize.y)}); ImGuiHelper_->processImGuiCommands(ImGui::GetDrawData(), io); } 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 (hasUiPass) { // 2. 准备并渲染 UI 视口 (输出到 SwapChain) options.clearColor = { 0.11f, 0.12f, 0.14f, 1.0f }; // 灰色 options.clear = true; Renderer_->setClearOptions(options); 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(); DestroyDeferredRenderTargetResources(true); } else if (!PendingRenderTargetResources_.empty()) { DebugRenderTargetState("RenderAll beginFrame failed with pending destroy"); } } uint32_t GetGLTextureId() const { return GLTextureId_; } void Resize(int width, int height) { if (width <= 0 || height <= 0) return; if (!RenderTarget_) { MetaCoreFilamentDebugLog( "Resize without render target width=" + std::to_string(width) + " height=" + std::to_string(height) ); View_->setViewport({0, 0, static_cast(width), static_cast(height)}); return; } // 【关键修复】:如果大小没有改变,不要重新创建纹理! // 否则会导致上一帧传给 ImGui 的纹理指针在这一帧被提前销毁,引发 Use-after-free 崩溃。 if (FilamentTexture_ && FilamentTexture_->getWidth() == static_cast(width) && FilamentTexture_->getHeight() == static_cast(height)) { return; } MetaCoreFilamentDebugLog( "Resize recreate begin width=" + std::to_string(width) + " height=" + std::to_string(height) + " oldWidth=" + (FilamentTexture_ != nullptr ? std::to_string(FilamentTexture_->getWidth()) : std::string("null")) + " oldHeight=" + (FilamentTexture_ != nullptr ? std::to_string(FilamentTexture_->getHeight()) : std::string("null")) ); DebugRenderTargetState("Resize before queue current resources"); QueueCurrentRenderTargetResourcesForDestroy(); DestroyDeferredRenderTargetResources(true); FilamentTexture_ = filament::Texture::Builder() .width(static_cast(width)) .height(static_cast(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(width)) .height(static_cast(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_); ++RenderTargetGeneration_; View_->setRenderTarget(RenderTarget_); View_->setViewport({0, 0, static_cast(width), static_cast(height)}); DebugRenderTargetState("Resize after recreate resources"); } void* GetFilamentTexturePointer() const { return FilamentTexture_; } void QueueCurrentRenderTargetResourcesForDestroy() { if (RenderTarget_ == nullptr && FilamentTexture_ == nullptr && DepthTexture_ == nullptr) { return; } PendingRenderTargetResources_.push_back(PendingRenderTargetResource{ RenderTarget_, FilamentTexture_, DepthTexture_, RenderTargetGeneration_ }); DebugRenderTargetState("Queue current render target resources for destroy"); RenderTarget_ = nullptr; FilamentTexture_ = nullptr; DepthTexture_ = nullptr; } void DestroyDeferredRenderTargetResources(bool waitForBackend) { if (PendingRenderTargetResources_.empty() || Engine_ == nullptr) { return; } if (waitForBackend) { DebugRenderTargetState("Destroy deferred resources flush begin"); Engine_->flushAndWait(); DebugRenderTargetState("Destroy deferred resources flush end"); } for (PendingRenderTargetResource& resource : PendingRenderTargetResources_) { std::ostringstream stream; stream << "Destroy deferred resource generation=" << resource.Generation << " renderTarget=" << MetaCoreDebugPointer(resource.RenderTarget) << " colorTexture=" << MetaCoreDebugPointer(resource.ColorTexture) << " depthTexture=" << MetaCoreDebugPointer(resource.DepthTexture); MetaCoreFilamentDebugLog(stream.str()); if (resource.RenderTarget != nullptr) { Engine_->destroy(resource.RenderTarget); } if (resource.ColorTexture != nullptr) { Engine_->destroy(resource.ColorTexture); } if (resource.DepthTexture != nullptr) { Engine_->destroy(resource.DepthTexture); } } PendingRenderTargetResources_.clear(); DebugRenderTargetState("Destroy deferred resources end"); } 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), ¤tMat[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()) { std::cout << "[DEBUG Verify] Cannot find objectId " << objectId << " in ObjectToFilamentEntity_" << std::endl; std::cout << "[DEBUG Verify] ObjectToFilamentEntity_ size: " << ObjectToFilamentEntity_.size() << std::endl; for (const auto& [oid, ent] : ObjectToFilamentEntity_) { std::cout << " - OID: " << oid << ", entity: " << ent.second.getId() << std::endl; } return false; } bool inScene = EntitiesInScene_.contains(it->second.second); if (!inScene) { std::cout << "[DEBUG Verify] Object " << objectId << " maps to entity " << it->second.second.getId() << ", but this entity is NOT in EntitiesInScene_" << std::endl; std::cout << "[DEBUG Verify] EntitiesInScene_ contains: "; for (auto ent : EntitiesInScene_) { std::cout << ent.getId() << " "; } std::cout << std::endl; } return inScene; } private: // 判断当前实体是否为过渡节点(即无名且无 Mesh 渲染组件的节点) bool IsTransitionNode(utils::Entity entity, filament::gltfio::FilamentAsset* asset) const { if (!entity) return false; if (entity == asset->getRoot()) return false; // 1. 判断是否有名字 const char* name = asset->getName(entity); if (name && strlen(name) > 0) { return false; } // 2. 判断是否是渲染实体 auto& rm = Engine_->getRenderableManager(); if (rm.getInstance(entity)) { return false; } return true; } // 穿透子节点链中的所有过渡节点,提取出所有具备有效名称或为渲染实体的第一代有效子节点 void GetEffectiveFilamentChildren( utils::Entity parent, filament::gltfio::FilamentAsset* asset, const std::unordered_map, utils::Entity::Hasher>& parentToChildren, std::vector& outEffectiveChildren ) const { auto it = parentToChildren.find(parent); if (it == parentToChildren.end()) return; for (utils::Entity child : it->second) { if (IsTransitionNode(child, asset)) { GetEffectiveFilamentChildren(child, asset, parentToChildren, outEffectiveChildren); } else { outEffectiveChildren.push_back(child); } } } // 自底向上溯源生成覆盖所有中间隐藏过渡节点的完整父子映射表 std::unordered_map, utils::Entity::Hasher> BuildFullParentToChildrenMap(filament::gltfio::FilamentAsset* asset) const { std::unordered_map, utils::Entity::Hasher> parentToChildren; if (!asset) return parentToChildren; const utils::Entity* entities = asset->getEntities(); size_t entityCount = asset->getEntityCount(); auto& tm = Engine_->getTransformManager(); for (size_t i = 0; i < entityCount; ++i) { utils::Entity current = entities[i]; if (current == asset->getRoot()) continue; while (current && current != asset->getRoot()) { auto instance = tm.getInstance(current); if (!instance) break; utils::Entity parent = tm.getParent(instance); if (parent.isNull()) break; auto& children = parentToChildren[parent]; if (std::find(children.begin(), children.end(), current) == children.end()) { children.push_back(current); } current = parent; } } return parentToChildren; } 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({ color.x, color.y, color.z }); } static float BuildFilamentLightIntensity(float intensity) { return (intensity > 0.0F ? intensity : 0.0F) * 100000.0F; } void SyncSceneLights(const MetaCoreSceneRenderSyncSnapshot& snapshot) { if (!Engine_ || !Scene_) { return; } std::unordered_set 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, const glm::mat4& worldMatrix) { 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) { auto parent = tm.getParent(instance); glm::mat4 matrix = parent ? localMatrix : worldMatrix; // 【关键修复】:如果当前 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(glm::value_ptr(matrix))); } } void DebugRenderTargetState(const char* event) const { std::ostringstream stream; stream << event << " frame=" << RenderFrameIndex_ << " generation=" << RenderTargetGeneration_ << " renderTarget=" << MetaCoreDebugPointer(RenderTarget_) << " colorTexture=" << MetaCoreDebugPointer(FilamentTexture_) << " depthTexture=" << MetaCoreDebugPointer(DepthTexture_) << " pending=" << PendingRenderTargetResources_.size() << " loadedAssets=" << LoadedAssets_.size() << " objectMappings=" << ObjectToFilamentEntity_.size(); MetaCoreFilamentDebugLog(stream.str()); } 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 ObjectWorldMatrices_{}; std::unordered_map> ObjectToFilamentEntity_; std::unordered_map LoadedAssets_; std::unordered_map HostRootSourceModelGuids_; std::unordered_set InvalidatedModelGuids_; std::unordered_map> AssetDuplicatedMaterials_; std::unordered_map SceneLightEntities_; std::unordered_set EntitiesInScene_; filament::View* UIView_ = nullptr; MetaCoreImGuiHelper* ImGuiHelper_ = nullptr; GLuint GLTextureId_ = 0; struct PendingRenderTargetResource { filament::RenderTarget* RenderTarget = nullptr; filament::Texture* ColorTexture = nullptr; filament::Texture* DepthTexture = nullptr; std::uint64_t Generation = 0; }; filament::Texture* FilamentTexture_ = nullptr; filament::Texture* DepthTexture_ = nullptr; filament::RenderTarget* RenderTarget_ = nullptr; std::vector PendingRenderTargetResources_; std::uint64_t RenderFrameIndex_ = 0; std::uint64_t RenderTargetGeneration_ = 0; utils::Entity Light_; std::filesystem::path ProjectRootPath_{}; std::string EmptyString_{}; MetaCoreRuntimeAssetRegistry::SubscriptionId RuntimeAssetSubscriptionId_ = 0; }; MetaCoreFilamentSceneBridge::MetaCoreFilamentSceneBridge() : Impl_(std::make_unique()) {} 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