Enable linear filtering for octahedron lightgrid probes

This commit is contained in:
Robert Beckebans 2021-04-23 00:21:22 +02:00
parent d11fae0c20
commit f3ee2baac8
14 changed files with 182 additions and 32 deletions

View file

@ -75,8 +75,6 @@ int3 GetBaseGridCoord( float3 origin )
return pos;
}
void main( PS_IN fragment, out PS_OUT result )
{
const int LIGHTGRID_IRRADIANCE_SIZE = 32;
@ -108,7 +106,20 @@ void main( PS_IN fragment, out PS_OUT result )
normalizedOctCoordZeroOne.x += ( gridCoord[0] * gridStep[0] + gridCoord[2] * gridStep[1] ) * invXZ;
normalizedOctCoordZeroOne.y += ( gridCoord[1] * invY );
float4 envMap = tex2D( samp0, normalizedOctCoordZeroOne );
// offset by one pixel border bleed size for linear filtering
#if 1
float2 octCoordNormalizedToTextureDimensions = ( normalizedOctCoordZeroOne * ( 32.0 / ( 34.0 * 1.0 ) ) );
float2 probeTopLeftPosition;
probeTopLeftPosition.x = ( gridCoord[0] * gridStep[0] + gridCoord[2] * gridStep[1] ) * 2.0 + 1.0;
probeTopLeftPosition.y = ( gridCoord[1] ) * 2.0 + 1.0;
float2 normalizedProbeTopLeftPosition = probeTopLeftPosition * rpCascadeDistances.zw;
normalizedOctCoordZeroOne.xy = normalizedProbeTopLeftPosition + octCoordNormalizedToTextureDimensions;
#endif
float4 envMap = texture( samp0, normalizedOctCoordZeroOne, 0 );
result.color = float4( envMap.xyz, 1.0f ) * 1.0 * fragment.color;
}

View file

@ -58,7 +58,17 @@ void main( PS_IN fragment, out PS_OUT result )
float2 normalizedOctCoord = octEncode( reflectionVector );
float2 normalizedOctCoordZeroOne = ( normalizedOctCoord + float2( 1.0 ) ) * 0.5;
float4 envMap = tex2D( samp0, normalizedOctCoordZeroOne );
// offset by one pixel border bleed size for linear filtering
float2 octCoordNormalizedToTextureDimensions = ( normalizedOctCoordZeroOne * ( rpCascadeDistances.x - float( 2.0 ) ) ) / rpCascadeDistances.xy;
result.color = float4( sRGBToLinearRGB( envMap.xyz ), 1.0f ) * fragment.color;
float2 probeTopLeftPosition = float2( 1.0, 1.0 );
float2 normalizedProbeTopLeftPosition = probeTopLeftPosition * rpCascadeDistances.zw;
normalizedOctCoordZeroOne.xy = normalizedProbeTopLeftPosition + octCoordNormalizedToTextureDimensions;
//normalizedOctCoordZeroOne = TextureCoordFromDirection( reflectionVector, 0, int( rpCascadeDistances.x ), int( rpCascadeDistances.y ), int( rpCascadeDistances.x ) - 2 );
float4 envMap = texture( samp0, normalizedOctCoordZeroOne, 0 );
result.color = float4( envMap.xyz, 1.0f ) * fragment.color * 1.0;
}

View file

