Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generate skybrush material #1299

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
109 changes: 100 additions & 9 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 @@ -959,7 +959,7 @@ void MaterialSystem::GenerateWorldCommandBuffer() {
}

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

Expand Down Expand Up @@ -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,
Expand All @@ -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<Material>& materials = materialPacks[materialPack].materials;
Expand Down Expand Up @@ -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];
Expand All @@ -1447,7 +1457,7 @@ void MaterialSystem::GenerateWorldMaterials() {
}

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

Expand Down Expand Up @@ -1831,6 +1841,8 @@ void MaterialSystem::Free() {
nextFrame = 1;
maxStages = 0;

renderSkyBrushDepth = false;

for ( MaterialPack& pack : materialPacks ) {
for ( Material& material : pack.materials ) {
material.drawCommands.clear();
Expand Down Expand Up @@ -1975,15 +1987,94 @@ 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;
}

tr.drawingSky = true;
Tess_Begin( Tess_StageIteratorSky, skyShader, nullptr, false, -1, 0, false );
Tess_End();
// 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;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is not needed, it should be 0 to start with

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it was breaking otherwise with portals. Maybe not and I put there just in case because it was breaking elsewhere, but either way doesn't matter now because this way of rendering the skybox seems infeasible. Well, maybe I'll actually keep the stenciled skybrush part to reset depth, I'll need to look at it again later.


for ( Material& material : materialPacks[3].materials ) {
if ( material.skyShader == skyShader ) {
RenderMaterial( material, viewID );
renderedMaterials.emplace_back( &material );
}
}

// Set depth to 1.0 on skybrushes
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 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;

/* 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 ) {
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 );
}
}
}

if ( environmentNoFogDraw && renderSkyBrushDepth ) {
renderSkyBrushDepth = false;
}
}

void MaterialSystem::RenderMaterial( Material& material, const uint32_t viewID ) {
Expand Down
14 changes: 11 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 );
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why can't it just be skyShader == other.skyShader?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IIRC I did it because if one material has a skybox shader and the other doesn't, then they still can be considered the same.

}

void AddTexture( Texture* texture ) {
Expand Down Expand Up @@ -220,6 +223,7 @@ class MaterialSystem {
std::vector<PortalSurface> portalBounds;
uint32_t totalPortals;
std::vector<shader_t*> skyShaders;
bool renderSkyBrushDepth = false;

std::vector<Material*> renderedMaterials;

Expand All @@ -237,12 +241,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 @@ -303,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 ) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Needs a check that we don't overflow the stages array

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