Improved shadow mapping performance using the shadow LOD and tweaked

polygon offsets to fight shadow acne
This commit is contained in:
Robert Beckebans 2014-05-11 22:30:01 +02:00
parent 5153422d0d
commit 0eaaea4b96
10 changed files with 92 additions and 43 deletions

View file

@ -185,13 +185,13 @@ void main( PS_IN fragment, out PS_OUT result )
shadowTexcoord.z = dot4( modelPosition, shadowMatrixZ );
shadowTexcoord.w = dot4( modelPosition, shadowMatrixW );
//float bias = 0.001 * tan( acos( ldotN ) );
//bias = clamp( bias, 0, 0.001 );
//float bias = 0.005 * tan( acos( ldotN ) );
//bias = clamp( bias, 0, 0.01 );
float bias = 0.001;
shadowTexcoord.xyz /= shadowTexcoord.w;
shadowTexcoord.z = shadowTexcoord.z * 0.9991;
//shadowTexcoord.z = shadowTexcoord.z - bias;
//shadowTexcoord.z = shadowTexcoord.z * 0.9991;
shadowTexcoord.z = shadowTexcoord.z - bias;
shadowTexcoord.w = float(shadowIndex);
#if 0

View file

@ -77,9 +77,14 @@ void Framebuffer::Init()
int width, height;
width = height = r_shadowMapImageSize.GetInteger();
globalFramebuffers.shadowFBO = new Framebuffer( "_shadowMap" , width, height );
globalFramebuffers.shadowFBO->Bind();
glDrawBuffers( 0, NULL );
for( int i = 0; i < MAX_SHADOWMAP_RESOLUTIONS; i++ )
{
width = height = shadowMapResolutions[i];
globalFramebuffers.shadowFBO[i] = new Framebuffer( "_shadowMap" , width, height );
globalFramebuffers.shadowFBO[i]->Bind();
glDrawBuffers( 0, NULL );
}
// globalFramebuffers.shadowFBO->AddColorBuffer( GL_RGBA8, 0 );
// globalFramebuffers.shadowFBO->AddDepthBuffer( GL_DEPTH_COMPONENT24 );
// globalFramebuffers.shadowFBO->Check();

View file

@ -29,6 +29,13 @@ If you have questions concerning this license or the applicable additional terms
#ifndef __FRAMEBUFFER_H__
#define __FRAMEBUFFER_H__
static const int MAX_SHADOWMAP_RESOLUTIONS = 5;
#if 1
static int shadowMapResolutions[MAX_SHADOWMAP_RESOLUTIONS] = { 2048, 1024, 512, 512, 256 };
#else
static int shadowMapResolutions[MAX_SHADOWMAP_RESOLUTIONS] = { 1024, 1024, 1024, 1024, 1024 };
#endif
class Framebuffer
{
public:
@ -82,7 +89,7 @@ private:
struct globalFramebuffers_t
{
Framebuffer* shadowFBO;
Framebuffer* shadowFBO[MAX_SHADOWMAP_RESOLUTIONS];
};
extern globalFramebuffers_t globalFramebuffers;

View file

@ -337,7 +337,7 @@ public:
idImage* fogImage; // increasing alpha is denser fog
idImage* fogEnterImage; // adjust fogImage alpha based on terminator plane
// RB begin
idImage* shadowImage;
idImage* shadowImage[5];
idImage* jitterImage1; // shadow jitter
idImage* jitterImage4;
idImage* jitterImage16;

View file

@ -451,9 +451,33 @@ void R_QuadraticImage( idImage* image )
}
// RB begin
static void R_CreateShadowMapImage( idImage* image )
static void R_CreateShadowMapImage_Res0( idImage* image )
{
int size = r_shadowMapImageSize.GetInteger();
int size = shadowMapResolutions[0];
image->GenerateShadowArray( size, size, TF_LINEAR, TR_CLAMP_TO_ZERO_ALPHA, TD_SHADOW_ARRAY );
}
static void R_CreateShadowMapImage_Res1( idImage* image )
{
int size = shadowMapResolutions[1];
image->GenerateShadowArray( size, size, TF_LINEAR, TR_CLAMP_TO_ZERO_ALPHA, TD_SHADOW_ARRAY );
}
static void R_CreateShadowMapImage_Res2( idImage* image )
{
int size = shadowMapResolutions[2];
image->GenerateShadowArray( size, size, TF_LINEAR, TR_CLAMP_TO_ZERO_ALPHA, TD_SHADOW_ARRAY );
}
static void R_CreateShadowMapImage_Res3( idImage* image )
{
int size = shadowMapResolutions[3];
image->GenerateShadowArray( size, size, TF_LINEAR, TR_CLAMP_TO_ZERO_ALPHA, TD_SHADOW_ARRAY );
}
static void R_CreateShadowMapImage_Res4( idImage* image )
{
int size = shadowMapResolutions[4];
image->GenerateShadowArray( size, size, TF_LINEAR, TR_CLAMP_TO_ZERO_ALPHA, TD_SHADOW_ARRAY );
}
@ -562,7 +586,11 @@ void idImageManager::CreateIntrinsicImages()
ImageFromFunction( "_quadratic", R_QuadraticImage );
// RB begin
shadowImage = ImageFromFunction( va( "_shadowMap%i_0", r_shadowMapImageSize.GetInteger() ), R_CreateShadowMapImage );
shadowImage[0] = ImageFromFunction( va( "_shadowMapArray%i", shadowMapResolutions[0] ), R_CreateShadowMapImage_Res0 );
shadowImage[1] = ImageFromFunction( va( "_shadowMapArray%i", shadowMapResolutions[1] ), R_CreateShadowMapImage_Res1 );
shadowImage[2] = ImageFromFunction( va( "_shadowMapArray%i", shadowMapResolutions[2] ), R_CreateShadowMapImage_Res2 );
shadowImage[3] = ImageFromFunction( va( "_shadowMapArray%i", shadowMapResolutions[3] ), R_CreateShadowMapImage_Res3 );
shadowImage[4] = ImageFromFunction( va( "_shadowMapArray%i", shadowMapResolutions[4] ), R_CreateShadowMapImage_Res4 );
jitterImage1 = globalImages->ImageFromFunction( "_jitter1", R_CreateJitterImage1 );
jitterImage4 = globalImages->ImageFromFunction( "_jitter4", R_CreateJitterImage4 );

