MetaCore/Source/MetaCoreRender/Private/MetaCoreFilamentSceneBridge.cpp

460 lines
17 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 <filament/Engine.h>
#include <filament/Scene.h>
#include <filament/View.h>
#include <filament/Camera.h>
#include <filament/SwapChain.h>
#include <filament/Renderer.h>
#include <filament/Viewport.h>
#include <filament/TransformManager.h>
#include <filament/Texture.h>
#include <filament/RenderTarget.h>
#include <filament/LightManager.h>
#include <gltfio/AssetLoader.h>
#include <gltfio/FilamentAsset.h>
#include <gltfio/ResourceLoader.h>
#include <gltfio/MaterialProvider.h>
#include <utils/Entity.h>
#include <utils/EntityManager.h>
#define GLM_ENABLE_EXPERIMENTAL
#include <glm/gtc/type_ptr.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <iostream>
#include <fstream>
#include <unordered_map>
#include <vector>
// 引入 Windows 和 OpenGL 头文件以创建纹理
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <GL/gl.h>
namespace MetaCore {
class MetaCoreFilamentSceneBridge::MetaCoreFilamentSceneBridgeImpl {
public:
MetaCoreFilamentSceneBridgeImpl() = default;
~MetaCoreFilamentSceneBridgeImpl() {
Shutdown();
}
bool Initialize(MetaCoreWindow& window) {
std::cout << "FilamentSceneBridge: Initializing..." << std::endl;
// 创建 Filament Engine (不共享上下文,避免闪退)
Engine_ = filament::Engine::create();
if (!Engine_) {
std::cerr << "Failed to create Filament Engine with shared context!" << std::endl;
return false;
}
// 创建无窗口的 1x1 交换链 (因为我们是离屏渲染,不需要绑定真实窗口,避免 OpenGL 上下文冲突)
SwapChain_ = Engine_->createSwapChain(1, 1, 0);
if (!SwapChain_) {
std::cerr << "Failed to create Filament headless SwapChain!" << std::endl;
return false;
}
// 创建渲染器
Renderer_ = Engine_->createRenderer();
// 创建场景
Scene_ = Engine_->createScene();
// 创建默认灯光
Light_ = utils::EntityManager::get().create();
filament::LightManager::Builder(filament::LightManager::Type::DIRECTIONAL)
.color(filament::Color::toLinear<filament::ACCURATE>({ 1.0f, 1.0f, 1.0f }))
.intensity(100000.0f)
.direction({ 0.5f, -1.0f, -0.5f })
.castShadows(true)
.build(*Engine_, Light_);
Scene_->addEntity(Light_);
// 创建相机
utils::Entity cameraEntity = utils::EntityManager::get().create();
Camera_ = Engine_->createCamera(cameraEntity);
// 创建视图
View_ = Engine_->createView();
View_->setScene(Scene_);
View_->setCamera(Camera_);
// 初始化离屏渲染纹理
auto [width, height] = window.GetFramebufferSize();
// 1. 创建 OpenGL 纹理
glGenTextures(1, &GLTextureId_);
glBindTexture(GL_TEXTURE_2D, GLTextureId_);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glBindTexture(GL_TEXTURE_2D, 0);
// 2. 导入到 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)
.import(static_cast<intptr_t>(GLTextureId_))
.build(*Engine_);
// 3. 创建深度纹理
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_);
// 4. 创建 RenderTarget 并绑定
RenderTarget_ = filament::RenderTarget::Builder()
.texture(filament::RenderTarget::AttachmentPoint::COLOR, FilamentTexture_)
.texture(filament::RenderTarget::AttachmentPoint::DEPTH, DepthTexture_)
.build(*Engine_);
// 5. 设置到 View
View_->setRenderTarget(RenderTarget_);
View_->setViewport({0, 0, static_cast<uint32_t>(width), static_cast<uint32_t>(height)});
// 初始化 gltfio (使用 JIT Shader Provider需要链接 filamat)
MaterialProvider_ = filament::gltfio::createJitShaderProvider(Engine_);
AssetLoader_ = filament::gltfio::AssetLoader::create({ Engine_, MaterialProvider_, nullptr });
std::cout << "FilamentSceneBridge: Initialized with Offscreen Texture ID: " << GLTextureId_ << std::endl;
return true;
}
void Shutdown() {
if (Engine_) {
std::cout << "FilamentSceneBridge: Shutting down..." << std::endl;
// 销毁所有加载的资产
for (auto& [id, asset] : LoadedAssets_) {
AssetLoader_->destroyAsset(asset);
}
LoadedAssets_.clear();
// 销毁 gltfio 资源
if (AssetLoader_) {
filament::gltfio::AssetLoader::destroy(&AssetLoader_);
AssetLoader_ = nullptr;
}
if (MaterialProvider_) {
MaterialProvider_->destroyMaterials();
delete MaterialProvider_;
MaterialProvider_ = nullptr;
}
// 销毁离屏渲染资源
if (RenderTarget_) {
Engine_->destroy(RenderTarget_);
RenderTarget_ = nullptr;
}
if (FilamentTexture_) {
Engine_->destroy(FilamentTexture_);
FilamentTexture_ = nullptr;
}
if (DepthTexture_) {
Engine_->destroy(DepthTexture_);
DepthTexture_ = nullptr;
}
if (GLTextureId_) {
glDeleteTextures(1, &GLTextureId_);
GLTextureId_ = 0;
}
// 销毁 View
Engine_->destroy(View_);
// 销毁相机组件和实体
if (Camera_) {
utils::Entity cameraEntity = Camera_->getEntity();
Engine_->destroyCameraComponent(cameraEntity);
utils::EntityManager::get().destroy(cameraEntity);
}
// 销毁其他资源
Engine_->destroy(Scene_);
Engine_->destroy(Renderer_);
Engine_->destroy(SwapChain_);
// 最后销毁 Engine
filament::Engine::destroy(&Engine_);
Engine_ = nullptr;
}
}
void SetProjectRootPath(const std::filesystem::path& projectRootPath) {
ProjectRootPath_ = projectRootPath;
}
void SyncScene(const MetaCoreScene& scene, bool compatibilityMeshOnly) {
if (!AssetLoader_) return;
for (const auto& gameObject : scene.GetGameObjects()) {
if (!gameObject.HasComponent<MetaCoreMeshRendererComponent>()) {
continue;
}
const auto& meshRenderer = gameObject.GetComponent<MetaCoreMeshRendererComponent>();
if (meshRenderer.MeshSource != MetaCoreMeshSourceKind::Asset) {
continue;
}
std::string modelPath = meshRenderer.SourceModelPath;
if (modelPath.empty()) {
continue;
}
std::filesystem::path absolutePath = ProjectRootPath_ / modelPath;
// 如果已经加载过,更新位置即可
if (LoadedAssets_.contains(gameObject.GetId())) {
UpdateTransform(gameObject);
continue;
}
// 加载新模型
std::cout << "FilamentSceneBridge: Loading GLTF: " << absolutePath << std::endl;
std::ifstream file(absolutePath, std::ios::binary);
if (!file.is_open()) {
std::cerr << "Failed to open file: " << absolutePath << std::endl;
continue;
}
std::vector<char> buffer((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
filament::gltfio::FilamentAsset* asset = AssetLoader_->createAsset(
reinterpret_cast<const uint8_t*>(buffer.data()),
static_cast<uint32_t>(buffer.size())
);
if (!asset) {
std::cerr << "Failed to create asset!" << std::endl;
continue;
}
// 加载贴图等资源
filament::gltfio::ResourceLoader resourceLoader({ Engine_ });
resourceLoader.loadResources(asset);
// 添加到场景
Scene_->addEntities(asset->getEntities(), asset->getEntityCount());
LoadedAssets_[gameObject.GetId()] = asset;
// 更新初始位置
UpdateTransform(gameObject);
}
}
void ApplySceneView(const MetaCoreSceneView& sceneView) {
if (!Camera_ || !View_) return;
// 设置相机位置和朝向
Camera_->lookAt(
{ sceneView.CameraPosition.x, sceneView.CameraPosition.y, sceneView.CameraPosition.z },
{ sceneView.CameraTarget.x, sceneView.CameraTarget.y, sceneView.CameraTarget.z },
{ sceneView.CameraUp.x, sceneView.CameraUp.y, sceneView.CameraUp.z }
);
// 获取当前视口大小计算宽高比
const auto& viewport = View_->getViewport();
double aspect = 1.0;
if (viewport.height > 0) {
aspect = static_cast<double>(viewport.width) / static_cast<double>(viewport.height);
}
// 设置透视投影
double fov = sceneView.VerticalFieldOfViewDegrees;
double nearClip = 0.1;
double farClip = 1000.0;
Camera_->setProjection(fov, aspect, nearClip, farClip, filament::Camera::Fov::VERTICAL);
}
void Render() {
if (Renderer_ && SwapChain_ && View_) {
filament::Renderer::ClearOptions options;
options.clearColor = { 1.0f, 0.0f, 1.0f, 1.0f }; // 粉色,方便辨认
options.clear = true;
Renderer_->setClearOptions(options);
if (Renderer_->beginFrame(SwapChain_)) {
Renderer_->render(View_);
Renderer_->endFrame();
}
}
}
uint32_t GetGLTextureId() const {
return GLTextureId_;
}
void Resize(int width, int height) {
if (width <= 0 || height <= 0) return;
if (RenderTarget_) Engine_->destroy(RenderTarget_);
if (FilamentTexture_) Engine_->destroy(FilamentTexture_);
if (DepthTexture_) Engine_->destroy(DepthTexture_);
if (GLTextureId_) glDeleteTextures(1, &GLTextureId_);
glGenTextures(1, &GLTextureId_);
glBindTexture(GL_TEXTURE_2D, GLTextureId_);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glBindTexture(GL_TEXTURE_2D, 0);
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)
.import(static_cast<intptr_t>(GLTextureId_))
.build(*Engine_);
DepthTexture_ = filament::Texture::Builder()
.width(static_cast<uint32_t>(width))
.height(static_cast<uint32_t>(height))
.usage(filament::Texture::Usage::DEPTH_ATTACHMENT)
.format(filament::Texture::InternalFormat::DEPTH24)
.build(*Engine_);
RenderTarget_ = filament::RenderTarget::Builder()
.texture(filament::RenderTarget::AttachmentPoint::COLOR, FilamentTexture_)
.texture(filament::RenderTarget::AttachmentPoint::DEPTH, DepthTexture_)
.build(*Engine_);
View_->setRenderTarget(RenderTarget_);
View_->setViewport({0, 0, static_cast<uint32_t>(width), static_cast<uint32_t>(height)});
}
void* GetFilamentTexturePointer() const {
return FilamentTexture_;
}
bool TryGetObjectWorldMatrix(MetaCoreId objectId, glm::mat4& worldMatrix) const {
return false;
}
bool HasRuntimeSyncFailure() const { return false; }
const std::string& GetLastRuntimeSyncFailure() const { return EmptyString_; }
private:
void UpdateTransform(const MetaCoreGameObject& gameObject) {
auto it = LoadedAssets_.find(gameObject.GetId());
if (it == LoadedAssets_.end()) return;
filament::gltfio::FilamentAsset* asset = it->second;
utils::Entity rootEntity = asset->getRoot();
auto& tm = Engine_->getTransformManager();
auto instance = tm.getInstance(rootEntity);
if (instance) {
if (!gameObject.HasComponent<MetaCoreTransformComponent>()) return;
const auto& transform = gameObject.GetComponent<MetaCoreTransformComponent>();
glm::mat4 matrix = glm::mat4(1.0f);
matrix = glm::translate(matrix, transform.Position);
matrix = glm::rotate(matrix, glm::radians(transform.RotationEulerDegrees.x), {1, 0, 0});
matrix = glm::rotate(matrix, glm::radians(transform.RotationEulerDegrees.y), {0, 1, 0});
matrix = glm::rotate(matrix, glm::radians(transform.RotationEulerDegrees.z), {0, 0, 1});
matrix = glm::scale(matrix, transform.Scale);
tm.setTransform(instance, *reinterpret_cast<const filament::math::mat4f*>(glm::value_ptr(matrix)));
}
}
filament::Engine* Engine_ = nullptr;
filament::SwapChain* SwapChain_ = nullptr;
filament::Renderer* Renderer_ = nullptr;
filament::Scene* Scene_ = nullptr;
filament::Camera* Camera_ = nullptr;
filament::View* View_ = nullptr;
filament::gltfio::AssetLoader* AssetLoader_ = nullptr;
filament::gltfio::MaterialProvider* MaterialProvider_ = nullptr;
std::unordered_map<MetaCoreId, filament::gltfio::FilamentAsset*> LoadedAssets_;
GLuint GLTextureId_ = 0;
filament::Texture* FilamentTexture_ = nullptr;
filament::Texture* DepthTexture_ = nullptr;
filament::RenderTarget* RenderTarget_ = nullptr;
utils::Entity Light_;
std::filesystem::path ProjectRootPath_{};
std::string EmptyString_{};
};
MetaCoreFilamentSceneBridge::MetaCoreFilamentSceneBridge()
: Impl_(std::make_unique<MetaCoreFilamentSceneBridgeImpl>()) {}
MetaCoreFilamentSceneBridge::~MetaCoreFilamentSceneBridge() = default;
bool MetaCoreFilamentSceneBridge::Initialize(MetaCoreWindow& window) {
return Impl_->Initialize(window);
}
void MetaCoreFilamentSceneBridge::Shutdown() {
Impl_->Shutdown();
}
void MetaCoreFilamentSceneBridge::SetProjectRootPath(const std::filesystem::path& projectRootPath) {
Impl_->SetProjectRootPath(projectRootPath);
}
void MetaCoreFilamentSceneBridge::SyncScene(const MetaCoreScene& scene, bool compatibilityMeshOnly) {
Impl_->SyncScene(scene, compatibilityMeshOnly);
}
void MetaCoreFilamentSceneBridge::ApplySceneView(const MetaCoreSceneView& sceneView) {
Impl_->ApplySceneView(sceneView);
}
void MetaCoreFilamentSceneBridge::Render() {
Impl_->Render();
}
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