Added Vogel Disk Sampling by Panos Karabelas

This commit is contained in:
Robert Beckebans 2020-05-11 23:49:04 +02:00
parent 99235ec92c
commit 1b3378cb94
6 changed files with 134 additions and 26 deletions

View file

@ -77,7 +77,7 @@ The main goal is that the new content looks the same in RBDOOM-3-BFG as in Blend
* Added Blue Noise based Filmic Dithering by Timothy Lottes and Chromatic Aberration
* Improved Shadow Mapping performance by reducing the number of taps from 12 to 6 and keeping a good quality using dithering the result with Blue Noise magic by Alan Wolfe
* Improved Shadow Mapping quality with Vogel Disk Sampling by Panos Karabelas and using dithering the result with Blue Noise magic by Alan Wolfe
* Improved Screen Space Ambient Occlusion performance by enhancing the quality with Blue Noise and skipping the expensive extra bilateral filtering pass

View file

@ -278,6 +278,16 @@ float RemapNoiseTriErp( const float v )
// http://advances.realtimerendering.com/s2014/index.html
float InterleavedGradientNoise( float2 uv )
{
const float3 magic = float3( 0.06711056, 0.00583715, 52.9829189 );
float rnd = fract( magic.z * fract( dot( uv, magic.xy ) ) );
return rnd;
}
// this noise, including the 5.58... scrolling constant are from Jorge Jimenez
float InterleavedGradientNoiseAnim( float2 uv, float frameIndex )
{
uv += ( frameIndex * 5.588238f );
const float3 magic = float3( 0.06711056, 0.00583715, 52.9829189 );
float rnd = fract( magic.z * fract( dot( uv, magic.xy ) ) );

View file

@ -4,6 +4,7 @@
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
Copyright (C) 2013-2020 Robert Beckebans
Copyright (C) 2020 Panos Karabelas
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
@ -76,6 +77,19 @@ float BlueNoise( float2 n, float x )
return noise;
}
float2 VogelDiskSample( float sampleIndex, float samplesCount, float phi )
{
float goldenAngle = 2.4f;
float r = sqrt( sampleIndex + 0.5f ) / sqrt( samplesCount );
float theta = sampleIndex * goldenAngle + phi;
float sine = sin( theta );
float cosine = cos( theta );
return float2( r * cosine, r * sine );
}
void main( PS_IN fragment, out PS_OUT result )
{
half4 bumpMap = tex2D( samp0, fragment.texcoord1.xy );
@ -228,7 +242,7 @@ void main( PS_IN fragment, out PS_OUT result )
float numSamples = 16;
float stepSize = 1.0 / numSamples;
float4 jitterTC = ( fragment.position * rpScreenCorrectionFactor ) + rpJitterTexOffset;
float2 jitterTC = ( fragment.position.xy * rpScreenCorrectionFactor.xy ) + rpJitterTexOffset.ww;
for( float i = 0.0; i < numSamples; i += 1.0 )
{
float4 jitter = base + tex2D( samp6, jitterTC.xy ) * rpJitterTexScale;
@ -240,8 +254,11 @@ void main( PS_IN fragment, out PS_OUT result )
shadow *= stepSize;
#elif 0
// Poisson Disk with White Noise used for years int RBDOOM-3-BFG
const float2 poissonDisk[12] = float2[](
float2( 0.6111618, 0.1050905 ),
float2( 0.1088336, 0.1127091 ),
@ -285,9 +302,12 @@ void main( PS_IN fragment, out PS_OUT result )
shadow *= stepSize;
#elif 1
#if 0
// Poisson Disk with animated Blue Noise or Interleaved Gradient Noise
const float2 poissonDisk[12] = float2[](
float2( 0.6111618, 0.1050905 ),
float2( 0.1088336, 0.1127091 ),
@ -305,15 +325,11 @@ void main( PS_IN fragment, out PS_OUT result )
float shadow = 0.0;
// RB: casting a float to int and using it as index can really kill the performance ...
float numSamples = 6.0;
float numSamples = 12.0;
float stepSize = 1.0 / numSamples;
//float4 jitterTC = ( fragment.position * rpScreenCorrectionFactor ) + rpJitterTexOffset;
//float random = tex2D( samp6, jitterTC.xy ).x;
float random = BlueNoise( fragment.position.xy, 100.0 );
//float random = InterleavedGradientNoise( fragment.position.xy );
float random = BlueNoise( fragment.position.xy, 1.0 );
//float random = InterleavedGradientNoiseAnim( fragment.position.xy, rpJitterTexOffset.w );
random *= PI;
@ -322,7 +338,7 @@ void main( PS_IN fragment, out PS_OUT result )
rot.y = sin( random );
float shadowTexelSize = rpScreenCorrectionFactor.z * rpJitterTexScale.x;
for( int i = 0; i < 6; i++ )
for( int i = 0; i < 12; i++ )
{
float2 jitter = poissonDisk[i];
float2 jitterRotated;
@ -336,6 +352,34 @@ void main( PS_IN fragment, out PS_OUT result )
shadow *= stepSize;
#else
// Vogel Disk Sampling
// https://twitter.com/panoskarabelas1/status/1222663889659355140
// this approach is more dynamic and can be controlled by r_shadowMapSamples
float shadow = 0.0;
float numSamples = rpJitterTexScale.w;
float stepSize = 1.0 / numSamples;
float vogelPhi = BlueNoise( fragment.position.xy, 1.0 );
//float vogelPhi = InterleavedGradientNoiseAnim( fragment.position.xy, rpJitterTexOffset.w );
float shadowTexelSize = rpScreenCorrectionFactor.z * rpJitterTexScale.x;
for( float i = 0; i < numSamples; i += 1.0 )
{
float2 jitter = VogelDiskSample( i, numSamples, vogelPhi );
float4 shadowTexcoordJittered = float4( shadowTexcoord.xy + jitter * shadowTexelSize, shadowTexcoord.z, shadowTexcoord.w );
shadow += texture( samp5, shadowTexcoordJittered.xywz );
}
shadow *= stepSize;
#endif
#else
float shadow = texture( samp5, shadowTexcoord.xywz );
@ -374,7 +418,7 @@ void main( PS_IN fragment, out PS_OUT result )
half3 specularColor = specMapSRGB.rgb; // RB: should be linear but it looks too flat
#endif
//diffuseColor = half3( 1.0 );
diffuseColor = half3( 1.0 );
// RB: compensate r_lightScale 3 and the division of Pi
//lambert *= 1.3;

View file

@ -1677,7 +1677,7 @@ void idRenderBackend::RenderInteractions( const drawSurf_t* surfList, const view
jitterTexScale[0] = r_shadowMapJitterScale.GetFloat() * jitterSampleScale; // TODO shadow buffer size fraction shadowMapSize / maxShadowMapSize
jitterTexScale[1] = r_shadowMapJitterScale.GetFloat() * jitterSampleScale;
jitterTexScale[2] = -r_shadowMapBiasScale.GetFloat();
jitterTexScale[3] = 0.0f;
jitterTexScale[3] = shadowMapSamples;
SetFragmentParm( RENDERPARM_JITTERTEXSCALE, jitterTexScale ); // rpJitterTexScale
float jitterTexOffset[4];

View file

@ -292,6 +292,16 @@ static const cgShaderDef_t cg_renderprogs[] =
"// http://advances.realtimerendering.com/s2014/index.html\n"
"float InterleavedGradientNoise( float2 uv )\n"
"{\n"
" const float3 magic = float3( 0.06711056, 0.00583715, 52.9829189 );\n"
" float rnd = fract( magic.z * fract( dot( uv, magic.xy ) ) );\n"
"\n"
" return rnd;\n"
"}\n"
"\n"
"// this noise, including the 5.58... scrolling constant are from Jorge Jimenez\n"
"float InterleavedGradientNoiseAnim( float2 uv, float frameIndex )\n"
"{\n"
" uv += ( frameIndex * 5.588238f );\n"
"\n"
" const float3 magic = float3( 0.06711056, 0.00583715, 52.9829189 );\n"
" float rnd = fract( magic.z * fract( dot( uv, magic.xy ) ) );\n"
@ -9806,6 +9816,7 @@ static const cgShaderDef_t cg_renderprogs[] =
"Doom 3 BFG Edition GPL Source Code\n"
"Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.\n"
"Copyright (C) 2013-2020 Robert Beckebans\n"
"Copyright (C) 2020 Panos Karabelas\n"
"\n"
"This file is part of the Doom 3 BFG Edition GPL Source Code (\"Doom 3 BFG Edition Source Code\").\n"
"\n"
@ -9878,6 +9889,19 @@ static const cgShaderDef_t cg_renderprogs[] =
" return noise;\n"
"}\n"
"\n"
"float2 VogelDiskSample( float sampleIndex, float samplesCount, float phi )\n"
"{\n"
" float goldenAngle = 2.4f;\n"
"\n"
" float r = sqrt( sampleIndex + 0.5f ) / sqrt( samplesCount );\n"
" float theta = sampleIndex * goldenAngle + phi;\n"
"\n"
" float sine = sin( theta );\n"
" float cosine = cos( theta );\n"
"\n"
" return float2( r * cosine, r * sine );\n"
"}\n"
"\n"
"void main( PS_IN fragment, out PS_OUT result )\n"
"{\n"
" half4 bumpMap = tex2D( samp0, fragment.texcoord1.xy );\n"
@ -10030,7 +10054,7 @@ static const cgShaderDef_t cg_renderprogs[] =
" float numSamples = 16;\n"
" float stepSize = 1.0 / numSamples;\n"
"\n"
" float4 jitterTC = ( fragment.position * rpScreenCorrectionFactor ) + rpJitterTexOffset;\n"
" float2 jitterTC = ( fragment.position.xy * rpScreenCorrectionFactor.xy ) + rpJitterTexOffset.ww;\n"
" for( float i = 0.0; i < numSamples; i += 1.0 )\n"
" {\n"
" float4 jitter = base + tex2D( samp6, jitterTC.xy ) * rpJitterTexScale;\n"
@ -10042,8 +10066,11 @@ static const cgShaderDef_t cg_renderprogs[] =
"\n"
" shadow *= stepSize;\n"
"\n"
"\n"
"#elif 0\n"
"\n"
" // Poisson Disk with White Noise used for years int RBDOOM-3-BFG\n"
"\n"
" const float2 poissonDisk[12] = float2[](\n"
" float2( 0.6111618, 0.1050905 ),\n"
" float2( 0.1088336, 0.1127091 ),\n"
@ -10087,9 +10114,12 @@ static const cgShaderDef_t cg_renderprogs[] =
"\n"
" shadow *= stepSize;\n"
"\n"
"\n"
"#elif 1\n"
"\n"
"#if 0\n"
"\n"
" // Poisson Disk with animated Blue Noise or Interleaved Gradient Noise\n"
"\n"
" const float2 poissonDisk[12] = float2[](\n"
" float2( 0.6111618, 0.1050905 ),\n"
" float2( 0.1088336, 0.1127091 ),\n"
@ -10107,15 +10137,11 @@ static const cgShaderDef_t cg_renderprogs[] =
" float shadow = 0.0;\n"
"\n"
" // RB: casting a float to int and using it as index can really kill the performance ...\n"
" float numSamples = 6.0;\n"
" float numSamples = 12.0;\n"
" float stepSize = 1.0 / numSamples;\n"
"\n"
" //float4 jitterTC = ( fragment.position * rpScreenCorrectionFactor ) + rpJitterTexOffset;\n"
" //float random = tex2D( samp6, jitterTC.xy ).x;\n"
"\n"
" float random = BlueNoise( fragment.position.xy, 100.0 );\n"
"\n"
" //float random = InterleavedGradientNoise( fragment.position.xy );\n"
" float random = BlueNoise( fragment.position.xy, 1.0 );\n"
" //float random = InterleavedGradientNoiseAnim( fragment.position.xy, rpJitterTexOffset.w );\n"
"\n"
" random *= PI;\n"
"\n"
@ -10124,7 +10150,7 @@ static const cgShaderDef_t cg_renderprogs[] =
" rot.y = sin( random );\n"
"\n"
" float shadowTexelSize = rpScreenCorrectionFactor.z * rpJitterTexScale.x;\n"
" for( int i = 0; i < 6; i++ )\n"
" for( int i = 0; i < 12; i++ )\n"
" {\n"
" float2 jitter = poissonDisk[i];\n"
" float2 jitterRotated;\n"
@ -10140,6 +10166,34 @@ static const cgShaderDef_t cg_renderprogs[] =
"\n"
"#else\n"
"\n"
" // Vogel Disk Sampling\n"
" // https://twitter.com/panoskarabelas1/status/1222663889659355140\n"
"\n"
" // this approach is more dynamic and can be controlled by r_shadowMapSamples\n"
"\n"
" float shadow = 0.0;\n"
"\n"
" float numSamples = rpJitterTexScale.w;\n"
" float stepSize = 1.0 / numSamples;\n"
"\n"
" float vogelPhi = BlueNoise( fragment.position.xy, 1.0 );\n"
" //float vogelPhi = InterleavedGradientNoiseAnim( fragment.position.xy, rpJitterTexOffset.w );\n"
"\n"
" float shadowTexelSize = rpScreenCorrectionFactor.z * rpJitterTexScale.x;\n"
" for( float i = 0; i < numSamples; i += 1.0 )\n"
" {\n"
" float2 jitter = VogelDiskSample( i, numSamples, vogelPhi );\n"
"\n"
" float4 shadowTexcoordJittered = float4( shadowTexcoord.xy + jitter * shadowTexelSize, shadowTexcoord.z, shadowTexcoord.w );\n"
"\n"
" shadow += texture( samp5, shadowTexcoordJittered.xywz );\n"
" }\n"
"\n"
" shadow *= stepSize;\n"
"#endif\n"
"\n"
"#else\n"
"\n"
" float shadow = texture( samp5, shadowTexcoord.xywz );\n"
"#endif\n"
"\n"
@ -10176,7 +10230,7 @@ static const cgShaderDef_t cg_renderprogs[] =
" half3 specularColor = specMapSRGB.rgb; // RB: should be linear but it looks too flat\n"
"#endif\n"
"\n"
" //diffuseColor = half3( 1.0 );\n"
" diffuseColor = half3( 1.0 );\n"
"\n"
" // RB: compensate r_lightScale 3 and the division of Pi\n"
" //lambert *= 1.3;\n"

View file

@ -245,10 +245,10 @@ idCVar r_useVirtualScreenResolution( "r_useVirtualScreenResolution", "1", CVAR_R
idCVar r_shadowMapFrustumFOV( "r_shadowMapFrustumFOV", "92", CVAR_RENDERER | CVAR_FLOAT, "oversize FOV for point light side matching" );
idCVar r_shadowMapSingleSide( "r_shadowMapSingleSide", "-1", CVAR_RENDERER | CVAR_INTEGER, "only draw a single side (0-5) of point lights" );
idCVar r_shadowMapImageSize( "r_shadowMapImageSize", "1024", CVAR_RENDERER | CVAR_INTEGER, "", 128, 2048 );
idCVar r_shadowMapJitterScale( "r_shadowMapJitterScale", "3", CVAR_RENDERER | CVAR_FLOAT, "scale factor for jitter offset" );
idCVar r_shadowMapJitterScale( "r_shadowMapJitterScale", "2.5", CVAR_RENDERER | CVAR_FLOAT, "scale factor for jitter offset" );
idCVar r_shadowMapBiasScale( "r_shadowMapBiasScale", "0.0001", CVAR_RENDERER | CVAR_FLOAT, "scale factor for jitter bias" );
idCVar r_shadowMapRandomizeJitter( "r_shadowMapRandomizeJitter", "1", CVAR_RENDERER | CVAR_BOOL, "randomly offset jitter texture each draw" );
idCVar r_shadowMapSamples( "r_shadowMapSamples", "1", CVAR_RENDERER | CVAR_INTEGER, "0, 1, 4, or 16" );
idCVar r_shadowMapSamples( "r_shadowMapSamples", "16", CVAR_RENDERER | CVAR_INTEGER, "1, 4, 12 or 16", 1, 64 );
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", "1.4", CVAR_RENDERER | CVAR_FLOAT, "" );