diff --git a/base/materials/invisible.mtr b/base/materials/invisible.mtr index 21da2637..2c0e1b96 100644 --- a/base/materials/invisible.mtr +++ b/base/materials/invisible.mtr @@ -433,4 +433,13 @@ textures/common/origin qer_nocarve // don't let an awry CSG operation cut it up origin } + +// if an ASE/LWO/GLTF model has a surface that uses this material that surface will +// be used for occlusion culling instead of the visual surface(s) +textures/common/occlusion +{ + qer_editorimage textures/common/occlusion.tga + noshadows + occlusion +} // RB end \ No newline at end of file diff --git a/base/textures/common/occlusion.png b/base/textures/common/occlusion.png new file mode 100644 index 00000000..2d85cd2a Binary files /dev/null and b/base/textures/common/occlusion.png differ diff --git a/neo/renderer/Material.cpp b/neo/renderer/Material.cpp index 09503040..f01b20e5 100644 --- a/neo/renderer/Material.cpp +++ b/neo/renderer/Material.cpp @@ -341,6 +341,7 @@ static infoParm_t infoParms[] = // because they represent discrete objects like gui shaders // mirrors, or autosprites {"noFragment", 0, SURF_NOFRAGMENT, 0 }, + {"occlusion", 0, SURF_OCCLUSION, 0 }, // RB: surface becomes vis blocker in software depth buffer {"slick", 0, SURF_SLICK, 0 }, {"collision", 0, SURF_COLLISION, 0 }, diff --git a/neo/renderer/Material.h b/neo/renderer/Material.h index 3e01c377..53af6a96 100644 --- a/neo/renderer/Material.h +++ b/neo/renderer/Material.h @@ -441,8 +441,8 @@ typedef enum SURF_NOSTEPS = BIT( 9 ), // no footstep sounds SURF_DISCRETE = BIT( 10 ), // not clipped or merged by utilities SURF_NOFRAGMENT = BIT( 11 ), // dmap won't cut surface at each bsp boundary - SURF_NULLNORMAL = BIT( 12 ) // renderbump will draw this surface as 0x80 0x80 0x80, which - // won't collect light from any angle + SURF_NULLNORMAL = BIT( 12 ), // renderbump will draw this surface as 0x80 0x80 0x80, which won't collect light from any angle + SURF_OCCLUSION = BIT( 13 ), // RB: occluder surface } surfaceFlags_t; @@ -684,6 +684,12 @@ public: return ( surfaceFlags & SURF_NOFRAGMENT ) != 0; } + // RB: occluder surfaces are invisible and only get rendered to the masked occlusion depth buffer + bool IsOccluder() const + { + return ( surfaceFlags & SURF_OCCLUSION ) != 0; + } + //------------------------------------------------------------------ // light shader specific functions, only called for light entities diff --git a/neo/renderer/tr_frontend_masked_occlusion_culling.cpp b/neo/renderer/tr_frontend_masked_occlusion_culling.cpp index 5ebfb836..b9524d09 100644 --- a/neo/renderer/tr_frontend_masked_occlusion_culling.cpp +++ b/neo/renderer/tr_frontend_masked_occlusion_culling.cpp @@ -196,6 +196,23 @@ void R_RenderSingleModel( viewEntity_t* vEntity ) //--------------------------- // add all the model surfaces //--------------------------- + bool occlusionSurface = false; + for( int surfaceNum = 0; surfaceNum < model->NumSurfaces(); surfaceNum++ ) + { + const modelSurface_t* surf = model->Surface( surfaceNum ); + + const idMaterial* shader = surf->shader; + if( shader == NULL ) + { + continue; + } + + if( shader->IsOccluder() ) + { + occlusionSurface = true; + } + } + for( int surfaceNum = 0; surfaceNum < model->NumSurfaces(); surfaceNum++ ) { const modelSurface_t* surf = model->Surface( surfaceNum ); @@ -221,6 +238,12 @@ void R_RenderSingleModel( viewEntity_t* vEntity ) continue; } + // if the model has a occlusion surface and this surface is not a occluder + if( occlusionSurface && !shader->IsOccluder() ) + { + continue; + } + // motorsep 11-24-2014; checking for LOD surface for LOD1 iteration if( shader->IsLOD() ) { @@ -249,7 +272,7 @@ void R_RenderSingleModel( viewEntity_t* vEntity ) } // foresthale 2014-09-01: don't skip surfaces that use the "forceShadows" flag - if( !shader->IsDrawn() && !shader->SurfaceCastsShadow() ) + if( !shader->IsDrawn() && !shader->SurfaceCastsShadow() && !shader->IsOccluder() ) { continue; // collision hulls, etc } @@ -330,13 +353,16 @@ void R_RenderSingleModel( viewEntity_t* vEntity ) const float* shaderRegisters = NULL; drawSurf_t* baseDrawSurf = NULL; - if( surfaceDirectlyVisible && shader->IsDrawn() && shader->Coverage() == MC_OPAQUE && !renderEntity->weaponDepthHack && renderEntity->modelDepthHack == 0.0f ) - //if( surfaceDirectlyVisible && shader->IsDrawn() && !renderEntity->weaponDepthHack && renderEntity->modelDepthHack == 0.0f ) + if( surfaceDirectlyVisible && + ( ( shader->IsDrawn() && shader->Coverage() == MC_OPAQUE && !renderEntity->weaponDepthHack && renderEntity->modelDepthHack == 0.0f ) || shader->IsOccluder() ) + ) { // render to masked occlusion buffer //if( !gpuSkinned ) - if( model->IsStaticWorldModel() ) + + // render the BSP area surfaces and from static model entities only the occlusion surfaces to keep the tris count at minimum + if( model->IsStaticWorldModel() || ( shader->IsOccluder() && !gpuSkinned ) ) { tr.pc.c_mocIndexes += tri->numIndexes; tr.pc.c_mocVerts += tri->numIndexes;