#include "Rendering/RenderSceneExtractor.h" #include "Components/CameraComponent.h" #include "Components/GameObject.h" #include "Components/MeshFilterComponent.h" #include "Components/MeshRendererComponent.h" #include "Components/TransformComponent.h" #include "Scene/Scene.h" namespace XCEngine { namespace Rendering { namespace { bool IsUsableCamera(const Components::CameraComponent* camera) { return camera != nullptr && camera->IsEnabled() && camera->GetGameObject() != nullptr && camera->GetGameObject()->IsActiveInHierarchy(); } } // namespace RenderSceneData RenderSceneExtractor::Extract( const Components::Scene& scene, Components::CameraComponent* overrideCamera, uint32_t viewportWidth, uint32_t viewportHeight) const { RenderSceneData sceneData; sceneData.camera = SelectCamera(scene, overrideCamera); if (sceneData.camera == nullptr) { return sceneData; } sceneData.cameraData = BuildCameraData(*sceneData.camera, viewportWidth, viewportHeight); const std::vector rootGameObjects = scene.GetRootGameObjects(); for (Components::GameObject* rootGameObject : rootGameObjects) { ExtractVisibleObjects(rootGameObject, sceneData.visibleObjects); } return sceneData; } Components::CameraComponent* RenderSceneExtractor::SelectCamera( const Components::Scene& scene, Components::CameraComponent* overrideCamera) const { if (IsUsableCamera(overrideCamera)) { return overrideCamera; } const std::vector cameras = scene.FindObjectsOfType(); Components::CameraComponent* primaryCamera = nullptr; for (Components::CameraComponent* camera : cameras) { if (!IsUsableCamera(camera)) { continue; } if (camera->IsPrimary()) { if (primaryCamera == nullptr || camera->GetDepth() > primaryCamera->GetDepth()) { primaryCamera = camera; } } } if (primaryCamera != nullptr) { return primaryCamera; } for (Components::CameraComponent* camera : cameras) { if (IsUsableCamera(camera)) { return camera; } } return nullptr; } RenderCameraData RenderSceneExtractor::BuildCameraData( const Components::CameraComponent& camera, uint32_t viewportWidth, uint32_t viewportHeight) const { RenderCameraData cameraData; cameraData.viewportWidth = viewportWidth; cameraData.viewportHeight = viewportHeight; cameraData.worldPosition = camera.transform().GetPosition(); cameraData.clearColor = camera.GetClearColor(); const Math::Matrix4x4 view = camera.transform().GetWorldToLocalMatrix(); const float aspect = viewportHeight > 0 ? static_cast(viewportWidth) / static_cast(viewportHeight) : 1.0f; Math::Matrix4x4 projection = Math::Matrix4x4::Identity(); if (camera.GetProjectionType() == Components::CameraProjectionType::Perspective) { projection = Math::Matrix4x4::Perspective( camera.GetFieldOfView() * Math::DEG_TO_RAD, aspect, camera.GetNearClipPlane(), camera.GetFarClipPlane()); } else { const float orthoSize = camera.GetOrthographicSize(); projection = Math::Matrix4x4::Orthographic( -orthoSize * aspect, orthoSize * aspect, -orthoSize, orthoSize, camera.GetNearClipPlane(), camera.GetFarClipPlane()); } cameraData.view = view.Transpose(); cameraData.projection = projection.Transpose(); cameraData.viewProjection = (projection * view).Transpose(); return cameraData; } void RenderSceneExtractor::ExtractVisibleObjects( Components::GameObject* gameObject, std::vector& visibleObjects) const { if (gameObject == nullptr || !gameObject->IsActiveInHierarchy()) { return; } auto* meshFilter = gameObject->GetComponent(); auto* meshRenderer = gameObject->GetComponent(); if (meshFilter != nullptr && meshRenderer != nullptr && meshFilter->IsEnabled() && meshRenderer->IsEnabled()) { Resources::Mesh* mesh = meshFilter->GetMesh(); if (mesh != nullptr && mesh->IsValid()) { VisibleRenderObject visibleObject; visibleObject.gameObject = gameObject; visibleObject.meshFilter = meshFilter; visibleObject.meshRenderer = meshRenderer; visibleObject.mesh = mesh; visibleObject.localToWorld = gameObject->GetTransform()->GetLocalToWorldMatrix(); visibleObjects.push_back(visibleObject); } } for (Components::GameObject* child : gameObject->GetChildren()) { ExtractVisibleObjects(child, visibleObjects); } } } // namespace Rendering } // namespace XCEngine