Fixed bad lightgrid lookups if models span multiple areas. close #965

This commit is contained in:
Robert Beckebans 2025-01-08 23:25:28 +01:00
parent 67987ab715
commit 56648e631f
7 changed files with 112 additions and 61 deletions

View file

@ -447,7 +447,7 @@ textures/common/occlusion
// so it works as a blocker for the lightgrid
textures/common/black
{
qer_editorimage textures/common/shadow.tga
qer_editorimage textures/common/black.tga
nonsolid
forceshadows
forceOpaque

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

View file

@ -4173,7 +4173,7 @@ CONSOLE_COMMAND_SHIP( makeMaterials, "Make .mtr file from a models or textures f
if( testStamp != FILE_NOT_FOUND_TIMESTAMP )
{
if( name.Cmp( "_normal_opengl" ) == 0 )
if( name.Cmp( "_normal_opengl" ) == 0 || ueMode )
{
mtrBuffer += va( "\tnormalmap invertGreen( %s )\n", testName.c_str() );
}

View file

@ -1177,7 +1177,7 @@ void idRenderBackend::DrawSingleInteraction( drawInteraction_t* din, bool useFas
const textureUsage_t specUsage = din->specularImage->GetUsage();
// RB begin
if( useIBL && currentSpace->useLightGrid && r_useLightGrid.GetBool() )
if( useIBL && din->surf->area != NULL && r_useLightGrid.GetBool() )
{
idVec4 probeMins, probeMaxs, probeCenter;
@ -1199,9 +1199,11 @@ void idRenderBackend::DrawSingleInteraction( drawInteraction_t* din, bool useFas
SetVertexParm( RENDERPARM_WOBBLESKY_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 );
idVec4 lightGridBounds( currentSpace->lightGridBounds[0], currentSpace->lightGridBounds[1], currentSpace->lightGridBounds[2], 1.0f );
const LightGrid& lightGrid = din->surf->area->lightGrid;
idVec4 lightGridOrigin( lightGrid.lightGridOrigin.x, lightGrid.lightGridOrigin.y, lightGrid.lightGridOrigin.z, 1.0f );
idVec4 lightGridSize( lightGrid.lightGridSize.x, lightGrid.lightGridSize.y, lightGrid.lightGridSize.z, 1.0f );
idVec4 lightGridBounds( lightGrid.lightGridBounds[0], lightGrid.lightGridBounds[1], lightGrid.lightGridBounds[2], 1.0f );
renderProgManager.SetUniformValue( RENDERPARM_GLOBALLIGHTORIGIN, lightGridOrigin.ToFloatPtr() );
renderProgManager.SetUniformValue( RENDERPARM_JITTERTEXSCALE, lightGridSize.ToFloatPtr() );
@ -1209,10 +1211,10 @@ void idRenderBackend::DrawSingleInteraction( drawInteraction_t* din, bool useFas
// individual probe sizes on the atlas image
idVec4 probeSize;
probeSize[0] = currentSpace->lightGridAtlasSingleProbeSize - currentSpace->lightGridAtlasBorderSize;
probeSize[1] = currentSpace->lightGridAtlasSingleProbeSize;
probeSize[2] = currentSpace->lightGridAtlasBorderSize;
probeSize[3] = float( currentSpace->lightGridAtlasSingleProbeSize - currentSpace->lightGridAtlasBorderSize ) / currentSpace->lightGridAtlasSingleProbeSize;
probeSize[0] = lightGrid.imageSingleProbeSize - lightGrid.imageBorderSize;
probeSize[1] = lightGrid.imageSingleProbeSize;
probeSize[2] = lightGrid.imageBorderSize;
probeSize[3] = float( lightGrid.imageSingleProbeSize - lightGrid.imageBorderSize ) / lightGrid.imageSingleProbeSize;
renderProgManager.SetUniformValue( RENDERPARM_SCREENCORRECTIONFACTOR, probeSize.ToFloatPtr() ); // rpScreenCorrectionFactor
// specular cubemap blend weights
@ -1256,9 +1258,9 @@ void idRenderBackend::DrawSingleInteraction( drawInteraction_t* din, bool useFas
}
GL_SelectTexture( INTERACTION_TEXUNIT_AMBIENT_CUBE1 );
currentSpace->lightGridAtlasImage->Bind();
lightGrid.GetIrradianceImage()->Bind();
idVec2i res = currentSpace->lightGridAtlasImage->GetUploadResolution();
idVec2i res = lightGrid.GetIrradianceImage()->GetUploadResolution();
idVec4 textureSize( res.x, res.y, 1.0f / res.x, 1.0f / res.y );
renderProgManager.SetUniformValue( RENDERPARM_CASCADEDISTANCES, textureSize.ToFloatPtr() );

View file

@ -98,10 +98,11 @@ struct drawSurf_t
const idMaterial* material; // may be NULL for shadow volumes
uint64 extraGLState; // Extra GL state |'d with material->stage[].drawStateBits
float sort; // material->sort, modified by gui / entity sort offsets
const float* shaderRegisters; // evaluated and adjusted for referenceShaders
const float* shaderRegisters; // evaluated and adjusted for referenceShaders
drawSurf_t* nextOnLight; // viewLight chains
drawSurf_t** linkChain; // defer linking to lights to a serial section to avoid a mutex
idScreenRect scissorRect; // for scissor clipping, local inside renderView viewport
const struct portalArea_s* area; // RB: if != NULL then the area provides valid lightgrid
};
// areas have references to hold all the lights and entities in them
@ -422,17 +423,6 @@ struct viewEntity_t
// parallelAddModels will build a chain of surfaces here that will need to
// be linked to the lights or added to the drawsurf list in a serial code section
drawSurf_t* drawSurfs;
// RB: use light grid of the best area this entity is in
bool useLightGrid;
idImage* lightGridAtlasImage;
int lightGridAtlasSingleProbeSize; // including border
int lightGridAtlasBorderSize;
idVec3 lightGridOrigin;
idVec3 lightGridSize;
int lightGridBounds[3];
// RB end
};
// RB: viewEnvprobes are allocated on the frame temporary stack memory

View file

@ -315,9 +315,6 @@ void R_AddSingleModel( viewEntity_t* vEntity )
// we will add all interaction surfs here, to be chained to the lights in later serial code
vEntity->drawSurfs = NULL;
// RB
vEntity->useLightGrid = false;
// globals we really should pass in...
const viewDef_t* viewDef = tr.viewDef;
@ -494,32 +491,6 @@ void R_AddSingleModel( viewEntity_t* vEntity )
}
}
// RB: use first valid lightgrid
for( areaReference_t* ref = entityDef->entityRefs; ref != NULL; ref = ref->ownerNext )
{
idImage* lightGridImage = ref->area->lightGrid.GetIrradianceImage();
if( ref->area->lightGrid.lightGridPoints.Num() && lightGridImage && !lightGridImage->IsDefaulted() )
{
vEntity->useLightGrid = true;
vEntity->lightGridAtlasImage = lightGridImage;
vEntity->lightGridAtlasSingleProbeSize = ref->area->lightGrid.imageSingleProbeSize;
vEntity->lightGridAtlasBorderSize = ref->area->lightGrid.imageBorderSize;
for( int i = 0; i < 3; i++ )
{
vEntity->lightGridOrigin[i] = ref->area->lightGrid.lightGridOrigin[i];
vEntity->lightGridSize[i] = ref->area->lightGrid.lightGridSize[i];
vEntity->lightGridBounds[i] = ref->area->lightGrid.lightGridBounds[i];
}
break;
}
}
// RB end
//---------------------------
// copy matrix related stuff for back-end use
// and setup a render matrix for faster culling
@ -756,8 +727,6 @@ void R_AddSingleModel( viewEntity_t* vEntity )
}
#endif // #if defined(USE_INTRINSICS_SSE)
//--------------------------
// base drawing surface
//--------------------------
@ -841,6 +810,99 @@ void R_AddSingleModel( viewEntity_t* vEntity )
baseDrawSurf->nextOnLight = vEntity->drawSurfs;
vEntity->drawSurfs = baseDrawSurf;
}
// RB: use area the surface is in because a model can span multiple areas #965
baseDrawSurf->area = NULL;
if( shader->ReceivesLighting() )
{
idVec3 surfaceCenter;
idVec3 triCenter = tri->bounds.GetCenter();
idRenderMatrix modelRenderMatrix;
idRenderMatrix::CreateFromOriginAxis( renderEntity->origin, renderEntity->axis, modelRenderMatrix );
modelRenderMatrix.TransformPoint( triCenter, surfaceCenter );
int surfaceArea = tr.primaryWorld->PointInArea( surfaceCenter );
for( areaReference_t* ref = entityDef->entityRefs; ref != NULL; ref = ref->ownerNext )
{
idImage* lightGridImage = ref->area->lightGrid.GetIrradianceImage();
if( surfaceArea == ref->area->areaNum && ref->area->lightGrid.lightGridPoints.Num() && lightGridImage != NULL && !lightGridImage->IsDefaulted() )
{
baseDrawSurf->area = ref->area;
break;
}
}
// RB: use first valid lightgrid
// this would be wrong but less wrong than a flickering env_probe fallback
if( baseDrawSurf->area == NULL )
{
for( areaReference_t* ref = entityDef->entityRefs; ref != NULL; ref = ref->ownerNext )
{
idImage* lightGridImage = ref->area->lightGrid.GetIrradianceImage();
if( ref->area->lightGrid.lightGridPoints.Num() && lightGridImage != NULL && !lightGridImage->IsDefaulted() )
{
baseDrawSurf->area = ref->area;
break;
}
}
}
#if 0
// show which area the surface is coming from
//if( baseDrawSurf->area == NULL )
{
idBounds surfaceBounds;
if( gpuSkinned )
{
surfaceBounds = vEntity->entityDef->localReferenceBounds;
}
else
{
surfaceBounds = tri->bounds;
}
idRenderMatrix modelRenderMatrix;
idRenderMatrix::CreateFromOriginAxis( renderEntity->origin, renderEntity->axis, modelRenderMatrix );
idRenderMatrix inverseBaseModelProject;
idRenderMatrix::OffsetScaleForBounds( modelRenderMatrix, surfaceBounds, inverseBaseModelProject );
// NOTE: unit cube instead of zeroToOne cube
idVec4* verts = tr.maskedUnitCubeVerts;
idVec4 triVerts[8];
for( int i = 0; i < 8; i++ )
{
// transform to clip space
inverseBaseModelProject.TransformPoint( verts[i], triVerts[i] );
}
static idVec4 colors[] = { colorBrown, colorBlue, colorCyan, colorGreen, colorYellow, colorRed, colorWhite };
idVec4 color = colors[surfaceArea & 7];
if( baseDrawSurf->area == NULL )
{
color = colorPurple;
}
// same as idRenderWorldLocal::DebugBox
const int lifetime = 0;
for( int i = 0; i < 4; i++ )
{
tr.viewDef->renderWorld->DebugLine( color, triVerts[i].ToVec3(), triVerts[( i + 1 ) & 3].ToVec3(), lifetime );
tr.viewDef->renderWorld->DebugLine( color, triVerts[4 + i].ToVec3(), triVerts[4 + ( ( i + 1 ) & 3 )].ToVec3(), lifetime );
tr.viewDef->renderWorld->DebugLine( color, triVerts[i].ToVec3(), triVerts[4 + i].ToVec3(), lifetime );
}
tr.viewDef->renderWorld->DebugAxis( surfaceCenter, renderEntity->axis );
}
#endif
}
}
//----------------------------------------

View file

@ -242,14 +242,11 @@ void main( PS_IN fragment, out PS_OUT result )
gridCoord[j] = int( floor( v ) );
frac[ j ] = v - gridCoord[ j ];
/*
if( gridCoord[i] < 0 )
if( gridCoord[j] < 0 )
{
gridCoord[i] = 0;
gridCoord[j] = 0;
}
else
*/
if( gridCoord[j] >= lightGridBounds[j] - 1 )
else if( gridCoord[j] >= lightGridBounds[j] - 1 )
{
gridCoord[j] = lightGridBounds[j] - 1;
}