Don't use 1 pixel border for non-lightgrid octahedrons

This commit is contained in:
Robert Beckebans 2021-04-27 14:15:11 +02:00
parent dcf9cc4e6d
commit b96b085d04
10 changed files with 83 additions and 84 deletions

View file

@ -59,12 +59,14 @@ void main( PS_IN fragment, out PS_OUT result )
float2 normalizedOctCoordZeroOne = ( normalizedOctCoord + float2( 1.0 ) ) * 0.5;
// offset by one pixel border bleed size for linear filtering
#if 0
float2 octCoordNormalizedToTextureDimensions = ( normalizedOctCoordZeroOne * ( rpCascadeDistances.x - float( 2.0 ) ) ) / rpCascadeDistances.xy;
float2 probeTopLeftPosition = float2( 1.0, 1.0 );
float2 normalizedProbeTopLeftPosition = probeTopLeftPosition * rpCascadeDistances.zw;
normalizedOctCoordZeroOne.xy = normalizedProbeTopLeftPosition + octCoordNormalizedToTextureDimensions;
#endif
//normalizedOctCoordZeroOne = TextureCoordFromDirection( reflectionVector, 0, int( rpCascadeDistances.x ), int( rpCascadeDistances.y ), int( rpCascadeDistances.x ) - 2 );

View file

