All lights can be culled now

This commit is contained in:
Robert Beckebans 2024-08-26 22:36:58 +02:00
parent e121472661
commit a7d1d7f72e
5 changed files with 113 additions and 95 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) 2014 Robert Beckebans
Copyright (C) 2014-2024 Robert Beckebans
Copyright (C) 2022 Stephen Pridham
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").

View file

@ -1975,40 +1975,6 @@ static void R_MakeZeroOneCubeTrisForMaskedOcclusionCulling()
verts[5].w = 1;
verts[6].w = 1;
verts[7].w = 1;
}
static void R_MakeUnitCubeTrisForMaskedOcclusionCulling()
{
const float low = -1.0f;
const float high = 1.0f;
idVec3 center( 0.0f );
idVec3 mx( low, 0.0f, 0.0f );
idVec3 px( high, 0.0f, 0.0f );
idVec3 my( 0.0f, low, 0.0f );
idVec3 py( 0.0f, high, 0.0f );
idVec3 mz( 0.0f, 0.0f, low );
idVec3 pz( 0.0f, 0.0f, high );
idVec4* verts = tr.maskedUnitCubeVerts;
verts[0].ToVec3() = center + mx + my + mz;
verts[1].ToVec3() = center + px + my + mz;
verts[2].ToVec3() = center + px + py + mz;
verts[3].ToVec3() = center + mx + py + mz;
verts[4].ToVec3() = center + mx + my + pz;
verts[5].ToVec3() = center + px + my + pz;
verts[6].ToVec3() = center + px + py + pz;
verts[7].ToVec3() = center + mx + py + pz;
verts[0].w = 1;
verts[1].w = 1;
verts[2].w = 1;
verts[3].w = 1;
verts[4].w = 1;
verts[5].w = 1;
verts[6].w = 1;
verts[7].w = 1;
unsigned int* indexes = tr.maskedZeroOneCubeIndexes;
@ -2056,6 +2022,40 @@ static void R_MakeUnitCubeTrisForMaskedOcclusionCulling()
indexes[11 * 3 + 2] = 6;
}
static void R_MakeUnitCubeTrisForMaskedOcclusionCulling()
{
const float low = -1.0f;
const float high = 1.0f;
idVec3 center( 0.0f );
idVec3 mx( low, 0.0f, 0.0f );
idVec3 px( high, 0.0f, 0.0f );
idVec3 my( 0.0f, low, 0.0f );
idVec3 py( 0.0f, high, 0.0f );
idVec3 mz( 0.0f, 0.0f, low );
idVec3 pz( 0.0f, 0.0f, high );
idVec4* verts = tr.maskedUnitCubeVerts;
verts[0].ToVec3() = center + mx + my + mz;
verts[1].ToVec3() = center + px + my + mz;
verts[2].ToVec3() = center + px + py + mz;
verts[3].ToVec3() = center + mx + py + mz;
verts[4].ToVec3() = center + mx + my + pz;
verts[5].ToVec3() = center + px + my + pz;
verts[6].ToVec3() = center + px + py + pz;
verts[7].ToVec3() = center + mx + py + pz;
verts[0].w = 1;
verts[1].w = 1;
verts[2].w = 1;
verts[3].w = 1;
verts[4].w = 1;
verts[5].w = 1;
verts[6].w = 1;
verts[7].w = 1;
}
static srfTriangles_t* R_MakeZeroOneSphereTris()
{
srfTriangles_t* tri = ( srfTriangles_t* )Mem_ClearedAlloc( sizeof( *tri ), TAG_RENDER_TOOLS );

View file

@ -371,7 +371,7 @@ void idRenderWorldLocal::AddAreaViewLights( int areaNum, const portalStack_t* ps
// debug tool to allow viewing of only one light at a time
// RB: use this elsewhere in the backend debug drawing code
#if 0
#if 1
if( r_singleLight.GetInteger() >= 0 && r_singleLight.GetInteger() != light->index )
{
continue;

View file

@ -271,10 +271,9 @@ static void R_AddSingleLight( viewLight_t* vLight )
// RB: test surface visibility by drawing the triangles of the bounds
// FIXME spot light projections are too short
if( r_useMaskedOcclusionCulling.GetBool() && !viewInsideLight && vLight->pointLight )
if( r_useMaskedOcclusionCulling.GetBool() && !viewInsideLight )
{
#if 1
idVec4 triVerts[3];
idVec4 triVerts[8];
unsigned int triIndices[] = { 0, 1, 2 };
tr.pc.c_mocIndexes += 36;
@ -285,64 +284,81 @@ static void R_AddSingleLight( viewLight_t* vLight )
tr.pc.c_mocTests += 1;
float wmin = idMath::INFINITUM;
bool maskVisible = false;
// NOTE: zeroToOne cube is only for lights and models need the unit cube
idVec4* verts = tr.maskedZeroOneCubeVerts;
unsigned int* indexes = tr.maskedZeroOneCubeIndexes;
for( int i = 0, face = 0; i < 36; i += 3, face++ )
for( int i = 0; i < 8; i++ )
{
const idVec4& v0 = verts[indexes[i + 0]];
const idVec4& v1 = verts[indexes[i + 1]];
const idVec4& v2 = verts[indexes[i + 2]];
// transform to clip space
invProjectMVPMatrix.TransformPoint( v0, triVerts[0] );
invProjectMVPMatrix.TransformPoint( v1, triVerts[1] );
invProjectMVPMatrix.TransformPoint( v2, triVerts[2] );
invProjectMVPMatrix.TransformPoint( verts[i], triVerts[i] );
float w = triVerts[i].w;
if( i == 0 )
{
wmin = w;
}
else if( w < wmin )
{
wmin = w;
}
}
if( vLight->pointLight || vLight->parallel )
{
unsigned int* indexes = tr.maskedZeroOneCubeIndexes;
for( int i = 0; i < 36; i += 3 )
{
triIndices[0] = indexes[i + 0];
triIndices[1] = indexes[i + 1];
triIndices[2] = indexes[i + 2];
#if 1
// backface none so objects are still visible where we run into
MaskedOcclusionCulling::CullingResult result = tr.maskedOcclusionCulling->TestTriangles( ( float* )triVerts, triIndices, 1, NULL, MaskedOcclusionCulling::BACKFACE_NONE );
if( result == MaskedOcclusionCulling::VISIBLE )
{
// backface none so objects are still visible where we run into
MaskedOcclusionCulling::CullingResult result = tr.maskedOcclusionCulling->TestTriangles( ( float* )triVerts, triIndices, 1, NULL, MaskedOcclusionCulling::BACKFACE_NONE );
if( result == MaskedOcclusionCulling::VISIBLE )
{
maskVisible = true;
}
#else
// draw for debugging
tr.maskedOcclusionCulling->RenderTriangles( ( float* )triVerts, triIndices, 1, NULL, MaskedOcclusionCulling::BACKFACE_CW );
maskVisible = true;
#endif
}
#else
// draw for debugging
tr.maskedOcclusionCulling->RenderTriangles( ( float* )triVerts, triIndices, 1, NULL, MaskedOcclusionCulling::BACKFACE_NONE );
maskVisible = true;
#endif
}
if( !maskVisible )
if( !maskVisible )
{
tr.pc.c_mocCulledLights += 1;
return;
}
}
else
{
tr.pc.c_mocCulledLights += 1;
return;
// scissor test alternative
// source scissor rectangle has GL convention and starts in the lower left corner
// convert to NDC values
float x1 = -1.0f + ( float( vLight->scissorRect.x1 ) / screenWidth ) * 2.0f;
float x2 = -1.0f + ( float( vLight->scissorRect.x2 ) / screenWidth ) * 2.0f;
float y1 = -1.0f + ( float( vLight->scissorRect.y1 ) / screenHeight ) * 2.0f;
float y2 = -1.0f + ( float( vLight->scissorRect.y2 ) / screenHeight ) * 2.0f;
float zmin = vLight->scissorRect.zmin;
//zmin = 2.0f * zmin -1.0f;
zmin = 1.0 - zmin; // reverse depth
float wmin2 = ( 1.0 / zmin );
wmin2 *= wmin;
wmin2 = Max( wmin2, 0.0f );
MaskedOcclusionCulling::CullingResult result = tr.maskedOcclusionCulling->TestRect( x1, y1, x2, y2, wmin2 );
if( result != MaskedOcclusionCulling::VISIBLE )
{
tr.pc.c_mocCulledLights += 1;
return;
}
}
#else
// scissor test alternative
// I would prefer this method however lights become visible again when the distance increases to the occluder surface
// source scissor rectangle has GL convention and starts in the lower left corner
// convert to NDC values
float x1 = -1.0f + ( float( vLight->scissorRect.x1 ) / screenWidth ) * 2.0f;
float x2 = -1.0f + ( float( vLight->scissorRect.x2 ) / screenWidth ) * 2.0f;
float y1 = -1.0f + ( float( vLight->scissorRect.y1 ) / screenHeight ) * 2.0f;
float y2 = -1.0f + ( float( vLight->scissorRect.y2 ) / screenHeight ) * 2.0f;
//float y2 = -1.0f + ( float( screenHeight - vLight->scissorRect.y1 ) / screenHeight ) * 2.0f;
//float y1 = -1.0f + ( float( screenHeight - vLight->scissorRect.y2 ) / screenHeight ) * 2.0f;
double zmin = 1.0 - vLight->scissorRect.zmin; // reverse depth
double wmin = 1.0 / zmin;
MaskedOcclusionCulling::CullingResult result = tr.maskedOcclusionCulling->TestRect( x1, y1, x2, y2, wmin );
if( result != MaskedOcclusionCulling::VISIBLE )
{
tr.pc.c_mocCulledLights += 1;
return;
}
#endif
}
// RB end

View file

@ -686,7 +686,7 @@ void R_AddSingleModel( viewEntity_t* vEntity )
#if 1
if( !model->IsStaticWorldModel() && !renderEntity->weaponDepthHack && renderEntity->modelDepthHack == 0.0f )
{
idVec4 triVerts[3];
idVec4 triVerts[8];
unsigned int triIndices[] = { 0, 1, 2 };
tr.pc.c_mocIndexes += 36;
@ -719,19 +719,21 @@ void R_AddSingleModel( viewEntity_t* vEntity )
tr.pc.c_mocTests += 1;
bool maskVisible = false;
// NOTE: unit cube instead of zeroToOne cube
idVec4* verts = tr.maskedUnitCubeVerts;
unsigned int* indexes = tr.maskedZeroOneCubeIndexes;
for( int i = 0, face = 0; i < 36; i += 3, face++ )
for( int i = 0; i < 8; i++ )
{
const idVec4& v0 = verts[indexes[i + 0]];
const idVec4& v1 = verts[indexes[i + 1]];
const idVec4& v2 = verts[indexes[i + 2]];
// transform to clip space
invProjectMVPMatrix.TransformPoint( v0, triVerts[0] );
invProjectMVPMatrix.TransformPoint( v1, triVerts[1] );
invProjectMVPMatrix.TransformPoint( v2, triVerts[2] );
invProjectMVPMatrix.TransformPoint( verts[i], triVerts[i] );
}
unsigned int* indexes = tr.maskedZeroOneCubeIndexes;
for( int i = 0; i < 36; i += 3 )
{
triIndices[0] = indexes[i + 0];
triIndices[1] = indexes[i + 1];
triIndices[2] = indexes[i + 2];
// backface none so objects are still visible where we run into
MaskedOcclusionCulling::CullingResult result = tr.maskedOcclusionCulling->TestTriangles( ( float* )triVerts, triIndices, 1, NULL, MaskedOcclusionCulling::BACKFACE_NONE );