From 2e580b38ad0546c174ce28b3c257ae7b7f5ed47d Mon Sep 17 00:00:00 2001 From: Robert Beckebans Date: Sat, 14 Nov 2020 16:04:03 +0100 Subject: [PATCH] Some experiments with octahedron probes --- neo/idlib/math/Vector.cpp | 42 +++++++++++ neo/idlib/math/Vector.h | 8 +++ neo/renderer/RenderWorld_envprobes.cpp | 97 +++++++++++++++++++++++++- neo/renderer/tr_frontend_main.cpp | 4 +- 4 files changed, 147 insertions(+), 4 deletions(-) diff --git a/neo/idlib/math/Vector.cpp b/neo/idlib/math/Vector.cpp index 9d19d4ca..043f2a20 100644 --- a/neo/idlib/math/Vector.cpp +++ b/neo/idlib/math/Vector.cpp @@ -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 + //=============================================================== // diff --git a/neo/idlib/math/Vector.h b/neo/idlib/math/Vector.h index 8e89051e..362b35c1 100644 --- a/neo/idlib/math/Vector.h +++ b/neo/idlib/math/Vector.h @@ -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; diff --git a/neo/renderer/RenderWorld_envprobes.cpp b/neo/renderer/RenderWorld_envprobes.cpp index ad4c4c1c..796893da 100644 --- a/neo/renderer/RenderWorld_envprobes.cpp +++ b/neo/renderer/RenderWorld_envprobes.cpp @@ -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/_amb_ft.tga, etc", NUL } baseName = args.Argv( 1 ); - if( args.Argc() == 3 ) + if( args.Argc() >= 3 ) { outSize = atoi( args.Argv( 2 ) ); } diff --git a/neo/renderer/tr_frontend_main.cpp b/neo/renderer/tr_frontend_main.cpp index 54e104fa..c3d01322 100644 --- a/neo/renderer/tr_frontend_main.cpp +++ b/neo/renderer/tr_frontend_main.cpp @@ -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;