MetaCore/Source/MetaCoreRender/Private/MetaCoreSceneRenderSync.cpp

134 lines
4.6 KiB
C++

#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