Merged some SS2 shadow mapping performance improvements

This commit is contained in:
Robert Beckebans 2016-07-02 11:22:04 +02:00
parent 081c848f87
commit 3e1d21ef34
3 changed files with 367 additions and 205 deletions

View file

@ -3,6 +3,8 @@
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
Copyright (C) 2014-2016 Robert Beckebans
Copyright (C) 2014-2016 Kot in Action Creative Artel
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
@ -1205,6 +1207,11 @@ void idMaterial::ParseFragmentMap( idLexer& src, newShaderStage_t* newStage )
{
src.ReadTokenOnLine( &token );
if( !token.Icmp( "normalMap" ) )
{
td = TD_BUMP;
continue;
}
if( !token.Icmp( "cubeMap" ) )
{
cubeMap = CF_NATIVE;
@ -2337,7 +2344,8 @@ void idMaterial::ParseMaterial( idLexer& src )
// volume would be coplanar with the surface, giving depth fighting
// we could make this no-self-shadows, but it may be more important
// to receive shadows from no-self-shadow monsters
SetMaterialFlag( MF_NOSHADOWS );
if( !r_useShadowMapping.GetBool() ) // motorsep 11-08-2014; when shadow mapping is on, we allow two-sided surfaces to cast shadows
SetMaterialFlag( MF_NOSHADOWS );
}
// backSided
else if( !token.Icmp( "backSided" ) )
@ -2507,6 +2515,33 @@ void idMaterial::ParseMaterial( idLexer& src )
SetMaterialFlag( MF_NOSHADOWS );
continue;
}
// motorsep 11-23-2014; material LOD keys that define what LOD iteration the surface falls into
else if( !token.Icmp( "lod1" ) )
{
SetMaterialFlag( MF_LOD1 );
continue;
}
else if( !token.Icmp( "lod2" ) )
{
SetMaterialFlag( MF_LOD2 );
continue;
}
else if( !token.Icmp( "lod3" ) )
{
SetMaterialFlag( MF_LOD3 );
continue;
}
else if( !token.Icmp( "lod4" ) )
{
SetMaterialFlag( MF_LOD4 );
continue;
}
else if( !token.Icmp( "persistentLOD" ) )
{
SetMaterialFlag( MF_LOD_PERSISTENT );
continue;
}
else if( token == "{" )
{
// create the new stage

View file

@ -3,6 +3,8 @@
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
Copyright (C) 2014-2016 Robert Beckebans
Copyright (C) 2014-2016 Kot in Action Creative Artel
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
@ -280,8 +282,15 @@ typedef enum
MF_NOSHADOWS = BIT( 2 ),
MF_FORCESHADOWS = BIT( 3 ),
MF_NOSELFSHADOW = BIT( 4 ),
MF_NOPORTALFOG = BIT( 5 ), // this fog volume won't ever consider a portal fogged out
MF_EDITOR_VISIBLE = BIT( 6 ) // in use (visible) per editor
MF_NOPORTALFOG = BIT( 5 ), // this fog volume won't ever consider a portal fogged out
MF_EDITOR_VISIBLE = BIT( 6 ), // in use (visible) per editor
// motorsep 11-23-2014; material LOD keys that define what LOD iteration the surface falls into
MF_LOD1_SHIFT = 7,
MF_LOD1 = BIT( 7 ), // motorsep 11-24-2014; material flag for LOD1 iteration
MF_LOD2 = BIT( 8 ), // motorsep 11-24-2014; material flag for LOD2 iteration
MF_LOD3 = BIT( 9 ), // motorsep 11-24-2014; material flag for LOD3 iteration
MF_LOD4 = BIT( 10 ), // motorsep 11-24-2014; material flag for LOD4 iteration
MF_LOD_PERSISTENT = BIT( 11 ) // motorsep 11-24-2014; material flag for persistent LOD iteration
} materialFlags_t;
// contents flags, NOTE: make sure to keep the defines in doom_defs.script up to date with these!
@ -789,6 +798,24 @@ public:
};
void AddReference();
// motorsep 11-23-2014; material LOD keys that define what LOD iteration the surface falls into
// lod1 - lod4 defines several levels of LOD
// persistentLOD specifies the LOD iteration that still being rendered, even after the camera is beyond the distance at which LOD iteration should not be rendered
bool IsLOD() const
{
return ( materialFlags & ( MF_LOD1 | MF_LOD2 | MF_LOD3 | MF_LOD4 ) ) != 0;
}
// foresthale 2014-11-24: added IsLODVisibleForDistance method
bool IsLODVisibleForDistance( float distance, float lodBase ) const
{
int bit = ( materialFlags & ( MF_LOD1 | MF_LOD2 | MF_LOD3 | MF_LOD4 ) ) >> MF_LOD1_SHIFT;
float m1 = lodBase * ( bit >> 1 );
float m2 = lodBase * bit;
return distance >= m1 && ( distance < m2 || ( materialFlags & ( MF_LOD_PERSISTENT ) ) );
}
private:
// parse the entire material
void CommonInit();
@ -825,7 +852,7 @@ private:
idStr desc; // description
idStr renderBump; // renderbump command options, without the "renderbump" at the start
idImage* lightFalloffImage; // only for light shaders
idImage* lightFalloffImage; // only for light shaders
idImage* fastPathBumpImage; // if any of these are set, they all will be
idImage* fastPathDiffuseImage;

