Query only draw surface boxes with MOC

This commit is contained in:
Robert Beckebans 2024-08-22 22:05:47 +02:00
parent dba7404eff
commit fc6c1fef7a
5 changed files with 181 additions and 122 deletions

View file

@ -350,7 +350,7 @@ float idConsoleLocal::DrawFPS( float y )
if( com_showFPS.GetInteger() > 2 )
{
statsWindowWidth += 230;
statsWindowHeight += 135;
statsWindowHeight += 140;
}
ImVec2 pos;

View file

@ -1046,8 +1046,8 @@ public:
idRenderBackend backend;
MaskedOcclusionCulling* maskedOcclusionCulling;
idVec4 maskZeroOneCubeVerts[8];
unsigned int maskZeroOneCubeIndexes[36];
idVec4 maskedZeroOneCubeVerts[8];
unsigned int maskedZeroOneCubeIndexes[36];
private:
bool bInitialized;
@ -1204,9 +1204,9 @@ extern idCVar r_debugRenderToTexture;
extern idCVar stereoRender_enable;
extern idCVar stereoRender_deGhost; // subtract from opposite eye to reduce ghosting
// RB begin
extern idCVar r_useGPUSkinning;
// RB begin
extern idCVar r_shadowMapAtlasSize;
extern idCVar r_shadowMapFrustumFOV;
extern idCVar r_shadowMapSingleSide;
@ -1267,6 +1267,8 @@ extern idCVar r_useCRTPostFX;
extern idCVar r_crtCurvature;
extern idCVar r_crtVignette;
extern idCVar r_useMaskedOcclusionCulling;
enum RenderMode
{
RENDERMODE_DOOM,

View file

@ -305,6 +305,8 @@ idCVar r_renderMode( "r_renderMode", "0", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_IN
idCVar r_psxVertexJitter( "r_psxVertexJitter", "0.5", CVAR_RENDERER | CVAR_FLOAT | CVAR_NEW, "", 0.0f, 0.75f );
idCVar r_psxAffineTextures( "r_psxAffineTextures", "1", CVAR_RENDERER | CVAR_FLOAT | CVAR_NEW, "" );
idCVar r_useMaskedOcclusionCulling( "r_useMaskedOcclusionCulling", "1", CVAR_RENDERER | CVAR_BOOL | CVAR_NEW, "SIMD optimized software culling by Intel" );
// RB end
const char* fileExten[4] = { "tga", "png", "jpg", "exr" };
@ -1787,6 +1789,13 @@ void idRenderSystemLocal::Clear()
envprobeJobList = NULL;
envprobeJobs.Clear();
lightGridJobs.Clear();
// destroy occlusion culling object and free hierarchical z-buffer
if( maskedOcclusionCulling != NULL )
{
MaskedOcclusionCulling::Destroy( maskedOcclusionCulling );
maskedOcclusionCulling = NULL;
}
}
/*
@ -1936,9 +1945,7 @@ static srfTriangles_t* R_MakeZeroOneCubeTris()
// RB begin
static void R_MakeZeroOneCubeTrisForMaskedOcclusionCulling()
{
//idDrawVert* verts = tri->verts;
const float low = 0.0f;
const float low = -1.0f;
const float high = 1.0f;
idVec3 center( 0.0f );
@ -1949,7 +1956,7 @@ static void R_MakeZeroOneCubeTrisForMaskedOcclusionCulling()
idVec3 mz( 0.0f, 0.0f, low );
idVec3 pz( 0.0f, 0.0f, high );
idVec4* verts = tr.maskZeroOneCubeVerts;
idVec4* verts = tr.maskedZeroOneCubeVerts;
verts[0].ToVec3() = center + mx + my + mz;
verts[1].ToVec3() = center + px + my + mz;
@ -1969,7 +1976,7 @@ static void R_MakeZeroOneCubeTrisForMaskedOcclusionCulling()
verts[6].w = 1;
verts[7].w = 1;
unsigned int* indexes = tr.maskZeroOneCubeIndexes;
unsigned int* indexes = tr.maskedZeroOneCubeIndexes;
// bottom
indexes[ 0 * 3 + 0] = 2;

View file

@ -672,94 +672,92 @@ void R_AddSingleModel( viewEntity_t* vEntity )
// individual surfaces.
bool surfaceDirectlyVisible = modelIsVisible && !idRenderMatrix::CullBoundsToMVP( vEntity->mvp, tri->bounds );
#if 0
// RB: test surface visibility by drawing the triangles of the bounds
if( tr.maskedOcclusionCulling != NULL )
{
idRenderMatrix modelRenderMatrix;
idRenderMatrix::CreateFromOriginAxis( renderEntity->origin, renderEntity->axis, modelRenderMatrix );
idRenderMatrix inverseBaseModelProject;
idRenderMatrix::OffsetScaleForBounds( modelRenderMatrix, tri->bounds, inverseBaseModelProject );
idRenderMatrix invProjectMVPMatrix;
idRenderMatrix::Multiply( viewDef->worldSpace.mvp, inverseBaseModelProject, invProjectMVPMatrix );
idRenderMatrix invProjectMVPMatrix2;
idRenderMatrix::Transpose( invProjectMVPMatrix, invProjectMVPMatrix2 );
// query the triangle
MaskedOcclusionCulling::CullingResult result;
result = tr.maskedOcclusionCulling->TestTriangles( ( float* )tr.maskZeroOneCubeVerts, tr.maskZeroOneCubeIndexes, 36, ( float* )&invProjectMVPMatrix2[0][0], MaskedOcclusionCulling::BACKFACE_CCW );
if( result == MaskedOcclusionCulling::OCCLUDED )
{
surfaceDirectlyVisible = false;
tr.pc.c_mocCulls += 1;
}
}
#elif 1
{
idVec4 triVerts[3];
unsigned int triIndices[] = { 0, 1, 2 };
tr.pc.c_mocIndexes += tri->numIndexes;
tr.pc.c_mocVerts += tri->numIndexes;
tr.pc.c_mocTests += 1;
bool maskVisible = false;
for( int i = 0, face = 0; i < tri->numIndexes; i += 3, face++ )
{
const idDrawVert& v0 = tri->verts[tri->indexes[i + 0]];
const idDrawVert& v1 = tri->verts[tri->indexes[i + 1]];
const idDrawVert& v2 = tri->verts[tri->indexes[i + 2]];
// transform to clip space
vEntity->unjitteredMVP.TransformPoint( idVec4( v0.xyz.x, v0.xyz.y, v0.xyz.z, 1 ), triVerts[0] );
vEntity->unjitteredMVP.TransformPoint( idVec4( v1.xyz.x, v1.xyz.y, v1.xyz.z, 1 ), triVerts[1] );
vEntity->unjitteredMVP.TransformPoint( idVec4( v2.xyz.x, v2.xyz.y, v2.xyz.z, 1 ), triVerts[2] );
MaskedOcclusionCulling::CullingResult result = tr.maskedOcclusionCulling->TestTriangles( ( float* )triVerts, triIndices, 1, NULL, MaskedOcclusionCulling::BACKFACE_CCW );
if( result == MaskedOcclusionCulling::VISIBLE )
{
maskVisible = true;
}
}
if( !maskVisible )
{
tr.pc.c_mocCulls += 1;
surfaceDirectlyVisible = false;
}
}
#else
{
idVec4 triVerts[3];
unsigned int triIndices[] = { 0, 1, 2 };
tr.pc.c_mocIndexes += tri->numIndexes;
tr.pc.c_mocVerts += tri->numIndexes;
for( int i = 0, face = 0; i < tri->numIndexes; i += 3, face++ )
{
const idDrawVert& v0 = tri->verts[tri->indexes[i + 0]];
const idDrawVert& v1 = tri->verts[tri->indexes[i + 1]];
const idDrawVert& v2 = tri->verts[tri->indexes[i + 2]];
// transform to clip space
vEntity->mvp.TransformPoint( idVec4( v0.xyz.x, v0.xyz.y, v0.xyz.z, 1 ), triVerts[0] );
vEntity->mvp.TransformPoint( idVec4( v1.xyz.x, v1.xyz.y, v1.xyz.z, 1 ), triVerts[1] );
vEntity->mvp.TransformPoint( idVec4( v2.xyz.x, v2.xyz.y, v2.xyz.z, 1 ), triVerts[2] );
tr.maskedOcclusionCulling->RenderTriangles( ( float* )triVerts, triIndices, 1, NULL, MaskedOcclusionCulling::BACKFACE_CCW );
}
}
#endif
// RB: added check wether GPU skinning is available at all
const bool gpuSkinned = ( tri->staticModelWithJoints != NULL && r_useGPUSkinning.GetBool() );
// RB end
// RB: test surface visibility by drawing the triangles of the bounds
if( r_useMaskedOcclusionCulling.GetBool() )
{
#if 1
if( !model->IsStaticWorldModel() && !renderEntity->weaponDepthHack && renderEntity->modelDepthHack == 0.0f )
{
idVec4 triVerts[3];
unsigned int triIndices[] = { 0, 1, 2 };
tr.pc.c_mocIndexes += 36;
tr.pc.c_mocVerts += 8;
idRenderMatrix modelRenderMatrix;
idRenderMatrix::CreateFromOriginAxis( renderEntity->origin, renderEntity->axis, modelRenderMatrix );
const float size = 16.0f;
idBounds debugBounds( idVec3( -size ), idVec3( size ) );
//debugBounds = vEntity->entityDef->localReferenceBounds;
debugBounds = tri->bounds;
idRenderMatrix inverseBaseModelProject;
idRenderMatrix::OffsetScaleForBounds( modelRenderMatrix, debugBounds, inverseBaseModelProject );
idRenderMatrix invProjectMVPMatrix;
idRenderMatrix::Multiply( viewDef->worldSpace.unjitteredMVP, inverseBaseModelProject, invProjectMVPMatrix );
tr.pc.c_mocTests += 1;
bool maskVisible = false;
idVec4* verts = tr.maskedZeroOneCubeVerts;
unsigned int* indexes = tr.maskedZeroOneCubeIndexes;
for( int i = 0, face = 0; i < 36; i += 3, face++ )
{
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] );
MaskedOcclusionCulling::CullingResult result = tr.maskedOcclusionCulling->TestTriangles( ( float* )triVerts, triIndices, 1, NULL, MaskedOcclusionCulling::BACKFACE_CCW );
if( result == MaskedOcclusionCulling::VISIBLE )
{
maskVisible = true;
}
}
if( !maskVisible )
{
tr.pc.c_mocCulls += 1;
surfaceDirectlyVisible = false;
}
}
#else
{
idVec4 triVerts[3];
unsigned int triIndices[] = { 0, 1, 2 };
tr.pc.c_mocIndexes += tri->numIndexes;
tr.pc.c_mocVerts += tri->numIndexes;
for( int i = 0, face = 0; i < tri->numIndexes; i += 3, face++ )
{
const idDrawVert& v0 = tri->verts[tri->indexes[i + 0]];
const idDrawVert& v1 = tri->verts[tri->indexes[i + 1]];
const idDrawVert& v2 = tri->verts[tri->indexes[i + 2]];
// transform to clip space
vEntity->unjitteredMVP.TransformPoint( idVec4( v0.xyz.x, v0.xyz.y, v0.xyz.z, 1 ), triVerts[0] );
vEntity->unjitteredMVP.TransformPoint( idVec4( v1.xyz.x, v1.xyz.y, v1.xyz.z, 1 ), triVerts[1] );
vEntity->unjitteredMVP.TransformPoint( idVec4( v2.xyz.x, v2.xyz.y, v2.xyz.z, 1 ), triVerts[2] );
tr.maskedOcclusionCulling->RenderTriangles( ( float* )triVerts, triIndices, 1, NULL, MaskedOcclusionCulling::BACKFACE_CCW );
}
}
#endif
}
//--------------------------
// base drawing surface

View file

@ -411,45 +411,92 @@ void R_RenderSingleModel( viewEntity_t* vEntity )
// RB: added check wether GPU skinning is available at all
const bool gpuSkinned = ( tri->staticModelWithJoints != NULL && r_useGPUSkinning.GetBool() );
// RB end
//--------------------------
// base drawing surface
//--------------------------
const float* shaderRegisters = NULL;
drawSurf_t* baseDrawSurf = NULL;
if( surfaceDirectlyVisible && shader->IsDrawn() )
if( surfaceDirectlyVisible && shader->IsDrawn() && shader->Coverage() == MC_OPAQUE && !renderEntity->weaponDepthHack && renderEntity->modelDepthHack == 0.0f )
{
// TODO render to masked occlusion buffer
// render to masked occlusion buffer
//if( model->IsStaticWorldModel() )
{
// super simple bruteforce
idVec4 triVerts[3];
unsigned int triIndices[] = { 0, 1, 2 };
tr.pc.c_mocIndexes += tri->numIndexes;
tr.pc.c_mocVerts += tri->numIndexes;
for( int i = 0, face = 0; i < tri->numIndexes; i += 3, face++ )
{
const idDrawVert& v0 = tri->verts[tri->indexes[i + 0]];
const idDrawVert& v1 = tri->verts[tri->indexes[i + 1]];
const idDrawVert& v2 = tri->verts[tri->indexes[i + 2]];
// transform to clip space
vEntity->unjitteredMVP.TransformPoint( idVec4( v0.xyz.x, v0.xyz.y, v0.xyz.z, 1 ), triVerts[0] );
vEntity->unjitteredMVP.TransformPoint( idVec4( v1.xyz.x, v1.xyz.y, v1.xyz.z, 1 ), triVerts[1] );
vEntity->unjitteredMVP.TransformPoint( idVec4( v2.xyz.x, v2.xyz.y, v2.xyz.z, 1 ), triVerts[2] );
// tri->indexes is unsigned short instead of uint
//triIndices[0] = tri->indexes[i + 0];
//triIndices[1] = tri->indexes[i + 1];
//triIndices[2] = tri->indexes[i + 2];
tr.maskedOcclusionCulling->RenderTriangles( ( float* )triVerts, triIndices, 1, NULL, MaskedOcclusionCulling::BACKFACE_CCW );
}
}
#if 0
else
{
idVec4 triVerts[3];
unsigned int triIndices[] = { 0, 1, 2 };
tr.pc.c_mocIndexes += 36;
tr.pc.c_mocVerts += 8;
idRenderMatrix modelRenderMatrix;
idRenderMatrix::CreateFromOriginAxis( renderEntity->origin, renderEntity->axis, modelRenderMatrix );
const float size = 16.0f;
idBounds debugBounds( idVec3( -size ), idVec3( size ) );
//debugBounds = vEntity->entityDef->localReferenceBounds;
debugBounds = tri->bounds;
idRenderMatrix inverseBaseModelProject;
idRenderMatrix::OffsetScaleForBounds( modelRenderMatrix, debugBounds, inverseBaseModelProject );
idRenderMatrix invProjectMVPMatrix;
idRenderMatrix::Multiply( viewDef->worldSpace.unjitteredMVP, inverseBaseModelProject, invProjectMVPMatrix );
#if 1
// super simple bruteforce
idVec4 triVerts[3];
unsigned int triIndices[] = { 0, 1, 2 };
idVec4* verts = tr.maskedZeroOneCubeVerts;
unsigned int* indexes = tr.maskedZeroOneCubeIndexes;
for( int i = 0, face = 0; i < 36; i += 3, face++ )
{
const idVec4& v0 = verts[indexes[i + 0]];
const idVec4& v1 = verts[indexes[i + 1]];
const idVec4& v2 = verts[indexes[i + 2]];
tr.pc.c_mocIndexes += tri->numIndexes;
tr.pc.c_mocVerts += tri->numIndexes;
// transform to clip space
invProjectMVPMatrix.TransformPoint( v0, triVerts[0] );
invProjectMVPMatrix.TransformPoint( v1, triVerts[1] );
invProjectMVPMatrix.TransformPoint( v2, triVerts[2] );
for( int i = 0, face = 0; i < tri->numIndexes; i += 3, face++ )
{
const idDrawVert& v0 = tri->verts[tri->indexes[i + 0]];
const idDrawVert& v1 = tri->verts[tri->indexes[i + 1]];
const idDrawVert& v2 = tri->verts[tri->indexes[i + 2]];
tr.maskedOcclusionCulling->RenderTriangles( ( float* )triVerts, triIndices, 1, NULL, MaskedOcclusionCulling::BACKFACE_CCW );
}
#else
// transform to clip space
vEntity->unjitteredMVP.TransformPoint( idVec4( v0.xyz.x, v0.xyz.y, v0.xyz.z, 1 ), triVerts[0] );
vEntity->unjitteredMVP.TransformPoint( idVec4( v1.xyz.x, v1.xyz.y, v1.xyz.z, 1 ), triVerts[1] );
vEntity->unjitteredMVP.TransformPoint( idVec4( v2.xyz.x, v2.xyz.y, v2.xyz.z, 1 ), triVerts[2] );
// TODO get faster alternative working
idRenderMatrix invProjectMVPMatrix2;
idRenderMatrix::Transpose( invProjectMVPMatrix, invProjectMVPMatrix2 );
// tri->indexes is unsigned short instead of uint
//triIndices[0] = tri->indexes[i + 0];
//triIndices[1] = tri->indexes[i + 1];
//triIndices[2] = tri->indexes[i + 2];
tr.maskedOcclusionCulling->RenderTriangles( ( float* )triVerts, triIndices, 1, NULL, MaskedOcclusionCulling::BACKFACE_CCW );
tr.maskedOcclusionCulling->RenderTriangles( ( float* )tr.maskedZeroOneCubeVerts, tr.maskedZeroOneCubeIndexes, 12, ( float* )&invProjectMVPMatrix2[0][0], MaskedOcclusionCulling::BACKFACE_NONE, MaskedOcclusionCulling::CLIP_PLANE_ALL, MaskedOcclusionCulling::VertexLayout( 16, 4, 8 ) );
#endif
}
// TODO write faster alternative
#endif
/*
@ -526,6 +573,11 @@ void R_FillMaskedOcclusionBufferWithModels( viewDef_t* viewDef )
{
SCOPED_PROFILE_EVENT( "R_FillMaskedOcclusionBufferWithModels" );
if( !r_useMaskedOcclusionCulling.GetBool() )
{
return;
}
const int viewWidth = viewDef->viewport.x2 - viewDef->viewport.x1 + 1;
const int viewHeight = viewDef->viewport.y2 - viewDef->viewport.y1 + 1;
@ -562,7 +614,7 @@ void R_FillMaskedOcclusionBufferWithModels( viewDef_t* viewDef )
// skip after rendering BSP area models
if( !model->IsStaticWorldModel() )
{
continue;
//continue;
}
R_RenderSingleModel( vEntity );
@ -612,6 +664,6 @@ CONSOLE_COMMAND( maskShot, "Dumping masked occlusion culling buffer", NULL )
unsigned char* image = new unsigned char[width * height * 3];
TonemapDepth( perPixelZBuffer, image, width, height );
R_WritePNG( "occlusion_buffer.png", image, 3, width, height, "fs_basepath" );
R_WritePNG( "screenshots/soft_occlusion_buffer.png", image, 3, width, height, "fs_basepath" );
delete[] image;
}