#include "MetaCoreRender/MetaCoreSceneRenderSync.h" #include "MetaCoreRender/MetaCoreRenderTypes.h" #include "MetaCoreScene/MetaCoreScene.h" #include "MetaCoreScene/MetaCoreTransformUtils.h" #include #include 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()) { localMatrix = MetaCoreBuildTransformMatrix(gameObject.GetComponent()); } 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()) { const auto& meshRenderer = gameObject.GetComponent(); 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()) { const auto& camera = gameObject.GetComponent(); 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()) { const auto& light = gameObject.GetComponent(); 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