View file

@ -222,8 +222,11 @@ idCVar r_shadowMapBiasScale( "r_shadowMapBiasScale", "0.0001", CVAR_RENDERER | C
idCVar r_shadowMapSamples( "r_shadowMapSamples", "16", CVAR_RENDERER | CVAR_INTEGER, "0, 1, 4, or 16" );
idCVar r_shadowMapSplits( "r_shadowMapSplits", "3", CVAR_RENDERER | CVAR_INTEGER, "number of splits for cascaded shadow mapping with parallel lights", 0, 4 );
idCVar r_shadowMapSplitWeight( "r_shadowMapSplitWeight", "0.9", CVAR_RENDERER | CVAR_FLOAT, "" );
idCVar r_shadowMapLodScale( "r_shadowMapLodScale", "0.8", CVAR_RENDERER | CVAR_FLOAT, "" );
idCVar r_shadowMapLodScale( "r_shadowMapLodScale", "1.4", CVAR_RENDERER | CVAR_FLOAT, "" );
idCVar r_shadowMapLodBias( "r_shadowMapLodBias", "0", CVAR_RENDERER | CVAR_INTEGER, "" );
idCVar r_shadowMapPolygonFactor( "r_shadowMapPolygonFactor", "2", CVAR_RENDERER | CVAR_FLOAT, "polygonOffset factor for drawing shadow buffer" );
idCVar r_shadowMapPolygonOffset( "r_shadowMapPolygonOffset", "3000", CVAR_RENDERER | CVAR_FLOAT, "polygonOffset units for drawing shadow buffer" );
idCVar r_shadowMapOccluderFacing( "r_shadowMapOccluderFacing", "2", CVAR_RENDERER | CVAR_INTEGER, "0 = front faces, 1 = back faces, 2 = twosided" );
// RB end

View file

@ -1346,7 +1346,7 @@ static void RB_RenderInteractions( const drawSurf_t* surfList, const viewLight_t
{
// texture 5 will be the shadow maps array
GL_SelectTexture( INTERACTION_TEXUNIT_SHADOWMAPS );
globalImages->shadowImage->Bind();
globalImages->shadowImage[vLight->shadowLOD]->Bind();
// texture 6 will be the jitter texture for soft shadowing
GL_SelectTexture( INTERACTION_TEXUNIT_JITTER );
@ -2237,18 +2237,28 @@ static void RB_ShadowMapPass( const drawSurf_t* drawSurfs, const viewLight_t* vL
uint64 glState = 0;
//GL_PolygonOffset( r_shadowPolygonFactor.GetFloat(), -r_shadowPolygonOffset.GetFloat() );
// the actual stencil func will be set in the draw code, but we need to make sure it isn't
// disabled here, and that the value will get reset for the interactions without looking
// like a no-change-required
//GL_State( glState | GLS_POLYGON_OFFSET );
GL_State( glState | GLS_POLYGON_OFFSET );
GL_State( GLS_DEFAULT );
// Two Sided Stencil reduces two draw calls to one for slightly faster shadows
GL_Cull( CT_TWO_SIDED );
switch( r_shadowMapOccluderFacing.GetInteger() )
{
case 0:
GL_Cull( CT_FRONT_SIDED );
GL_PolygonOffset( r_shadowMapPolygonFactor.GetFloat(), r_shadowMapPolygonOffset.GetFloat() );
break;
case 1:
GL_Cull( CT_BACK_SIDED );
GL_PolygonOffset( -r_shadowMapPolygonFactor.GetFloat(), -r_shadowMapPolygonOffset.GetFloat() );
break;
default:
GL_Cull( CT_TWO_SIDED );
GL_PolygonOffset( r_shadowMapPolygonFactor.GetFloat(), r_shadowMapPolygonOffset.GetFloat() );
break;
}
idRenderMatrix lightProjectionRenderMatrix;
idRenderMatrix lightViewRenderMatrix;
@ -2546,20 +2556,20 @@ static void RB_ShadowMapPass( const drawSurf_t* drawSurfs, const viewLight_t* vL
globalFramebuffers.shadowFBO->Bind();
globalFramebuffers.shadowFBO[vLight->shadowLOD]->Bind();
if( side < 0 )
{
globalFramebuffers.shadowFBO->AttachImageDepthLayer( globalImages->shadowImage, 0 );
globalFramebuffers.shadowFBO[vLight->shadowLOD]->AttachImageDepthLayer( globalImages->shadowImage[vLight->shadowLOD], 0 );
}
else
{
globalFramebuffers.shadowFBO->AttachImageDepthLayer( globalImages->shadowImage, side );
globalFramebuffers.shadowFBO[vLight->shadowLOD]->AttachImageDepthLayer( globalImages->shadowImage[vLight->shadowLOD], side );
}
globalFramebuffers.shadowFBO->Check();
globalFramebuffers.shadowFBO[vLight->shadowLOD]->Check();
GL_ViewportAndScissor( 0, 0, r_shadowMapImageSize.GetInteger(), r_shadowMapImageSize.GetInteger() );
GL_ViewportAndScissor( 0, 0, shadowMapResolutions[vLight->shadowLOD], shadowMapResolutions[vLight->shadowLOD] );
glClear( GL_DEPTH_BUFFER_BIT );

View file

@ -1888,20 +1888,11 @@ static void RB_ShowShadowMapLODs()
int count = 0;
for( viewLight_t* vLight = backEnd.viewDef->viewLights; vLight != NULL; vLight = vLight->next )
{
#if 0
const idMaterial* lightShader = vLight->lightShader;
if( lightShader->IsFogLight() )
if( !vLight->lightDef->LightCastsShadows() )
{
continue;
}
if( lightShader->IsBlendLight() )
{
continue;
}
#endif
count++;
// depth buffered planes
@ -2925,7 +2916,7 @@ void RB_ShowShadowMaps()
if( !r_showShadowMaps.GetBool() )
return;
image = globalImages->shadowImage;
image = globalImages->shadowImage[0];
if( !image )
{
return;

View file

@ -266,7 +266,7 @@ static void R_AddSingleLight( viewLight_t* vLight )
vLight->scissorRect.zmax = projected[1][2];
// RB: calculate shadow LOD similar to Q3A .md3 LOD code
vLight->shadowLOD = -1;
vLight->shadowLOD = 0;
if( r_useShadowMapping.GetBool() && lightCastsShadows )
{
@ -275,7 +275,7 @@ static void R_AddSingleLight( viewLight_t* vLight )
int lod;
int numLods;
numLods = 5;
numLods = MAX_SHADOWMAP_RESOLUTIONS;
// compute projected bounding sphere
// and use that as a criteria for selecting LOD
@ -323,15 +323,17 @@ static void R_AddSingleLight( viewLight_t* vLight )
if( lod >= numLods )
{
// don't draw any shadow
lod = -1;
//lod = -1;
//lod = numLods - 1;
lod = numLods - 1;
}
// never give ultra quality for point lights
if( lod == 0 && light->parms.pointLight )
{
lod = 1;
}
vLight->shadowLOD = lod;
}
// RB end

View file

@ -1065,6 +1065,9 @@ extern idCVar r_shadowMapSplits;
extern idCVar r_shadowMapSplitWeight;
extern idCVar r_shadowMapLodScale;
extern idCVar r_shadowMapLodBias;
extern idCVar r_shadowMapPolygonFactor;
extern idCVar r_shadowMapPolygonOffset;
extern idCVar r_shadowMapOccluderFacing;
// RB end
/*