From 0b4be8c73a5fb65ca723d1c7ab28e2d1600c6eb2 Mon Sep 17 00:00:00 2001 From: Robert Beckebans Date: Wed, 28 Apr 2021 15:44:33 +0200 Subject: [PATCH] Added interpolation of the 3 nearest reflection probes --- .../lighting/ambient_lightgrid_IBL.ps.hlsl | 12 +- .../lighting/ambient_lighting_IBL.ps.hlsl | 8 +- neo/renderer/OpenGL/RenderDebug_GL.cpp | 159 +++++++++++++++++- neo/renderer/RenderBackend.cpp | 52 +++--- neo/renderer/RenderCommon.h | 6 +- neo/renderer/RenderProgs_embedded.h | 20 ++- neo/renderer/tr_frontend_main.cpp | 144 +++++++++++++--- neo/renderer/tr_trisurf.cpp | 80 ++++++++- 8 files changed, 416 insertions(+), 65 deletions(-) diff --git a/base/renderprogs/builtin/lighting/ambient_lightgrid_IBL.ps.hlsl b/base/renderprogs/builtin/lighting/ambient_lightgrid_IBL.ps.hlsl index 5490f298..a681d850 100644 --- a/base/renderprogs/builtin/lighting/ambient_lightgrid_IBL.ps.hlsl +++ b/base/renderprogs/builtin/lighting/ambient_lightgrid_IBL.ps.hlsl @@ -40,7 +40,11 @@ uniform sampler2D samp3 : register(s3); // texture 3 is the BRDF LUT uniform sampler2D samp4 : register(s4); // texture 4 is SSAO uniform sampler2D samp7 : register(s7); // texture 7 is the irradiance cube map -uniform sampler2D samp8 : register(s8); // texture 8 is the radiance cube map +uniform sampler2D samp8 : register(s8); // texture 8 is the radiance cube map 1 +uniform sampler2D samp9 : register(s9); // texture 9 is the radiance cube map 2 +uniform sampler2D samp10 : register(s10); // texture 10 is the radiance cube map 3 + +uniform float4 rpUser0 : register( c128 ); struct PS_IN { @@ -343,6 +347,7 @@ void main( PS_IN fragment, out PS_OUT result ) // rpScreenCorrectionFactor.w = probeSize factor accounting account offset border, e.g = ( 16 / 18 ) = 0.8888 float2 octCoordNormalizedToTextureDimensions = ( normalizedOctCoordZeroOne + atlasOffset ) * rpScreenCorrectionFactor.w; + // skip by default 2 pixels for each grid cell and offset the start position by (1,1) // rpScreenCorrectionFactor.z = borderSize e.g = 2 float2 probeTopLeftPosition; probeTopLeftPosition.x = ( gridCoord2[0] * gridStep[0] + gridCoord2[2] * gridStep[1] ) * rpScreenCorrectionFactor.z + rpScreenCorrectionFactor.z * 0.5; @@ -389,7 +394,10 @@ void main( PS_IN fragment, out PS_OUT result ) normalizedOctCoord = octEncode( reflectionVector ); normalizedOctCoordZeroOne = ( normalizedOctCoord + float2( 1.0 ) ) * 0.5; - float3 radiance = textureLod( samp8, normalizedOctCoordZeroOne, mip ).rgb; + float3 radiance = textureLod( samp8, normalizedOctCoordZeroOne, mip ).rgb * rpUser0.x; + radiance += textureLod( samp9, normalizedOctCoordZeroOne, mip ).rgb * rpUser0.y; + radiance += textureLod( samp10, normalizedOctCoordZeroOne, mip ).rgb * rpUser0.z; + //radiance = float3( 0.0 ); // RB: HACK dim down room radiance by better local irradiance brightness diff --git a/base/renderprogs/builtin/lighting/ambient_lighting_IBL.ps.hlsl b/base/renderprogs/builtin/lighting/ambient_lighting_IBL.ps.hlsl index 7593007c..9859d3c6 100644 --- a/base/renderprogs/builtin/lighting/ambient_lighting_IBL.ps.hlsl +++ b/base/renderprogs/builtin/lighting/ambient_lighting_IBL.ps.hlsl @@ -40,7 +40,9 @@ uniform sampler2D samp3 : register(s3); // texture 3 is the BRDF LUT uniform sampler2D samp4 : register(s4); // texture 4 is SSAO uniform sampler2D samp7 : register(s7); // texture 7 is the irradiance cube map -uniform sampler2D samp8 : register(s8); // texture 8 is the radiance cube map +uniform sampler2D samp8 : register(s8); // texture 8 is the radiance cube map 1 +uniform sampler2D samp9 : register(s9); // texture 9 is the radiance cube map 2 +uniform sampler2D samp10 : register(s10); // texture 10 is the radiance cube map 3 struct PS_IN { @@ -270,7 +272,9 @@ void main( PS_IN fragment, out PS_OUT result ) normalizedOctCoordZeroOne = OctTexCoord( reflectionVector ); - float3 radiance = textureLod( samp8, normalizedOctCoordZeroOne, mip ).rgb; + float3 radiance = textureLod( samp8, normalizedOctCoordZeroOne, mip ).rgb * rpGlobalLightOrigin.x; + radiance += textureLod( samp9, normalizedOctCoordZeroOne, mip ).rgb * rpGlobalLightOrigin.y; + radiance += textureLod( samp10, normalizedOctCoordZeroOne, mip ).rgb * rpGlobalLightOrigin.z; //radiance = float3( 0.0 ); float2 envBRDF = texture( samp3, float2( max( vDotN, 0.0 ), roughness ) ).rg; diff --git a/neo/renderer/OpenGL/RenderDebug_GL.cpp b/neo/renderer/OpenGL/RenderDebug_GL.cpp index 7f24b73c..fed113ad 100644 --- a/neo/renderer/OpenGL/RenderDebug_GL.cpp +++ b/neo/renderer/OpenGL/RenderDebug_GL.cpp @@ -1702,9 +1702,38 @@ void idRenderBackend::DBG_ShowLights() ============== RB_ShowViewEnvprobes -Visualize all environemnt probes used in the current scene +Visualize all environment probes used in the current scene ============== */ +class idSort_DebugCompareViewEnvprobe : public idSort_Quick< RenderEnvprobeLocal*, idSort_DebugCompareViewEnvprobe > +{ + idVec3 viewOrigin; + +public: + idSort_DebugCompareViewEnvprobe( const idVec3& origin ) + { + viewOrigin = origin; + } + + int Compare( RenderEnvprobeLocal* const& a, RenderEnvprobeLocal* const& b ) const + { + float adist = ( viewOrigin - a->parms.origin ).LengthSqr(); + float bdist = ( viewOrigin - b->parms.origin ).LengthSqr(); + + if( adist < bdist ) + { + return -1; + } + + if( adist > bdist ) + { + return 1; + } + + return 0; + } +}; + void idRenderBackend::DBG_ShowViewEnvprobes() { if( !r_showViewEnvprobes.GetInteger() ) @@ -1794,6 +1823,134 @@ void idRenderBackend::DBG_ShowViewEnvprobes() } #endif } + + + //if( r_showViewEnvprobes.GetInteger() >= 3 ) + if( tr.primaryWorld ) + { + /* + idList viewEnvprobes; + for( viewEnvprobe_t* vProbe = viewDef->viewEnvprobes; vProbe != NULL; vProbe = vProbe->next ) + { + viewEnvprobes.AddUnique( vProbe ); + } + */ + + idList viewEnvprobes; + for( int i = 0; i < tr.primaryWorld->envprobeDefs.Num(); i++ ) + { + RenderEnvprobeLocal* vProbe = tr.primaryWorld->envprobeDefs[i]; + if( vProbe ) + { + viewEnvprobes.AddUnique( vProbe ); + } + } + + if( viewEnvprobes.Num() == 0 ) + { + return; + } + + idVec3 testOrigin = viewDef->renderView.vieworg; + //testOrigin += viewDef->renderView.viewaxis[0] * 150.0f; + //testOrigin -= viewDef->renderView.viewaxis[2] * 16.0f; + + // sort by distance + viewEnvprobes.SortWithTemplate( idSort_DebugCompareViewEnvprobe( testOrigin ) ); + + // draw 3 nearest probes + renderProgManager.BindShader_Color(); + + const int numColors = 3; + static idVec4 colors[numColors] = { colorRed, colorGreen, colorBlue }; + + // form a triangle of the 3 closest probes + idVec3 verts[3]; + for( int i = 0; i < 3; i++ ) + { + verts[i] = viewEnvprobes[0]->parms.origin; + } + + for( int i = 0; i < viewEnvprobes.Num() && i < 3; i++ ) + { + RenderEnvprobeLocal* vProbe = viewEnvprobes[i]; + + verts[i] = vProbe->parms.origin; + } + + idVec3 closest = R_ClosestPointPointTriangle( testOrigin, verts[0], verts[1], verts[2] ); + idVec3 barycentricWeights; + + // find the barycentric coordinates + float denom = idWinding::TriangleArea( verts[0], verts[1], verts[2] ); + if( denom == 0 ) + { + // all points at same location + barycentricWeights.Set( 1, 0, 0 ); + } + else + { + float a, b, c; + + a = idWinding::TriangleArea( closest, verts[1], verts[2] ) / denom; + b = idWinding::TriangleArea( closest, verts[2], verts[0] ) / denom; + c = idWinding::TriangleArea( closest, verts[0], verts[1] ) / denom; + + barycentricWeights.Set( a, b, c ); + } + + idMat3 axis; + axis.Identity(); + + for( int i = 0; i < viewEnvprobes.Num() && i < 3; i++ ) + { + RenderEnvprobeLocal* vProbe = viewEnvprobes[i]; + + verts[i] = vProbe->parms.origin; + + //GL_Color( colors[i] ); + + idVec4 color = Lerp( colorBlack, colors[i], barycentricWeights[i] ); + GL_Color( color ); + + idRenderMatrix modelRenderMatrix; + idRenderMatrix::CreateFromOriginAxis( vProbe->parms.origin, axis, modelRenderMatrix ); + + // calculate the matrix that transforms the unit cube to exactly cover the model in world space + const float size = 16.0f; + idBounds debugBounds( idVec3( -size ), idVec3( size ) ); + + idRenderMatrix inverseBaseModelProject; + idRenderMatrix::OffsetScaleForBounds( modelRenderMatrix, debugBounds, inverseBaseModelProject ); + + idRenderMatrix invProjectMVPMatrix; + idRenderMatrix::Multiply( viewDef->worldSpace.mvp, inverseBaseModelProject, invProjectMVPMatrix ); + RB_SetMVP( invProjectMVPMatrix ); + + DrawElementsWithCounters( &zeroOneSphereSurface ); + } + + // draw closest hit + { + GL_Color( colorYellow ); + + idRenderMatrix modelRenderMatrix; + idRenderMatrix::CreateFromOriginAxis( closest, axis, modelRenderMatrix ); + + // calculate the matrix that transforms the unit cube to exactly cover the model in world space + const float size = 4.0f; + idBounds debugBounds( idVec3( -size ), idVec3( size ) ); + + idRenderMatrix inverseBaseModelProject; + idRenderMatrix::OffsetScaleForBounds( modelRenderMatrix, debugBounds, inverseBaseModelProject ); + + idRenderMatrix invProjectMVPMatrix; + idRenderMatrix::Multiply( viewDef->worldSpace.mvp, inverseBaseModelProject, invProjectMVPMatrix ); + RB_SetMVP( invProjectMVPMatrix ); + + DrawElementsWithCounters( &zeroOneSphereSurface ); + } + } } void idRenderBackend::DBG_ShowLightGrid() diff --git a/neo/renderer/RenderBackend.cpp b/neo/renderer/RenderBackend.cpp index 3beb3125..d3dfdd2f 100644 --- a/neo/renderer/RenderBackend.cpp +++ b/neo/renderer/RenderBackend.cpp @@ -1200,9 +1200,13 @@ const int INTERACTION_TEXUNIT_JITTER = 6; #if defined( USE_VULKAN ) const int INTERACTION_TEXUNIT_AMBIENT_CUBE1 = 5; const int INTERACTION_TEXUNIT_SPECULAR_CUBE1 = 6; + const int INTERACTION_TEXUNIT_SPECULAR_CUBE2 = 7; + const int INTERACTION_TEXUNIT_SPECULAR_CUBE3 = 8; #else const int INTERACTION_TEXUNIT_AMBIENT_CUBE1 = 7; const int INTERACTION_TEXUNIT_SPECULAR_CUBE1 = 8; + const int INTERACTION_TEXUNIT_SPECULAR_CUBE2 = 9; + const int INTERACTION_TEXUNIT_SPECULAR_CUBE3 = 10; #endif /* @@ -1344,8 +1348,6 @@ void idRenderBackend::DrawSingleInteraction( drawInteraction_t* din, bool useFas SetVertexParm( RENDERPARM_WOBBLESKY_Y, probeMaxs.ToFloatPtr() ); SetVertexParm( RENDERPARM_WOBBLESKY_Z, probeCenter.ToFloatPtr() ); - //SetVertexParm( RENDERPARM_WOBBLESK_Z, probeCenter.ToFloatPtr() ); - // use rpGlobalLightOrigin for lightGrid center idVec4 lightGridOrigin( currentSpace->lightGridOrigin.x, currentSpace->lightGridOrigin.y, currentSpace->lightGridOrigin.z, 1.0f ); idVec4 lightGridSize( currentSpace->lightGridSize.x, currentSpace->lightGridSize.y, currentSpace->lightGridSize.z, 1.0f ); @@ -1363,6 +1365,9 @@ void idRenderBackend::DrawSingleInteraction( drawInteraction_t* din, bool useFas probeSize[3] = float( currentSpace->lightGridAtlasSingleProbeSize - currentSpace->lightGridAtlasBorderSize ) / currentSpace->lightGridAtlasSingleProbeSize; renderProgManager.SetUniformValue( RENDERPARM_SCREENCORRECTIONFACTOR, probeSize.ToFloatPtr() ); // rpScreenCorrectionFactor + // specular cubemap blend weights + renderProgManager.SetUniformValue( RENDERPARM_USER0, viewDef->radianceImageBlends.ToFloatPtr() ); + if( specUsage == TD_SPECULAR_PBR_RMAO || specUsage == TD_SPECULAR_PBR_RMAOD ) { // PBR path with roughness, metal and AO @@ -1413,14 +1418,13 @@ void idRenderBackend::DrawSingleInteraction( drawInteraction_t* din, bool useFas renderProgManager.SetUniformValue( RENDERPARM_CASCADEDISTANCES, textureSize.ToFloatPtr() ); GL_SelectTexture( INTERACTION_TEXUNIT_SPECULAR_CUBE1 ); - if( viewDef->radianceImage ) - { - viewDef->radianceImage->Bind(); - } - else - { - globalImages->defaultUACRadianceCube->Bind(); - } + viewDef->radianceImages[0]->Bind(); + + GL_SelectTexture( INTERACTION_TEXUNIT_SPECULAR_CUBE2 ); + viewDef->radianceImages[1]->Bind(); + + GL_SelectTexture( INTERACTION_TEXUNIT_SPECULAR_CUBE3 ); + viewDef->radianceImages[2]->Bind(); } else if( useIBL ) { @@ -1443,6 +1447,9 @@ void idRenderBackend::DrawSingleInteraction( drawInteraction_t* din, bool useFas SetVertexParm( RENDERPARM_WOBBLESKY_Y, probeMaxs.ToFloatPtr() ); SetVertexParm( RENDERPARM_WOBBLESKY_Z, probeCenter.ToFloatPtr() ); + // specular cubemap blend weights + renderProgManager.SetUniformValue( RENDERPARM_GLOBALLIGHTORIGIN, viewDef->radianceImageBlends.ToFloatPtr() ); + if( specUsage == TD_SPECULAR_PBR_RMAO || specUsage == TD_SPECULAR_PBR_RMAOD ) { // PBR path with roughness, metal and AO @@ -1484,26 +1491,17 @@ void idRenderBackend::DrawSingleInteraction( drawInteraction_t* din, bool useFas } #endif - // TODO bind the 3 closest probes GL_SelectTexture( INTERACTION_TEXUNIT_AMBIENT_CUBE1 ); - if( viewDef->irradianceImage ) - { - viewDef->irradianceImage->Bind(); - } - else - { - globalImages->defaultUACIrradianceCube->Bind(); - } + viewDef->irradianceImage->Bind(); GL_SelectTexture( INTERACTION_TEXUNIT_SPECULAR_CUBE1 ); - if( viewDef->radianceImage ) - { - viewDef->radianceImage->Bind(); - } - else - { - globalImages->defaultUACRadianceCube->Bind(); - } + viewDef->radianceImages[0]->Bind(); + + GL_SelectTexture( INTERACTION_TEXUNIT_SPECULAR_CUBE2 ); + viewDef->radianceImages[1]->Bind(); + + GL_SelectTexture( INTERACTION_TEXUNIT_SPECULAR_CUBE3 ); + viewDef->radianceImages[2]->Bind(); } else if( setInteractionShader ) { diff --git a/neo/renderer/RenderCommon.h b/neo/renderer/RenderCommon.h index 248d4102..09ef1a09 100644 --- a/neo/renderer/RenderCommon.h +++ b/neo/renderer/RenderCommon.h @@ -648,7 +648,8 @@ struct viewDef_t idBounds globalProbeBounds; idRenderMatrix inverseBaseEnvProbeProject; // the matrix for deforming the 'zeroOneCubeModel' to exactly cover the environent probe volume in world space idImage* irradianceImage; // cubemap image used for diffuse IBL by backend - idImage* radianceImage; // cubemap image used for specular IBL by backend + idImage* radianceImages[3]; // cubemap image used for specular IBL by backend + idVec4 radianceImageBlends; // blending weights }; @@ -1613,6 +1614,9 @@ void R_InitDrawSurfFromTri( drawSurf_t& ds, srfTriangles_t& tri ); // time, rather than being re-created each frame in the frame temporary buffers. void R_CreateStaticBuffersForTri( srfTriangles_t& tri ); +// RB +idVec3 R_ClosestPointPointTriangle( const idVec3& point, const idVec3& vertex1, const idVec3& vertex2, const idVec3& vertex3 ); + // deformable meshes precalculate as much as possible from a base frame, then generate // complete srfTriangles_t from just a new set of vertexes struct deformInfo_t diff --git a/neo/renderer/RenderProgs_embedded.h b/neo/renderer/RenderProgs_embedded.h index ea58d2b5..04cbd26d 100644 --- a/neo/renderer/RenderProgs_embedded.h +++ b/neo/renderer/RenderProgs_embedded.h @@ -4807,7 +4807,9 @@ static const cgShaderDef_t cg_renderprogs[] = "uniform sampler2D samp4 : register(s4); // texture 4 is SSAO\n" "\n" "uniform sampler2D samp7 : register(s7); // texture 7 is the irradiance cube map\n" - "uniform sampler2D samp8 : register(s8); // texture 8 is the radiance cube map\n" + "uniform sampler2D samp8 : register(s8); // texture 8 is the radiance cube map 1\n" + "uniform sampler2D samp9 : register(s9); // texture 9 is the radiance cube map 2\n" + "uniform sampler2D samp10 : register(s10); // texture 10 is the radiance cube map 3\n" "\n" "struct PS_IN \n" "{\n" @@ -5037,7 +5039,9 @@ static const cgShaderDef_t cg_renderprogs[] = "\n" " normalizedOctCoordZeroOne = OctTexCoord( reflectionVector );\n" "\n" - " float3 radiance = textureLod( samp8, normalizedOctCoordZeroOne, mip ).rgb;\n" + " float3 radiance = textureLod( samp8, normalizedOctCoordZeroOne, mip ).rgb * rpGlobalLightOrigin.x;\n" + " radiance += textureLod( samp9, normalizedOctCoordZeroOne, mip ).rgb * rpGlobalLightOrigin.y;\n" + " radiance += textureLod( samp10, normalizedOctCoordZeroOne, mip ).rgb * rpGlobalLightOrigin.z;\n" " //radiance = float3( 0.0 );\n" "\n" " float2 envBRDF = texture( samp3, float2( max( vDotN, 0.0 ), roughness ) ).rg;\n" @@ -5323,7 +5327,11 @@ static const cgShaderDef_t cg_renderprogs[] = "uniform sampler2D samp4 : register(s4); // texture 4 is SSAO\n" "\n" "uniform sampler2D samp7 : register(s7); // texture 7 is the irradiance cube map\n" - "uniform sampler2D samp8 : register(s8); // texture 8 is the radiance cube map\n" + "uniform sampler2D samp8 : register(s8); // texture 8 is the radiance cube map 1\n" + "uniform sampler2D samp9 : register(s9); // texture 9 is the radiance cube map 2\n" + "uniform sampler2D samp10 : register(s10); // texture 10 is the radiance cube map 3\n" + "\n" + "uniform float4 rpUser0 : register( c128 );\n" "\n" "struct PS_IN \n" "{\n" @@ -5626,6 +5634,7 @@ static const cgShaderDef_t cg_renderprogs[] = " // rpScreenCorrectionFactor.w = probeSize factor accounting account offset border, e.g = ( 16 / 18 ) = 0.8888\n" " float2 octCoordNormalizedToTextureDimensions = ( normalizedOctCoordZeroOne + atlasOffset ) * rpScreenCorrectionFactor.w;\n" "\n" + " // skip by default 2 pixels for each grid cell and offset the start position by (1,1)\n" " // rpScreenCorrectionFactor.z = borderSize e.g = 2\n" " float2 probeTopLeftPosition;\n" " probeTopLeftPosition.x = ( gridCoord2[0] * gridStep[0] + gridCoord2[2] * gridStep[1] ) * rpScreenCorrectionFactor.z + rpScreenCorrectionFactor.z * 0.5;\n" @@ -5672,7 +5681,10 @@ static const cgShaderDef_t cg_renderprogs[] = " normalizedOctCoord = octEncode( reflectionVector );\n" " normalizedOctCoordZeroOne = ( normalizedOctCoord + float2( 1.0 ) ) * 0.5;\n" "\n" - " float3 radiance = textureLod( samp8, normalizedOctCoordZeroOne, mip ).rgb;\n" + " float3 radiance = textureLod( samp8, normalizedOctCoordZeroOne, mip ).rgb * rpUser0.x;\n" + " radiance += textureLod( samp9, normalizedOctCoordZeroOne, mip ).rgb * rpUser0.y;\n" + " radiance += textureLod( samp10, normalizedOctCoordZeroOne, mip ).rgb * rpUser0.z;\n" + "\n" " //radiance = float3( 0.0 );\n" "\n" " // RB: HACK dim down room radiance by better local irradiance brightness\n" diff --git a/neo/renderer/tr_frontend_main.cpp b/neo/renderer/tr_frontend_main.cpp index 54d17e19..82a60885 100644 --- a/neo/renderer/tr_frontend_main.cpp +++ b/neo/renderer/tr_frontend_main.cpp @@ -454,6 +454,121 @@ static void R_SetupSplitFrustums( viewDef_t* viewDef ) } } } + +class idSort_CompareEnvprobe : public idSort_Quick< RenderEnvprobeLocal*, idSort_CompareEnvprobe > +{ + idVec3 viewOrigin; + +public: + idSort_CompareEnvprobe( const idVec3& origin ) + { + viewOrigin = origin; + } + + int Compare( RenderEnvprobeLocal* const& a, RenderEnvprobeLocal* const& b ) const + { + float adist = ( viewOrigin - a->parms.origin ).LengthSqr(); + float bdist = ( viewOrigin - b->parms.origin ).LengthSqr(); + + if( adist < bdist ) + { + return -1; + } + + if( adist > bdist ) + { + return 1; + } + + return 0; + } +}; + +static void R_FindClosestEnvironmentProbes() +{ + // set safe defaults + tr.viewDef->globalProbeBounds.Clear(); + + tr.viewDef->irradianceImage = globalImages->defaultUACIrradianceCube; + tr.viewDef->radianceImageBlends.Set( 1, 0, 0, 0 ); + for( int i = 0; i < 3; i++ ) + { + tr.viewDef->radianceImages[i] = globalImages->defaultUACRadianceCube; + } + + // early out + if( tr.viewDef->areaNum == -1 || tr.viewDef->isSubview ) + { + return; + } + + idList viewEnvprobes; + for( int i = 0; i < tr.primaryWorld->envprobeDefs.Num(); i++ ) + { + RenderEnvprobeLocal* vProbe = tr.primaryWorld->envprobeDefs[i]; + if( vProbe ) + { + viewEnvprobes.AddUnique( vProbe ); + } + } + + if( viewEnvprobes.Num() == 0 ) + { + return; + } + + idVec3 testOrigin = tr.viewDef->renderView.vieworg; + + // sort by distance + // RB: each Doom 3 level has ~50 - 150 probes so this should be ok for each frame + viewEnvprobes.SortWithTemplate( idSort_CompareEnvprobe( testOrigin ) ); + + RenderEnvprobeLocal* nearest = viewEnvprobes[0]; + tr.viewDef->globalProbeBounds = nearest->globalProbeBounds; + tr.viewDef->irradianceImage = nearest->irradianceImage; + + // form a triangle of the 3 closest probes + idVec3 verts[3]; + for( int i = 0; i < 3; i++ ) + { + verts[i] = viewEnvprobes[0]->parms.origin; + } + + for( int i = 0; i < viewEnvprobes.Num() && i < 3; i++ ) + { + RenderEnvprobeLocal* vProbe = viewEnvprobes[i]; + + verts[i] = vProbe->parms.origin; + } + + idVec3 closest = R_ClosestPointPointTriangle( testOrigin, verts[0], verts[1], verts[2] ); + idVec3 bary; + + // find the barycentric coordinates + float denom = idWinding::TriangleArea( verts[0], verts[1], verts[2] ); + if( denom == 0 ) + { + // all points at same location + bary.Set( 1, 0, 0 ); + } + else + { + float a, b, c; + + a = idWinding::TriangleArea( closest, verts[1], verts[2] ) / denom; + b = idWinding::TriangleArea( closest, verts[2], verts[0] ) / denom; + c = idWinding::TriangleArea( closest, verts[0], verts[1] ) / denom; + + bary.Set( a, b, c ); + } + + tr.viewDef->radianceImageBlends.Set( bary.x, bary.y, bary.z, 0.0f ); + + for( int i = 0; i < viewEnvprobes.Num() && i < 3; i++ ) + { + tr.viewDef->radianceImages[i] = viewEnvprobes[i]->radianceImage; + } +} // RB end /* @@ -539,33 +654,8 @@ void R_RenderView( viewDef_t* parms ) } } - // RB: find closest environment probe - if( tr.viewDef->areaNum != -1 && !tr.viewDef->isSubview ) - { - float bestDist = idMath::INFINITY; - - tr.viewDef->globalProbeBounds.Clear(); - - tr.viewDef->irradianceImage = globalImages->defaultUACIrradianceCube; - tr.viewDef->radianceImage = globalImages->defaultUACRadianceCube; - - for( viewEnvprobe_t* vProbe = tr.viewDef->viewEnvprobes; vProbe != NULL; vProbe = vProbe->next ) - { - float dist = ( tr.viewDef->renderView.vieworg - vProbe->globalOrigin ).Length(); - if( ( dist < bestDist ) ) - { - if( vProbe->irradianceImage->IsLoaded() && !vProbe->irradianceImage->IsDefaulted() ) - { - tr.viewDef->globalProbeBounds = vProbe->globalProbeBounds; - - tr.viewDef->irradianceImage = vProbe->irradianceImage; - tr.viewDef->radianceImage = vProbe->radianceImage; - - bestDist = dist; - } - } - } - } + // RB: find closest environment probes so we can interpolate between them in the ambient shaders + R_FindClosestEnvironmentProbes(); // write everything needed to the demo file if( common->WriteDemo() ) diff --git a/neo/renderer/tr_trisurf.cpp b/neo/renderer/tr_trisurf.cpp index 8800676e..d77554a7 100644 --- a/neo/renderer/tr_trisurf.cpp +++ b/neo/renderer/tr_trisurf.cpp @@ -2367,4 +2367,82 @@ static void SetUpMikkTSpaceContext( SMikkTSpaceContext* context ) context->m_pInterface = &mikkTSpaceInterface.mkInterface; } -// SP end \ No newline at end of file +// SP end + + +// RB: Determines the closest point between a point and a triangle +idVec3 R_ClosestPointPointTriangle( const idVec3& point, const idVec3& vertex1, const idVec3& vertex2, const idVec3& vertex3 ) +{ + idVec3 result; + + // Source: Real-Time Collision Detection by Christer Ericson + // Reference: Page 136 + + // check if P in vertex region outside A + idVec3 ab = vertex2 - vertex1; + idVec3 ac = vertex3 - vertex1; + idVec3 ap = point - vertex1; + + float d1 = ( ab * ap ); + float d2 = ( ac * ap ); + if( d1 <= 0.0f && d2 <= 0.0f ) + { + result = vertex1; //Barycentric coordinates (1,0,0) + return result; + } + + // Check if P in vertex region outside B + idVec3 bp = point - vertex2; + float d3 = ( ab * bp ); + float d4 = ( ac * bp ); + if( d3 >= 0.0f && d4 <= d3 ) + { + result = vertex2; // barycentric coordinates (0,1,0) + return result; + } + + // Check if P in edge region of AB, if so return projection of P onto AB + float vc = d1 * d4 - d3 * d2; + if( vc <= 0.0f && d1 >= 0.0f && d3 <= 0.0f ) + { + float v = d1 / ( d1 - d3 ); + result = vertex1 + v * ab; //Barycentric coordinates (1-v,v,0) + return result; + } + + // Check if P in vertex region outside C + idVec3 cp = point - vertex3; + float d5 = ( ab * cp ); + float d6 = ( ac * cp ); + if( d6 >= 0.0f && d5 <= d6 ) + { + result = vertex3; //Barycentric coordinates (0,0,1) + return result; + } + + // Check if P in edge region of AC, if so return projection of P onto AC + float vb = d5 * d2 - d1 * d6; + if( vb <= 0.0f && d2 >= 0.0f && d6 <= 0.0f ) + { + float w = d2 / ( d2 - d6 ); + result = vertex1 + w * ac; //Barycentric coordinates (1-w,0,w) + return result; + } + + // Check if P in edge region of BC, if so return projection of P onto BC + float va = d3 * d6 - d5 * d4; + if( va <= 0.0f && ( d4 - d3 ) >= 0.0f && ( d5 - d6 ) >= 0.0f ) + { + float w = ( d4 - d3 ) / ( ( d4 - d3 ) + ( d5 - d6 ) ); + result = vertex2 + w * ( vertex3 - vertex2 ); //Barycentric coordinates (0,1-w,w) + return result; + } + + // P inside face region. Compute Q through its barycentric coordinates (u,v,w) + float denom = 1.0f / ( va + vb + vc ); + float v2 = vb * denom; + float w2 = vc * denom; + result = vertex1 + ab * v2 + ac * w2; //= u*vertex1 + v*vertex2 + w*vertex3, u = va * denom = 1.0f - v - w + + return result; +} \ No newline at end of file