Added interpolation of the 3 nearest reflection probes

This commit is contained in:
Robert Beckebans 2021-04-28 15:44:33 +02:00
parent 167085385b
commit 0b4be8c73a
8 changed files with 416 additions and 65 deletions

View file

@ -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

View file

@ -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;

View file

@ -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<viewEnvprobe_t*, TAG_RENDER_ENVPROBE> viewEnvprobes;
for( viewEnvprobe_t* vProbe = viewDef->viewEnvprobes; vProbe != NULL; vProbe = vProbe->next )
{
viewEnvprobes.AddUnique( vProbe );
}
*/
idList<RenderEnvprobeLocal*, TAG_RENDER_ENVPROBE> 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()

View file

@ -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 )
{

View file

@ -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

View file

@ -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"

View file

@ -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<RenderEnvprobeLocal*, TAG_RENDER_ENVPROBE> 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() )

View file

@ -2367,4 +2367,82 @@ static void SetUpMikkTSpaceContext( SMikkTSpaceContext* context )
context->m_pInterface = &mikkTSpaceInterface.mkInterface;
}
// SP end
// 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;
}