Skip to content

Commit

Permalink
Generate skybrush material
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
VReaperV committed Sep 14, 2024
1 parent e98fbad commit 4fa3b84
Show file tree
Hide file tree
Showing 6 changed files with 129 additions and 28 deletions.
78 changes: 73 additions & 5 deletions src/engine/renderer/Material.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 ) {
Expand Down Expand Up @@ -960,7 +960,7 @@ void MaterialSystem::GenerateWorldCommandBuffer() {
}

shader = shader->remappedShader ? shader->remappedShader : shader;
if ( shader->isSky || shader->isPortal ) {
if ( shader->isPortal ) {
continue;
}

Expand Down Expand Up @@ -1332,6 +1332,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,
Expand All @@ -1358,6 +1361,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<Material>& materials = materialPacks[materialPack].materials;
Expand Down Expand Up @@ -1433,8 +1444,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];
Expand All @@ -1448,7 +1458,7 @@ void MaterialSystem::GenerateWorldMaterials() {
}

shader = shader->remappedShader ? shader->remappedShader : shader;
if ( shader->isSky || shader->isPortal ) {
if ( shader->isPortal ) {
continue;
}

Expand Down Expand Up @@ -1981,9 +1991,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 );
}
}
}
}
Expand Down
13 changes: 10 additions & 3 deletions src/engine/renderer/Material.h
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,8 @@ struct Material {
bool enableNormalMapping;
bool enablePhysicalMapping;

shader_t* skyShader = nullptr;

cullType_t cullType;

bool usePolygonOffset = false;
Expand All @@ -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 ) {
Expand Down Expand Up @@ -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 );
Expand Down Expand Up @@ -304,6 +310,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();
};
Expand Down
2 changes: 2 additions & 0 deletions src/engine/renderer/tr_local.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 );
Expand Down
29 changes: 9 additions & 20 deletions src/engine/renderer/tr_main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
}

Expand Down
12 changes: 12 additions & 0 deletions src/engine/renderer/tr_shade.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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" );
Expand Down
23 changes: 23 additions & 0 deletions src/engine/renderer/tr_shader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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++ )
{
Expand Down

0 comments on commit 4fa3b84

Please sign in to comment.