View file

@ -3,7 +3,8 @@
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
Copyright (C) 2013-2014 Robert Beckebans
Copyright (C) 2014-2016 Robert Beckebans
Copyright (C) 2014-2016 Kot in Action Creative Artel
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
@ -26,7 +27,6 @@ If you have questions concerning this license or the applicable additional terms
===========================================================================
*/
#pragma hdrstop
#include "precompiled.h"
@ -44,6 +44,8 @@ idCVar r_forceShadowCaps( "r_forceShadowCaps", "0", CVAR_RENDERER | CVAR_BOOL, "
// RB begin
idCVar r_forceShadowMapsOnAlphaTestedSurfaces( "r_forceShadowMapsOnAlphaTestedSurfaces", "1", CVAR_RENDERER | CVAR_BOOL, "0 = same shadowing as with stencil shadows, 1 = ignore noshadows for alpha tested materials" );
// RB end
// foresthale 2014-11-24: cvar to control the material lod flags - this is the distance at which a mesh switches from lod1 to lod2, where lod3 will appear at this distance *2, lod4 at *4, and persistentLOD keyword will disable the max distance check (thus extending this LOD to all further distances, rather than disappearing)
idCVar r_lodMaterialDistance( "r_lodMaterialDistance", "500", CVAR_RENDERER | CVAR_FLOAT, "surfaces further than this distance will use lower quality versions (if their material uses the lod1-4 keywords, persistentLOD disables the max distance checks)" );
static const float CHECK_BOUNDS_EPSILON = 1.0f;
@ -315,7 +317,7 @@ void R_SetupDrawSurfShader( drawSurf_t* drawSurf, const idMaterial* shader, cons
shaderParms = generatedShaderParms;
}
// allocte frame memory for the shader register values
// allocate frame memory for the shader register values
float* regs = ( float* )R_FrameAlloc( shader->GetNumRegisters() * sizeof( float ), FRAME_ALLOC_SHADER_REGISTER );
drawSurf->shaderRegisters = regs;
@ -602,7 +604,36 @@ void R_AddSingleModel( viewEntity_t* vEntity )
{
continue;
}
if( !shader->IsDrawn() )
// motorsep 11-24-2014; checking for LOD surface for LOD1 iteration
if( shader->IsLOD() )
{
// foresthale 2014-11-24: calculate the bounds and get the distance from camera to bounds
idBounds& localBounds = tri->bounds;
if( tri->staticModelWithJoints )
{
// skeletal models have difficult to compute bounds for surfaces, so use the whole entity
localBounds = vEntity->entityDef->localReferenceBounds;
}
const float* bounds = localBounds.ToFloatPtr();
idVec3 nearestPointOnBounds = localViewOrigin;
nearestPointOnBounds.x = Max( nearestPointOnBounds.x, bounds[0] );
nearestPointOnBounds.x = Min( nearestPointOnBounds.x, bounds[3] );
nearestPointOnBounds.y = Max( nearestPointOnBounds.y, bounds[1] );
nearestPointOnBounds.y = Min( nearestPointOnBounds.y, bounds[4] );
nearestPointOnBounds.z = Max( nearestPointOnBounds.z, bounds[2] );
nearestPointOnBounds.z = Min( nearestPointOnBounds.z, bounds[5] );
idVec3 delta = nearestPointOnBounds - localViewOrigin;
float distance = delta.LengthFast();
if( !shader->IsLODVisibleForDistance( distance, r_lodMaterialDistance.GetFloat() ) )
{
continue;
}
}
// foresthale 2014-09-01: don't skip surfaces that use the "forceShadows" flag
if( !shader->IsDrawn() && !shader->SurfaceCastsShadow() )
{
continue; // collision hulls, etc
}
@ -625,7 +656,8 @@ void R_AddSingleModel( viewEntity_t* vEntity )
{
continue;
}
if( !shader->IsDrawn() )
// foresthale 2014-09-01: don't skip surfaces that use the "forceShadows" flag
if( !shader->IsDrawn() && !shader->SurfaceCastsShadow() )
{
continue;
}
@ -680,84 +712,90 @@ void R_AddSingleModel( viewEntity_t* vEntity )
//--------------------------
// base drawing surface
//--------------------------
drawSurf_t* baseDrawSurf = NULL;
if( surfaceDirectlyVisible )
const float* shaderRegisters = NULL;
if( shader->IsDrawn() )
{
// make sure we have an ambient cache and all necessary normals / tangents
if( !vertexCache.CacheIsCurrent( tri->indexCache ) )
drawSurf_t* baseDrawSurf = NULL;
if( surfaceDirectlyVisible )
{
tri->indexCache = vertexCache.AllocIndex( tri->indexes, ALIGN( tri->numIndexes * sizeof( triIndex_t ), INDEX_CACHE_ALIGN ) );
}
if( !vertexCache.CacheIsCurrent( tri->ambientCache ) )
{
// we are going to use it for drawing, so make sure we have the tangents and normals
if( shader->ReceivesLighting() && !tri->tangentsCalculated )
{
assert( tri->staticModelWithJoints == NULL );
R_DeriveTangents( tri );
// RB: this was hit by parametric particle models ..
//assert( false ); // this should no longer be hit
// RB end
}
tri->ambientCache = vertexCache.AllocVertex( tri->verts, ALIGN( tri->numVerts * sizeof( idDrawVert ), VERTEX_CACHE_ALIGN ) );
}
// add the surface for drawing
// we can re-use some of the values for light interaction surfaces
baseDrawSurf = ( drawSurf_t* )R_FrameAlloc( sizeof( *baseDrawSurf ), FRAME_ALLOC_DRAW_SURFACE );
baseDrawSurf->frontEndGeo = tri;
baseDrawSurf->space = vEntity;
baseDrawSurf->scissorRect = vEntity->scissorRect;
baseDrawSurf->extraGLState = 0;
baseDrawSurf->renderZFail = 0;
R_SetupDrawSurfShader( baseDrawSurf, shader, renderEntity );
// Check for deformations (eyeballs, flares, etc)
const deform_t shaderDeform = shader->Deform();
if( shaderDeform != DFRM_NONE )
{
drawSurf_t* deformDrawSurf = R_DeformDrawSurf( baseDrawSurf );
if( deformDrawSurf != NULL )
{
// any deforms may have created multiple draw surfaces
for( drawSurf_t* surf = deformDrawSurf, * next = NULL; surf != NULL; surf = next )
{
next = surf->nextOnLight;
surf->linkChain = NULL;
surf->nextOnLight = vEntity->drawSurfs;
vEntity->drawSurfs = surf;
}
}
}
// Most deform source surfaces do not need to be rendered.
// However, particles are rendered in conjunction with the source surface.
if( shaderDeform == DFRM_NONE || shaderDeform == DFRM_PARTICLE || shaderDeform == DFRM_PARTICLE2 )
{
// copy verts and indexes to this frame's hardware memory if they aren't already there
if( !vertexCache.CacheIsCurrent( tri->ambientCache ) )
{
tri->ambientCache = vertexCache.AllocVertex( tri->verts, ALIGN( tri->numVerts * sizeof( tri->verts[0] ), VERTEX_CACHE_ALIGN ) );
}
// make sure we have an ambient cache and all necessary normals / tangents
if( !vertexCache.CacheIsCurrent( tri->indexCache ) )
{
tri->indexCache = vertexCache.AllocIndex( tri->indexes, ALIGN( tri->numIndexes * sizeof( tri->indexes[0] ), INDEX_CACHE_ALIGN ) );
tri->indexCache = vertexCache.AllocIndex( tri->indexes, ALIGN( tri->numIndexes * sizeof( triIndex_t ), INDEX_CACHE_ALIGN ) );
}
R_SetupDrawSurfJoints( baseDrawSurf, tri, shader );
if( !vertexCache.CacheIsCurrent( tri->ambientCache ) )
{
// we are going to use it for drawing, so make sure we have the tangents and normals
if( shader->ReceivesLighting() && !tri->tangentsCalculated )
{
assert( tri->staticModelWithJoints == NULL );
R_DeriveTangents( tri );
// RB: this was hit by parametric particle models ..
//assert( false ); // this should no longer be hit
// RB end
}
tri->ambientCache = vertexCache.AllocVertex( tri->verts, ALIGN( tri->numVerts * sizeof( idDrawVert ), VERTEX_CACHE_ALIGN ) );
}
baseDrawSurf->numIndexes = tri->numIndexes;
baseDrawSurf->ambientCache = tri->ambientCache;
baseDrawSurf->indexCache = tri->indexCache;
baseDrawSurf->shadowCache = 0;
// add the surface for drawing
// we can re-use some of the values for light interaction surfaces
baseDrawSurf = ( drawSurf_t* )R_FrameAlloc( sizeof( *baseDrawSurf ), FRAME_ALLOC_DRAW_SURFACE );
baseDrawSurf->frontEndGeo = tri;
baseDrawSurf->space = vEntity;
baseDrawSurf->scissorRect = vEntity->scissorRect;
baseDrawSurf->extraGLState = 0;
baseDrawSurf->renderZFail = 0;
baseDrawSurf->linkChain = NULL; // link to the view
baseDrawSurf->nextOnLight = vEntity->drawSurfs;
vEntity->drawSurfs = baseDrawSurf;
R_SetupDrawSurfShader( baseDrawSurf, shader, renderEntity );
shaderRegisters = baseDrawSurf->shaderRegisters;
// Check for deformations (eyeballs, flares, etc)
const deform_t shaderDeform = shader->Deform();
if( shaderDeform != DFRM_NONE )
{
drawSurf_t* deformDrawSurf = R_DeformDrawSurf( baseDrawSurf );
if( deformDrawSurf != NULL )
{
// any deforms may have created multiple draw surfaces
for( drawSurf_t* surf = deformDrawSurf, * next = NULL; surf != NULL; surf = next )
{
next = surf->nextOnLight;
surf->linkChain = NULL;
surf->nextOnLight = vEntity->drawSurfs;
vEntity->drawSurfs = surf;
}
}
}
// Most deform source surfaces do not need to be rendered.
// However, particles are rendered in conjunction with the source surface.
if( shaderDeform == DFRM_NONE || shaderDeform == DFRM_PARTICLE || shaderDeform == DFRM_PARTICLE2 )
{
// copy verts and indexes to this frame's hardware memory if they aren't already there
if( !vertexCache.CacheIsCurrent( tri->ambientCache ) )
{
tri->ambientCache = vertexCache.AllocVertex( tri->verts, ALIGN( tri->numVerts * sizeof( tri->verts[0] ), VERTEX_CACHE_ALIGN ) );
}
if( !vertexCache.CacheIsCurrent( tri->indexCache ) )
{
tri->indexCache = vertexCache.AllocIndex( tri->indexes, ALIGN( tri->numIndexes * sizeof( tri->indexes[0] ), INDEX_CACHE_ALIGN ) );
}
R_SetupDrawSurfJoints( baseDrawSurf, tri, shader );
baseDrawSurf->numIndexes = tri->numIndexes;
baseDrawSurf->ambientCache = tri->ambientCache;
baseDrawSurf->indexCache = tri->indexCache;
baseDrawSurf->shadowCache = 0;
baseDrawSurf->linkChain = NULL; // link to the view
baseDrawSurf->nextOnLight = vEntity->drawSurfs;
vEntity->drawSurfs = baseDrawSurf;
}
}
}
@ -810,104 +848,117 @@ void R_AddSingleModel( viewEntity_t* vEntity )
// contact the light, even when the total model does
if( surfInter == NULL || surfInter->lightTrisIndexCache > 0 )
{
// create a drawSurf for this interaction
drawSurf_t* lightDrawSurf = ( drawSurf_t* )R_FrameAlloc( sizeof( *lightDrawSurf ), FRAME_ALLOC_DRAW_SURFACE );
if( surfInter != NULL )
// make sure we have a valid shader register even if we didn't generate a drawn mesh above
if( shaderRegisters == NULL )
{
// optimized static interaction
lightDrawSurf->numIndexes = surfInter->numLightTrisIndexes;
lightDrawSurf->indexCache = surfInter->lightTrisIndexCache;
drawSurf_t scratchSurf;
R_SetupDrawSurfShader( &scratchSurf, shader, renderEntity );
shaderRegisters = scratchSurf.shaderRegisters;
}
else
if( shaderRegisters != NULL )
{
// throw the entire source surface at it without any per-triangle culling
lightDrawSurf->numIndexes = tri->numIndexes;
lightDrawSurf->indexCache = tri->indexCache;
// create a drawSurf for this interaction
drawSurf_t* lightDrawSurf = ( drawSurf_t* )R_FrameAlloc( sizeof( *lightDrawSurf ), FRAME_ALLOC_DRAW_SURFACE );
// optionally cull the triangles to the light volume
if( r_cullDynamicLightTriangles.GetBool() )
if( surfInter != NULL )
{
vertCacheHandle_t lightIndexCache = vertexCache.AllocIndex( NULL, ALIGN( lightDrawSurf->numIndexes * sizeof( triIndex_t ), INDEX_CACHE_ALIGN ) );
if( vertexCache.CacheIsCurrent( lightIndexCache ) )
// optimized static interaction
lightDrawSurf->numIndexes = surfInter->numLightTrisIndexes;
lightDrawSurf->indexCache = surfInter->lightTrisIndexCache;
}
else
{
// throw the entire source surface at it without any per-triangle culling
lightDrawSurf->numIndexes = tri->numIndexes;
lightDrawSurf->indexCache = tri->indexCache;
// optionally cull the triangles to the light volume
// motorsep 11-09-2014; added && shader->SurfaceCastsShadow() per Lordhavoc's recommendation; should skip shadows calculation for surfaces with noShadows material flag
// when using shadow volumes
if( r_cullDynamicLightTriangles.GetBool() && !r_skipDynamicShadows.GetBool() && !r_useShadowMapping.GetBool() && shader->SurfaceCastsShadow() )
{
lightDrawSurf->indexCache = lightIndexCache;
dynamicShadowParms = ( dynamicShadowVolumeParms_t* )R_FrameAlloc( sizeof( dynamicShadowParms[0] ), FRAME_ALLOC_SHADOW_VOLUME_PARMS );
dynamicShadowParms->verts = tri->verts;
dynamicShadowParms->numVerts = tri->numVerts;
dynamicShadowParms->indexes = tri->indexes;
dynamicShadowParms->numIndexes = tri->numIndexes;
dynamicShadowParms->silEdges = tri->silEdges;
dynamicShadowParms->numSilEdges = tri->numSilEdges;
dynamicShadowParms->joints = gpuSkinned ? tri->staticModelWithJoints->jointsInverted : NULL;
dynamicShadowParms->numJoints = gpuSkinned ? tri->staticModelWithJoints->numInvertedJoints : 0;
dynamicShadowParms->triangleBounds = tri->bounds;
dynamicShadowParms->triangleMVP = vEntity->mvp;
dynamicShadowParms->localLightOrigin = localLightOrigin;
dynamicShadowParms->localViewOrigin = localViewOrigin;
idRenderMatrix::Multiply( vLight->lightDef->baseLightProject, entityDef->modelRenderMatrix, dynamicShadowParms->localLightProject );
dynamicShadowParms->zNear = znear;
dynamicShadowParms->lightZMin = vLight->scissorRect.zmin;
dynamicShadowParms->lightZMax = vLight->scissorRect.zmax;
dynamicShadowParms->cullShadowTrianglesToLight = false;
dynamicShadowParms->forceShadowCaps = false;
dynamicShadowParms->useShadowPreciseInsideTest = false;
dynamicShadowParms->useShadowDepthBounds = false;
dynamicShadowParms->tempFacing = NULL;
dynamicShadowParms->tempCulled = NULL;
dynamicShadowParms->tempVerts = NULL;
dynamicShadowParms->indexBuffer = NULL;
dynamicShadowParms->shadowIndices = NULL;
dynamicShadowParms->maxShadowIndices = 0;
dynamicShadowParms->numShadowIndices = NULL;
dynamicShadowParms->lightIndices = ( triIndex_t* )vertexCache.MappedIndexBuffer( lightIndexCache );
dynamicShadowParms->maxLightIndices = lightDrawSurf->numIndexes;
dynamicShadowParms->numLightIndices = &lightDrawSurf->numIndexes;
dynamicShadowParms->renderZFail = NULL;
dynamicShadowParms->shadowZMin = NULL;
dynamicShadowParms->shadowZMax = NULL;
dynamicShadowParms->shadowVolumeState = & lightDrawSurf->shadowVolumeState;
lightDrawSurf->shadowVolumeState = SHADOWVOLUME_UNFINISHED;
dynamicShadowParms->next = vEntity->dynamicShadowVolumes;
vEntity->dynamicShadowVolumes = dynamicShadowParms;
vertCacheHandle_t lightIndexCache = vertexCache.AllocIndex( NULL, ALIGN( lightDrawSurf->numIndexes * sizeof( triIndex_t ), INDEX_CACHE_ALIGN ) );
if( vertexCache.CacheIsCurrent( lightIndexCache ) )
{
lightDrawSurf->indexCache = lightIndexCache;
dynamicShadowParms = ( dynamicShadowVolumeParms_t* )R_FrameAlloc( sizeof( dynamicShadowParms[0] ), FRAME_ALLOC_SHADOW_VOLUME_PARMS );
dynamicShadowParms->verts = tri->verts;
dynamicShadowParms->numVerts = tri->numVerts;
dynamicShadowParms->indexes = tri->indexes;
dynamicShadowParms->numIndexes = tri->numIndexes;
dynamicShadowParms->silEdges = tri->silEdges;
dynamicShadowParms->numSilEdges = tri->numSilEdges;
dynamicShadowParms->joints = gpuSkinned ? tri->staticModelWithJoints->jointsInverted : NULL;
dynamicShadowParms->numJoints = gpuSkinned ? tri->staticModelWithJoints->numInvertedJoints : 0;
dynamicShadowParms->triangleBounds = tri->bounds;
dynamicShadowParms->triangleMVP = vEntity->mvp;
dynamicShadowParms->localLightOrigin = localLightOrigin;
dynamicShadowParms->localViewOrigin = localViewOrigin;
idRenderMatrix::Multiply( vLight->lightDef->baseLightProject, entityDef->modelRenderMatrix, dynamicShadowParms->localLightProject );
dynamicShadowParms->zNear = znear;
dynamicShadowParms->lightZMin = vLight->scissorRect.zmin;
dynamicShadowParms->lightZMax = vLight->scissorRect.zmax;
dynamicShadowParms->cullShadowTrianglesToLight = false;
dynamicShadowParms->forceShadowCaps = false;
dynamicShadowParms->useShadowPreciseInsideTest = false;
dynamicShadowParms->useShadowDepthBounds = false;
dynamicShadowParms->tempFacing = NULL;
dynamicShadowParms->tempCulled = NULL;
dynamicShadowParms->tempVerts = NULL;
dynamicShadowParms->indexBuffer = NULL;
dynamicShadowParms->shadowIndices = NULL;
dynamicShadowParms->maxShadowIndices = 0;
dynamicShadowParms->numShadowIndices = NULL;
dynamicShadowParms->lightIndices = ( triIndex_t* )vertexCache.MappedIndexBuffer( lightIndexCache );
dynamicShadowParms->maxLightIndices = lightDrawSurf->numIndexes;
dynamicShadowParms->numLightIndices = &lightDrawSurf->numIndexes;
dynamicShadowParms->renderZFail = NULL;
dynamicShadowParms->shadowZMin = NULL;
dynamicShadowParms->shadowZMax = NULL;
dynamicShadowParms->shadowVolumeState = & lightDrawSurf->shadowVolumeState;
lightDrawSurf->shadowVolumeState = SHADOWVOLUME_UNFINISHED;
dynamicShadowParms->next = vEntity->dynamicShadowVolumes;
vEntity->dynamicShadowVolumes = dynamicShadowParms;
}
}
}
lightDrawSurf->ambientCache = tri->ambientCache;
lightDrawSurf->shadowCache = 0;
lightDrawSurf->frontEndGeo = tri;
lightDrawSurf->space = vEntity;
lightDrawSurf->material = shader;
lightDrawSurf->extraGLState = 0;
lightDrawSurf->scissorRect = vLight->scissorRect; // interactionScissor;
lightDrawSurf->sort = 0.0f;
lightDrawSurf->renderZFail = 0;
lightDrawSurf->shaderRegisters = shaderRegisters;
R_SetupDrawSurfJoints( lightDrawSurf, tri, shader );
// Determine which linked list to add the light surface to.
// There will only be localSurfaces if the light casts shadows and
// there are surfaces with NOSELFSHADOW.
if( shader->Coverage() == MC_TRANSLUCENT )
{
lightDrawSurf->linkChain = &vLight->translucentInteractions;
}
else if( !lightDef->parms.noShadows && shader->TestMaterialFlag( MF_NOSELFSHADOW ) )
{
lightDrawSurf->linkChain = &vLight->localInteractions;
}
else
{
lightDrawSurf->linkChain = &vLight->globalInteractions;
}
lightDrawSurf->nextOnLight = vEntity->drawSurfs;
vEntity->drawSurfs = lightDrawSurf;
}
lightDrawSurf->ambientCache = tri->ambientCache;
lightDrawSurf->shadowCache = 0;
lightDrawSurf->frontEndGeo = tri;
lightDrawSurf->space = vEntity;
lightDrawSurf->material = shader;
lightDrawSurf->extraGLState = 0;
lightDrawSurf->scissorRect = vLight->scissorRect; // interactionScissor;
lightDrawSurf->sort = 0.0f;
lightDrawSurf->renderZFail = 0;
lightDrawSurf->shaderRegisters = baseDrawSurf->shaderRegisters;
R_SetupDrawSurfJoints( lightDrawSurf, tri, shader );
// Determine which linked list to add the light surface to.
// There will only be localSurfaces if the light casts shadows and
// there are surfaces with NOSELFSHADOW.
if( shader->Coverage() == MC_TRANSLUCENT )
{
lightDrawSurf->linkChain = &vLight->translucentInteractions;
}
else if( !lightDef->parms.noShadows && shader->TestMaterialFlag( MF_NOSELFSHADOW ) )
{
lightDrawSurf->linkChain = &vLight->localInteractions;
}
else
{
lightDrawSurf->linkChain = &vLight->globalInteractions;
}
lightDrawSurf->nextOnLight = vEntity->drawSurfs;
vEntity->drawSurfs = lightDrawSurf;
}
}
@ -915,10 +966,51 @@ void R_AddSingleModel( viewEntity_t* vEntity )
// surface shadows
//--------------------------
#if 1
if( !shader->SurfaceCastsShadow() && !( r_useShadowMapping.GetBool() && r_forceShadowMapsOnAlphaTestedSurfaces.GetBool() && shader->Coverage() == MC_PERFORATED ) )
{
continue;
}
#else
// Steel Storm 2 behaviour - this destroys many alpha tested shadows in vanilla BFG
// motorsep 11-08-2014; if r_forceShadowMapsOnAlphaTestedSurfaces is 0 when shadow mapping is on,
// don't render shadows from all alphaTest surfaces.
// Useful as global performance booster for old GPUs to disable shadows from grass/foliage/etc.
if( r_useShadowMapping.GetBool() )
{
if( shader->Coverage() == MC_PERFORATED )
{
if( !r_forceShadowMapsOnAlphaTestedSurfaces.GetBool() )
continue;
}
}
// if material has "noShadows" global key
if( !shader->SurfaceCastsShadow() )
{
// motorsep 11-08-2014; if r_forceShadowMapsOnAlphaTestedSurfaces is 1 when shadow mapping is on,
// check if a surface IS NOT alphaTested and has "noShadows" global key;
// or if a surface IS alphaTested and has "noShadows" global key;
// if either is true, don't make surfaces cast shadow maps.
if( r_useShadowMapping.GetBool() )
{
if( shader->Coverage() != MC_PERFORATED && shader->TestMaterialFlag( MF_NOSHADOWS ) )
{
continue;
}
else if( shader->Coverage() == MC_PERFORATED && shader->TestMaterialFlag( MF_NOSHADOWS ) )
{
continue;
}
}
else
{
continue;
}
}
#endif
if( !lightDef->LightCastsShadows() )
{
continue;
@ -929,9 +1021,10 @@ void R_AddSingleModel( viewEntity_t* vEntity )
}
// if the static shadow does not have any shadows
if( surfInter != NULL && surfInter->numShadowIndexes == 0 && !r_useShadowMapping.GetBool() )
if( surfInter != NULL && surfInter->numShadowIndexes == 0 )
{
continue;
if( !r_useShadowMapping.GetBool() )
continue;
}
// some entities, like view weapons, don't cast any shadows
@ -946,6 +1039,7 @@ void R_AddSingleModel( viewEntity_t* vEntity )
continue;
}
// RB begin
if( r_useShadowMapping.GetBool() )
{
@ -1050,7 +1144,7 @@ void R_AddSingleModel( viewEntity_t* vEntity )
shadowDrawSurf->scissorRect = vLight->scissorRect; // default to the light scissor and light depth bounds
shadowDrawSurf->shadowVolumeState = SHADOWVOLUME_DONE; // assume the shadow volume is done in case r_skipStaticShadows is set
if( !r_skipStaticShadows.GetBool() )
if( !r_skipStaticShadows.GetBool() && !r_useShadowMapping.GetBool() )
{
staticShadowVolumeParms_t* staticShadowParms = ( staticShadowVolumeParms_t* )R_FrameAlloc( sizeof( staticShadowParms[0] ), FRAME_ALLOC_SHADOW_VOLUME_PARMS );
@ -1107,9 +1201,8 @@ void R_AddSingleModel( viewEntity_t* vEntity )
shadowDrawSurf->shadowVolumeState = SHADOWVOLUME_DONE; // assume the shadow volume is done in case the index cache allocation failed
// if the index cache was successfully allocated then setup the parms to create a shadow volume in parallel
if( vertexCache.CacheIsCurrent( shadowDrawSurf->indexCache ) && !r_skipDynamicShadows.GetBool() )
if( vertexCache.CacheIsCurrent( shadowDrawSurf->indexCache ) && !r_skipDynamicShadows.GetBool() && !r_useShadowMapping.GetBool() )
{
// if the parms were not already allocated for culling interaction triangles to the light frustum
if( dynamicShadowParms == NULL )
{
@ -1265,48 +1358,55 @@ void R_AddModels()
//-------------------------------------------------
// Kick off jobs to setup static and dynamic shadow volumes.
//-------------------------------------------------
if( r_useParallelAddShadows.GetInteger() == 1 )
if( ( r_skipStaticShadows.GetBool() && r_skipDynamicShadows.GetBool() ) || r_useShadowMapping.GetBool() )
{
for( viewEntity_t* vEntity = tr.viewDef->viewEntitys; vEntity != NULL; vEntity = vEntity->next )
{
for( staticShadowVolumeParms_t* shadowParms = vEntity->staticShadowVolumes; shadowParms != NULL; shadowParms = shadowParms->next )
{
tr.frontEndJobList->AddJob( ( jobRun_t )StaticShadowVolumeJob, shadowParms );
}
for( dynamicShadowVolumeParms_t* shadowParms = vEntity->dynamicShadowVolumes; shadowParms != NULL; shadowParms = shadowParms->next )
{
tr.frontEndJobList->AddJob( ( jobRun_t )DynamicShadowVolumeJob, shadowParms );
}
vEntity->staticShadowVolumes = NULL;
vEntity->dynamicShadowVolumes = NULL;
}
tr.frontEndJobList->Submit();
// wait here otherwise the shadow volume index buffer may be unmapped before all shadow volumes have been constructed
tr.frontEndJobList->Wait();
// no shadow volumes were chained to any entity, all are in DONE state, we don't need to Submit() or Wait()
}
else
{
int start = Sys_Microseconds();
for( viewEntity_t* vEntity = tr.viewDef->viewEntitys; vEntity != NULL; vEntity = vEntity->next )
if( r_useParallelAddShadows.GetInteger() == 1 )
{
for( staticShadowVolumeParms_t* shadowParms = vEntity->staticShadowVolumes; shadowParms != NULL; shadowParms = shadowParms->next )
for( viewEntity_t* vEntity = tr.viewDef->viewEntitys; vEntity != NULL; vEntity = vEntity->next )
{
StaticShadowVolumeJob( shadowParms );
for( staticShadowVolumeParms_t* shadowParms = vEntity->staticShadowVolumes; shadowParms != NULL; shadowParms = shadowParms->next )
{
tr.frontEndJobList->AddJob( ( jobRun_t )StaticShadowVolumeJob, shadowParms );
}
for( dynamicShadowVolumeParms_t* shadowParms = vEntity->dynamicShadowVolumes; shadowParms != NULL; shadowParms = shadowParms->next )
{
tr.frontEndJobList->AddJob( ( jobRun_t )DynamicShadowVolumeJob, shadowParms );
}
vEntity->staticShadowVolumes = NULL;
vEntity->dynamicShadowVolumes = NULL;
}
for( dynamicShadowVolumeParms_t* shadowParms = vEntity->dynamicShadowVolumes; shadowParms != NULL; shadowParms = shadowParms->next )
{
DynamicShadowVolumeJob( shadowParms );
}
vEntity->staticShadowVolumes = NULL;
vEntity->dynamicShadowVolumes = NULL;
tr.frontEndJobList->Submit();
// wait here otherwise the shadow volume index buffer may be unmapped before all shadow volumes have been constructed
tr.frontEndJobList->Wait();
}
else
{
int start = Sys_Microseconds();
for( viewEntity_t* vEntity = tr.viewDef->viewEntitys; vEntity != NULL; vEntity = vEntity->next )
{
for( staticShadowVolumeParms_t* shadowParms = vEntity->staticShadowVolumes; shadowParms != NULL; shadowParms = shadowParms->next )
{
StaticShadowVolumeJob( shadowParms );
}
for( dynamicShadowVolumeParms_t* shadowParms = vEntity->dynamicShadowVolumes; shadowParms != NULL; shadowParms = shadowParms->next )
{
DynamicShadowVolumeJob( shadowParms );
}
vEntity->staticShadowVolumes = NULL;
vEntity->dynamicShadowVolumes = NULL;
}
int end = Sys_Microseconds();
backEnd.pc.shadowMicroSec += end - start;
}
int end = Sys_Microseconds();
backEnd.pc.shadowMicroSec += end - start;
}
//-------------------------------------------------
// Move the draw surfs to the view.
//-------------------------------------------------