mirror of
https://github.com/id-Software/DOOM-3-BFG.git
synced 2025-03-13 22:22:05 +00:00
Failed specular AA experiment but better PBR shader
This commit is contained in:
parent
80c52c50c8
commit
f3fd486c60
6 changed files with 128 additions and 58 deletions
|
@ -573,6 +573,7 @@ public:
|
|||
idImage* blackImage; // full of 0x00
|
||||
idImage* blackDiffuseImage; // full of 0x00
|
||||
idImage* cyanImage; // cyan
|
||||
idImage* redClayImage; // dark red
|
||||
idImage* noFalloffImage; // all 255, but zero clamped
|
||||
idImage* fogImage; // increasing alpha is denser fog
|
||||
idImage* fogEnterImage; // adjust fogImage alpha based on terminator plane
|
||||
|
|
|
@ -170,6 +170,24 @@ static void R_CyanImage( idImage* image, nvrhi::ICommandList* commandList )
|
|||
image->GenerateImage( ( byte* )data, DEFAULT_SIZE, DEFAULT_SIZE, TF_DEFAULT, TR_REPEAT, TD_DIFFUSE, commandList );
|
||||
}
|
||||
|
||||
static void R_RedClayImage( idImage* image, nvrhi::ICommandList* commandList )
|
||||
{
|
||||
byte data[DEFAULT_SIZE][DEFAULT_SIZE][4];
|
||||
|
||||
for( int x = 0; x < DEFAULT_SIZE; x++ )
|
||||
{
|
||||
for( int y = 0; y < DEFAULT_SIZE; y++ )
|
||||
{
|
||||
data[y][x][0] = 165;
|
||||
data[y][x][1] = 42;
|
||||
data[y][x][2] = 42;
|
||||
data[y][x][3] = 255;
|
||||
}
|
||||
}
|
||||
|
||||
image->GenerateImage( ( byte* )data, DEFAULT_SIZE, DEFAULT_SIZE, TF_DEFAULT, TR_REPEAT, TD_DIFFUSE, commandList );
|
||||
}
|
||||
|
||||
static void R_ChromeSpecImage( idImage* image, nvrhi::ICommandList* commandList )
|
||||
{
|
||||
byte data[DEFAULT_SIZE][DEFAULT_SIZE][4];
|
||||
|
@ -181,7 +199,7 @@ static void R_ChromeSpecImage( idImage* image, nvrhi::ICommandList* commandList
|
|||
data[y][x][0] = 0;
|
||||
data[y][x][1] = 255;
|
||||
data[y][x][2] = 255;
|
||||
data[y][x][3] = 255;
|
||||
data[y][x][3] = 128;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -196,10 +214,10 @@ static void R_PlasticSpecImage( idImage* image, nvrhi::ICommandList* commandList
|
|||
{
|
||||
for( int y = 0; y < DEFAULT_SIZE; y++ )
|
||||
{
|
||||
data[y][x][0] = 0;
|
||||
data[y][x][0] = 32;
|
||||
data[y][x][1] = 0;
|
||||
data[y][x][2] = 255;
|
||||
data[y][x][3] = 255;
|
||||
data[y][x][3] = 128;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1046,6 +1064,7 @@ void idImageManager::CreateIntrinsicImages()
|
|||
blackImage = ImageFromFunction( "_black", R_BlackImage );
|
||||
blackDiffuseImage = ImageFromFunction( "_blackDiffuse", R_BlackDiffuseImage );
|
||||
cyanImage = ImageFromFunction( "_cyan", R_CyanImage );
|
||||
redClayImage = ImageFromFunction( "_redClay", R_RedClayImage );
|
||||
flatNormalMap = ImageFromFunction( "_flat", R_FlatNormalImage );
|
||||
alphaNotchImage = ImageFromFunction( "_alphaNotch", R_AlphaNotchImage );
|
||||
fogImage = ImageFromFunction( "_fog", R_FogImage );
|
||||
|
|
|
@ -994,7 +994,14 @@ void idRenderBackend::DrawSingleInteraction( drawInteraction_t* din, bool useFas
|
|||
return;
|
||||
}
|
||||
|
||||
if( r_skipDiffuse.GetInteger() == 2 )
|
||||
if( r_skipDiffuse.GetInteger() == 3 )
|
||||
{
|
||||
// RB: for testing specular aliasing
|
||||
din->diffuseImage = globalImages->redClayImage;
|
||||
din->specularImage = globalImages->plasticSpecImage;
|
||||
din->specularColor = colorWhite;
|
||||
}
|
||||
else if( r_skipDiffuse.GetInteger() == 2 )
|
||||
{
|
||||
din->diffuseImage = globalImages->whiteImage;
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ If you have questions concerning this license or the applicable additional terms
|
|||
|
||||
// Normal Distribution Function ( NDF ) or D( h )
|
||||
// GGX ( Trowbridge-Reitz )
|
||||
half Distribution_GGX( half hdotN, half alpha )
|
||||
float Distribution_GGX( float hdotN, float alpha )
|
||||
{
|
||||
// alpha is assumed to be roughness^2
|
||||
float a2 = alpha * alpha;
|
||||
|
@ -38,16 +38,17 @@ half Distribution_GGX( half hdotN, half alpha )
|
|||
return ( a2 / ( PI * tmp * tmp ) );
|
||||
}
|
||||
|
||||
half Distribution_GGX_Disney( half hdotN, half alphaG )
|
||||
float Distribution_GGX_Disney( float hdotN, float alphaG )
|
||||
{
|
||||
float a2 = alphaG * alphaG;
|
||||
float tmp = ( hdotN * hdotN ) * ( a2 - 1.0 ) + 1.0;
|
||||
//tmp *= tmp;
|
||||
tmp *= tmp;
|
||||
|
||||
return ( a2 / ( PI * tmp ) );
|
||||
//return ( a2 / ( PI * tmp ) );
|
||||
return ( a2 / tmp );
|
||||
}
|
||||
|
||||
half Distribution_GGX_1886( half hdotN, half alpha )
|
||||
float Distribution_GGX_1886( float hdotN, float alpha )
|
||||
{
|
||||
// alpha is assumed to be roughness^2
|
||||
return ( alpha / ( PI * pow( hdotN * hdotN * ( alpha - 1.0 ) + 1.0, 2.0 ) ) );
|
||||
|
@ -55,16 +56,16 @@ half Distribution_GGX_1886( half hdotN, half alpha )
|
|||
|
||||
// Fresnel term F( v, h )
|
||||
// Fnone( v, h ) = F(0) = specularColor
|
||||
half3 Fresnel_Schlick( half3 specularColor, half vDotN )
|
||||
float3 Fresnel_Schlick( float3 specularColor, float vDotN )
|
||||
{
|
||||
return specularColor + ( 1.0 - specularColor ) * pow( 1.0 - vDotN, 5.0 );
|
||||
}
|
||||
|
||||
// Fresnel term that takes roughness into account so rough non-metal surfaces aren't too shiny [Lagarde11]
|
||||
half3 Fresnel_SchlickRoughness( half3 specularColor, half vDotN, half roughness )
|
||||
float3 Fresnel_SchlickRoughness( float3 specularColor, float vDotN, float roughness )
|
||||
{
|
||||
float oneMinusRoughness = 1.0 - roughness;
|
||||
return specularColor + ( max( half3( oneMinusRoughness, oneMinusRoughness, oneMinusRoughness ), specularColor ) - specularColor ) * pow( 1.0 - vDotN, 5.0 );
|
||||
return specularColor + ( max( float3( oneMinusRoughness, oneMinusRoughness, oneMinusRoughness ), specularColor ) - specularColor ) * pow( 1.0 - vDotN, 5.0 );
|
||||
}
|
||||
|
||||
// Sebastien Lagarde proposes an empirical approach to derive the specular occlusion term from the diffuse occlusion term in [Lagarde14].
|
||||
|
@ -77,21 +78,21 @@ float ComputeSpecularAO( float vDotN, float ao, float roughness )
|
|||
|
||||
// Visibility term G( l, v, h )
|
||||
// Very similar to Marmoset Toolbag 2 and gives almost the same results as Smith GGX
|
||||
float Visibility_Schlick( half vdotN, half ldotN, float alpha )
|
||||
float Visibility_Schlick( float vdotN, float ldotN, float alpha )
|
||||
{
|
||||
float k = alpha * 0.5;
|
||||
|
||||
float schlickL = ( ldotN * ( 1.0 - k ) + k );
|
||||
float schlickV = ( vdotN * ( 1.0 - k ) + k );
|
||||
|
||||
return ( 0.25 / ( schlickL * schlickV ) );
|
||||
return ( 0.25 / max( 0.001, schlickL * schlickV ) );
|
||||
//return ( ( schlickL * schlickV ) / ( 4.0 * vdotN * ldotN ) );
|
||||
}
|
||||
|
||||
// see s2013_pbs_rad_notes.pdf
|
||||
// Crafting a Next-Gen Material Pipeline for The Order: 1886
|
||||
// this visibility function also provides some sort of back lighting
|
||||
float Visibility_SmithGGX( half vdotN, half ldotN, float alpha )
|
||||
float Visibility_SmithGGX( float vdotN, float ldotN, float alpha )
|
||||
{
|
||||
// alpha is already roughness^2
|
||||
|
||||
|
@ -148,73 +149,100 @@ void PBRFromSpecmap( float3 specMap, out float3 F0, out float roughness )
|
|||
// RB: do another sqrt because PBR shader squares it
|
||||
roughness = sqrt( roughness );
|
||||
}
|
||||
|
||||
// takes roughness, unnormalized 0-1 normalmap texture and the distance to the camera
|
||||
// returns roughness
|
||||
float ApplySpecularAA( float roughness, float3 bumpMap, float camDist )
|
||||
{
|
||||
float normLen = saturate( length( bumpMap.xyz * 2.0 - 1.0 ) );
|
||||
|
||||
// roughness to specular power
|
||||
float specPow = ( 2.0 / ( roughness * roughness ) ) - 2.0;
|
||||
|
||||
// toksvig AA to prevent speckles from sharp normal edges
|
||||
float specAA = 1.0 / ( 1.0 + specPow * ( ( 1.0 / normLen ) - 1.0 ) );
|
||||
|
||||
// fade out AA close to the camera to prevent dull highlights close up
|
||||
float distMax = 100.0;
|
||||
float disMin = 1.0;
|
||||
specAA = lerp( specAA, 1.0, smoothstep( disMin, distMax, camDist ) );
|
||||
|
||||
//apply AA
|
||||
specPow *= specAA;
|
||||
|
||||
// specular power to roughness
|
||||
roughness = sqrt( 2.0 / ( specPow + 2.0 ) );
|
||||
|
||||
return roughness;
|
||||
}
|
||||
// Kennedith98 end
|
||||
|
||||
// https://yusuketokuyoshi.com/papers/2021/Tokuyoshi2021SAA.pdf
|
||||
|
||||
float2x2 NonAxisAlignedNDFFiltering( float3 halfvectorTS, float2 roughness2 )
|
||||
{
|
||||
// Compute the derivatives of the halfvector in the projected space.
|
||||
float2 halfvector2D = halfvectorTS.xy / abs( halfvectorTS.z );
|
||||
float2 deltaU = ddx( halfvector2D );
|
||||
float2 deltaV = ddy( halfvector2D );
|
||||
|
||||
// Compute 2 * covariance matrix for the filter kernel (Eq. (3)).
|
||||
float SIGMA2 = 0.15915494;
|
||||
float2x2 delta = {deltaU, deltaV};
|
||||
float2x2 kernelRoughnessMat = 2.0 * SIGMA2 * mul( transpose( delta ), delta );
|
||||
|
||||
// Approximate NDF filtering (Eq. (9)).
|
||||
float2x2 roughnessMat = {roughness2.x, 0.0, 0.0, roughness2.y};
|
||||
float2x2 filteredRoughnessMat = roughnessMat + kernelRoughnessMat;
|
||||
|
||||
return filteredRoughnessMat;
|
||||
}
|
||||
|
||||
float2 AxisAlignedNDFFiltering( float3 halfvectorTS, float2 roughness2 )
|
||||
{
|
||||
// Compute the bounding rectangle of halfvector derivatives.
|
||||
float2 halfvector2D = halfvectorTS.xy / abs( halfvectorTS.z );
|
||||
float2 bounds = fwidth( halfvector2D );
|
||||
|
||||
// Compute an axis-aligned filter kernel from the bounding rectangle.
|
||||
float SIGMA2 = 0.15915494;
|
||||
float2 kernelRoughness2 = 2.0 * SIGMA2 * ( bounds * bounds );
|
||||
|
||||
// Approximate NDF filtering (Eq. (9)).
|
||||
// We clamp the kernel size to avoid overfiltering.
|
||||
float KAPPA = 0.18;
|
||||
float2 clampedKernelRoughness2 = min( kernelRoughness2, KAPPA );
|
||||
float2 filteredRoughness2 = saturate( roughness2 + clampedKernelRoughness2 );
|
||||
return filteredRoughness2;
|
||||
}
|
||||
|
||||
|
||||
float IsotropicNDFFiltering( float3 normal, float roughness2 )
|
||||
{
|
||||
const float SIGMA2 = 0.15915494;
|
||||
const float KAPPA = 0.18;
|
||||
float3 dndu = ddx( normal );
|
||||
float3 dndv = ddy( normal );
|
||||
float kernelRoughness2 = 2.0 * SIGMA2 * ( dot( dndu, dndu ) + dot( dndv, dndv ) );
|
||||
float clampedKernelRoughness2 = min( kernelRoughness2, KAPPA );
|
||||
float filteredRoughness2 = saturate( roughness2 + clampedKernelRoughness2 );
|
||||
|
||||
return filteredRoughness2;
|
||||
}
|
||||
|
||||
// Environment BRDF approximations
|
||||
// see s2013_pbs_black_ops_2_notes.pdf
|
||||
/*
|
||||
half a1vf( half g )
|
||||
float a1vf( float g )
|
||||
{
|
||||
return ( 0.25 * g + 0.75 );
|
||||
}
|
||||
|
||||
half a004( half g, half vdotN )
|
||||
float a004( float g, float vdotN )
|
||||
{
|
||||
float t = min( 0.475 * g, exp2( -9.28 * vdotN ) );
|
||||
return ( t + 0.0275 ) * g + 0.015;
|
||||
}
|
||||
|
||||
half a0r( half g, half vdotN )
|
||||
float a0r( float g, float vdotN )
|
||||
{
|
||||
return ( ( a004( g, vdotN ) - a1vf( g ) * 0.04 ) / 0.96 );
|
||||
}
|
||||
|
||||
float3 EnvironmentBRDF( half g, half vdotN, float3 rf0 )
|
||||
float3 EnvironmentBRDF( float g, float vdotN, float3 rf0 )
|
||||
{
|
||||
float4 t = float4( 1.0 / 0.96, 0.475, ( 0.0275 - 0.25 * 0.04 ) / 0.96, 0.25 );
|
||||
t *= float4( g, g, g, g );
|
||||
t += float4( 0.0, 0.0, ( 0.015 - 0.75 * 0.04 ) / 0.96, 0.75 );
|
||||
half a0 = t.x * min( t.y, exp2( -9.28 * vdotN ) ) + t.z;
|
||||
half a1 = t.w;
|
||||
float a0 = t.x * min( t.y, exp2( -9.28 * vdotN ) ) + t.z;
|
||||
float a1 = t.w;
|
||||
|
||||
return saturate( a0 + rf0 * ( a1 - a0 ) );
|
||||
}
|
||||
|
||||
|
||||
half3 EnvironmentBRDFApprox( half roughness, half vdotN, half3 specularColor )
|
||||
float3 EnvironmentBRDFApprox( float roughness, float vdotN, float3 specularColor )
|
||||
{
|
||||
const half4 c0 = half4( -1, -0.0275, -0.572, 0.022 );
|
||||
const half4 c1 = half4( 1, 0.0425, 1.04, -0.04 );
|
||||
const float4 c0 = float4( -1, -0.0275, -0.572, 0.022 );
|
||||
const float4 c1 = float4( 1, 0.0425, 1.04, -0.04 );
|
||||
|
||||
half4 r = roughness * c0 + c1;
|
||||
half a004 = min( r.x * r.x, exp2( -9.28 * vdotN ) ) * r.x + r.y;
|
||||
half2 AB = half2( -1.04, 1.04 ) * a004 + r.zw;
|
||||
float4 r = roughness * c0 + c1;
|
||||
float a004 = min( r.x * r.x, exp2( -9.28 * vdotN ) ) * r.x + r.y;
|
||||
float2 AB = float2( -1.04, 1.04 ) * a004 + r.zw;
|
||||
|
||||
return specularColor * AB.x + AB.y;
|
||||
}
|
||||
|
|
|
@ -116,9 +116,9 @@ void main( PS_IN fragment, out PS_OUT result )
|
|||
float hdotN = clamp( dot3( halfAngleVector, localNormal ), 0.0, 1.0 );
|
||||
|
||||
#if USE_PBR
|
||||
// RB: roughness 0 somehow is not shiny so we clamp it
|
||||
float roughness = max( 0.05, specMapSRGB.r );
|
||||
const float metallic = specMapSRGB.g;
|
||||
const float roughness = specMapSRGB.r;
|
||||
const float glossiness = 1.0 - roughness;
|
||||
|
||||
// the vast majority of real-world materials (anything not metal or gems) have F(0)
|
||||
// values in a very narrow range (~0.02 - 0.08)
|
||||
|
|
|
@ -474,9 +474,9 @@ void main( PS_IN fragment, out PS_OUT result )
|
|||
float hdotN = clamp( dot3( halfAngleVector, localNormal ), 0.0, 1.0 );
|
||||
|
||||
#if USE_PBR
|
||||
// RB: roughness 0 somehow is not shiny so we clamp it
|
||||
float roughness = max( 0.05, specMapSRGB.r );
|
||||
const float metallic = specMapSRGB.g;
|
||||
const float roughness = specMapSRGB.r;
|
||||
const float glossiness = 1.0 - roughness;
|
||||
|
||||
// the vast majority of real-world materials (anything not metal or gems) have F(0)
|
||||
// values in a very narrow range (~0.02 - 0.08)
|
||||
|
@ -497,12 +497,21 @@ void main( PS_IN fragment, out PS_OUT result )
|
|||
|
||||
PBRFromSpecmap( specMapSRGB.rgb, specularColor, roughness );
|
||||
#else
|
||||
const float roughness = EstimateLegacyRoughness( specMapSRGB.rgb );
|
||||
float roughness = EstimateLegacyRoughness( specMapSRGB.rgb );
|
||||
|
||||
float3 diffuseColor = diffuseMap;
|
||||
float3 specularColor = specMapSRGB.rgb; // RB: should be linear but it looks too flat
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
// specular AA - https://yusuketokuyoshi.com/papers/2021/Tokuyoshi2021SAA.pdf
|
||||
|
||||
//roughness = IsotropicNDFFiltering( localNormal, roughness * roughness );
|
||||
|
||||
float r2 = roughness * roughness;
|
||||
roughness = AxisAlignedNDFFiltering( halfAngleVector, float2( r2, r2 ) ).x;
|
||||
#endif
|
||||
|
||||
|
||||
// RB FIXME or not: compensate r_lightScale 3 and the division of Pi
|
||||
//lambert *= 1.3;
|
||||
|
@ -531,6 +540,12 @@ void main( PS_IN fragment, out PS_OUT result )
|
|||
float VFapprox = ( ldotH * ldotH ) * ( roughness + 0.5 );
|
||||
|
||||
#if KENNY_PBR
|
||||
// specular cook-torrance brdf (visibility, geo and denom in one)
|
||||
//float D = Distribution_GGX_Disney( hdotN, rr );
|
||||
//float Vis = Visibility_Schlick( vdotN, lambert, rr );
|
||||
//float3 F = Fresnel_Schlick( reflectColor, vdotH );
|
||||
//float3 specularLight = D * Vis * F;
|
||||
|
||||
float3 specularLight = ( rrrr / ( 4.0 * D * D * VFapprox ) ) * ldotN * reflectColor;
|
||||
#else
|
||||
float3 specularLight = ( rrrr / ( 4.0 * PI * D * D * VFapprox ) ) * ldotN * reflectColor;
|
||||
|
|
Loading…
Reference in a new issue