#include "Rendering/RenderSceneExtractor.h" #include "Components/CameraComponent.h" #include "Components/GameObject.h" #include "Components/LightComponent.h" #include "Rendering/RenderMaterialUtility.h" #include "Rendering/RenderSceneUtility.h" #include "Scene/Scene.h" #include namespace XCEngine { namespace Rendering { namespace { bool IsUsableCamera(const Components::CameraComponent* camera) { return camera != nullptr && camera->IsEnabled() && camera->GetGameObject() != nullptr && camera->GetGameObject()->IsActiveInHierarchy(); } bool IsUsableLight(const Components::LightComponent* light) { return light != nullptr && light->IsEnabled() && light->GetGameObject() != nullptr && light->GetGameObject()->IsActiveInHierarchy(); } bool CompareVisibleItems(const VisibleRenderItem& lhs, const VisibleRenderItem& rhs) { if (lhs.renderQueue != rhs.renderQueue) { return lhs.renderQueue < rhs.renderQueue; } const bool isTransparentQueue = IsTransparentRenderQueue(lhs.renderQueue); if (lhs.cameraDistanceSq != rhs.cameraDistanceSq) { return isTransparentQueue ? lhs.cameraDistanceSq > rhs.cameraDistanceSq : lhs.cameraDistanceSq < rhs.cameraDistanceSq; } if (lhs.gameObject != rhs.gameObject) { return lhs.gameObject < rhs.gameObject; } return lhs.sectionIndex < rhs.sectionIndex; } } // 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 = BuildRenderCameraData(*sceneData.camera, viewportWidth, viewportHeight); const Math::Vector3 cameraPosition = sceneData.cameraData.worldPosition; const uint32_t cullingMask = sceneData.camera->GetCullingMask(); const std::vector rootGameObjects = scene.GetRootGameObjects(); for (Components::GameObject* rootGameObject : rootGameObjects) { ExtractVisibleItems(rootGameObject, cameraPosition, cullingMask, sceneData.visibleItems); } std::stable_sort( sceneData.visibleItems.begin(), sceneData.visibleItems.end(), CompareVisibleItems); ExtractLighting(scene, sceneData.lighting); return sceneData; } RenderSceneData RenderSceneExtractor::ExtractForCamera( const Components::Scene& scene, Components::CameraComponent& camera, uint32_t viewportWidth, uint32_t viewportHeight) const { RenderSceneData sceneData; if (!IsUsableCamera(&camera)) { return sceneData; } sceneData.camera = &camera; sceneData.cameraData = BuildRenderCameraData(camera, viewportWidth, viewportHeight); const Math::Vector3 cameraPosition = sceneData.cameraData.worldPosition; const uint32_t cullingMask = camera.GetCullingMask(); const std::vector rootGameObjects = scene.GetRootGameObjects(); for (Components::GameObject* rootGameObject : rootGameObjects) { ExtractVisibleItems(rootGameObject, cameraPosition, cullingMask, sceneData.visibleItems); } std::stable_sort( sceneData.visibleItems.begin(), sceneData.visibleItems.end(), CompareVisibleItems); ExtractLighting(scene, sceneData.lighting); 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; } void RenderSceneExtractor::ExtractLighting( const Components::Scene& scene, RenderLightingData& lightingData) const { const std::vector lights = scene.FindObjectsOfType(); Components::LightComponent* mainDirectionalLight = nullptr; for (Components::LightComponent* light : lights) { if (!IsUsableLight(light) || light->GetLightType() != Components::LightType::Directional) { continue; } if (mainDirectionalLight == nullptr || light->GetIntensity() > mainDirectionalLight->GetIntensity()) { mainDirectionalLight = light; } } if (mainDirectionalLight == nullptr) { lightingData = {}; return; } RenderDirectionalLightData lightData; lightData.enabled = true; lightData.castsShadows = mainDirectionalLight->GetCastsShadows(); lightData.intensity = mainDirectionalLight->GetIntensity(); lightData.color = mainDirectionalLight->GetColor(); Math::Vector3 direction = mainDirectionalLight->transform().GetForward() * -1.0f; if (direction.SqrMagnitude() <= Math::EPSILON) { direction = Math::Vector3::Back(); } else { direction = direction.Normalized(); } lightData.direction = direction; lightingData.mainDirectionalLight = lightData; } void RenderSceneExtractor::ExtractVisibleItems( Components::GameObject* gameObject, const Math::Vector3& cameraPosition, uint32_t cullingMask, std::vector& visibleItems) const { if (gameObject == nullptr || !gameObject->IsActiveInHierarchy()) { return; } const uint32_t gameObjectLayerMask = 1u << gameObject->GetLayer(); const bool isVisibleInCameraMask = (cullingMask & gameObjectLayerMask) != 0; if (isVisibleInCameraMask) { AppendRenderItemsForGameObject(*gameObject, cameraPosition, visibleItems); } for (Components::GameObject* child : gameObject->GetChildren()) { ExtractVisibleItems(child, cameraPosition, cullingMask, visibleItems); } } } // namespace Rendering } // namespace XCEngine