Added parallax correction for local cubemaps

This commit is contained in:
Robert Beckebans 2021-04-09 22:28:09 +02:00
parent c40ab1e7e8
commit 5d26aaddb3
10 changed files with 294 additions and 132 deletions

View file

@ -3,7 +3,7 @@
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
Copyright (C) 2013-2020 Robert Beckebans
Copyright (C) 2013-2021 Robert Beckebans
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
@ -52,6 +52,7 @@ struct PS_IN
half4 texcoord4 : TEXCOORD4_centroid;
half4 texcoord5 : TEXCOORD5_centroid;
half4 texcoord6 : TEXCOORD6_centroid;
half4 texcoord7 : TEXCOORD7_centroid;
half4 color : COLOR0;
};
@ -61,6 +62,61 @@ struct PS_OUT
};
// *INDENT-ON*
// RB: TODO OPTIMIZE
// this is a straight port of idBounds::RayIntersection
bool AABBRayIntersection( float3 b[2], float3 start, float3 dir, out float scale )
{
int i, ax0, ax1, ax2, side, inside;
float f;
float3 hit;
ax0 = -1;
inside = 0;
for( i = 0; i < 3; i++ )
{
if( start[i] < b[0][i] )
{
side = 0;
}
else if( start[i] > b[1][i] )
{
side = 1;
}
else
{
inside++;
continue;
}
if( dir[i] == 0.0f )
{
continue;
}
f = ( start[i] - b[side][i] );
if( ax0 < 0 || abs( f ) > abs( scale * dir[i] ) )
{
scale = - ( f / dir[i] );
ax0 = i;
}
}
if( ax0 < 0 )
{
scale = 0.0f;
// return true if the start point is inside the bounds
return ( inside == 3 );
}
ax1 = ( ax0 + 1 ) % 3;
ax2 = ( ax0 + 2 ) % 3;
hit[ax1] = start[ax1] + scale * dir[ax1];
hit[ax2] = start[ax2] + scale * dir[ax2];
return ( hit[ax1] >= b[0][ax1] && hit[ax1] <= b[1][ax1] &&
hit[ax2] >= b[0][ax2] && hit[ax2] <= b[1][ax2] );
}
void main( PS_IN fragment, out PS_OUT result )
{
@ -86,11 +142,41 @@ void main( PS_IN fragment, out PS_OUT result )
globalNormal.z = dot3( localNormal, fragment.texcoord6 );
globalNormal = normalize( globalNormal );
float3 globalEye = normalize( fragment.texcoord3.xyz );
float3 globalPosition = fragment.texcoord7.xyz;
// RB: rpGlobalLightOrigin is global view origin
float3 globalEye = normalize( rpGlobalLightOrigin.xyz - globalPosition );
float3 reflectionVector = globalNormal * dot3( globalEye, globalNormal );
reflectionVector = normalize( ( reflectionVector * 2.0f ) - globalEye );
#if 1
// parallax box correction using portal area bounds
float hitScale;
float3 bounds[2];
bounds[0].x = rpWobbleSkyX.x;
bounds[0].y = rpWobbleSkyX.y;
bounds[0].z = rpWobbleSkyX.z;
bounds[1].x = rpWobbleSkyY.x;
bounds[1].y = rpWobbleSkyY.y;
bounds[1].z = rpWobbleSkyY.z;
// global fragment position
float3 rayStart = fragment.texcoord7.xyz;
// we can't start inside the box so move this outside and use the reverse path
rayStart += reflectionVector * 10000;
if( AABBRayIntersection( bounds, rayStart, -reflectionVector, hitScale ) )
{
float3 hitPoint = rayStart - reflectionVector * hitScale;
// rpWobbleSkyZ is cubemap center
reflectionVector = hitPoint - rpWobbleSkyZ.xyz;
}
#endif
half vDotN = saturate( dot3( globalEye, globalNormal ) );
#if defined( USE_PBR )

View file

@ -53,6 +53,7 @@ struct VS_OUT {
float4 texcoord4 : TEXCOORD4;
float4 texcoord5 : TEXCOORD5;
float4 texcoord6 : TEXCOORD6;
float4 texcoord7 : TEXCOORD7;
float4 color : COLOR0;
};
// *INDENT-ON*
@ -157,6 +158,8 @@ void main( VS_IN vertex, out VS_OUT result )
result.texcoord2.y = dot4( vertex.texcoord.xy, rpSpecularMatrixT );
//# calculate normalized vector to viewer in R1
//result.texcoord3 = modelPosition;
float4 toEye = normalize( rpLocalViewOrigin - modelPosition );
result.texcoord3.x = dot3( toEye, rpModelMatrixX );
@ -175,6 +178,13 @@ void main( VS_IN vertex, out VS_OUT result )
result.texcoord5.z = dot3( normal, rpModelMatrixY );
result.texcoord6.z = dot3( normal, rpModelMatrixZ );
float4 worldPosition;
worldPosition.x = dot4( modelPosition, rpModelMatrixX );
worldPosition.y = dot4( modelPosition, rpModelMatrixY );
worldPosition.z = dot4( modelPosition, rpModelMatrixZ );
worldPosition.w = dot4( modelPosition, rpModelMatrixW );
result.texcoord7 = worldPosition;
#if defined( USE_GPU_SKINNING )
// for joint transformation of the tangent space, we use color and
// color2 for weighting information, so hopefully there aren't any

View file

@ -1714,13 +1714,13 @@ void idRenderBackend::DBG_ShowViewEnvprobes()
GL_State( GLS_DEFAULT | GLS_CULL_TWOSIDED );
renderProgManager.BindShader_Octahedron();
int count = 0;
for( viewEnvprobe_t* vProbe = viewDef->viewEnvprobes; vProbe != NULL; vProbe = vProbe->next )
{
count++;
renderProgManager.BindShader_Octahedron();
GL_State( GLS_DEPTHFUNC_ALWAYS | GLS_DEPTHMASK );
GL_Color( 1.0f, 1.0f, 1.0f );
@ -1768,6 +1768,22 @@ void idRenderBackend::DBG_ShowViewEnvprobes()
}
DrawElementsWithCounters( &zeroOneSphereSurface );
// non-hidden lines
#if 0
if( r_showViewEnvprobes.GetInteger() >= 3 )
{
renderProgManager.BindShader_Color();
GL_State( GLS_DEPTHFUNC_ALWAYS | GLS_POLYMODE_LINE | GLS_DEPTHMASK );
GL_Color( 1.0f, 1.0f, 1.0f );
idRenderMatrix invProjectMVPMatrix;
idRenderMatrix::Multiply( viewDef->worldSpace.mvp, vProbe->inverseBaseProbeProject, invProjectMVPMatrix );
RB_SetMVP( invProjectMVPMatrix );
DrawElementsWithCounters( &zeroOneCubeSurface );
}
#endif
}
}

