#include "Rendering/CameraRenderer.h" #include "Rendering/Passes/BuiltinDepthOnlyPass.h" #include "Rendering/Passes/BuiltinObjectIdPass.h" #include "Rendering/Passes/BuiltinShadowCasterPass.h" #include "Rendering/Pipelines/BuiltinForwardPipeline.h" #include "Rendering/RenderPipelineAsset.h" #include "Rendering/RenderSurface.h" #include "RHI/RHIDevice.h" #include "RHI/RHIResourceView.h" #include "RHI/RHITexture.h" #include "Scene/Scene.h" namespace XCEngine { namespace Rendering { struct CameraRenderer::DirectionalShadowSurfaceResources { RHI::RHIDevice* device = nullptr; uint32_t width = 0; uint32_t height = 0; RHI::RHITexture* depthTexture = nullptr; RHI::RHIResourceView* depthView = nullptr; RHI::RHIResourceView* depthShaderView = nullptr; RenderSurface surface = {}; DirectionalShadowSurfaceResources() = default; DirectionalShadowSurfaceResources(const DirectionalShadowSurfaceResources&) = delete; DirectionalShadowSurfaceResources& operator=(const DirectionalShadowSurfaceResources&) = delete; ~DirectionalShadowSurfaceResources() { Reset(); } bool Matches(const RenderContext& context, const DirectionalShadowRenderPlan& plan) const { return device == context.device && width == plan.mapWidth && height == plan.mapHeight && depthTexture != nullptr && depthView != nullptr && depthShaderView != nullptr; } void Reset() { if (depthView != nullptr) { depthView->Shutdown(); delete depthView; depthView = nullptr; } if (depthShaderView != nullptr) { depthShaderView->Shutdown(); delete depthShaderView; depthShaderView = nullptr; } if (depthTexture != nullptr) { depthTexture->Shutdown(); delete depthTexture; depthTexture = nullptr; } device = nullptr; width = 0; height = 0; surface = RenderSurface(); } }; namespace { constexpr RHI::Format kDirectionalShadowMapFormat = RHI::Format::D32_Float; bool InitializePassSequence( RenderPassSequence* sequence, const RenderContext& context, bool& initialized) { if (sequence == nullptr) { initialized = false; return true; } initialized = sequence->Initialize(context); if (!initialized) { sequence->Shutdown(); } return initialized; } void ShutdownPassSequence(RenderPassSequence* sequence, bool initialized) { if (sequence != nullptr && initialized) { sequence->Shutdown(); } } std::shared_ptr CreateDefaultPipelineAsset() { static const std::shared_ptr s_defaultPipelineAsset = std::make_shared(); return s_defaultPipelineAsset; } std::unique_ptr CreateDefaultDepthOnlyPass() { return std::make_unique(); } std::unique_ptr CreateDefaultShadowCasterPass() { return std::make_unique(); } std::unique_ptr CreatePipelineFromAsset( const std::shared_ptr& pipelineAsset) { if (pipelineAsset != nullptr) { std::unique_ptr pipeline = pipelineAsset->CreatePipeline(); if (pipeline != nullptr) { return pipeline; } } return std::make_unique(); } bool InitializeStandalonePass( RenderPass* pass, const RenderContext& context) { if (pass == nullptr) { return false; } if (pass->Initialize(context)) { return true; } pass->Shutdown(); return false; } bool ExecuteScenePassRequest( RenderPass* pass, const ScenePassRenderRequest& request, const RenderContext& context, const RenderSceneData& baseSceneData) { if (!request.IsRequested()) { return true; } if (!InitializeStandalonePass(pass, context)) { return false; } RenderSceneData sceneData = baseSceneData; if (request.hasCameraDataOverride) { sceneData.cameraData = request.cameraDataOverride; } sceneData.cameraData.viewportWidth = request.surface.GetRenderAreaWidth(); sceneData.cameraData.viewportHeight = request.surface.GetRenderAreaHeight(); sceneData.cameraData.clearFlags = request.clearFlags; if (request.hasClearColorOverride) { sceneData.cameraData.clearColor = request.clearColorOverride; } const RenderPassContext passContext = { context, request.surface, sceneData }; return pass->Execute(passContext); } RenderDirectionalShadowData BuildDirectionalShadowData( const DirectionalShadowRenderPlan& plan, RHI::RHIResourceView* shadowMapView) { RenderDirectionalShadowData shadowData = {}; if (!plan.IsValid() || shadowMapView == nullptr) { return shadowData; } shadowData.enabled = true; shadowData.viewProjection = plan.cameraData.viewProjection; shadowData.shadowMap = shadowMapView; shadowData.shadowParams = Math::Vector4( 0.0015f, 1.0f / static_cast(plan.mapWidth), 1.0f / static_cast(plan.mapHeight), 0.85f); return shadowData; } } // namespace CameraRenderer::CameraRenderer() : CameraRenderer(CreateDefaultPipelineAsset()) { } CameraRenderer::CameraRenderer(std::unique_ptr pipeline) : CameraRenderer( std::move(pipeline), std::make_unique(), CreateDefaultDepthOnlyPass(), CreateDefaultShadowCasterPass()) { } CameraRenderer::CameraRenderer( std::unique_ptr pipeline, std::unique_ptr objectIdPass, std::unique_ptr depthOnlyPass, std::unique_ptr shadowCasterPass) : m_pipelineAsset(nullptr) , m_objectIdPass(std::move(objectIdPass)) , m_depthOnlyPass(std::move(depthOnlyPass)) , m_shadowCasterPass(std::move(shadowCasterPass)) { if (m_objectIdPass == nullptr) { m_objectIdPass = std::make_unique(); } if (m_depthOnlyPass == nullptr) { m_depthOnlyPass = CreateDefaultDepthOnlyPass(); } if (m_shadowCasterPass == nullptr) { m_shadowCasterPass = CreateDefaultShadowCasterPass(); } ResetPipeline(std::move(pipeline)); } CameraRenderer::CameraRenderer(std::shared_ptr pipelineAsset) : m_pipelineAsset(std::move(pipelineAsset)) , m_objectIdPass(std::make_unique()) , m_depthOnlyPass(CreateDefaultDepthOnlyPass()) , m_shadowCasterPass(CreateDefaultShadowCasterPass()) { SetPipelineAsset(m_pipelineAsset); } CameraRenderer::~CameraRenderer() { if (m_pipeline) { m_pipeline->Shutdown(); } if (m_objectIdPass != nullptr) { m_objectIdPass->Shutdown(); } if (m_depthOnlyPass != nullptr) { m_depthOnlyPass->Shutdown(); } if (m_shadowCasterPass != nullptr) { m_shadowCasterPass->Shutdown(); } } void CameraRenderer::SetPipeline(std::unique_ptr pipeline) { m_pipelineAsset.reset(); ResetPipeline(std::move(pipeline)); } void CameraRenderer::SetPipelineAsset(std::shared_ptr pipelineAsset) { m_pipelineAsset = pipelineAsset != nullptr ? std::move(pipelineAsset) : CreateDefaultPipelineAsset(); ResetPipeline(CreatePipelineFromAsset(m_pipelineAsset)); } void CameraRenderer::SetObjectIdPass(std::unique_ptr objectIdPass) { if (m_objectIdPass != nullptr) { m_objectIdPass->Shutdown(); } m_objectIdPass = std::move(objectIdPass); if (m_objectIdPass == nullptr) { m_objectIdPass = std::make_unique(); } } void CameraRenderer::SetDepthOnlyPass(std::unique_ptr depthOnlyPass) { if (m_depthOnlyPass != nullptr) { m_depthOnlyPass->Shutdown(); } m_depthOnlyPass = std::move(depthOnlyPass); if (m_depthOnlyPass == nullptr) { m_depthOnlyPass = CreateDefaultDepthOnlyPass(); } } void CameraRenderer::SetShadowCasterPass(std::unique_ptr shadowCasterPass) { if (m_shadowCasterPass != nullptr) { m_shadowCasterPass->Shutdown(); } m_shadowCasterPass = std::move(shadowCasterPass); if (m_shadowCasterPass == nullptr) { m_shadowCasterPass = CreateDefaultShadowCasterPass(); } } void CameraRenderer::ResetPipeline(std::unique_ptr pipeline) { if (m_pipeline != nullptr) { m_pipeline->Shutdown(); } m_pipeline = std::move(pipeline); if (m_pipeline == nullptr) { m_pipelineAsset = CreateDefaultPipelineAsset(); m_pipeline = CreatePipelineFromAsset(m_pipelineAsset); } } CameraRenderer::DirectionalShadowSurfaceResources* CameraRenderer::AcquireDirectionalShadowSurface( const RenderContext& context, const DirectionalShadowRenderPlan& plan) { if (!context.IsValid() || !plan.IsValid()) { return nullptr; } if (m_directionalShadowSurface == nullptr) { m_directionalShadowSurface = std::make_unique(); } if (!m_directionalShadowSurface->Matches(context, plan)) { RHI::TextureDesc depthDesc = {}; depthDesc.width = plan.mapWidth; depthDesc.height = plan.mapHeight; depthDesc.depth = 1; depthDesc.mipLevels = 1; depthDesc.arraySize = 1; depthDesc.format = static_cast(kDirectionalShadowMapFormat); depthDesc.textureType = static_cast(RHI::TextureType::Texture2D); depthDesc.sampleCount = 1; depthDesc.sampleQuality = 0; depthDesc.flags = 0; RHI::RHITexture* depthTexture = context.device->CreateTexture(depthDesc); if (depthTexture == nullptr) { return nullptr; } RHI::ResourceViewDesc depthViewDesc = {}; depthViewDesc.format = static_cast(kDirectionalShadowMapFormat); depthViewDesc.dimension = RHI::ResourceViewDimension::Texture2D; depthViewDesc.mipLevel = 0; RHI::RHIResourceView* depthView = context.device->CreateDepthStencilView(depthTexture, depthViewDesc); if (depthView == nullptr) { depthTexture->Shutdown(); delete depthTexture; return nullptr; } RHI::ResourceViewDesc depthShaderViewDesc = {}; depthShaderViewDesc.dimension = RHI::ResourceViewDimension::Texture2D; depthShaderViewDesc.mipLevel = 0; RHI::RHIResourceView* depthShaderView = context.device->CreateShaderResourceView(depthTexture, depthShaderViewDesc); if (depthShaderView == nullptr) { depthView->Shutdown(); delete depthView; depthTexture->Shutdown(); delete depthTexture; return nullptr; } m_directionalShadowSurface->Reset(); m_directionalShadowSurface->device = context.device; m_directionalShadowSurface->width = plan.mapWidth; m_directionalShadowSurface->height = plan.mapHeight; m_directionalShadowSurface->depthTexture = depthTexture; m_directionalShadowSurface->depthView = depthView; m_directionalShadowSurface->depthShaderView = depthShaderView; m_directionalShadowSurface->surface = RenderSurface(plan.mapWidth, plan.mapHeight); m_directionalShadowSurface->surface.SetDepthAttachment(depthView); } return m_directionalShadowSurface.get(); } bool CameraRenderer::Render( const CameraRenderRequest& request) { if (!request.IsValid() || m_pipeline == nullptr) { return false; } if (request.surface.GetRenderAreaWidth() == 0 || request.surface.GetRenderAreaHeight() == 0) { return false; } if (request.depthOnly.IsRequested() && !request.depthOnly.IsValid()) { return false; } if (request.objectId.IsRequested() && !request.objectId.IsValid()) { return false; } ShadowCasterRenderRequest resolvedShadowCaster = request.shadowCaster; DirectionalShadowSurfaceResources* directionalShadowSurface = nullptr; if (resolvedShadowCaster.IsRequested()) { if (!resolvedShadowCaster.IsValid()) { return false; } } else if (request.directionalShadow.IsValid()) { directionalShadowSurface = AcquireDirectionalShadowSurface( request.context, request.directionalShadow); if (directionalShadowSurface == nullptr) { return false; } resolvedShadowCaster.surface = directionalShadowSurface->surface; resolvedShadowCaster.clearFlags = RenderClearFlags::Depth; if (!resolvedShadowCaster.hasCameraDataOverride) { resolvedShadowCaster.hasCameraDataOverride = true; resolvedShadowCaster.cameraDataOverride = request.directionalShadow.cameraData; } } RenderSceneData sceneData = m_sceneExtractor.ExtractForCamera( *request.scene, *request.camera, request.surface.GetRenderAreaWidth(), request.surface.GetRenderAreaHeight()); if (!sceneData.HasCamera()) { return false; } if (request.directionalShadow.IsValid()) { RHI::RHIResourceView* shadowMapView = directionalShadowSurface != nullptr ? directionalShadowSurface->depthShaderView : nullptr; sceneData.lighting.mainDirectionalShadow = BuildDirectionalShadowData(request.directionalShadow, shadowMapView); } sceneData.cameraData.clearFlags = request.clearFlags; if (request.hasClearColorOverride) { sceneData.cameraData.clearColor = request.clearColorOverride; } const RenderPassContext passContext = { request.context, request.surface, sceneData }; bool preScenePassesInitialized = false; if (!InitializePassSequence( request.preScenePasses, request.context, preScenePassesInitialized)) { return false; } if (request.preScenePasses != nullptr && !request.preScenePasses->Execute(passContext)) { ShutdownPassSequence(request.preScenePasses, preScenePassesInitialized); return false; } if (!ExecuteScenePassRequest( m_shadowCasterPass.get(), resolvedShadowCaster, request.context, sceneData)) { ShutdownPassSequence(request.preScenePasses, preScenePassesInitialized); return false; } if (!ExecuteScenePassRequest( m_depthOnlyPass.get(), request.depthOnly, request.context, sceneData)) { ShutdownPassSequence(request.preScenePasses, preScenePassesInitialized); return false; } if (!m_pipeline->Render(request.context, request.surface, sceneData)) { ShutdownPassSequence(request.preScenePasses, preScenePassesInitialized); return false; } if (request.objectId.IsRequested() && (m_objectIdPass == nullptr || !m_objectIdPass->Render(request.context, request.objectId.surface, sceneData))) { ShutdownPassSequence(request.preScenePasses, preScenePassesInitialized); return false; } bool postScenePassesInitialized = false; if (!InitializePassSequence( request.postScenePasses, request.context, postScenePassesInitialized)) { ShutdownPassSequence(request.preScenePasses, preScenePassesInitialized); return false; } if (request.postScenePasses != nullptr && !request.postScenePasses->Execute(passContext)) { ShutdownPassSequence(request.postScenePasses, postScenePassesInitialized); ShutdownPassSequence(request.preScenePasses, preScenePassesInitialized); return false; } bool overlayPassesInitialized = false; if (!InitializePassSequence( request.overlayPasses, request.context, overlayPassesInitialized)) { ShutdownPassSequence(request.postScenePasses, postScenePassesInitialized); ShutdownPassSequence(request.preScenePasses, preScenePassesInitialized); return false; } if (request.overlayPasses != nullptr && !request.overlayPasses->Execute(passContext)) { ShutdownPassSequence(request.overlayPasses, overlayPassesInitialized); ShutdownPassSequence(request.postScenePasses, postScenePassesInitialized); ShutdownPassSequence(request.preScenePasses, preScenePassesInitialized); return false; } ShutdownPassSequence(request.overlayPasses, overlayPassesInitialized); ShutdownPassSequence(request.postScenePasses, postScenePassesInitialized); ShutdownPassSequence(request.preScenePasses, preScenePassesInitialized); return true; } } // namespace Rendering } // namespace XCEngine