@ -331,7 +331,22 @@ void main( PS_IN fragment, out PS_OUT result )
atlasOffset.x = ( gridCoord2[0] * gridStep[0] + gridCoord2[2] * gridStep[1] ) * invXZ;
atlasOffset.y = ( gridCoord2[1] * invY );
float3 color = tex2D( samp7, normalizedOctCoordZeroOne + atlasOffset ).rgb;
// offset by one pixel border bleed size for linear filtering
#if 1
float2 octCoordNormalizedToTextureDimensions = ( ( normalizedOctCoordZeroOne + atlasOffset ) * ( 32.0 / ( 34.0 * 1.0 ) ) );
float2 probeTopLeftPosition;
probeTopLeftPosition.x = ( gridCoord2[0] * gridStep[0] + gridCoord2[2] * gridStep[1] ) * 2.0 + 1.0;
probeTopLeftPosition.y = ( gridCoord2[1] ) * 2.0 + 1.0;
float2 normalizedProbeTopLeftPosition = probeTopLeftPosition * rpCascadeDistances.zw;
float2 atlasCoord = normalizedProbeTopLeftPosition + octCoordNormalizedToTextureDimensions;
#else
float2 atlasCoord = normalizedOctCoordZeroOne + atlasOffset;
#endif
float3 color = texture( samp7, atlasCoord, 0 ).rgb;
if( ( color.r + color.g + color.b ) < 0.0001 )
{

View file

@ -35,7 +35,7 @@ static const int MAX_SSAO_BUFFERS = 2;
static const int MAX_HIERARCHICAL_ZBUFFERS = 6; // native resolution + 5 MIP LEVELS
static const int RADIANCE_CUBEMAP_SIZE = 256;
static const int IRRADIANCE_CUBEMAP_SIZE = 128;
static const int IRRADIANCE_CUBEMAP_SIZE = 34;
#if 1
static int shadowMapResolutions[MAX_SHADOWMAP_RESOLUTIONS] = { 2048, 1024, 512, 512, 256 };

View file

@ -309,6 +309,11 @@ public:
return opts.height;
}
idVec2i GetUploadResolution() const
{
return idVec2i( opts.width, opts.height );
}
void SetReferencedOutsideLevelLoad()
{
referencedOutsideLevelLoad = true;

View file

@ -736,7 +736,7 @@ void idImage::Reload( bool force )
if( !force )
{
ID_TIME_T current;
if( cubeFiles != CF_2D )
if( cubeFiles == CF_NATIVE || cubeFiles == CF_CAMERA )
{
R_LoadCubeImages( imgName, cubeFiles, NULL, NULL, &current );
}

View file

@ -1756,16 +1756,26 @@ void idRenderBackend::DBG_ShowViewEnvprobes()
renderProgManager.SetUniformValue( RENDERPARM_LOCALVIEWORIGIN, localViewOrigin.ToFloatPtr() ); // rpLocalViewOrigin
idVec4 textureSize;
GL_SelectTexture( 0 );
if( r_showViewEnvprobes.GetInteger() >= 2 )
{
vProbe->irradianceImage->Bind();
idVec2i res = vProbe->irradianceImage->GetUploadResolution();
textureSize.Set( res.x, res.y, 1.0f / res.x, 1.0f / res.y );
}
else
{
vProbe->radianceImage->Bind();
idVec2i res = vProbe->radianceImage->GetUploadResolution();
textureSize.Set( res.x, res.y, 1.0f / res.x, 1.0f / res.y );
}
renderProgManager.SetUniformValue( RENDERPARM_CASCADEDISTANCES, textureSize.ToFloatPtr() );
DrawElementsWithCounters( &zeroOneSphereSurface );
// non-hidden lines
@ -1911,6 +1921,11 @@ void idRenderBackend::DBG_ShowLightGrid()
GL_SelectTexture( 0 );
area->lightGrid.GetIrradianceImage()->Bind();
idVec2i res = area->lightGrid.GetIrradianceImage()->GetUploadResolution();
idVec4 textureSize( res.x, res.y, 1.0f / res.x, 1.0f / res.y );
renderProgManager.SetUniformValue( RENDERPARM_CASCADEDISTANCES, textureSize.ToFloatPtr() );
}
#endif

View file

@ -1399,6 +1399,11 @@ void idRenderBackend::DrawSingleInteraction( drawInteraction_t* din, bool useFas
GL_SelectTexture( INTERACTION_TEXUNIT_AMBIENT_CUBE1 );
currentSpace->irradianceAtlasImage->Bind();
idVec2i res = currentSpace->irradianceAtlasImage->GetUploadResolution();
idVec4 textureSize( res.x, res.y, 1.0f / res.x, 1.0f / res.y );
renderProgManager.SetUniformValue( RENDERPARM_CASCADEDISTANCES, textureSize.ToFloatPtr() );
GL_SelectTexture( INTERACTION_TEXUNIT_SPECULAR_CUBE1 );
if( viewDef->radianceImage )
{

View file

@ -513,7 +513,7 @@ struct calcEnvprobeParms_t
static const int LIGHTGRID_IRRADIANCE_SIZE = 32;
static const int LIGHTGRID_IRRADIANCE_SIZE = ( 16 * 2 ) + 2;
struct calcLightGridPointParms_t
{

View file

@ -2627,9 +2627,19 @@ static const cgShaderDef_t cg_renderprogs[] =
" float2 normalizedOctCoord = octEncode( reflectionVector );\n"
" float2 normalizedOctCoordZeroOne = ( normalizedOctCoord + float2( 1.0 ) ) * 0.5;\n"
"\n"
" float4 envMap = tex2D( samp0, normalizedOctCoordZeroOne );\n"
" // offset by one pixel border bleed size for linear filtering\n"
" float2 octCoordNormalizedToTextureDimensions = ( normalizedOctCoordZeroOne * ( rpCascadeDistances.x - float( 2.0 ) ) ) / rpCascadeDistances.xy;\n"
"\n"
" result.color = float4( sRGBToLinearRGB( envMap.xyz ), 1.0f ) * fragment.color;\n"
" float2 probeTopLeftPosition = float2( 1.0, 1.0 );\n"
" float2 normalizedProbeTopLeftPosition = probeTopLeftPosition * rpCascadeDistances.zw;\n"
"\n"
" normalizedOctCoordZeroOne.xy = normalizedProbeTopLeftPosition + octCoordNormalizedToTextureDimensions;\n"
"\n"
" //normalizedOctCoordZeroOne = TextureCoordFromDirection( reflectionVector, 0, int( rpCascadeDistances.x ), int( rpCascadeDistances.y ), int( rpCascadeDistances.x ) - 2 );\n"
"\n"
" float4 envMap = texture( samp0, normalizedOctCoordZeroOne, 0 );\n"
"\n"
" result.color = float4( envMap.xyz, 1.0f ) * fragment.color * 1.0;\n"
"}\n"
"\n"
@ -2840,8 +2850,6 @@ static const cgShaderDef_t cg_renderprogs[] =
" return pos;\n"
"}\n"
"\n"
"\n"
"\n"
"void main( PS_IN fragment, out PS_OUT result )\n"
"{\n"
" const int LIGHTGRID_IRRADIANCE_SIZE = 32;\n"
@ -2873,7 +2881,20 @@ static const cgShaderDef_t cg_renderprogs[] =
" normalizedOctCoordZeroOne.x += ( gridCoord[0] * gridStep[0] + gridCoord[2] * gridStep[1] ) * invXZ;\n"
" normalizedOctCoordZeroOne.y += ( gridCoord[1] * invY );\n"
"\n"
" float4 envMap = tex2D( samp0, normalizedOctCoordZeroOne );\n"
" // offset by one pixel border bleed size for linear filtering\n"
"#if 1\n"
" float2 octCoordNormalizedToTextureDimensions = ( normalizedOctCoordZeroOne * ( 32.0 / ( 34.0 * 1.0 ) ) );\n"
"\n"
" float2 probeTopLeftPosition;\n"
" probeTopLeftPosition.x = ( gridCoord[0] * gridStep[0] + gridCoord[2] * gridStep[1] ) * 2.0 + 1.0;\n"
" probeTopLeftPosition.y = ( gridCoord[1] ) * 2.0 + 1.0;\n"
"\n"
" float2 normalizedProbeTopLeftPosition = probeTopLeftPosition * rpCascadeDistances.zw;\n"
"\n"
" normalizedOctCoordZeroOne.xy = normalizedProbeTopLeftPosition + octCoordNormalizedToTextureDimensions;\n"
"#endif\n"
"\n"
" float4 envMap = texture( samp0, normalizedOctCoordZeroOne, 0 );\n"
"\n"
" result.color = float4( envMap.xyz, 1.0f ) * 1.0 * fragment.color;\n"
"}\n"
@ -4890,7 +4911,7 @@ static const cgShaderDef_t cg_renderprogs[] =
" float3 reflectionVector = globalNormal * dot3( globalView, globalNormal );\n"
" reflectionVector = normalize( ( reflectionVector * 2.0f ) - globalView );\n"
"\n"
"#if 1\n"
"#if 0\n"
" // parallax box correction using portal area bounds\n"
" float hitScale = 0.0;\n"
" float3 bounds[2];\n"
@ -5006,7 +5027,7 @@ static const cgShaderDef_t cg_renderprogs[] =
" float specAO = ComputeSpecularAO( vDotN, ao, roughness );\n"
" float3 specularLight = radiance * ( kS * envBRDF.x + float3( envBRDF.y ) ) * specAO * ( rpSpecularModifier.xyz * 0.5 );\n"
"\n"
"#if 0\n"
"#if 1\n"
" // Marmoset Horizon Fade trick\n"
" const half horizonFade = 1.3;\n"
" half horiz = saturate( 1.0 + horizonFade * saturate( dot3( reflectionVector, globalNormal ) ) );\n"
@ -5015,11 +5036,12 @@ static const cgShaderDef_t cg_renderprogs[] =
"#endif\n"
"\n"
" half3 lightColor = sRGBToLinearRGB( rpAmbientColor.rgb );\n"
" //half3 lightColor = ( rpAmbientColor.rgb );\n"
"\n"
" //result.color.rgb = diffuseLight;\n"
" //result.color.rgb = diffuseLight * lightColor;\n"
" //result.color.rgb = specularLight;\n"
" result.color.rgb = ( diffuseLight + specularLight ) * lightColor * fragment.color.rgb;\n"
" result.color.rgb = ( diffuseLight + specularLight * horiz ) * lightColor * fragment.color.rgb;\n"
" //result.color.rgb = localNormal.xyz * 0.5 + 0.5;\n"
" //result.color.rgb = float3( ao );\n"
" result.color.w = fragment.color.a;\n"
@ -5387,7 +5409,7 @@ static const cgShaderDef_t cg_renderprogs[] =
" float3 reflectionVector = globalNormal * dot3( globalView, globalNormal );\n"
" reflectionVector = normalize( ( reflectionVector * 2.0f ) - globalView );\n"
"\n"
"#if 1\n"
"#if 0\n"
" // parallax box correction using portal area bounds\n"
" float hitScale = 0.0;\n"
" float3 bounds[2];\n"
@ -5568,7 +5590,22 @@ static const cgShaderDef_t cg_renderprogs[] =
" atlasOffset.x = ( gridCoord2[0] * gridStep[0] + gridCoord2[2] * gridStep[1] ) * invXZ;\n"
" atlasOffset.y = ( gridCoord2[1] * invY );\n"
"\n"
" float3 color = tex2D( samp7, normalizedOctCoordZeroOne + atlasOffset ).rgb;\n"
" // offset by one pixel border bleed size for linear filtering\n"
"#if 1\n"
" float2 octCoordNormalizedToTextureDimensions = ( ( normalizedOctCoordZeroOne + atlasOffset ) * ( 32.0 / ( 34.0 * 1.0 ) ) );\n"
"\n"
" float2 probeTopLeftPosition;\n"
" probeTopLeftPosition.x = ( gridCoord2[0] * gridStep[0] + gridCoord2[2] * gridStep[1] ) * 2.0 + 1.0;\n"
" probeTopLeftPosition.y = ( gridCoord2[1] ) * 2.0 + 1.0;\n"
"\n"
" float2 normalizedProbeTopLeftPosition = probeTopLeftPosition * rpCascadeDistances.zw;\n"
"\n"
" float2 atlasCoord = normalizedProbeTopLeftPosition + octCoordNormalizedToTextureDimensions;\n"
"#else\n"
" float2 atlasCoord = normalizedOctCoordZeroOne + atlasOffset;\n"
"#endif\n"
"\n"
" float3 color = texture( samp7, atlasCoord, 0 ).rgb;\n"
"\n"
" if( ( color.r + color.g + color.b ) < 0.0001 )\n"
" {\n"
@ -5605,6 +5642,12 @@ static const cgShaderDef_t cg_renderprogs[] =
" float3 radiance = textureLod( samp8, normalizedOctCoordZeroOne, mip ).rgb;\n"
" //radiance = float3( 0.0 );\n"
"\n"
" // RB: HACK dim down room radiance by better local irradiance brightness\n"
" //float luma = PhotoLuma( irradiance );\n"
" //float luma = dot( irradiance, LUMINANCE_LINEAR.rgb );\n"
" //float luma = length( irradiance.rgb );\n"
" //radiance *= ( luma * rpSpecularModifier.x * 3.0 );\n"
"\n"
" float2 envBRDF = texture( samp3, float2( max( vDotN, 0.0 ), roughness ) ).rg;\n"
"\n"
"#if 0\n"
@ -5625,6 +5668,7 @@ static const cgShaderDef_t cg_renderprogs[] =
"#endif\n"
"\n"
" half3 lightColor = sRGBToLinearRGB( rpAmbientColor.rgb );\n"
" //half3 lightColor = ( rpAmbientColor.rgb );\n"
"\n"
" //result.color.rgb = diffuseLight;\n"
" //result.color.rgb = diffuseLight * lightColor;\n"

View file

@ -769,10 +769,10 @@ void R_DeriveEnvprobeData( RenderEnvprobeLocal* probe )
// TODO get preconvolved cubemaps
fullname.Format( "env/%s/envprobe%i_amb", basename.c_str(), probeIndex );
probe->irradianceImage = globalImages->ImageFromFile( fullname, TF_DEFAULT, TR_CLAMP, TD_R11G11B10F, CF_2D_PACKED_MIPCHAIN );
probe->irradianceImage = globalImages->ImageFromFile( fullname, TF_LINEAR, TR_REPEAT, TD_R11G11B10F, CF_2D_PACKED_MIPCHAIN );
fullname.Format( "env/%s/envprobe%i_spec", basename.c_str(), probeIndex );
probe->radianceImage = globalImages->ImageFromFile( fullname, TF_DEFAULT, TR_CLAMP, TD_R11G11B10F, CF_2D_PACKED_MIPCHAIN );
probe->radianceImage = globalImages->ImageFromFile( fullname, TF_LINEAR, TR_REPEAT, TD_R11G11B10F, CF_2D_PACKED_MIPCHAIN );
// ------------------------------------
// compute the probe projection matrix

View file

@ -449,16 +449,32 @@ idVec2 IntegrateBRDF( float NdotV, float roughness, int sampleCount )
// Compute normalized oct coord, mapping top left of top left pixel to (-1,-1)
idVec2 NormalizedOctCoord( int x, int y, const int probeSideLength )
idVec2 NormalizedOctCoord( int x, int y, const int probeWithBorderSide )
{
const int margin = 0;
#if 0
// 1 pixel border
const int margin = 1;
int probeWithBorderSide = probeSideLength + margin;
int probeSideLength = Max( 2, probeWithBorderSide - ( margin * 2 ) );
idVec2 octFragCoord;
octFragCoord.x = idMath::ClampInt( 0, probeSideLength - 1, x - margin );
octFragCoord.y = idMath::ClampInt( 0, probeSideLength - 1, y - margin );
return ( idVec2( octFragCoord ) ) * ( 2.0f / float( probeSideLength ) ) - idVec2( 1.0f, 1.0f );
#else
const int margin = 2;
// RB: FIXME - margin * 2 is wrong but looks better
int probeSideLength = Max( 2, probeWithBorderSide - ( margin * 2 ) );
idVec2 octFragCoord = idVec2( ( x - margin ) % probeWithBorderSide, ( y - margin ) % probeWithBorderSide );
// Add back the half pixel to get pixel center normalized coordinates
return ( idVec2( octFragCoord ) + idVec2( 0.5f, 0.5f ) ) * ( 2.0f / float( probeSideLength ) ) - idVec2( 1.0f, 1.0f );
#endif
}
/*
@ -1093,6 +1109,21 @@ CONSOLE_COMMAND( bakeEnvironmentProbes, "Bake environment probes", NULL )
int end = Sys_Milliseconds();
common->Printf( "convolved probes in %5.1f seconds\n\n", ( end - start ) * 0.001f );
//--------------------------------------------
// LOAD CONVOLVED OCTAHEDRONS INTO THE GPU
//--------------------------------------------
for( int i = 0; i < tr.primaryWorld->envprobeDefs.Num(); i++ )
{
RenderEnvprobeLocal* def = tr.primaryWorld->envprobeDefs[i];
if( def == NULL )
{
continue;
}
def->irradianceImage->Reload( false );
def->radianceImage->Reload( false );
}
}
/*

View file

@ -372,14 +372,7 @@ void idRenderWorldLocal::SetupLightGrid()
bool loaded = LoadLightGridFile( filename );
if( loaded )
{
// try to load existing lightgrid image data
for( int i = 0; i < numPortalAreas; i++ )
{
portalArea_t* area = &portalAreas[i];
filename.Format( "env/%s/area%i_lightgrid_amb", baseName.c_str(), i );
area->lightGrid.irradianceImage = globalImages->ImageFromFile( filename, TF_NEAREST, TR_CLAMP, TD_R11G11B10F, CF_2D );
}
LoadLightGridImages();
}
else
{
@ -399,6 +392,24 @@ void idRenderWorldLocal::SetupLightGrid()
}
}
void idRenderWorldLocal::LoadLightGridImages()
{
idLib::Printf( "----- LoadLightGridImages -----\n" );
idStrStatic< MAX_OSPATH > baseName = mapName;
baseName.StripFileExtension();
idStr filename;
// try to load existing lightgrid image data
for( int i = 0; i < numPortalAreas; i++ )
{
portalArea_t* area = &portalAreas[i];
filename.Format( "env/%s/area%i_lightgrid_amb", baseName.c_str(), i );
area->lightGrid.irradianceImage = globalImages->ImageFromFile( filename, TF_LINEAR, TR_CLAMP, TD_R11G11B10F, CF_2D );
}
}
/*
===============================================================================
@ -1333,6 +1344,8 @@ CONSOLE_COMMAND( bakeLightGrids, "Bake irradiance/vis light grid data", NULL )
// so we can load the texture atlases with the correct subdivisions next time
filename.Format( "%s.lightgrid", baseName.c_str() );
tr.primaryWorld->WriteLightGridsToFile( filename );
tr.primaryWorld->LoadLightGridImages();
}
#if 0

View file

@ -401,6 +401,7 @@ public:
void WriteLightGrid( idFile* fp, const LightGrid& lightGrid );
bool LoadLightGridFile( const char* name );
void LoadLightGridImages();
void ParseLightGridPoints( idLexer* src, idFile* fileOut );
void ReadBinaryLightGridPoints( idFile* file );