View file

@ -1325,6 +1325,25 @@ void idRenderBackend::DrawSingleInteraction( drawInteraction_t* din, bool useFas
// RB begin
if( useIBL )
{
idVec4 probeMins, probeMaxs, probeCenter;
probeMins[0] = viewDef->globalProbeBounds[0][0];
probeMins[1] = viewDef->globalProbeBounds[0][1];
probeMins[2] = viewDef->globalProbeBounds[0][2];
probeMins[3] = viewDef->globalProbeBounds.IsCleared() ? 1.0f : 0.0f;
probeMaxs[0] = viewDef->globalProbeBounds[1][0];
probeMaxs[1] = viewDef->globalProbeBounds[1][1];
probeMaxs[2] = viewDef->globalProbeBounds[1][2];
probeMaxs[3] = 0.0f;
idVec3& center = viewDef->globalProbeBounds.GetCenter();
probeCenter.Set( center.x, center.y, center.z, 1.0f );
SetVertexParm( RENDERPARM_WOBBLESKY_X, probeMins.ToFloatPtr() );
SetVertexParm( RENDERPARM_WOBBLESKY_Y, probeMaxs.ToFloatPtr() );
SetVertexParm( RENDERPARM_WOBBLESKY_Z, probeCenter.ToFloatPtr() );
if( specUsage == TD_SPECULAR_PBR_RMAO || specUsage == TD_SPECULAR_PBR_RMAOD )
{
// PBR path with roughness, metal and AO
@ -2210,6 +2229,10 @@ void idRenderBackend::AmbientPass( const drawSurf_t* const* drawSurfs, int numDr
renderProgManager.SetRenderParm( RENDERPARM_AMBIENT_COLOR, ambientColor.ToFloatPtr() );
// use rpGlobalLightOrigin for camera center
idVec4 globalViewOrigin( viewDef->renderView.vieworg.x, viewDef->renderView.vieworg.y, viewDef->renderView.vieworg.z, 1.0f );
SetVertexParm( RENDERPARM_GLOBALLIGHTORIGIN, globalViewOrigin.ToFloatPtr() );
// setup renderparms assuming we will be drawing trivial surfaces first
RB_SetupForFastPathInteractions( diffuseColor, specularColor );

View file

@ -271,8 +271,8 @@ public:
// derived information
//idPlane lightProject[4]; // old style light projection where Z and W are flipped and projected lights lightProject[3] is divided by ( zNear + zFar )
idRenderMatrix baseLightProject; // global xyz1 to projected light strq
idRenderMatrix inverseBaseLightProject;// transforms the zero-to-one cube to exactly cover the light in world space
//idRenderMatrix baseLightProject; // global xyz1 to projected light strq
idRenderMatrix inverseBaseProbeProject;// transforms the zero-to-one cube to exactly cover the light in world space
idBounds globalProbeBounds;
@ -477,8 +477,9 @@ struct viewEnvprobe_t
bool removeFromList;
idVec3 globalOrigin; // global envprobe origin used by backend
idBounds globalProbeBounds;
idRenderMatrix inverseBaseLightProject; // the matrix for deforming the 'zeroOneCubeModel' to exactly cover the light volume in world space
idRenderMatrix inverseBaseProbeProject; // the matrix for deforming the 'zeroOneCubeModel' to exactly cover the light volume in world space
idImage* irradianceImage; // cubemap image used for diffuse IBL by backend
idImage* radianceImage; // cubemap image used for specular IBL by backend
};
@ -612,6 +613,7 @@ struct viewDef_t
viewEnvprobe_t* viewEnvprobes;
// RB: nearest probe for now
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

View file

@ -147,6 +147,7 @@ enum renderParm_t
// RB begin
RENDERPARM_AMBIENT_COLOR,
// RENDERPARM_GLOBALVIEWORIGIN,
RENDERPARM_GLOBALLIGHTORIGIN,
RENDERPARM_JITTERTEXSCALE,
RENDERPARM_JITTERTEXOFFSET,

View file

@ -4491,7 +4491,7 @@ static const cgShaderDef_t cg_renderprogs[] =
"\n"
"Doom 3 BFG Edition GPL Source Code\n"
"Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.\n"
"Copyright (C) 2013-2020 Robert Beckebans\n"
"Copyright (C) 2013-2021 Robert Beckebans\n"
"\n"
"This file is part of the Doom 3 BFG Edition GPL Source Code (\"Doom 3 BFG Edition Source Code\").\n"
"\n"
@ -4540,6 +4540,7 @@ static const cgShaderDef_t cg_renderprogs[] =
" half4 texcoord4 : TEXCOORD4_centroid;\n"
" half4 texcoord5 : TEXCOORD5_centroid;\n"
" half4 texcoord6 : TEXCOORD6_centroid;\n"
" half4 texcoord7 : TEXCOORD7_centroid;\n"
" half4 color : COLOR0;\n"
"};\n"
"\n"
@ -4549,6 +4550,61 @@ static const cgShaderDef_t cg_renderprogs[] =
"};\n"
"// *INDENT-ON*\n"
"\n"
"// RB: TODO OPTIMIZE\n"
"// this is a straight port of idBounds::RayIntersection\n"
"bool AABBRayIntersection( float3 b[2], float3 start, float3 dir, out float scale )\n"
"{\n"
" int i, ax0, ax1, ax2, side, inside;\n"
" float f;\n"
" float3 hit;\n"
"\n"
" ax0 = -1;\n"
" inside = 0;\n"
" for( i = 0; i < 3; i++ )\n"
" {\n"
" if( start[i] < b[0][i] )\n"
" {\n"
" side = 0;\n"
" }\n"
" else if( start[i] > b[1][i] )\n"
" {\n"
" side = 1;\n"
" }\n"
" else\n"
" {\n"
" inside++;\n"
" continue;\n"
" }\n"
" if( dir[i] == 0.0f )\n"
" {\n"
" continue;\n"
" }\n"
"\n"
" f = ( start[i] - b[side][i] );\n"
"\n"
" if( ax0 < 0 || abs( f ) > abs( scale * dir[i] ) )\n"
" {\n"
" scale = - ( f / dir[i] );\n"
" ax0 = i;\n"
" }\n"
" }\n"
"\n"
" if( ax0 < 0 )\n"
" {\n"
" scale = 0.0f;\n"
"\n"
" // return true if the start point is inside the bounds\n"
" return ( inside == 3 );\n"
" }\n"
"\n"
" ax1 = ( ax0 + 1 ) % 3;\n"
" ax2 = ( ax0 + 2 ) % 3;\n"
" hit[ax1] = start[ax1] + scale * dir[ax1];\n"
" hit[ax2] = start[ax2] + scale * dir[ax2];\n"
"\n"
" return ( hit[ax1] >= b[0][ax1] && hit[ax1] <= b[1][ax1] &&\n"
" hit[ax2] >= b[0][ax2] && hit[ax2] <= b[1][ax2] );\n"
"}\n"
"\n"
"void main( PS_IN fragment, out PS_OUT result )\n"
"{\n"
@ -4574,11 +4630,41 @@ static const cgShaderDef_t cg_renderprogs[] =
" globalNormal.z = dot3( localNormal, fragment.texcoord6 );\n"
" globalNormal = normalize( globalNormal );\n"
"\n"
" float3 globalEye = normalize( fragment.texcoord3.xyz );\n"
" float3 globalPosition = fragment.texcoord7.xyz;\n"
"\n"
" // RB: rpGlobalLightOrigin is global view origin\n"
" float3 globalEye = normalize( rpGlobalLightOrigin.xyz - globalPosition );\n"
"\n"
" float3 reflectionVector = globalNormal * dot3( globalEye, globalNormal );\n"
" reflectionVector = normalize( ( reflectionVector * 2.0f ) - globalEye );\n"
"\n"
"#if 1\n"
" // parallax box correction using portal area bounds\n"
" float hitScale;\n"
" float3 bounds[2];\n"
" bounds[0].x = rpWobbleSkyX.x;\n"
" bounds[0].y = rpWobbleSkyX.y;\n"
" bounds[0].z = rpWobbleSkyX.z;\n"
"\n"
" bounds[1].x = rpWobbleSkyY.x;\n"
" bounds[1].y = rpWobbleSkyY.y;\n"
" bounds[1].z = rpWobbleSkyY.z;\n"
"\n"
" // global fragment position\n"
" float3 rayStart = fragment.texcoord7.xyz;\n"
"\n"
" // we can't start inside the box so move this outside and use the reverse path\n"
" rayStart += reflectionVector * 10000;\n"
"\n"
" if( AABBRayIntersection( bounds, rayStart, -reflectionVector, hitScale ) )\n"
" {\n"
" float3 hitPoint = rayStart - reflectionVector * hitScale;\n"
"\n"
" // rpWobbleSkyZ is cubemap center\n"
" reflectionVector = hitPoint - rpWobbleSkyZ.xyz;\n"
" }\n"
"#endif\n"
"\n"
" half vDotN = saturate( dot3( globalEye, globalNormal ) );\n"
"\n"
"#if defined( USE_PBR )\n"
@ -4746,6 +4832,7 @@ static const cgShaderDef_t cg_renderprogs[] =
" float4 texcoord4 : TEXCOORD4;\n"
" float4 texcoord5 : TEXCOORD5;\n"
" float4 texcoord6 : TEXCOORD6;\n"
" float4 texcoord7 : TEXCOORD7;\n"
" float4 color : COLOR0;\n"
"};\n"
"// *INDENT-ON*\n"
@ -4850,6 +4937,8 @@ static const cgShaderDef_t cg_renderprogs[] =
" result.texcoord2.y = dot4( vertex.texcoord.xy, rpSpecularMatrixT );\n"
"\n"
" //# calculate normalized vector to viewer in R1\n"
" //result.texcoord3 = modelPosition;\n"
"\n"
" float4 toEye = normalize( rpLocalViewOrigin - modelPosition );\n"
"\n"
" result.texcoord3.x = dot3( toEye, rpModelMatrixX );\n"
@ -4868,6 +4957,13 @@ static const cgShaderDef_t cg_renderprogs[] =
" result.texcoord5.z = dot3( normal, rpModelMatrixY );\n"
" result.texcoord6.z = dot3( normal, rpModelMatrixZ );\n"
"\n"
" float4 worldPosition;\n"
" worldPosition.x = dot4( modelPosition, rpModelMatrixX );\n"
" worldPosition.y = dot4( modelPosition, rpModelMatrixY );\n"
" worldPosition.z = dot4( modelPosition, rpModelMatrixZ );\n"
" worldPosition.w = dot4( modelPosition, rpModelMatrixW );\n"
" result.texcoord7 = worldPosition;\n"
"\n"
"#if defined( USE_GPU_SKINNING )\n"
" // for joint transformation of the tangent space, we use color and\n"
" // color2 for weighting information, so hopefully there aren't any\n"

View file

@ -775,83 +775,67 @@ void R_DeriveEnvprobeData( RenderEnvprobeLocal* probe )
probe->radianceImage = globalImages->ImageFromFile( fullname, TF_DEFAULT, TR_CLAMP, TD_R11G11B10F, CF_2D_PACKED_MIPCHAIN );
// ------------------------------------
// compute the light projection matrix
// compute the probe projection matrix
// ------------------------------------
idRenderMatrix localProject;
float zScale = 1.0f;
float radius = 300.0f; // TODO
// determine the areaNum for the envprobe origin, which may let us
// cull the envprobe if it is behind a closed door
int areaNum = probe->world->PointInArea( probe->parms.origin );
// An environemt probe uses a box projection like a point light.
// This projects into the 0.0 - 1.0 texture range instead of -1.0 to 1.0 clip space range.
localProject.Zero();
localProject[0][0] = 0.5f / radius;
localProject[1][1] = 0.5f / radius;
localProject[2][2] = 0.5f / radius;
localProject[0][3] = 0.5f;
localProject[1][3] = 0.5f;
localProject[2][3] = 0.5f;
localProject[3][3] = 1.0f; // identity perspective
// HACK: this should be in the gamecode and set by the entity properties
probe->globalProbeBounds = probe->world->AreaBounds( areaNum );
// set the old style light projection where Z and W are flipped and
// for projected lights lightProject[3] is divided by ( zNear + zFar )
/*
light->lightProject[0][0] = localProject[0][0];
light->lightProject[0][1] = localProject[0][1];
light->lightProject[0][2] = localProject[0][2];
light->lightProject[0][3] = localProject[0][3];
light->lightProject[1][0] = localProject[1][0];
light->lightProject[1][1] = localProject[1][1];
light->lightProject[1][2] = localProject[1][2];
light->lightProject[1][3] = localProject[1][3];
light->lightProject[2][0] = localProject[3][0];
light->lightProject[2][1] = localProject[3][1];
light->lightProject[2][2] = localProject[3][2];
light->lightProject[2][3] = localProject[3][3];
light->lightProject[3][0] = localProject[2][0] * zScale;
light->lightProject[3][1] = localProject[2][1] * zScale;
light->lightProject[3][2] = localProject[2][2] * zScale;
light->lightProject[3][3] = localProject[2][3] * zScale;
// transform the lightProject
float lightTransform[16];
R_AxisToModelMatrix( light->parms.axis, light->parms.origin, lightTransform );
for( int i = 0; i < 4; i++ )
{
idPlane temp = light->lightProject[i];
R_LocalPlaneToGlobal( lightTransform, temp, light->lightProject[i] );
}
*/
// Rotate and translate the light projection by the light matrix.
// 99% of lights remain axis aligned in world space.
idMat3 axis;
axis.Identity();
idRenderMatrix lightMatrix;
idRenderMatrix::CreateFromOriginAxis( probe->parms.origin, axis, lightMatrix );
idRenderMatrix modelRenderMatrix;
idRenderMatrix::CreateFromOriginAxis( vec3_origin, axis, modelRenderMatrix );
idRenderMatrix inverseLightMatrix;
if( !idRenderMatrix::Inverse( lightMatrix, inverseLightMatrix ) )
// render from mins to maxs for debug rendering
//idRenderMatrix::CreateFromOriginAxis( probe->globalProbeBounds[0], axis, modelRenderMatrix );
idRenderMatrix inverseModelMatrix;
if( !idRenderMatrix::Inverse( modelRenderMatrix, inverseModelMatrix ) )
{
idLib::Warning( "lightMatrix invert failed" );
}
// 'baseLightProject' goes from global space -> light local space -> light projective space
idRenderMatrix::Multiply( localProject, inverseLightMatrix, probe->baseLightProject );
// move local bounds to center
idBounds localBounds;
// Invert the light projection so we can deform zero-to-one cubes into
// the light model and calculate global bounds.
if( !idRenderMatrix::Inverse( probe->baseLightProject, probe->inverseBaseLightProject ) )
#if 0
idVec3 corners[8];
probe->globalProbeBounds.ToPoints( corners );
idVec3 corners2[8];
for( int i = 0; i < 8; i++ )
{
idLib::Warning( "baseLightProject invert failed" );
idVec4 p( corners[i].x, corners[i].y, corners[i].z, 1.0f );
idVec4 o;
inverseModelMatrix.TransformPoint( p, o );
corners2[i].Set( o.x, o.y, o.z );
}
// calculate the global light bounds by inverse projecting the zero to one cube with the 'inverseBaseLightProject'
idRenderMatrix::ProjectedBounds( probe->globalProbeBounds, probe->inverseBaseLightProject, bounds_zeroOneCube, false );
localBounds.FromPoints( corners2, 8 );
#else
//idVec3 center = probe->globalProbeBounds.GetCenter();
// offset it so it sits on 0 0 0
//center += center;
localBounds[0] = probe->globalProbeBounds[0] * 2;
localBounds[1] = probe->globalProbeBounds[1] * 2;
//idRenderMatrix::CreateFromOriginAxis( -probe->globalProbeBounds[0] * 2, axis, modelRenderMatrix );
#endif
// calculate the matrix that transforms the unit cube to exactly cover the model in world space
idRenderMatrix::OffsetScaleForBounds( modelRenderMatrix, localBounds, probe->inverseBaseProbeProject );
// calculate the global model bounds by inverse projecting the unit cube with the 'inverseBaseModelProject'
//idRenderMatrix::ProjectedBounds( probe->globalProbeBounds, probe->inverseBaseProbeProject, bounds_unitCube, false );
}
void R_CreateEnvprobeRefs( RenderEnvprobeLocal* probe )

View file

@ -62,7 +62,8 @@ viewEnvprobe_t* R_SetEnvprobeDefViewEnvprobe( RenderEnvprobeLocal* probe )
// copy data used by backend
// RB: this would normaly go into R_AddSingleEnvprobe
vProbe->globalOrigin = probe->parms.origin;
vProbe->inverseBaseLightProject = probe->inverseBaseLightProject;
vProbe->globalProbeBounds = probe->globalProbeBounds;
vProbe->inverseBaseProbeProject = probe->inverseBaseProbeProject;
//if( probe->irradianceImage->IsLoaded() )
{
@ -104,7 +105,7 @@ bool idRenderWorldLocal::CullEnvprobeByPortals( const RenderEnvprobeLocal* probe
if( r_useLightPortalCulling.GetInteger() == 1 )
{
ALIGNTYPE16 frustumCorners_t corners;
idRenderMatrix::GetFrustumCorners( corners, probe->inverseBaseLightProject, bounds_zeroOneCube );
idRenderMatrix::GetFrustumCorners( corners, probe->inverseBaseProbeProject, bounds_zeroOneCube );
for( int i = 0; i < ps->numPortalPlanes; i++ )
{
if( idRenderMatrix::CullFrustumCornersToPlane( corners, ps->portalPlanes[i] ) == FRUSTUM_CULL_FRONT )
@ -114,66 +115,6 @@ bool idRenderWorldLocal::CullEnvprobeByPortals( const RenderEnvprobeLocal* probe
}
}
else if( r_useLightPortalCulling.GetInteger() >= 2 )
{
idPlane frustumPlanes[6];
idRenderMatrix::GetFrustumPlanes( frustumPlanes, probe->baseLightProject, true, true );
// exact clip of light faces against all planes
for( int i = 0; i < 6; i++ )
{
// the light frustum planes face inward, so the planes that have the
// view origin on the positive side will be the "back" faces of the light,
// which must have some fragment inside the the portal stack planes to be visible
if( frustumPlanes[i].Distance( tr.viewDef->renderView.vieworg ) <= 0.0f )
{
continue;
}
// calculate a winding for this frustum side
idFixedWinding w;
w.BaseForPlane( frustumPlanes[i] );
for( int j = 0; j < 6; j++ )
{
if( j == i )
{
continue;
}
if( !w.ClipInPlace( frustumPlanes[j], ON_EPSILON ) )
{
break;
}
}
if( w.GetNumPoints() <= 2 )
{
continue;
}
assert( ps->numPortalPlanes <= MAX_PORTAL_PLANES );
assert( w.GetNumPoints() + ps->numPortalPlanes < MAX_POINTS_ON_WINDING );
// now clip the winding against each of the portalStack planes
// skip the last plane which is the last portal itself
for( int j = 0; j < ps->numPortalPlanes - 1; j++ )
{
if( !w.ClipInPlace( -ps->portalPlanes[j], ON_EPSILON ) )
{
break;
}
}
if( w.GetNumPoints() > 2 )
{
// part of the winding is visible through the portalStack,
// so the light is not culled
return false;
}
}
// nothing was visible
return true;
}
return false;
}

View file

@ -544,6 +544,8 @@ void R_RenderView( viewDef_t* parms )
{
float bestDist = idMath::INFINITY;
tr.viewDef->globalProbeBounds.Clear();
tr.viewDef->irradianceImage = globalImages->defaultUACIrradianceCube;
tr.viewDef->radianceImage = globalImages->defaultUACRadianceCube;
@ -554,6 +556,7 @@ void R_RenderView( viewDef_t* parms )
{
if( vProbe->irradianceImage->IsLoaded() && !vProbe->irradianceImage->IsDefaulted() )
{
tr.viewDef->globalProbeBounds = vProbe->globalProbeBounds;
tr.viewDef->irradianceImage = vProbe->irradianceImage;
tr.viewDef->radianceImage = vProbe->radianceImage;