diff --git a/neo/renderer/Framebuffer.h b/neo/renderer/Framebuffer.h index 886eff6c..5d27e82a 100644 --- a/neo/renderer/Framebuffer.h +++ b/neo/renderer/Framebuffer.h @@ -39,6 +39,7 @@ static const int MAX_HIERARCHICAL_ZBUFFERS = 6; // native resolution + 5 MIP LEV static const int ENVPROBE_CAPTURE_SIZE = 256; static const int RADIANCE_OCTAHEDRON_SIZE = 512; static const int IRRADIANCE_OCTAHEDRON_SIZE = 30 + 2; +static const int SHADOW_ATLAS_SIZE = 8192; #if 1 static int shadowMapResolutions[MAX_SHADOWMAP_RESOLUTIONS] = { 2048, 1024, 512, 512, 256 }; @@ -139,6 +140,7 @@ private: struct globalFramebuffers_t { idList swapFramebuffers; + Framebuffer* shadowAtlasFBO; Framebuffer* shadowFBO[MAX_SHADOWMAP_RESOLUTIONS][6]; Framebuffer* hdrFBO; Framebuffer* ldrFBO; diff --git a/neo/renderer/Image.h b/neo/renderer/Image.h index 040727de..c9390e46 100644 --- a/neo/renderer/Image.h +++ b/neo/renderer/Image.h @@ -666,6 +666,7 @@ public: idImage* fogImage; // increasing alpha is denser fog idImage* fogEnterImage; // adjust fogImage alpha based on terminator plane // RB begin + idImage* shadowAtlasImage; // 8192 * 8192 for clustered forward shading idImage* shadowImage[5]; idImage* jitterImage1; // shadow jitter idImage* jitterImage4; diff --git a/neo/renderer/Image_intrinsic.cpp b/neo/renderer/Image_intrinsic.cpp index cfd55ba3..40b402fd 100644 --- a/neo/renderer/Image_intrinsic.cpp +++ b/neo/renderer/Image_intrinsic.cpp @@ -623,6 +623,11 @@ void R_QuadraticImage( idImage* image, nvrhi::ICommandList* commandList ) } // RB begin +static void R_CreateShadowMapImage_Atlas( idImage* image, nvrhi::ICommandList* commandList ) +{ + image->GenerateShadowArray( SHADOW_ATLAS_SIZE, SHADOW_ATLAS_SIZE, TF_LINEAR, TR_CLAMP_TO_ZERO_ALPHA, TD_DEPTH, commandList ); +} + static void R_CreateShadowMapImage_Res0( idImage* image, nvrhi::ICommandList* commandList ) { int size = shadowMapResolutions[0]; @@ -1005,6 +1010,7 @@ void idImageManager::CreateIntrinsicImages() ImageFromFunction( "_quadratic", R_QuadraticImage ); // RB begin + shadowAtlasImage = ImageFromFunction( "_shadowMapAtlas", R_CreateShadowMapImage_Atlas ); shadowImage[0] = ImageFromFunction( va( "_shadowMapArray0_%i", shadowMapResolutions[0] ), R_CreateShadowMapImage_Res0 ); shadowImage[1] = ImageFromFunction( va( "_shadowMapArray1_%i", shadowMapResolutions[1] ), R_CreateShadowMapImage_Res1 ); shadowImage[2] = ImageFromFunction( va( "_shadowMapArray2_%i", shadowMapResolutions[2] ), R_CreateShadowMapImage_Res2 ); diff --git a/neo/renderer/NVRHI/Framebuffer_NVRHI.cpp b/neo/renderer/NVRHI/Framebuffer_NVRHI.cpp index caffe8cc..d13305b9 100644 --- a/neo/renderer/NVRHI/Framebuffer_NVRHI.cpp +++ b/neo/renderer/NVRHI/Framebuffer_NVRHI.cpp @@ -120,6 +120,7 @@ void Framebuffer::ResizeFramebuffers() globalImages->currentNormalsImage->Reload( false, tr.backend.commandList ); globalImages->smaaEdgesImage->Reload( false, tr.backend.commandList ); globalImages->smaaBlendImage->Reload( false, tr.backend.commandList ); + globalImages->shadowAtlasImage->Reload( false, tr.backend.commandList ); for( int i = 0; i < MAX_SHADOWMAP_RESOLUTIONS; i++ ) { globalImages->shadowImage[i]->Reload( false, tr.backend.commandList ); @@ -151,6 +152,10 @@ void Framebuffer::ResizeFramebuffers() } } + globalFramebuffers.shadowAtlasFBO = new Framebuffer( "_shadowAtlas", + nvrhi::FramebufferDesc() + .setDepthAttachment( globalImages->shadowAtlasImage->texture ) ); + globalFramebuffers.ldrFBO = new Framebuffer( "_ldr", nvrhi::FramebufferDesc() .addColorAttachment( globalImages->currentRenderLDR->texture ) diff --git a/neo/renderer/RenderBackend.cpp b/neo/renderer/RenderBackend.cpp index 38fa1835..14865cf7 100644 --- a/neo/renderer/RenderBackend.cpp +++ b/neo/renderer/RenderBackend.cpp @@ -3300,7 +3300,7 @@ void idRenderBackend::ShadowMapPassPerforated( const drawSurf_t** drawSurfs, int idRenderBackend::ShadowMapPassFast ===================== */ -void idRenderBackend::ShadowMapPassFast( const drawSurf_t* drawSurfs, const viewLight_t* vLight, int side ) +void idRenderBackend::ShadowMapPassFast( const drawSurf_t* drawSurfs, const viewLight_t* vLight, int side, bool atlas ) { if( r_skipShadows.GetBool() ) { @@ -3354,23 +3354,35 @@ void idRenderBackend::ShadowMapPassFast( const drawSurf_t* drawSurfs, const view SetupShadowMapMatrices( vLight, side, lightProjectionRenderMatrix, lightViewRenderMatrix ); #if defined( USE_NVRHI ) - if( side < 0 ) + + if( atlas ) { - globalFramebuffers.shadowFBO[vLight->shadowLOD][0]->Bind(); + //globalFramebuffers.shadowAtlasFBO->Bind(); + + // TODO light offset in atlas + + //GL_ViewportAndScissor( 0, 0, shadowMapResolutions[vLight->shadowLOD], shadowMapResolutions[vLight->shadowLOD] ); } else { - globalFramebuffers.shadowFBO[vLight->shadowLOD][side]->Bind(); - } + if( side < 0 ) + { + globalFramebuffers.shadowFBO[vLight->shadowLOD][0]->Bind(); + } + else + { + globalFramebuffers.shadowFBO[vLight->shadowLOD][side]->Bind(); + } - GL_ViewportAndScissor( 0, 0, shadowMapResolutions[vLight->shadowLOD], shadowMapResolutions[vLight->shadowLOD] ); + GL_ViewportAndScissor( 0, 0, shadowMapResolutions[vLight->shadowLOD], shadowMapResolutions[vLight->shadowLOD] ); - const nvrhi::FramebufferAttachment& att = currentFrameBuffer->GetApiObject()->getDesc().depthAttachment; - if( att.texture ) - { - int slice = std::max( 0, side ); - commandList->clearDepthStencilTexture( att.texture, nvrhi::TextureSubresourceSet().setArraySlices( slice, 1 ), true, 1.f, false, 0x80 ); + const nvrhi::FramebufferAttachment& att = currentFrameBuffer->GetApiObject()->getDesc().depthAttachment; + if( att.texture ) + { + int slice = std::max( 0, side ); + commandList->clearDepthStencilTexture( att.texture, nvrhi::TextureSubresourceSet().setArraySlices( slice, 1 ), true, 1.f, false, 0x80 ); + } } #elif !defined( USE_VULKAN ) @@ -3802,6 +3814,129 @@ void idRenderBackend::ShadowMapPassOld( const drawSurf_t* drawSurfs, const viewL renderLog.CloseBlock(); } + +void idRenderBackend::ShadowAtlasPass( const viewDef_t* _viewDef ) +{ + if( r_skipShadows.GetBool() || viewDef->viewLights == NULL ) + { + return; + } + + renderLog.OpenMainBlock( MRB_SHADOW_ATLAS_PASS ); + renderLog.OpenBlock( "Render_ShadowAtlas", colorYellow ); + + GL_SelectTexture( 0 ); + + const bool useLightDepthBounds = r_useLightDepthBounds.GetBool() && !r_useShadowMapping.GetBool(); + + Framebuffer* previousFramebuffer = Framebuffer::GetActiveFramebuffer(); + + globalFramebuffers.shadowAtlasFBO->Bind(); + + GL_ViewportAndScissor( 0, 0, SHADOW_ATLAS_SIZE, SHADOW_ATLAS_SIZE ); + + const nvrhi::FramebufferAttachment& att = currentFrameBuffer->GetApiObject()->getDesc().depthAttachment; + if( att.texture ) + { + commandList->clearDepthStencilTexture( att.texture, nvrhi::AllSubresources, true, 1.0f, false, 0x80 ); + } + + // + // for each light, perform shadowing to a big atlas Framebuffer + // + for( const viewLight_t* vLight = viewDef->viewLights; vLight != NULL; vLight = vLight->next ) + { + if( vLight->lightShader->IsFogLight() ) + { + continue; + } + + if( vLight->lightShader->IsBlendLight() ) + { + continue; + } + + if( vLight->localInteractions == NULL && vLight->globalInteractions == NULL && vLight->translucentInteractions == NULL ) + { + continue; + } + + const idMaterial* lightShader = vLight->lightShader; + renderLog.OpenBlock( lightShader->GetName(), colorMdGrey ); + + // set the depth bounds for the whole light + if( useLightDepthBounds ) + { + GL_DepthBoundsTest( vLight->scissorRect.zmin, vLight->scissorRect.zmax ); + } + + // RB: shadow mapping + //if( r_useShadowMapping.GetBool() ) + int side, sideStop; + + if( vLight->parallel ) + { + side = 0; + sideStop = r_shadowMapSplits.GetInteger() + 1; + } + else if( vLight->pointLight ) + { + if( r_shadowMapSingleSide.GetInteger() != -1 ) + { + side = r_shadowMapSingleSide.GetInteger(); + sideStop = side + 1; + } + else + { + side = 0; + sideStop = 6; + } + } + else + { + side = -1; + sideStop = 0; + } + + for( ; side < sideStop ; side++ ) + { + ShadowMapPassFast( vLight->globalShadows, vLight, side, true ); + } + + renderLog.CloseBlock(); + } + + // go back to main render target + if( previousFramebuffer != NULL ) + { + previousFramebuffer->Bind(); + } + else + { + Framebuffer::Unbind(); + } + renderProgManager.Unbind(); + + GL_State( GLS_DEFAULT ); + + SetFragmentParm( RENDERPARM_ALPHA_TEST, vec4_zero.ToFloatPtr() ); + + // go back from light view to default camera view + ResetViewportAndScissorToDefaultCamera( _viewDef ); + + // unbind texture units + GL_SelectTexture( 0 ); + + // reset depth bounds + if( useLightDepthBounds ) + { + GL_DepthBoundsTest( 0.0f, 0.0f ); + } + + renderLog.CloseBlock(); + renderLog.CloseMainBlock(); +} + /* ============================================================================================== @@ -3890,7 +4025,7 @@ void idRenderBackend::DrawInteractions( const viewDef_t* _viewDef ) for( ; side < sideStop ; side++ ) { - ShadowMapPassFast( vLight->globalShadows, vLight, side ); + ShadowMapPassFast( vLight->globalShadows, vLight, side, false ); } // go back to main render target @@ -6161,7 +6296,10 @@ void idRenderBackend::DrawViewInternal( const viewDef_t* _viewDef, const int ste //------------------------------------------------- AmbientPass( drawSurfs, numDrawSurfs, false ); - //GL_EndRenderPass(); + //------------------------------------------------- + // render all light <-> geometry interactions to a depth buffer atlas + //------------------------------------------------- + ShadowAtlasPass( _viewDef ); //------------------------------------------------- // main light renderer diff --git a/neo/renderer/RenderBackend.h b/neo/renderer/RenderBackend.h index 04f2548a..a6f453a5 100644 --- a/neo/renderer/RenderBackend.h +++ b/neo/renderer/RenderBackend.h @@ -331,10 +331,12 @@ private: void AmbientPass( const drawSurf_t* const* drawSurfs, int numDrawSurfs, bool fillGbuffer ); void SetupShadowMapMatrices( const viewLight_t* vLight, int side, idRenderMatrix& lightProjectionRenderMatrix, idRenderMatrix& lightViewRenderMatrix ); - void ShadowMapPassFast( const drawSurf_t* drawSurfs, const viewLight_t* vLight, int side ); + void ShadowMapPassFast( const drawSurf_t* drawSurfs, const viewLight_t* vLight, int side, bool atlas ); void ShadowMapPassPerforated( const drawSurf_t** drawSurfs, int numDrawSurfs, const viewLight_t* vLight, int side, const idRenderMatrix& lightProjectionRenderMatrix, const idRenderMatrix& lightViewRenderMatrix ); void ShadowMapPassOld( const drawSurf_t* drawSurfs, const viewLight_t* vLight, int side ); + void ShadowAtlasPass( const viewDef_t* _viewDef ); + void StencilShadowPass( const drawSurf_t* drawSurfs, const viewLight_t* vLight ); void StencilSelectLight( const viewLight_t* vLight ); diff --git a/neo/renderer/RenderLog.cpp b/neo/renderer/RenderLog.cpp index 613cb3ea..1f15bac5 100644 --- a/neo/renderer/RenderLog.cpp +++ b/neo/renderer/RenderLog.cpp @@ -55,16 +55,17 @@ const char* renderLogMainBlockLabels[] = ASSERT_ENUM_STRING( MRB_FILL_GEOMETRY_BUFFER, 3 ), // RB ASSERT_ENUM_STRING( MRB_SSAO_PASS, 4 ), // RB ASSERT_ENUM_STRING( MRB_AMBIENT_PASS, 5 ), // RB - ASSERT_ENUM_STRING( MRB_DRAW_INTERACTIONS, 6 ), - ASSERT_ENUM_STRING( MRB_DRAW_SHADER_PASSES, 7 ), - ASSERT_ENUM_STRING( MRB_FOG_ALL_LIGHTS, 8 ), - ASSERT_ENUM_STRING( MRB_BLOOM, 9 ), - ASSERT_ENUM_STRING( MRB_DRAW_SHADER_PASSES_POST, 10 ), - ASSERT_ENUM_STRING( MRB_DRAW_DEBUG_TOOLS, 11 ), - ASSERT_ENUM_STRING( MRB_CAPTURE_COLORBUFFER, 12 ), - ASSERT_ENUM_STRING( MRB_POSTPROCESS, 13 ), - ASSERT_ENUM_STRING( MRB_DRAW_GUI, 14 ), - ASSERT_ENUM_STRING( MRB_TOTAL, 15 ) + ASSERT_ENUM_STRING( MRB_SHADOW_ATLAS_PASS, 6 ), // RB + ASSERT_ENUM_STRING( MRB_DRAW_INTERACTIONS, 7 ), + ASSERT_ENUM_STRING( MRB_DRAW_SHADER_PASSES, 8 ), + ASSERT_ENUM_STRING( MRB_FOG_ALL_LIGHTS, 9 ), + ASSERT_ENUM_STRING( MRB_BLOOM, 10 ), + ASSERT_ENUM_STRING( MRB_DRAW_SHADER_PASSES_POST, 11 ), + ASSERT_ENUM_STRING( MRB_DRAW_DEBUG_TOOLS, 12 ), + ASSERT_ENUM_STRING( MRB_CAPTURE_COLORBUFFER, 13 ), + ASSERT_ENUM_STRING( MRB_POSTPROCESS, 14 ), + ASSERT_ENUM_STRING( MRB_DRAW_GUI, 15 ), + ASSERT_ENUM_STRING( MRB_TOTAL, 16 ) }; #if defined( USE_VULKAN ) diff --git a/neo/renderer/RenderLog.h b/neo/renderer/RenderLog.h index 44bbec17..de706141 100644 --- a/neo/renderer/RenderLog.h +++ b/neo/renderer/RenderLog.h @@ -45,6 +45,7 @@ enum renderLogMainBlock_t MRB_FILL_GEOMETRY_BUFFER, MRB_SSAO_PASS, MRB_AMBIENT_PASS, + MRB_SHADOW_ATLAS_PASS, MRB_DRAW_INTERACTIONS, MRB_DRAW_SHADER_PASSES, MRB_FOG_ALL_LIGHTS,