From bdbdd24f51e0bd314d8789ae43e56b8bd1269593 Mon Sep 17 00:00:00 2001 From: VReaperV Date: Sat, 14 Sep 2024 01:52:29 +0300 Subject: [PATCH 1/2] Generate skybrush material Generate a material for skybrushes and use it with the stencil buffer to prevent material system from rendering stuff over the skybox which would be normally culled by the BSP. --- src/engine/renderer/Material.cpp | 78 +++++++++++++++++++++++++++++-- src/engine/renderer/Material.h | 13 ++++-- src/engine/renderer/tr_local.h | 2 + src/engine/renderer/tr_main.cpp | 29 ++++-------- src/engine/renderer/tr_shade.cpp | 12 +++++ src/engine/renderer/tr_shader.cpp | 23 +++++++++ 6 files changed, 129 insertions(+), 28 deletions(-) diff --git a/src/engine/renderer/Material.cpp b/src/engine/renderer/Material.cpp index c164975929..d88c003af9 100644 --- a/src/engine/renderer/Material.cpp +++ b/src/engine/renderer/Material.cpp @@ -792,7 +792,7 @@ void MaterialSystem::GenerateWorldMaterialsBuffer() { uint32_t* materialsData = materialsSSBO.MapBufferRange( offset ); memset( materialsData, 0, offset * sizeof( uint32_t ) ); - for ( uint32_t materialPackID = 0; materialPackID < 3; materialPackID++ ) { + for ( uint32_t materialPackID = 0; materialPackID < 4; materialPackID++ ) { for ( Material& material : materialPacks[materialPackID].materials ) { for ( drawSurf_t* drawSurf : material.drawSurfs ) { @@ -959,7 +959,7 @@ void MaterialSystem::GenerateWorldCommandBuffer() { } shader = shader->remappedShader ? shader->remappedShader : shader; - if ( shader->isSky || shader->isPortal ) { + if ( shader->isPortal ) { continue; } @@ -1331,6 +1331,9 @@ void MaterialSystem::ProcessStage( drawSurf_t* drawSurf, shaderStage_t* pStage, } else { materialPack = 2; } + if ( shader->isSky ) { + materialPack = 3; + } uint32_t id = packIDs[materialPack]; // In surfaces with multiple stages each consecutive stage must be drawn after the previous stage, @@ -1357,6 +1360,14 @@ void MaterialSystem::ProcessStage( drawSurf_t* drawSurf, shaderStage_t* pStage, drawSurf->texturesDynamic[stage] = true; } + if ( shader->isSky ) { + if ( std::find( skyShaders.begin(), skyShaders.end(), shader ) == skyShaders.end() ) { + skyShaders.emplace_back( shader ); + } + + material.skyShader = shader; + } + pStage->materialProcessor( &material, pStage, drawSurf ); std::vector& materials = materialPacks[materialPack].materials; @@ -1432,8 +1443,7 @@ void MaterialSystem::GenerateWorldMaterials() { drawSurf_t* drawSurf; totalDrawSurfs = 0; - - uint32_t packIDs[3] = { 0, 0, 0 }; + uint32_t packIDs[4] = { 0, 0, 0, 0 }; for ( int i = 0; i < tr.refdef.numDrawSurfs; i++ ) { drawSurf = &tr.refdef.drawSurfs[i]; @@ -1447,7 +1457,7 @@ void MaterialSystem::GenerateWorldMaterials() { } shader = shader->remappedShader ? shader->remappedShader : shader; - if ( shader->isSky || shader->isPortal ) { + if ( shader->isPortal ) { continue; } @@ -1979,9 +1989,67 @@ void MaterialSystem::RenderMaterials( const shaderSort_t fromSort, const shaderS continue; } + // Use stencil buffer to avoid rendering stuff over the skybox that would normally be culled by the BSP + if ( backEnd.viewParms.portalLevel == 0 ) { + glEnable( GL_STENCIL_TEST ); + glStencilMask( 0xff ); + } + + glStencilFunc( GL_EQUAL, backEnd.viewParms.portalLevel, 0xff ); + glStencilOp( GL_KEEP, GL_KEEP, GL_INCR ); + + glState.glStateBitsMask = 0; + + for ( Material& material : materialPacks[3].materials ) { + if ( material.skyShader == skyShader ) { + RenderMaterial( material, viewID ); + renderedMaterials.emplace_back( &material ); + } + } + + glStencilFunc( GL_EQUAL, backEnd.viewParms.portalLevel + 1, 0xff ); + glStencilOp( GL_KEEP, GL_KEEP, GL_KEEP ); + + GL_State( GLS_DEPTHMASK_TRUE | GLS_DEPTHFUNC_ALWAYS ); + glState.glStateBitsMask = GLS_COLORMASK_BITS | GLS_DEPTHMASK_TRUE | GLS_DEPTHFUNC_ALWAYS; + glDepthRange( 1.0, 1.0 ); + + for ( Material& material : materialPacks[3].materials ) { + if ( material.skyShader == skyShader ) { + RenderMaterial( material, viewID ); + renderedMaterials.emplace_back( &material ); + } + } + + // Actually draw the skybox tr.drawingSky = true; Tess_Begin( Tess_StageIteratorSky, skyShader, nullptr, false, -1, 0, false ); Tess_End(); + + glStencilOp( GL_KEEP, GL_KEEP, GL_DECR ); + + glState.glStateBitsMask = 0; + GL_State( GLS_COLORMASK_BITS | GLS_DEPTHMASK_TRUE | GLS_DEPTHFUNC_ALWAYS ); + glState.glStateBitsMask = GLS_COLORMASK_BITS | GLS_DEPTHMASK_TRUE | GLS_DEPTHFUNC_ALWAYS; + glDepthRange( 1.0, 1.0 ); + + for ( Material& material : materialPacks[3].materials ) { + if ( material.skyShader == skyShader ) { + RenderMaterial( material, viewID ); + renderedMaterials.emplace_back( &material ); + } + } + + glStencilFunc( GL_EQUAL, backEnd.viewParms.portalLevel, 0xff ); + glStencilOp( GL_KEEP, GL_KEEP, GL_KEEP ); + + glState.glStateBitsMask = 0; + GL_State( GLS_DEFAULT ); + glDepthRange( 0.0, 1.0 ); + + if ( backEnd.viewParms.portalLevel == 0 ) { + glDisable( GL_STENCIL_TEST ); + } } } } diff --git a/src/engine/renderer/Material.h b/src/engine/renderer/Material.h index 979478c941..043052403f 100644 --- a/src/engine/renderer/Material.h +++ b/src/engine/renderer/Material.h @@ -110,6 +110,8 @@ struct Material { bool enableNormalMapping; bool enablePhysicalMapping; + shader_t* skyShader = nullptr; + cullType_t cullType; bool usePolygonOffset = false; @@ -124,7 +126,8 @@ struct Material { bool operator==( const Material& other ) { return program == other.program && stateBits == other.stateBits && vbo == other.vbo && ibo == other.ibo - && cullType == other.cullType && usePolygonOffset == other.usePolygonOffset; + && cullType == other.cullType && usePolygonOffset == other.usePolygonOffset + && ( skyShader == nullptr || other.skyShader == nullptr || skyShader == other.skyShader ); } void AddTexture( Texture* texture ) { @@ -237,12 +240,15 @@ class MaterialSystem { } }; - MaterialPack materialPacks[3]{ + MaterialPack materialPacks[4] { { shaderSort_t::SS_DEPTH, shaderSort_t::SS_DEPTH }, { shaderSort_t::SS_ENVIRONMENT_FOG, shaderSort_t::SS_OPAQUE }, - { shaderSort_t::SS_ENVIRONMENT_NOFOG, shaderSort_t::SS_POST_PROCESS } + { shaderSort_t::SS_ENVIRONMENT_NOFOG, shaderSort_t::SS_POST_PROCESS }, + { shaderSort_t::SS_BAD, shaderSort_t::SS_BAD } }; + Material skyBrushMaterial; + bool frameStart = false; void AddTexture( Texture* texture ); @@ -303,6 +309,7 @@ class MaterialSystem { bool AddPortalSurface( uint32_t viewID, PortalSurface* portalSurfs ); + void RenderMaterialPack( MaterialPack& materialPack, const uint32_t viewID ); void RenderMaterial( Material& material, const uint32_t viewID ); void UpdateFrameData(); }; diff --git a/src/engine/renderer/tr_local.h b/src/engine/renderer/tr_local.h index f81eed0b26..456db1424c 100644 --- a/src/engine/renderer/tr_local.h +++ b/src/engine/renderer/tr_local.h @@ -1063,6 +1063,7 @@ enum class realtimeLightingRenderer_t { LEGACY, TILED }; ST_REFRACTIONMAP, ST_DISPERSIONMAP, ST_SKYBOXMAP, + ST_SKYBRUSHMAP, ST_SCREENMAP, // 2d offscreen or portal rendering ST_PORTALMAP, ST_HEATHAZEMAP, // heatHaze post process effect @@ -3446,6 +3447,7 @@ inline bool checkGLErrors() void Render_lightMapping( shaderStage_t *pStage ); void Render_reflection_CB( shaderStage_t *pStage ); void Render_skybox( shaderStage_t *pStage ); + void Render_materialPassThrough( shaderStage_t* pStage ); void Render_screen( shaderStage_t *pStage ); void Render_portal( shaderStage_t *pStage ); void Render_heatHaze( shaderStage_t *pStage ); diff --git a/src/engine/renderer/tr_main.cpp b/src/engine/renderer/tr_main.cpp index 83fdd30a6e..4c11dff585 100644 --- a/src/engine/renderer/tr_main.cpp +++ b/src/engine/renderer/tr_main.cpp @@ -1873,14 +1873,11 @@ R_AddDrawSurf */ void R_AddDrawSurf( surfaceType_t *surface, shader_t *shader, int lightmapNum, int fogNum, bool bspSurface ) { - int index; - drawSurf_t *drawSurf; - // instead of checking for overflow, we just mask the index // so it wraps around - index = tr.refdef.numDrawSurfs & DRAWSURF_MASK; + int index = tr.refdef.numDrawSurfs & DRAWSURF_MASK; - drawSurf = &tr.refdef.drawSurfs[ index ]; + drawSurf_t* drawSurf = &tr.refdef.drawSurfs[ index ]; drawSurf->entity = tr.currentEntity; drawSurf->surface = surface; @@ -1907,21 +1904,13 @@ void R_AddDrawSurf( surfaceType_t *surface, shader_t *shader, int lightmapNum, i tr.refdef.numDrawSurfs++; - // Portal and sky surfaces are not handled by the material system at all - if ( materialSystem.generatingWorldCommandBuffer && ( shader->isPortal || shader->isSky ) ) { - if ( shader->isSky && std::find( materialSystem.skyShaders.begin(), materialSystem.skyShaders.end(), shader ) - == materialSystem.skyShaders.end() ) { - materialSystem.skyShaders.emplace_back( shader ); - } - - if ( shader->isPortal ) - { - // R_AddWorldSurfaces guarantees not to add surfaces more than once - ASSERT_EQ( - std::find( materialSystem.portalSurfacesTmp.begin(), materialSystem.portalSurfacesTmp.end(), drawSurf ), - materialSystem.portalSurfacesTmp.end() ); - materialSystem.portalSurfacesTmp.emplace_back( drawSurf ); - } + // Portal surfaces are not handled by the material system at all + if ( materialSystem.generatingWorldCommandBuffer && shader->isPortal ) { + // R_AddWorldSurfaces guarantees not to add surfaces more than once + ASSERT_EQ( + std::find( materialSystem.portalSurfacesTmp.begin(), materialSystem.portalSurfacesTmp.end(), drawSurf ), + materialSystem.portalSurfacesTmp.end() ); + materialSystem.portalSurfacesTmp.emplace_back( drawSurf ); return; } diff --git a/src/engine/renderer/tr_shade.cpp b/src/engine/renderer/tr_shade.cpp index 8b5a5387db..87d8155511 100644 --- a/src/engine/renderer/tr_shade.cpp +++ b/src/engine/renderer/tr_shade.cpp @@ -2071,6 +2071,18 @@ void Render_skybox( shaderStage_t *pStage ) GL_CheckErrors(); } +void Render_materialPassThrough( shaderStage_t* ) { + GLimp_LogComment( "--- Render_materialPassThrough ---\n" ); + + // Pass-through for material system, not used normally + if ( materialSystem.generatingWorldCommandBuffer ) { + Tess_DrawElements(); + return; + } + + ASSERT_UNREACHABLE(); +} + void Render_screen( shaderStage_t *pStage ) { GLimp_LogComment( "--- Render_screen ---\n" ); diff --git a/src/engine/renderer/tr_shader.cpp b/src/engine/renderer/tr_shader.cpp index 1e81cddcfa..7b6792604e 100644 --- a/src/engine/renderer/tr_shader.cpp +++ b/src/engine/renderer/tr_shader.cpp @@ -5432,6 +5432,13 @@ static void SetStagesRenderers() false, false, }; break; + case stageType_t::ST_SKYBRUSHMAP: + stageRendererOptions = { + &Render_materialPassThrough, + &UpdateSurfaceDataGeneric3D, &BindShaderGeneric3D, &ProcessMaterialGeneric3D, + false, false, + }; + break; case stageType_t::ST_SCREENMAP: stageRendererOptions = { &Render_screen, @@ -5806,6 +5813,22 @@ static shader_t *FinishShader() numStages = MAX_SHADER_STAGES; GroupActiveStages(); + if ( glConfig2.materialSystemAvailable && shader.isSky ) { + shaderStage_t* pStage = &stages[numStages]; + + pStage->active = true; + + pStage->type = stageType_t::ST_SKYBRUSHMAP; + pStage->deformIndex = 0; + pStage->stateBits = GLS_COLORMASK_BITS; + pStage->rgbGen = colorGen_t::CGEN_IDENTITY; + pStage->alphaGen = alphaGen_t::AGEN_IDENTITY; + pStage->bundle[TB_COLORMAP].image[0] = tr.whiteImage; + pStage->hasDepthFade = false; + + numStages++; + } + // set appropriate stage information for ( size_t stage = 0; stage < numStages; stage++ ) { From aac0e5a10de339ab234f2a4acb309a9081379870 Mon Sep 17 00:00:00 2001 From: VReaperV Date: Tue, 17 Sep 2024 00:48:04 +0300 Subject: [PATCH 2/2] test --- src/engine/renderer/Material.cpp | 35 ++++++++++++++++++++++++++------ src/engine/renderer/Material.h | 1 + 2 files changed, 30 insertions(+), 6 deletions(-) diff --git a/src/engine/renderer/Material.cpp b/src/engine/renderer/Material.cpp index d88c003af9..50f38238e5 100644 --- a/src/engine/renderer/Material.cpp +++ b/src/engine/renderer/Material.cpp @@ -1841,6 +1841,8 @@ void MaterialSystem::Free() { nextFrame = 1; maxStages = 0; + renderSkyBrushDepth = false; + for ( MaterialPack& pack : materialPacks ) { for ( Material& material : pack.materials ) { material.drawCommands.clear(); @@ -1985,7 +1987,7 @@ void MaterialSystem::RenderMaterials( const shaderSort_t fromSort, const shaderS if ( tr.hasSkybox && ( environmentFogDraw || environmentNoFogDraw ) ) { const bool noFogPass = toSort >= shaderSort_t::SS_ENVIRONMENT_NOFOG; for ( shader_t* skyShader : skyShaders ) { - if ( skyShader->noFog != noFogPass ) { + if ( skyShader->noFog != noFogPass && !renderSkyBrushDepth ) { continue; } @@ -2007,6 +2009,7 @@ void MaterialSystem::RenderMaterials( const shaderSort_t fromSort, const shaderS } } + // Set depth to 1.0 on skybrushes glStencilFunc( GL_EQUAL, backEnd.viewParms.portalLevel + 1, 0xff ); glStencilOp( GL_KEEP, GL_KEEP, GL_KEEP ); @@ -2021,17 +2024,33 @@ void MaterialSystem::RenderMaterials( const shaderSort_t fromSort, const shaderS } } - // Actually draw the skybox - tr.drawingSky = true; - Tess_Begin( Tess_StageIteratorSky, skyShader, nullptr, false, -1, 0, false ); - Tess_End(); + // Actually render the skybox + if ( !renderSkyBrushDepth ) { + tr.drawingSky = true; + Tess_Begin( Tess_StageIteratorSky, skyShader, nullptr, false, -1, 0, false ); + Tess_End(); + } + // Decrease the stencil bits back on skybrushes glStencilOp( GL_KEEP, GL_KEEP, GL_DECR ); + // Set depth back to the skybrushes depth glState.glStateBitsMask = 0; GL_State( GLS_COLORMASK_BITS | GLS_DEPTHMASK_TRUE | GLS_DEPTHFUNC_ALWAYS ); glState.glStateBitsMask = GLS_COLORMASK_BITS | GLS_DEPTHMASK_TRUE | GLS_DEPTHFUNC_ALWAYS; - glDepthRange( 1.0, 1.0 ); + + /* SSAO excludes fragments with depth 1.0, so we need to change the depth on skybrushes back to 1.0 + if SSAO is enabled and it's an SS_ENVIRONMENT_FOG pass */ + if ( r_ssao->integer ) { + if ( environmentFogDraw && !renderSkyBrushDepth ) { + glDepthRange( 0.0, 1.0 ); + renderSkyBrushDepth = true; + } else { + glDepthRange( 1.0, 1.0 ); + } + } else { + glDepthRange( 0.0, 1.0 ); + } for ( Material& material : materialPacks[3].materials ) { if ( material.skyShader == skyShader ) { @@ -2052,6 +2071,10 @@ void MaterialSystem::RenderMaterials( const shaderSort_t fromSort, const shaderS } } } + + if ( environmentNoFogDraw && renderSkyBrushDepth ) { + renderSkyBrushDepth = false; + } } void MaterialSystem::RenderMaterial( Material& material, const uint32_t viewID ) { diff --git a/src/engine/renderer/Material.h b/src/engine/renderer/Material.h index 043052403f..26cb649428 100644 --- a/src/engine/renderer/Material.h +++ b/src/engine/renderer/Material.h @@ -223,6 +223,7 @@ class MaterialSystem { std::vector portalBounds; uint32_t totalPortals; std::vector skyShaders; + bool renderSkyBrushDepth = false; std::vector renderedMaterials;