Some experiments with octahedron probes

This commit is contained in:
Robert Beckebans 2020-11-14 16:04:03 +01:00
parent a3aeca213d
commit 2e580b38ad
4 changed files with 147 additions and 4 deletions

View file

@ -3,6 +3,7 @@
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
Copyright (C) 2020 Robert Beckebans
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
@ -352,6 +353,47 @@ void idVec3::ProjectSelfOntoSphere( const float radius )
}
// RB: more about this
// Cigolle, Donow, Evangelakos, Mara, McGuire, Meyer,
// A Survey of Efficient Representations for Independent Unit Vectors, Journal of Computer Graphics Techniques (JCGT), vol. 3, no. 2, 1-30, 2014
// Available online http://jcgt.org/published/0003/02/01/
idVec2 idVec3::ToOctahedral() const
{
const float L1norm = idMath::Fabs( x ) + idMath::Fabs( x ) + idMath::Fabs( x );
idVec2 result;
if( z < 0.0f )
{
result.x = ( 1.0f - idMath::Fabs( y ) ) * ( x >= 0.0f ) ? 1.0f : -1.0f;
result.y = ( 1.0f - idMath::Fabs( x ) ) * ( y >= 0.0f ) ? 1.0f : -1.0f;
}
else
{
result.x = x * ( 1.0f / L1norm );
result.y = y * ( 1.0f / L1norm );
}
return result;
}
void idVec3::FromOctahedral( const idVec2& o )
{
x = o.x;
y = o.y;
z = 1.0f - idMath::Fabs( o.x ) - idMath::Fabs( o.y );
if( z < 0.0f )
{
float oldX = x;
x = ( 1.0f - idMath::Fabs( y ) ) * ( oldX >= 0.0f ) ? 1.0f : -1.0f;
y = ( 1.0f - idMath::Fabs( oldX ) ) * ( y >= 0.0f ) ? 1.0f : -1.0f;
}
Normalize();
}
// RB end
//===============================================================
//

View file

@ -3,6 +3,7 @@
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
Copyright (C) 2020 Robert Beckebans
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
@ -430,6 +431,13 @@ public:
float* ToFloatPtr();
const char* ToString( int precision = 2 ) const;
// RB: assumes to be normalized, result is an octrahedral vector on the [-1, +1] square
idVec2 ToOctahedral() const;
// builds a 3D unit vector from an an octrahedral vector on the [-1, +1] square
void FromOctahedral( const idVec2& v );
// RB end
void NormalVectors( idVec3& left, idVec3& down ) const; // vector should be normalized
void OrthogonalBasis( idVec3& left, idVec3& up ) const;

View file

@ -594,6 +594,20 @@ static const unsigned char brfLutTexBytes[] =
Mem_Free( hdrBuffer );
}
// Compute normalized oct coord, mapping top left of top left pixel to (-1,-1)
idVec2 NormalizedOctCoord( int x, int y, const int probeSideLength )
{
const int margin = 0;
int probeWithBorderSide = probeSideLength + margin;
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 );
}
/*
==================
R_MakeAmbientMap_f
@ -662,7 +676,7 @@ void R_MakeAmbientMap( const char* baseName, const char* suffix, int outSize, fl
byte* outBuffer = ( byte* )_alloca( outSize * outSize * 4 );
//for( int map = 0 ; map < 2 ; map++ )
#if 0
{
CommandlineProgressBar progressBar( outSize * outSize * 6 );
@ -719,6 +733,85 @@ void R_MakeAmbientMap( const char* baseName, const char* suffix, int outSize, fl
common->Printf( "env/%s convolved in %5.1f seconds\n\n", baseName, ( end - start ) * 0.001f );
}
#else
{
// output an octahedron probe
CommandlineProgressBar progressBar( outSize * outSize );
int start = Sys_Milliseconds();
const float invDstSize = 1.0f / float( outSize );
//for( int i = 0 ; i < 6 ; i++ )
{
for( int x = 0 ; x < outSize ; x++ )
{
for( int y = 0 ; y < outSize ; y++ )
{
idVec3 dir;
float total[3];
// convert UV coord from [0, 1] to [-1, 1] space
const float u = 2.0f * x * invDstSize - 1.0f;
const float v = 2.0f * y * invDstSize - 1.0f;
//idVec2 octCoord( u, v );
idVec2 octCoord = NormalizedOctCoord( x, y, outSize );
// convert UV coord to 3D direction
dir.FromOctahedral( octCoord );
total[0] = total[1] = total[2] = 0;
//float roughness = map ? 0.1 : 0.95; // small for specular, almost hemisphere for ambient
for( int s = 0 ; s < samples ; s++ )
{
idVec2 Xi = Hammersley2D( s, samples );
idVec3 test = ImportanceSampleGGX( Xi, dir, roughness );
byte result[4];
//test = dir;
R_SampleCubeMap( test, width, buffers, result );
total[0] += result[0];
total[1] += result[1];
total[2] += result[2];
}
#if 1
outBuffer[( y * outSize + x ) * 4 + 0] = total[0] / samples;
outBuffer[( y * outSize + x ) * 4 + 1] = total[1] / samples;
outBuffer[( y * outSize + x ) * 4 + 2] = total[2] / samples;
outBuffer[( y * outSize + x ) * 4 + 3] = 255;
#else
outBuffer[( y * outSize + x ) * 4 + 0] = byte( ( dir.x * 0.5f + 0.5f ) * 255 );
outBuffer[( y * outSize + x ) * 4 + 1] = byte( ( dir.y * 0.5f + 0.5f ) * 255 );
outBuffer[( y * outSize + x ) * 4 + 2] = 0;
outBuffer[( y * outSize + x ) * 4 + 3] = 255;
#endif
progressBar.Increment();
}
}
fullname.Format( "env/%s%s.png", baseName, suffix );
//common->Printf( "writing %s\n", fullname.c_str() );
const bool captureToImage = false;
common->UpdateScreen( captureToImage );
//R_WriteTGA( fullname, outBuffer, outSize, outSize, false, "fs_basepath" );
R_WritePNG( fullname, outBuffer, 4, outSize, outSize, true, "fs_basepath" );
}
int end = Sys_Milliseconds();
common->Printf( "env/%s convolved in %5.1f seconds\n\n", baseName, ( end - start ) * 0.001f );
}
#endif
for( int i = 0 ; i < 6 ; i++ )
{
@ -752,7 +845,7 @@ CONSOLE_COMMAND( makeAmbientMap, "Saves out env/<basename>_amb_ft.tga, etc", NUL
}
baseName = args.Argv( 1 );
if( args.Argc() == 3 )
if( args.Argc() >= 3 )
{
outSize = atoi( args.Argv( 2 ) );
}

View file

@ -542,11 +542,11 @@ void R_RenderView( viewDef_t* parms )
// RB: find closest environment probe
if( tr.viewDef->areaNum != -1 && !tr.viewDef->isSubview )
{
float bestDist = 90000.0f;
float bestDist = 900000.0f;
for( viewEnvprobe_t* vProbe = tr.viewDef->viewEnvprobes; vProbe != NULL; vProbe = vProbe->next )
{
float dist = ( tr.viewDef->renderView.vieworg - vProbe->globalOrigin ).LengthSqr();
float dist = ( tr.viewDef->renderView.vieworg - vProbe->globalOrigin ).Length();
if( dist < bestDist )
{
tr.viewDef->irradianceImage = vProbe->irradianceImage;