feat: add scene render sync bridge for Filament P1
This commit is contained in:
parent
7d5887bbbb
commit
1a822288b7
@ -161,6 +161,7 @@ int main(int argc, char* argv[]) {
|
||||
return 1;
|
||||
}
|
||||
const std::filesystem::path projectPath = MetaCore::MetaCoreGetProjectFilePath(*projectRoot);
|
||||
viewportRenderer.SetProjectRootPath(*projectRoot);
|
||||
MetaCore::MetaCoreTypeRegistry typeRegistry;
|
||||
MetaCore::MetaCoreRegisterRuntimeDataGeneratedTypes(typeRegistry);
|
||||
const auto loadedRuntimeProjectDocument = MetaCore::MetaCoreReadRuntimeProjectDocument(
|
||||
@ -277,7 +278,7 @@ int main(int argc, char* argv[]) {
|
||||
}
|
||||
}
|
||||
}
|
||||
viewportRenderer.RenderSceneToViewport(scene, MetaCoreBuildPlayerSceneView());
|
||||
viewportRenderer.RenderSceneToViewport(scene, MetaCoreBuildPlayerSceneView(), true);
|
||||
renderDevice.RenderFrame();
|
||||
renderDevice.PresentFrame();
|
||||
window.EndFrame();
|
||||
|
||||
@ -215,6 +215,7 @@ set(METACORE_RENDER_HEADERS
|
||||
Source/MetaCoreRender/Public/MetaCoreRender/MetaCoreFilamentSceneBridge.h
|
||||
Source/MetaCoreRender/Public/MetaCoreRender/MetaCoreImGuiHelper.h
|
||||
Source/MetaCoreRender/Public/MetaCoreRender/MetaCoreRenderDevice.h
|
||||
Source/MetaCoreRender/Public/MetaCoreRender/MetaCoreSceneRenderSync.h
|
||||
Source/MetaCoreRender/Public/MetaCoreRender/MetaCoreRenderTypes.h
|
||||
)
|
||||
|
||||
@ -223,6 +224,7 @@ set(METACORE_RENDER_SOURCES
|
||||
Source/MetaCoreRender/Private/MetaCoreFilamentSceneBridge.cpp
|
||||
Source/MetaCoreRender/Private/MetaCoreImGuiHelper.cpp
|
||||
Source/MetaCoreRender/Private/MetaCoreRenderDevice.cpp
|
||||
Source/MetaCoreRender/Private/MetaCoreSceneRenderSync.cpp
|
||||
)
|
||||
|
||||
|
||||
|
||||
@ -79,7 +79,7 @@ void MetaCoreEditorViewportRenderer::SetViewportRect(const MetaCoreViewportRect&
|
||||
}
|
||||
}
|
||||
|
||||
void MetaCoreEditorViewportRenderer::RenderSceneToViewport(MetaCoreScene& scene, const MetaCoreSceneView& sceneView) {
|
||||
void MetaCoreEditorViewportRenderer::RenderSceneToViewport(MetaCoreScene& scene, const MetaCoreSceneView& sceneView, bool useScenePrimaryCamera) {
|
||||
if (RenderDevice_ == nullptr) {
|
||||
return;
|
||||
}
|
||||
@ -91,7 +91,7 @@ void MetaCoreEditorViewportRenderer::RenderSceneToViewport(MetaCoreScene& scene,
|
||||
|
||||
// 更新并同步 Filament 桥接器(但不在这里调用 Render,交由 RenderAll 统一渲染)
|
||||
FilamentSceneBridge_.ApplySceneView(sceneView);
|
||||
FilamentSceneBridge_.SyncScene(scene, false);
|
||||
FilamentSceneBridge_.SyncScene(scene, false, useScenePrimaryCamera);
|
||||
}
|
||||
|
||||
void MetaCoreEditorViewportRenderer::RenderAll() {
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
#include "MetaCoreScene/MetaCoreComponents.h"
|
||||
#include "MetaCoreRender/MetaCoreRenderTypes.h"
|
||||
#include "MetaCoreRender/MetaCoreImGuiHelper.h"
|
||||
#include "MetaCoreRender/MetaCoreSceneRenderSync.h"
|
||||
#include <imgui.h>
|
||||
#include "MetaCoreFoundation/MetaCoreAssetRegistry.h"
|
||||
|
||||
@ -31,13 +32,16 @@
|
||||
|
||||
#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>
|
||||
|
||||
@ -155,6 +159,17 @@ public:
|
||||
AssetLoader_->destroyAsset(asset);
|
||||
}
|
||||
LoadedAssets_.clear();
|
||||
ObjectToFilamentEntity_.clear();
|
||||
ObjectWorldMatrices_.clear();
|
||||
|
||||
for (auto& [id, entity] : SceneLightEntities_) {
|
||||
if (Scene_) {
|
||||
Scene_->remove(entity);
|
||||
}
|
||||
Engine_->destroy(entity);
|
||||
utils::EntityManager::get().destroy(entity);
|
||||
}
|
||||
SceneLightEntities_.clear();
|
||||
|
||||
// 销毁 gltfio 资源
|
||||
if (AssetLoader_) {
|
||||
@ -342,8 +357,19 @@ public:
|
||||
return path;
|
||||
}
|
||||
|
||||
void SyncScene(MetaCoreScene& scene, bool compatibilityMeshOnly) {
|
||||
void SyncScene(MetaCoreScene& scene, bool compatibilityMeshOnly, bool useScenePrimaryCamera) {
|
||||
if (!AssetLoader_) return;
|
||||
(void)compatibilityMeshOnly;
|
||||
|
||||
LastSyncSnapshot_ = RenderSync_.BuildSnapshot(scene);
|
||||
ObjectWorldMatrices_ = LastSyncSnapshot_.WorldMatrices;
|
||||
SyncSceneLights(LastSyncSnapshot_);
|
||||
if (useScenePrimaryCamera) {
|
||||
MetaCoreSceneView primarySceneView;
|
||||
if (MetaCoreSceneRenderSync::TryBuildSceneViewFromPrimaryCamera(LastSyncSnapshot_, primarySceneView)) {
|
||||
ApplySceneView(primarySceneView);
|
||||
}
|
||||
}
|
||||
|
||||
// 预处理:构建子树模型网格节点计数表,以支撑在没有 Tag 时的极速、完美 Fallback 回溯
|
||||
std::unordered_map<MetaCoreId, std::unordered_map<std::string, int>> subtreeModelCounts;
|
||||
@ -538,8 +564,8 @@ public:
|
||||
Camera_->setProjection(
|
||||
sceneView.VerticalFieldOfViewDegrees,
|
||||
aspect,
|
||||
0.1,
|
||||
1000.0,
|
||||
sceneView.NearClip,
|
||||
sceneView.FarClip,
|
||||
filament::Camera::Fov::VERTICAL
|
||||
);
|
||||
}
|
||||
@ -632,18 +658,92 @@ public:
|
||||
}
|
||||
|
||||
bool TryGetObjectWorldMatrix(MetaCoreId objectId, glm::mat4& worldMatrix) const {
|
||||
return false;
|
||||
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_; }
|
||||
|
||||
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_);
|
||||
if (defaultLightInstance) {
|
||||
lightManager.setIntensity(defaultLightInstance, snapshot.Lights.empty() ? 100000.0F : 0.0F);
|
||||
}
|
||||
|
||||
for (const MetaCoreRenderSyncLight& light : snapshot.Lights) {
|
||||
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);
|
||||
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);
|
||||
Engine_->destroy(it->second);
|
||||
utils::EntityManager::get().destroy(it->second);
|
||||
it = SceneLightEntities_.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateTransform(const MetaCoreGameObject& gameObject) {
|
||||
auto it = ObjectToFilamentEntity_.find(gameObject.GetId());
|
||||
if (it == ObjectToFilamentEntity_.end()) return;
|
||||
|
||||
filament::gltfio::FilamentAsset* asset = it->second.first;
|
||||
utils::Entity entity = it->second.second;
|
||||
|
||||
auto& tm = Engine_->getTransformManager();
|
||||
@ -678,8 +778,12 @@ private:
|
||||
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_;
|
||||
|
||||
filament::View* UIView_ = nullptr;
|
||||
MetaCoreImGuiHelper* ImGuiHelper_ = nullptr;
|
||||
@ -712,8 +816,8 @@ void MetaCoreFilamentSceneBridge::SetProjectRootPath(const std::filesystem::path
|
||||
Impl_->SetProjectRootPath(projectRootPath);
|
||||
}
|
||||
|
||||
void MetaCoreFilamentSceneBridge::SyncScene(MetaCoreScene& scene, bool compatibilityMeshOnly) {
|
||||
Impl_->SyncScene(scene, compatibilityMeshOnly);
|
||||
void MetaCoreFilamentSceneBridge::SyncScene(MetaCoreScene& scene, bool compatibilityMeshOnly, bool useScenePrimaryCamera) {
|
||||
Impl_->SyncScene(scene, compatibilityMeshOnly, useScenePrimaryCamera);
|
||||
}
|
||||
|
||||
void MetaCoreFilamentSceneBridge::ApplySceneView(const MetaCoreSceneView& sceneView) {
|
||||
|
||||
133
Source/MetaCoreRender/Private/MetaCoreSceneRenderSync.cpp
Normal file
133
Source/MetaCoreRender/Private/MetaCoreSceneRenderSync.cpp
Normal file
@ -0,0 +1,133 @@
|
||||
#include "MetaCoreRender/MetaCoreSceneRenderSync.h"
|
||||
|
||||
#include "MetaCoreRender/MetaCoreRenderTypes.h"
|
||||
#include "MetaCoreScene/MetaCoreScene.h"
|
||||
#include "MetaCoreScene/MetaCoreTransformUtils.h"
|
||||
|
||||
#include <glm/geometric.hpp>
|
||||
|
||||
#include <cmath>
|
||||
|
||||
namespace MetaCore {
|
||||
|
||||
namespace {
|
||||
|
||||
[[nodiscard]] bool MetaCoreIsUsableDirection(const glm::vec3& value) {
|
||||
return std::isfinite(value.x) &&
|
||||
std::isfinite(value.y) &&
|
||||
std::isfinite(value.z) &&
|
||||
glm::length(value) > 0.0001F;
|
||||
}
|
||||
|
||||
[[nodiscard]] glm::vec3 MetaCoreExtractTranslation(const glm::mat4& matrix) {
|
||||
return glm::vec3(matrix[3]);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
MetaCoreSceneRenderSyncSnapshot MetaCoreSceneRenderSync::BuildSnapshot(const MetaCoreScene& scene) const {
|
||||
MetaCoreSceneRenderSyncSnapshot snapshot;
|
||||
|
||||
for (MetaCoreId objectId : scene.BuildHierarchyPreorder()) {
|
||||
const MetaCoreGameObject gameObject = scene.FindGameObject(objectId);
|
||||
if (!gameObject) {
|
||||
continue;
|
||||
}
|
||||
|
||||
glm::mat4 localMatrix{1.0F};
|
||||
if (gameObject.HasComponent<MetaCoreTransformComponent>()) {
|
||||
localMatrix = MetaCoreBuildTransformMatrix(gameObject.GetComponent<MetaCoreTransformComponent>());
|
||||
}
|
||||
|
||||
glm::mat4 worldMatrix = localMatrix;
|
||||
const MetaCoreId parentId = gameObject.GetParentId();
|
||||
if (parentId != 0) {
|
||||
const auto parentWorldIt = snapshot.WorldMatrices.find(parentId);
|
||||
if (parentWorldIt != snapshot.WorldMatrices.end()) {
|
||||
worldMatrix = parentWorldIt->second * localMatrix;
|
||||
}
|
||||
}
|
||||
snapshot.WorldMatrices[objectId] = worldMatrix;
|
||||
|
||||
if (gameObject.HasComponent<MetaCoreMeshRendererComponent>()) {
|
||||
const auto& meshRenderer = gameObject.GetComponent<MetaCoreMeshRendererComponent>();
|
||||
snapshot.Renderables.push_back(MetaCoreRenderSyncRenderable{
|
||||
objectId,
|
||||
parentId,
|
||||
gameObject.GetName(),
|
||||
localMatrix,
|
||||
worldMatrix,
|
||||
meshRenderer.Visible,
|
||||
meshRenderer.MeshSource,
|
||||
meshRenderer.BuiltinMesh,
|
||||
meshRenderer.MeshAssetGuid,
|
||||
meshRenderer.SourceModelAssetGuid,
|
||||
meshRenderer.SourceModelPath,
|
||||
meshRenderer.ModelNodeIndex
|
||||
});
|
||||
}
|
||||
|
||||
if (gameObject.HasComponent<MetaCoreCameraComponent>()) {
|
||||
const auto& camera = gameObject.GetComponent<MetaCoreCameraComponent>();
|
||||
MetaCoreRenderSyncCamera syncCamera{
|
||||
objectId,
|
||||
camera.IsPrimary,
|
||||
camera.FieldOfViewDegrees,
|
||||
camera.NearClip,
|
||||
camera.FarClip,
|
||||
worldMatrix
|
||||
};
|
||||
snapshot.Cameras.push_back(syncCamera);
|
||||
if (syncCamera.IsPrimary && !snapshot.PrimaryCamera.has_value()) {
|
||||
snapshot.PrimaryCamera = syncCamera;
|
||||
}
|
||||
}
|
||||
|
||||
if (gameObject.HasComponent<MetaCoreLightComponent>()) {
|
||||
const auto& light = gameObject.GetComponent<MetaCoreLightComponent>();
|
||||
snapshot.Lights.push_back(MetaCoreRenderSyncLight{
|
||||
objectId,
|
||||
light.Color,
|
||||
light.Intensity,
|
||||
worldMatrix
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (!snapshot.PrimaryCamera.has_value() && !snapshot.Cameras.empty()) {
|
||||
snapshot.PrimaryCamera = snapshot.Cameras.front();
|
||||
}
|
||||
|
||||
return snapshot;
|
||||
}
|
||||
|
||||
bool MetaCoreSceneRenderSync::TryBuildSceneViewFromPrimaryCamera(
|
||||
const MetaCoreSceneRenderSyncSnapshot& snapshot,
|
||||
MetaCoreSceneView& sceneView
|
||||
) {
|
||||
if (!snapshot.PrimaryCamera.has_value()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const MetaCoreRenderSyncCamera& camera = *snapshot.PrimaryCamera;
|
||||
const glm::vec3 cameraPosition = MetaCoreExtractTranslation(camera.WorldMatrix);
|
||||
glm::vec3 cameraForward = glm::vec3(camera.WorldMatrix * glm::vec4(0.0F, 0.0F, -1.0F, 0.0F));
|
||||
glm::vec3 cameraUp = glm::vec3(camera.WorldMatrix * glm::vec4(0.0F, 1.0F, 0.0F, 0.0F));
|
||||
|
||||
if (!MetaCoreIsUsableDirection(cameraForward)) {
|
||||
cameraForward = glm::vec3(0.0F, 0.0F, -1.0F);
|
||||
}
|
||||
if (!MetaCoreIsUsableDirection(cameraUp)) {
|
||||
cameraUp = glm::vec3(0.0F, 1.0F, 0.0F);
|
||||
}
|
||||
|
||||
sceneView.CameraPosition = cameraPosition;
|
||||
sceneView.CameraTarget = cameraPosition + glm::normalize(cameraForward);
|
||||
sceneView.CameraUp = glm::normalize(cameraUp);
|
||||
sceneView.VerticalFieldOfViewDegrees = camera.FieldOfViewDegrees;
|
||||
sceneView.NearClip = camera.NearClip;
|
||||
sceneView.FarClip = camera.FarClip;
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace MetaCore
|
||||
@ -18,7 +18,7 @@ public:
|
||||
bool Initialize(MetaCoreRenderDevice& renderDevice, MetaCoreWindow& window);
|
||||
void Shutdown();
|
||||
void SetViewportRect(const MetaCoreViewportRect& viewportRect);
|
||||
void RenderSceneToViewport(MetaCoreScene& scene, const MetaCoreSceneView& sceneView);
|
||||
void RenderSceneToViewport(MetaCoreScene& scene, const MetaCoreSceneView& sceneView, bool useScenePrimaryCamera = false);
|
||||
void RenderAll();
|
||||
void SetProjectRootPath(const std::filesystem::path& projectRootPath);
|
||||
[[nodiscard]] uint32_t GetFilamentGLTextureId() const;
|
||||
|
||||
@ -26,7 +26,7 @@ public:
|
||||
void Shutdown();
|
||||
void Resize(int width, int height);
|
||||
void SetProjectRootPath(const std::filesystem::path& projectRootPath);
|
||||
void SyncScene(MetaCoreScene& scene, bool compatibilityMeshOnly = false);
|
||||
void SyncScene(MetaCoreScene& scene, bool compatibilityMeshOnly = false, bool useScenePrimaryCamera = false);
|
||||
void ApplySceneView(const MetaCoreSceneView& sceneView);
|
||||
void RenderAll();
|
||||
[[nodiscard]] uint32_t GetGLTextureId() const;
|
||||
|
||||
@ -18,6 +18,8 @@ struct MetaCoreSceneView {
|
||||
glm::vec3 CameraTarget{0.0F, 0.7F, 0.0F};
|
||||
glm::vec3 CameraUp{0.0F, 1.0F, 0.0F};
|
||||
float VerticalFieldOfViewDegrees = 60.0F;
|
||||
float NearClip = 0.1F;
|
||||
float FarClip = 1000.0F;
|
||||
MetaCoreId SelectedObjectId = 0;
|
||||
};
|
||||
|
||||
|
||||
@ -0,0 +1,68 @@
|
||||
#pragma once
|
||||
|
||||
#include "MetaCoreFoundation/MetaCoreAssetGuid.h"
|
||||
#include "MetaCoreFoundation/MetaCoreId.h"
|
||||
#include "MetaCoreScene/MetaCoreComponents.h"
|
||||
|
||||
#include <glm/mat4x4.hpp>
|
||||
#include <glm/vec3.hpp>
|
||||
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
namespace MetaCore {
|
||||
|
||||
class MetaCoreScene;
|
||||
struct MetaCoreSceneView;
|
||||
|
||||
struct MetaCoreRenderSyncRenderable {
|
||||
MetaCoreId ObjectId = 0;
|
||||
MetaCoreId ParentId = 0;
|
||||
std::string Name{};
|
||||
glm::mat4 LocalMatrix{1.0F};
|
||||
glm::mat4 WorldMatrix{1.0F};
|
||||
bool Visible = true;
|
||||
MetaCoreMeshSourceKind MeshSource = MetaCoreMeshSourceKind::Builtin;
|
||||
MetaCoreBuiltinMeshType BuiltinMesh = MetaCoreBuiltinMeshType::Cube;
|
||||
MetaCoreAssetGuid MeshAssetGuid{};
|
||||
MetaCoreAssetGuid SourceModelAssetGuid{};
|
||||
std::string SourceModelPath{};
|
||||
std::int32_t ModelNodeIndex = -1;
|
||||
};
|
||||
|
||||
struct MetaCoreRenderSyncCamera {
|
||||
MetaCoreId ObjectId = 0;
|
||||
bool IsPrimary = false;
|
||||
float FieldOfViewDegrees = 60.0F;
|
||||
float NearClip = 0.1F;
|
||||
float FarClip = 100.0F;
|
||||
glm::mat4 WorldMatrix{1.0F};
|
||||
};
|
||||
|
||||
struct MetaCoreRenderSyncLight {
|
||||
MetaCoreId ObjectId = 0;
|
||||
glm::vec3 Color{1.0F, 1.0F, 1.0F};
|
||||
float Intensity = 1.5F;
|
||||
glm::mat4 WorldMatrix{1.0F};
|
||||
};
|
||||
|
||||
struct MetaCoreSceneRenderSyncSnapshot {
|
||||
std::unordered_map<MetaCoreId, glm::mat4> WorldMatrices{};
|
||||
std::vector<MetaCoreRenderSyncRenderable> Renderables{};
|
||||
std::vector<MetaCoreRenderSyncCamera> Cameras{};
|
||||
std::vector<MetaCoreRenderSyncLight> Lights{};
|
||||
std::optional<MetaCoreRenderSyncCamera> PrimaryCamera{};
|
||||
};
|
||||
|
||||
class MetaCoreSceneRenderSync {
|
||||
public:
|
||||
[[nodiscard]] MetaCoreSceneRenderSyncSnapshot BuildSnapshot(const MetaCoreScene& scene) const;
|
||||
[[nodiscard]] static bool TryBuildSceneViewFromPrimaryCamera(
|
||||
const MetaCoreSceneRenderSyncSnapshot& snapshot,
|
||||
MetaCoreSceneView& sceneView
|
||||
);
|
||||
};
|
||||
|
||||
} // namespace MetaCore
|
||||
@ -9,12 +9,14 @@
|
||||
#include "MetaCorePlatform/MetaCoreWindow.h"
|
||||
#include "MetaCoreRender/MetaCoreEditorViewportRenderer.h"
|
||||
#include "MetaCoreRender/MetaCoreRenderDevice.h"
|
||||
#include "MetaCoreRender/MetaCoreSceneRenderSync.h"
|
||||
#include "MetaCoreRuntimeData/MetaCoreRuntimeDataDispatcher.h"
|
||||
#include "MetaCoreRuntimeData/MetaCoreRuntimeDataSource.h"
|
||||
#include "MetaCoreRuntimeData/MetaCoreRuntimeDataProject.h"
|
||||
#include "MetaCoreScene/MetaCoreScenePackage.h"
|
||||
#include "MetaCoreScene/MetaCoreScene.h"
|
||||
#include "MetaCoreScene/MetaCoreSceneSerializer.h"
|
||||
#include "MetaCoreScene/MetaCoreTransformUtils.h"
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cmath>
|
||||
@ -58,6 +60,21 @@ void MetaCoreExpectVec3Near(const glm::vec3& actual, const glm::vec3& expected,
|
||||
}
|
||||
}
|
||||
|
||||
void MetaCoreExpectMat4Near(const glm::mat4& actual, const glm::mat4& expected, const char* message) {
|
||||
for (int column = 0; column < 4; ++column) {
|
||||
for (int row = 0; row < 4; ++row) {
|
||||
if (std::abs(actual[column][row] - expected[column][row]) > 0.0001F) {
|
||||
std::cerr << "MetaCoreSmokeTests failed: " << message
|
||||
<< " (column=" << column
|
||||
<< " row=" << row
|
||||
<< " actual=" << actual[column][row]
|
||||
<< " expected=" << expected[column][row] << ")\n";
|
||||
std::exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class MetaCoreDummyPanelProvider final : public MetaCore::MetaCoreIEditorPanelProvider {
|
||||
public:
|
||||
std::string GetPanelId() const override { return "Dummy"; }
|
||||
@ -477,6 +494,61 @@ void MetaCoreTestComponentRegistryDescriptors() {
|
||||
moduleRegistry.ShutdownServices();
|
||||
}
|
||||
|
||||
void MetaCoreTestSceneRenderSyncBuildsRenderableCameraLightSnapshot() {
|
||||
MetaCore::MetaCoreScene scene;
|
||||
|
||||
MetaCore::MetaCoreGameObject root = scene.CreateGameObject("RenderRoot");
|
||||
root.GetComponent<MetaCore::MetaCoreTransformComponent>().Position = glm::vec3(1.0F, 2.0F, 3.0F);
|
||||
auto& rootMesh = root.AddComponent<MetaCore::MetaCoreMeshRendererComponent>();
|
||||
rootMesh.MeshSource = MetaCore::MetaCoreMeshSourceKind::Asset;
|
||||
rootMesh.SourceModelPath = "Assets/Models/SyncRoot.glb";
|
||||
|
||||
MetaCore::MetaCoreGameObject child = scene.CreateGameObject("RenderChild", root.GetId());
|
||||
child.GetComponent<MetaCore::MetaCoreTransformComponent>().Position = glm::vec3(4.0F, 5.0F, 6.0F);
|
||||
auto& childMesh = child.AddComponent<MetaCore::MetaCoreMeshRendererComponent>();
|
||||
childMesh.MeshSource = MetaCore::MetaCoreMeshSourceKind::Builtin;
|
||||
childMesh.Visible = false;
|
||||
|
||||
MetaCore::MetaCoreGameObject cameraObject = scene.CreateGameObject("PrimaryCamera");
|
||||
auto& camera = cameraObject.AddComponent<MetaCore::MetaCoreCameraComponent>();
|
||||
camera.IsPrimary = true;
|
||||
camera.FieldOfViewDegrees = 75.0F;
|
||||
camera.NearClip = 0.25F;
|
||||
camera.FarClip = 250.0F;
|
||||
cameraObject.GetComponent<MetaCore::MetaCoreTransformComponent>().Position = glm::vec3(0.0F, 1.0F, 9.0F);
|
||||
|
||||
MetaCore::MetaCoreGameObject lightObject = scene.CreateGameObject("KeyLight");
|
||||
auto& light = lightObject.AddComponent<MetaCore::MetaCoreLightComponent>();
|
||||
light.Color = glm::vec3(0.25F, 0.5F, 1.0F);
|
||||
light.Intensity = 3.0F;
|
||||
|
||||
const MetaCore::MetaCoreSceneRenderSync renderSync;
|
||||
const MetaCore::MetaCoreSceneRenderSyncSnapshot snapshot = renderSync.BuildSnapshot(scene);
|
||||
|
||||
MetaCoreExpect(snapshot.Renderables.size() == 2, "RenderSync 应收集 MeshRenderer 对象");
|
||||
MetaCoreExpect(snapshot.Cameras.size() == 1, "RenderSync 应收集 Camera 对象");
|
||||
MetaCoreExpect(snapshot.Lights.size() == 1, "RenderSync 应收集 Light 对象");
|
||||
MetaCoreExpect(snapshot.PrimaryCamera.has_value(), "RenderSync 应识别主相机");
|
||||
MetaCoreExpect(snapshot.PrimaryCamera->ObjectId == cameraObject.GetId(), "RenderSync 主相机 ID 应正确");
|
||||
|
||||
const glm::mat4 expectedRootWorld =
|
||||
MetaCore::MetaCoreBuildTransformMatrix(root.GetComponent<MetaCore::MetaCoreTransformComponent>());
|
||||
const glm::mat4 expectedChildWorld =
|
||||
expectedRootWorld * MetaCore::MetaCoreBuildTransformMatrix(child.GetComponent<MetaCore::MetaCoreTransformComponent>());
|
||||
MetaCoreExpectMat4Near(snapshot.WorldMatrices.at(root.GetId()), expectedRootWorld, "RenderSync 根对象 world matrix 应正确");
|
||||
MetaCoreExpectMat4Near(snapshot.WorldMatrices.at(child.GetId()), expectedChildWorld, "RenderSync 子对象 world matrix 应合成父级");
|
||||
|
||||
MetaCore::MetaCoreSceneView primarySceneView;
|
||||
MetaCoreExpect(
|
||||
MetaCore::MetaCoreSceneRenderSync::TryBuildSceneViewFromPrimaryCamera(snapshot, primarySceneView),
|
||||
"RenderSync 应能从主相机构建 SceneView"
|
||||
);
|
||||
MetaCoreExpectVec3Near(primarySceneView.CameraPosition, glm::vec3(0.0F, 1.0F, 9.0F), "主相机 SceneView 位置应来自 Transform");
|
||||
MetaCoreExpect(std::abs(primarySceneView.VerticalFieldOfViewDegrees - 75.0F) <= 0.0001F, "主相机 FOV 应同步");
|
||||
MetaCoreExpect(std::abs(primarySceneView.NearClip - 0.25F) <= 0.0001F, "主相机 NearClip 应同步");
|
||||
MetaCoreExpect(std::abs(primarySceneView.FarClip - 250.0F) <= 0.0001F, "主相机 FarClip 应同步");
|
||||
}
|
||||
|
||||
void MetaCoreTestJsonSceneSaveCurrentSceneUsesMcsceneJson() {
|
||||
const std::filesystem::path tempProjectRoot =
|
||||
std::filesystem::temp_directory_path() / "MetaCoreSceneRoundTripProject";
|
||||
@ -2404,6 +2476,8 @@ int main() {
|
||||
MetaCoreTestAssetDatabaseMovePathUpdatesProjectDescriptor();
|
||||
std::cout << "[RUN] MetaCoreTestComponentRegistryDescriptors..." << std::endl;
|
||||
MetaCoreTestComponentRegistryDescriptors();
|
||||
std::cout << "[RUN] MetaCoreTestSceneRenderSyncBuildsRenderableCameraLightSnapshot..." << std::endl;
|
||||
MetaCoreTestSceneRenderSyncBuildsRenderableCameraLightSnapshot();
|
||||
std::cout << "[RUN] MetaCoreTestJsonSceneSaveCurrentSceneUsesMcsceneJson..." << std::endl;
|
||||
MetaCoreTestJsonSceneSaveCurrentSceneUsesMcsceneJson();
|
||||
std::cout << "[RUN] MetaCoreTestImportPipelineAndCook..." << std::endl;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user