@ -119,6 +119,26 @@ bool AABBRayIntersection( float3 b[2], float3 start, float3 dir, out float scale
hit[ax2] >= b[0][ax2] && hit[ax2] <= b[1][ax2] );
}
float2 OctTexCoord( float3 worldDir )
{
float2 normalizedOctCoord = octEncode( worldDir );
float2 normalizedOctCoordZeroOne = ( normalizedOctCoord + float2( 1.0 ) ) * 0.5;
// offset by one pixel border bleed size for linear filtering
#if 0
// texcoord sizes in rpCascadeDistances are not valid
float2 octCoordNormalizedToTextureDimensions = ( normalizedOctCoordZeroOne * ( rpCascadeDistances.x - float( 2.0 ) ) ) / rpCascadeDistances.xy;
float2 probeTopLeftPosition = float2( 1.0, 1.0 );
float2 normalizedProbeTopLeftPosition = probeTopLeftPosition * rpCascadeDistances.zw;
normalizedOctCoordZeroOne.xy = normalizedProbeTopLeftPosition + octCoordNormalizedToTextureDimensions;
#endif
return normalizedOctCoordZeroOne;
}
void main( PS_IN fragment, out PS_OUT result )
{
half4 bumpMap = tex2D( samp0, fragment.texcoord0.xy );
@ -236,8 +256,7 @@ void main( PS_IN fragment, out PS_OUT result )
// evaluate diffuse IBL
float2 normalizedOctCoord = octEncode( globalNormal );
float2 normalizedOctCoordZeroOne = ( normalizedOctCoord + float2( 1.0 ) ) * 0.5;
float2 normalizedOctCoordZeroOne = OctTexCoord( globalNormal );
float3 irradiance = tex2D( samp7, normalizedOctCoordZeroOne ).rgb;
float3 diffuseLight = ( kD * irradiance * diffuseColor ) * ao * ( rpDiffuseModifier.xyz * 1.0 );
@ -249,8 +268,7 @@ void main( PS_IN fragment, out PS_OUT result )
float mip = clamp( ( roughness * MAX_REFLECTION_LOD ), 0.0, MAX_REFLECTION_LOD );
//float mip = 0.0;
normalizedOctCoord = octEncode( reflectionVector );
normalizedOctCoordZeroOne = ( normalizedOctCoord + float2( 1.0 ) ) * 0.5;
normalizedOctCoordZeroOne = OctTexCoord( reflectionVector );
float3 radiance = textureLod( samp8, normalizedOctCoordZeroOne, mip ).rgb;
//radiance = float3( 0.0 );

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 = 34;
static const int IRRADIANCE_CUBEMAP_SIZE = 30 + 2;
#if 1
static int shadowMapResolutions[MAX_SHADOWMAP_RESOLUTIONS] = { 2048, 1024, 512, 512, 256 };

View file

@ -1323,7 +1323,7 @@ void idRenderBackend::DrawSingleInteraction( drawInteraction_t* din, bool useFas
const textureUsage_t specUsage = din->specularImage->GetUsage();
// RB begin
if( useIBL && currentSpace->useLightGrid )
if( useIBL && currentSpace->useLightGrid && r_useLightGrid.GetBool() )
{
idVec4 probeMins, probeMaxs, probeCenter;

View file

@ -516,7 +516,7 @@ struct calcEnvprobeParms_t
static const int LIGHTGRID_IRRADIANCE_BORDER_SIZE = 2; // one pixel border all around the octahedron so 2 on each side
static const int LIGHTGRID_IRRADIANCE_SIZE = ( 16 * 1 ) + LIGHTGRID_IRRADIANCE_BORDER_SIZE;
static const int LIGHTGRID_IRRADIANCE_SIZE = 30 + LIGHTGRID_IRRADIANCE_BORDER_SIZE;
struct calcLightGridPointParms_t
{
@ -1208,6 +1208,8 @@ extern idCVar r_pbrDebug;
extern idCVar r_showViewEnvprobes;
extern idCVar r_showLightGrid; // show Quake 3 style light grid points
extern idCVar r_useLightGrid;
extern idCVar r_exposure;
// RB end

View file

@ -2628,12 +2628,14 @@ static const cgShaderDef_t cg_renderprogs[] =
" float2 normalizedOctCoordZeroOne = ( normalizedOctCoord + float2( 1.0 ) ) * 0.5;\n"
"\n"
" // offset by one pixel border bleed size for linear filtering\n"
"#if 0\n"
" float2 octCoordNormalizedToTextureDimensions = ( normalizedOctCoordZeroOne * ( rpCascadeDistances.x - float( 2.0 ) ) ) / rpCascadeDistances.xy;\n"
"\n"
" float2 probeTopLeftPosition = float2( 1.0, 1.0 );\n"
" float2 normalizedProbeTopLeftPosition = probeTopLeftPosition * rpCascadeDistances.zw;\n"
"\n"
" normalizedOctCoordZeroOne.xy = normalizedProbeTopLeftPosition + octCoordNormalizedToTextureDimensions;\n"
"#endif\n"
"\n"
" //normalizedOctCoordZeroOne = TextureCoordFromDirection( reflectionVector, 0, int( rpCascadeDistances.x ), int( rpCascadeDistances.y ), int( rpCascadeDistances.x ) - 2 );\n"
"\n"
@ -4884,6 +4886,26 @@ static const cgShaderDef_t cg_renderprogs[] =
" hit[ax2] >= b[0][ax2] && hit[ax2] <= b[1][ax2] );\n"
"}\n"
"\n"
"\n"
"float2 OctTexCoord( float3 worldDir )\n"
"{\n"
" float2 normalizedOctCoord = octEncode( worldDir );\n"
" float2 normalizedOctCoordZeroOne = ( normalizedOctCoord + float2( 1.0 ) ) * 0.5;\n"
"\n"
" // offset by one pixel border bleed size for linear filtering\n"
"#if 0\n"
" // texcoord sizes in rpCascadeDistances are not valid\n"
" float2 octCoordNormalizedToTextureDimensions = ( normalizedOctCoordZeroOne * ( rpCascadeDistances.x - float( 2.0 ) ) ) / rpCascadeDistances.xy;\n"
"\n"
" float2 probeTopLeftPosition = float2( 1.0, 1.0 );\n"
" float2 normalizedProbeTopLeftPosition = probeTopLeftPosition * rpCascadeDistances.zw;\n"
"\n"
" normalizedOctCoordZeroOne.xy = normalizedProbeTopLeftPosition + octCoordNormalizedToTextureDimensions;\n"
"#endif\n"
"\n"
" return normalizedOctCoordZeroOne;\n"
"}\n"
"\n"
"void main( PS_IN fragment, out PS_OUT result )\n"
"{\n"
" half4 bumpMap = tex2D( samp0, fragment.texcoord0.xy );\n"
@ -5001,8 +5023,7 @@ static const cgShaderDef_t cg_renderprogs[] =
"\n"
" // evaluate diffuse IBL\n"
"\n"
" float2 normalizedOctCoord = octEncode( globalNormal );\n"
" float2 normalizedOctCoordZeroOne = ( normalizedOctCoord + float2( 1.0 ) ) * 0.5;\n"
" float2 normalizedOctCoordZeroOne = OctTexCoord( globalNormal );\n"
"\n"
" float3 irradiance = tex2D( samp7, normalizedOctCoordZeroOne ).rgb;\n"
" float3 diffuseLight = ( kD * irradiance * diffuseColor ) * ao * ( rpDiffuseModifier.xyz * 1.0 );\n"
@ -5014,8 +5035,7 @@ static const cgShaderDef_t cg_renderprogs[] =
" float mip = clamp( ( roughness * MAX_REFLECTION_LOD ), 0.0, MAX_REFLECTION_LOD );\n"
" //float mip = 0.0;\n"
"\n"
" normalizedOctCoord = octEncode( reflectionVector );\n"
" normalizedOctCoordZeroOne = ( normalizedOctCoord + float2( 1.0 ) ) * 0.5;\n"
" normalizedOctCoordZeroOne = OctTexCoord( reflectionVector );\n"
"\n"
" float3 radiance = textureLod( samp8, normalizedOctCoordZeroOne, mip ).rgb;\n"
" //radiance = float3( 0.0 );\n"

View file

@ -301,6 +301,8 @@ idCVar r_pbrDebug( "r_pbrDebug", "0", CVAR_RENDERER | CVAR_INTEGER, "show which
idCVar r_showViewEnvprobes( "r_showViewEnvprobes", "0", CVAR_RENDERER | CVAR_INTEGER, "1 = displays the bounding boxes of all view environment probes, 2 = show irradiance" );
idCVar r_showLightGrid( "r_showLightGrid", "0", CVAR_RENDERER | CVAR_INTEGER, "show Quake 3 style light grid points" );
idCVar r_useLightGrid( "r_useLightGrid", "1", CVAR_RENDERER | CVAR_BOOL, "" );
idCVar r_exposure( "r_exposure", "0.5", CVAR_ARCHIVE | CVAR_RENDERER | CVAR_FLOAT, "HDR exposure or LDR brightness [0.0 .. 1.0]", 0.0f, 1.0f );
// RB end

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_LINEAR, TR_REPEAT, TD_R11G11B10F, CF_2D_PACKED_MIPCHAIN );
probe->irradianceImage = globalImages->ImageFromFile( fullname, TF_LINEAR, TR_CLAMP, 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_REPEAT, TD_R11G11B10F, CF_2D_PACKED_MIPCHAIN );
probe->radianceImage = globalImages->ImageFromFile( fullname, TF_DEFAULT, TR_CLAMP, TD_R11G11B10F, CF_2D_PACKED_MIPCHAIN );
// ------------------------------------
// compute the probe projection matrix

View file

@ -467,6 +467,7 @@ idVec2 NormalizedOctCoord( int x, int y, const int probeWithBorderSide )
const int margin = 2;
// RB: FIXME - margin * 2 is wrong but looks better
// figure out why
int probeSideLength = Max( 2, probeWithBorderSide - ( margin * 2 ) );
idVec2 octFragCoord = idVec2( ( x - margin ) % probeWithBorderSide, ( y - margin ) % probeWithBorderSide );
@ -477,6 +478,16 @@ idVec2 NormalizedOctCoord( int x, int y, const int probeWithBorderSide )
#endif
}
static inline idVec2 NormalizedOctCoordNoBorder( int x, int y, const int probeWithBorderSide )
{
int probeSideLength = probeWithBorderSide;
idVec2 octFragCoord = idVec2( x % probeWithBorderSide, y % 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 );
}
/*
static inline float LatLongTexelArea( const idVec2i& pos, const idVec2i& imageSize )
{
@ -615,7 +626,7 @@ void CalculateIrradianceJob( calcEnvprobeParms_t* parms )
{
for( int y = dstRect.y; y < ( dstRect.y + dstRect.w ); y++ )
{
idVec2 octCoord = NormalizedOctCoord( x, y, dstRect.z );
idVec2 octCoord = NormalizedOctCoordNoBorder( x, y, dstRect.z );
// convert UV coord to 3D direction
idVec3 dir;
@ -727,11 +738,11 @@ void CalculateIrradianceJob( calcEnvprobeParms_t* parms )
if( mip > 0 )
{
// move back to [0, 1] coords
octCoord = NormalizedOctCoord( x - dstRect.x, y - dstRect.y, dstRect.z );
octCoord = NormalizedOctCoordNoBorder( x - dstRect.x, y - dstRect.y, dstRect.z );
}
else
{
octCoord = NormalizedOctCoord( x, y, dstRect.z );
octCoord = NormalizedOctCoordNoBorder( x, y, dstRect.z );
}
// convert UV coord to 3D direction
@ -838,11 +849,11 @@ void CalculateRadianceJob( calcEnvprobeParms_t* parms )
if( mip > 0 )
{
// move back to [0, 1] coords
octCoord = NormalizedOctCoord( x - dstRect.x, y - dstRect.y, dstRect.z );
octCoord = NormalizedOctCoordNoBorder( x - dstRect.x, y - dstRect.y, dstRect.z );
}
else
{
octCoord = NormalizedOctCoord( x, y, dstRect.z );
octCoord = NormalizedOctCoordNoBorder( x, y, dstRect.z );
}
// convert UV coord to 3D direction

View file

@ -38,7 +38,7 @@ If you have questions concerning this license or the applicable additional terms
#define STORE_LIGHTGRID_SHDATA 0
static const byte BLGRID_VERSION = 3;
static const byte BLGRID_VERSION = 4;
static const unsigned int BLGRID_MAGIC = ( 'P' << 24 ) | ( 'R' << 16 ) | ( 'O' << 8 ) | BLGRID_VERSION;
@ -513,7 +513,7 @@ bool idRenderWorldLocal::LoadLightGridFile( const char* name )
// if we are reloading the same map, check the timestamp
// and try to skip all the work
ID_TIME_T currentTimeStamp = fileSystem->GetTimestamp( fileName );
ID_TIME_T sourceTimeStamp = fileSystem->GetTimestamp( fileName );
// see if we have a generated version of this
bool loaded = false;
@ -524,11 +524,14 @@ bool idRenderWorldLocal::LoadLightGridFile( const char* name )
{
int numEntries = 0;
int magic = 0;
ID_TIME_T storedTimeStamp;
file->ReadBig( magic );
file->ReadBig( storedTimeStamp );
file->ReadBig( numEntries );
if( magic == BLGRID_MAGIC && numEntries > 0 )
if( ( magic == BLGRID_MAGIC ) && ( sourceTimeStamp == storedTimeStamp ) && ( numEntries > 0 ) )
{
loaded = true;
for( int i = 0; i < numEntries; i++ )
{
idStrStatic< MAX_OSPATH > type;
@ -564,6 +567,7 @@ bool idRenderWorldLocal::LoadLightGridFile( const char* name )
{
int magic = BLGRID_MAGIC;
outputFile->WriteBig( magic );
outputFile->WriteBig( sourceTimeStamp );
outputFile->WriteBig( numEntries );
}
@ -646,8 +650,10 @@ bool idRenderWorldLocal::LoadLightGridFile( const char* name )
if( outputFile != NULL )
{
outputFile->Seek( 0, FS_SEEK_SET );
int magic = BLGRID_MAGIC;
outputFile->WriteBig( magic );
outputFile->WriteBig( sourceTimeStamp );
outputFile->WriteBig( numEntries );
}
}
@ -913,58 +919,6 @@ void CalculateLightGridPointJob( calcLightGridPointParms_t* parms )
shRadiance[i].Zero();
}
#if 0
// build SH by only iterating over the octahedron
// RB: not used because I don't know the texel area of an octahedron pixel and the cubemap texel area is too small
// however it would be nice to use this because it would be 6 times faster
idVec4 dstRect = R_CalculateMipRect( parms->outHeight, 0 );
for( int x = dstRect.x; x < ( dstRect.x + dstRect.z ); x++ )
{
for( int y = dstRect.y; y < ( dstRect.y + dstRect.w ); y++ )
{
idVec2 octCoord = NormalizedOctCoord( x, y, dstRect.z );
// convert UV coord to 3D direction
idVec3 dir;
dir.FromOctahedral( octCoord );
float u, v;
idVec3 radiance;
R_SampleCubeMapHDR( dir, parms->outHeight, buffers, &radiance[0], u, v );
//radiance = dir * 0.5 + idVec3( 0.5f, 0.5f, 0.5f );
// convert from [0 .. size-1] to [-1.0 + invSize .. 1.0 - invSize]
const float uu = 2.0f * ( u * invDstSize ) - 1.0f;
const float vv = 2.0f * ( v * invDstSize ) - 1.0f;
float texelArea = CubemapTexelSolidAngle( uu, vv, invDstSize );
const SphericalHarmonicsT<float, 4>& sh = shEvaluate<4>( dir );
bool shValid = true;
for( int i = 0; i < 25; i++ )
{
if( IsNAN( sh[i] ) )
{
shValid = false;
break;
}
}
if( shValid )
{
shAddWeighted( shRadiance, sh, radiance * texelArea );
}
}
}
#else
// build SH by iterating over all cubemap pixels
for( int side = 0; side < 6; side++ )
@ -1008,8 +962,6 @@ void CalculateLightGridPointJob( calcLightGridPointParms_t* parms )
}
}
#endif
for( int i = 0; i < shSize( 3 ); i++ )
{
parms->shRadiance[i] = shRadiance[i];
@ -1259,7 +1211,7 @@ CONSOLE_COMMAND( bakeLightGrids, "Bake irradiance/vis light grid data", NULL )
lightGridPoint_t* gridPoint = &area->lightGrid.lightGridPoints[ gridCoord[0] * gridStep[0] + gridCoord[1] * gridStep[1] + gridCoord[2] * gridStep[2] ];
if( !gridPoint->valid )
{
progressBar.Increment();
//progressBar.Increment();
continue;
}
@ -1284,14 +1236,6 @@ CONSOLE_COMMAND( bakeLightGrids, "Bake irradiance/vis light grid data", NULL )
byte* float16FRGB = tr.CaptureRenderToBuffer( captureSize, captureSize, &ref );
jobParms->radiance[ side ] = float16FRGB;
#if 0
if( i < 3 )
{
filename.Format( "env/%s/area%i_lightgridpoint%i%s.exr", baseName.c_str(), a, i, extension );
R_WriteEXR( filename, float16FRGB, 3, size, size, "fs_basepath" );
}
#endif
}
tr.lightGridJobs.Append( jobParms );