dmap now contains path tracing optimizations stored in iceproc files.

This commit is contained in:
Justin Marshall
2026-05-26 12:14:39 -07:00
parent 754f5b4aa0
commit 41cbd5669b
50 changed files with 350449 additions and 624741 deletions
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 MiB

After

Width:  |  Height:  |  Size: 1.0 MiB

+65355 -64630
View File
File diff suppressed because it is too large Load Diff
+37235 -184817
View File
File diff suppressed because it is too large Load Diff
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 MiB

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 256 KiB

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 MiB

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 MiB

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 MiB

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 MiB

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 MiB

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 MiB

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 256 KiB

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 256 KiB

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 256 KiB

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 MiB

After

Width:  |  Height:  |  Size: 1.0 MiB

+62570 -62887
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+18053 -86942
View File
File diff suppressed because it is too large Load Diff
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 MiB

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 MiB

After

Width:  |  Height:  |  Size: 1.0 MiB

+49926 -49861
View File
File diff suppressed because it is too large Load Diff
+62201 -175560
View File
File diff suppressed because it is too large Load Diff
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 MiB

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 MiB

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 MiB

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 MiB

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 MiB

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 MiB

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 MiB

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 MiB

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 MiB

After

Width:  |  Height:  |  Size: 1.0 MiB

+41 -8
View File
@@ -7,9 +7,9 @@
This file has been generated with the Type Info Generator v1.1 (c) 2004 id Software This file has been generated with the Type Info Generator v1.1 (c) 2004 id Software
1199 constants 1204 constants
135 enums 135 enums
620 classes/structs/unions 621 classes/structs/unions
38 templates 38 templates
7 max inheritance level for 'idAI_Vagary' 7 max inheritance level for 'idAI_Vagary'
@@ -383,6 +383,11 @@ static constantInfo_t constantInfo[] = {
{ "int", "GEOMETRY_FLAG_UNLIT", "2" }, { "int", "GEOMETRY_FLAG_UNLIT", "2" },
{ "int", "GEOMETRY_FLAG_GLASS", "4" }, { "int", "GEOMETRY_FLAG_GLASS", "4" },
{ "static const uint32_t", "GL_RAYTRACING_MAX_LIGHTS", "256" }, { "static const uint32_t", "GL_RAYTRACING_MAX_LIGHTS", "256" },
{ "static const uint32_t", "GL_RAYTRACING_PROC_SURFACE_EMISSIVE", "0x00000001" },
{ "static const uint32_t", "GL_RAYTRACING_PROC_SURFACE_UNLIT", "0x00000002" },
{ "static const uint32_t", "GL_RAYTRACING_PROC_SURFACE_SKY", "0x00000004" },
{ "static const uint32_t", "GL_RAYTRACING_PROC_SURFACE_ALPHA_TESTED", "0x00000008" },
{ "static const uint32_t", "GL_RAYTRACING_PROC_SURFACE_TWO_SIDED", "0x00000010" },
{ "static const int", "GL_RAYTRACING_LIGHT_TYPE_POINT", "0" }, { "static const int", "GL_RAYTRACING_LIGHT_TYPE_POINT", "0" },
{ "static const int", "GL_RAYTRACING_LIGHT_TYPE_RECT", "1" }, { "static const int", "GL_RAYTRACING_LIGHT_TYPE_RECT", "1" },
{ "static const int", "GL_RAYTRACING_LIGHT_TYPE_SPOT", "2" }, { "static const int", "GL_RAYTRACING_LIGHT_TYPE_SPOT", "2" },
@@ -4114,6 +4119,33 @@ static classVariableInfo_t glRaytracingLightingPassDesc_t_typeInfo[] = {
{ NULL, 0 } { NULL, 0 }
}; };
static classVariableInfo_t glRaytracingProfileCounters_t_typeInfo[] = {
{ "uint32_t", "frameCounter", (intptr_t)(&((glRaytracingProfileCounters_t *)0)->frameCounter), sizeof( ((glRaytracingProfileCounters_t *)0)->frameCounter ) },
{ "uint32_t", "width", (intptr_t)(&((glRaytracingProfileCounters_t *)0)->width), sizeof( ((glRaytracingProfileCounters_t *)0)->width ) },
{ "uint32_t", "height", (intptr_t)(&((glRaytracingProfileCounters_t *)0)->height), sizeof( ((glRaytracingProfileCounters_t *)0)->height ) },
{ "uint32_t", "lightCount", (intptr_t)(&((glRaytracingProfileCounters_t *)0)->lightCount), sizeof( ((glRaytracingProfileCounters_t *)0)->lightCount ) },
{ "uint32_t", "pointLightCount", (intptr_t)(&((glRaytracingProfileCounters_t *)0)->pointLightCount), sizeof( ((glRaytracingProfileCounters_t *)0)->pointLightCount ) },
{ "uint32_t", "spotLightCount", (intptr_t)(&((glRaytracingProfileCounters_t *)0)->spotLightCount), sizeof( ((glRaytracingProfileCounters_t *)0)->spotLightCount ) },
{ "uint32_t", "rectLightCount", (intptr_t)(&((glRaytracingProfileCounters_t *)0)->rectLightCount), sizeof( ((glRaytracingProfileCounters_t *)0)->rectLightCount ) },
{ "uint32_t", "shadowCastingLightCount", (intptr_t)(&((glRaytracingProfileCounters_t *)0)->shadowCastingLightCount), sizeof( ((glRaytracingProfileCounters_t *)0)->shadowCastingLightCount ) },
{ "uint32_t", "volumetricLightCount", (intptr_t)(&((glRaytracingProfileCounters_t *)0)->volumetricLightCount), sizeof( ((glRaytracingProfileCounters_t *)0)->volumetricLightCount ) },
{ "uint32_t", "samplesPerPixel", (intptr_t)(&((glRaytracingProfileCounters_t *)0)->samplesPerPixel), sizeof( ((glRaytracingProfileCounters_t *)0)->samplesPerPixel ) },
{ "uint32_t", "maxBounces", (intptr_t)(&((glRaytracingProfileCounters_t *)0)->maxBounces), sizeof( ((glRaytracingProfileCounters_t *)0)->maxBounces ) },
{ "uint32_t", "enableSpecular", (intptr_t)(&((glRaytracingProfileCounters_t *)0)->enableSpecular), sizeof( ((glRaytracingProfileCounters_t *)0)->enableSpecular ) },
{ "uint32_t", "enableDenoiser", (intptr_t)(&((glRaytracingProfileCounters_t *)0)->enableDenoiser), sizeof( ((glRaytracingProfileCounters_t *)0)->enableDenoiser ) },
{ "uint32_t", "meshCount", (intptr_t)(&((glRaytracingProfileCounters_t *)0)->meshCount), sizeof( ((glRaytracingProfileCounters_t *)0)->meshCount ) },
{ "uint32_t", "instanceCount", (intptr_t)(&((glRaytracingProfileCounters_t *)0)->instanceCount), sizeof( ((glRaytracingProfileCounters_t *)0)->instanceCount ) },
{ "uint32_t", "directLightSamplesPerPixel", (intptr_t)(&((glRaytracingProfileCounters_t *)0)->directLightSamplesPerPixel), sizeof( ((glRaytracingProfileCounters_t *)0)->directLightSamplesPerPixel ) },
{ "uint32_t", "directShadowRaysPerPixel", (intptr_t)(&((glRaytracingProfileCounters_t *)0)->directShadowRaysPerPixel), sizeof( ((glRaytracingProfileCounters_t *)0)->directShadowRaysPerPixel ) },
{ "uint32_t", "indirectBounceRaysPerPixel", (intptr_t)(&((glRaytracingProfileCounters_t *)0)->indirectBounceRaysPerPixel), sizeof( ((glRaytracingProfileCounters_t *)0)->indirectBounceRaysPerPixel ) },
{ "uint32_t", "indirectLightEvalsPerPixel", (intptr_t)(&((glRaytracingProfileCounters_t *)0)->indirectLightEvalsPerPixel), sizeof( ((glRaytracingProfileCounters_t *)0)->indirectLightEvalsPerPixel ) },
{ "uint32_t", "finalGatherRaysPerPixel", (intptr_t)(&((glRaytracingProfileCounters_t *)0)->finalGatherRaysPerPixel), sizeof( ((glRaytracingProfileCounters_t *)0)->finalGatherRaysPerPixel ) },
{ "uint32_t", "reflectionRaysPerPixel", (intptr_t)(&((glRaytracingProfileCounters_t *)0)->reflectionRaysPerPixel), sizeof( ((glRaytracingProfileCounters_t *)0)->reflectionRaysPerPixel ) },
{ "uint32_t", "volumetricShadowRaysPerPixel", (intptr_t)(&((glRaytracingProfileCounters_t *)0)->volumetricShadowRaysPerPixel), sizeof( ((glRaytracingProfileCounters_t *)0)->volumetricShadowRaysPerPixel ) },
{ "float", "gpuMsec", (intptr_t)(&((glRaytracingProfileCounters_t *)0)->gpuMsec), sizeof( ((glRaytracingProfileCounters_t *)0)->gpuMsec ) },
{ NULL, 0 }
};
static classVariableInfo_t glScreenSpaceDecal_t_typeInfo[] = { static classVariableInfo_t glScreenSpaceDecal_t_typeInfo[] = {
{ "glRaytracingVec3_t", "origin", (intptr_t)(&((glScreenSpaceDecal_t *)0)->origin), sizeof( ((glScreenSpaceDecal_t *)0)->origin ) }, { "glRaytracingVec3_t", "origin", (intptr_t)(&((glScreenSpaceDecal_t *)0)->origin), sizeof( ((glScreenSpaceDecal_t *)0)->origin ) },
{ "float", "halfSize", (intptr_t)(&((glScreenSpaceDecal_t *)0)->halfSize), sizeof( ((glScreenSpaceDecal_t *)0)->halfSize ) }, { "float", "halfSize", (intptr_t)(&((glScreenSpaceDecal_t *)0)->halfSize), sizeof( ((glScreenSpaceDecal_t *)0)->halfSize ) },
@@ -5259,11 +5291,11 @@ static classVariableInfo_t frameLookup_t_typeInfo[] = {
{ NULL, 0 } { NULL, 0 }
}; };
static classVariableInfo_t class_288_class_288_typeInfo[] = { static classVariableInfo_t class_289_class_289_typeInfo[] = {
// { "const idSoundShader *", "soundShader", (intptr_t)(&((class_288::class_288 *)0)->soundShader), sizeof( ((class_288::class_288 *)0)->soundShader ) }, // { "const idSoundShader *", "soundShader", (intptr_t)(&((class_289::class_289 *)0)->soundShader), sizeof( ((class_289::class_289 *)0)->soundShader ) },
// { "const function_t *", "function", (intptr_t)(&((class_288::class_288 *)0)->function), sizeof( ((class_288::class_288 *)0)->function ) }, // { "const function_t *", "function", (intptr_t)(&((class_289::class_289 *)0)->function), sizeof( ((class_289::class_289 *)0)->function ) },
// { "const idDeclSkin *", "skin", (intptr_t)(&((class_288::class_288 *)0)->skin), sizeof( ((class_288::class_288 *)0)->skin ) }, // { "const idDeclSkin *", "skin", (intptr_t)(&((class_289::class_289 *)0)->skin), sizeof( ((class_289::class_289 *)0)->skin ) },
// { "int", "index", (intptr_t)(&((class_288::class_288 *)0)->index), sizeof( ((class_288::class_288 *)0)->index ) }, // { "int", "index", (intptr_t)(&((class_289::class_289 *)0)->index), sizeof( ((class_289::class_289 *)0)->index ) },
{ NULL, 0 } { NULL, 0 }
}; };
@@ -9184,6 +9216,7 @@ static classTypeInfo_t classTypeInfo[] = {
// { "glRaytracingLight_s::class_173", "", sizeof(glRaytracingLight_s::class_173), glRaytracingLight_s_class_173_typeInfo }, // { "glRaytracingLight_s::class_173", "", sizeof(glRaytracingLight_s::class_173), glRaytracingLight_s_class_173_typeInfo },
{ "glRaytracingLight_t", "", sizeof(glRaytracingLight_t), glRaytracingLight_t_typeInfo }, { "glRaytracingLight_t", "", sizeof(glRaytracingLight_t), glRaytracingLight_t_typeInfo },
{ "glRaytracingLightingPassDesc_t", "", sizeof(glRaytracingLightingPassDesc_t), glRaytracingLightingPassDesc_t_typeInfo }, { "glRaytracingLightingPassDesc_t", "", sizeof(glRaytracingLightingPassDesc_t), glRaytracingLightingPassDesc_t_typeInfo },
{ "glRaytracingProfileCounters_t", "", sizeof(glRaytracingProfileCounters_t), glRaytracingProfileCounters_t_typeInfo },
{ "glScreenSpaceDecal_t", "", sizeof(glScreenSpaceDecal_t), glScreenSpaceDecal_t_typeInfo }, { "glScreenSpaceDecal_t", "", sizeof(glScreenSpaceDecal_t), glScreenSpaceDecal_t_typeInfo },
{ "glScreenSpaceParticleVertex_t", "", sizeof(glScreenSpaceParticleVertex_t), glScreenSpaceParticleVertex_t_typeInfo }, { "glScreenSpaceParticleVertex_t", "", sizeof(glScreenSpaceParticleVertex_t), glScreenSpaceParticleVertex_t_typeInfo },
{ "QD3D12NeuralPOMImageRGBA8", "", sizeof(QD3D12NeuralPOMImageRGBA8), QD3D12NeuralPOMImageRGBA8_typeInfo }, { "QD3D12NeuralPOMImageRGBA8", "", sizeof(QD3D12NeuralPOMImageRGBA8), QD3D12NeuralPOMImageRGBA8_typeInfo },
@@ -9296,7 +9329,7 @@ static classTypeInfo_t classTypeInfo[] = {
{ "jointAnimInfo_t", "", sizeof(jointAnimInfo_t), jointAnimInfo_t_typeInfo }, { "jointAnimInfo_t", "", sizeof(jointAnimInfo_t), jointAnimInfo_t_typeInfo },
{ "jointMod_t", "", sizeof(jointMod_t), jointMod_t_typeInfo }, { "jointMod_t", "", sizeof(jointMod_t), jointMod_t_typeInfo },
{ "frameLookup_t", "", sizeof(frameLookup_t), frameLookup_t_typeInfo }, { "frameLookup_t", "", sizeof(frameLookup_t), frameLookup_t_typeInfo },
// { "class_288::class_288", "", sizeof(class_288::class_288), class_288_class_288_typeInfo }, // { "class_289::class_289", "", sizeof(class_289::class_289), class_289_class_289_typeInfo },
{ "frameCommand_t", "", sizeof(frameCommand_t), frameCommand_t_typeInfo }, { "frameCommand_t", "", sizeof(frameCommand_t), frameCommand_t_typeInfo },
{ "animFlags_t", "", sizeof(animFlags_t), animFlags_t_typeInfo }, { "animFlags_t", "", sizeof(animFlags_t), animFlags_t_typeInfo },
{ "idModelExport", "", sizeof(idModelExport), idModelExport_typeInfo }, { "idModelExport", "", sizeof(idModelExport), idModelExport_typeInfo },
+2 -2
View File
@@ -15,9 +15,9 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LocalDebuggerCommand>D:\projects\Doom3\Doom3.exe</LocalDebuggerCommand> <LocalDebuggerCommand>D:\projects\Doom3\Doom3.exe</LocalDebuggerCommand>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor> <DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
<LocalDebuggerCommandArguments>+set r_fullscreen 0 +set r_mode 9 +set sv_pure 0</LocalDebuggerCommandArguments> <LocalDebuggerCommandArguments>+set r_fullscreen 0 +set r_mode 11 +set sv_pure 0</LocalDebuggerCommandArguments>
<LocalDebuggerWorkingDirectory>D:\projects\Doom3</LocalDebuggerWorkingDirectory> <LocalDebuggerWorkingDirectory>D:\projects\Doom3</LocalDebuggerWorkingDirectory>
<LocalDebuggerCommandArgumentsHistory>+set r_fullscreen 0 +set r_mode 11 +set sv_pure 0 +set fs_game e3|+set r_fullscreen 0 +set r_mode 11 +set sv_pure 0 |+set r_fullscreen 0 +set r_mode 9 +set sv_pure 0 |+set r_fullscreen 0 +set r_mode 9 +set sv_pure 0 +set fs_game rage|+set r_fullscreen 0 +set r_mode 9 +set sv_pure 0|</LocalDebuggerCommandArgumentsHistory> <LocalDebuggerCommandArgumentsHistory>+set r_fullscreen 0 +set r_mode 11 +set sv_pure 0 |+set r_fullscreen 0 +set r_mode 9 +set sv_pure 0 |+set r_fullscreen 0 +set r_mode 9 +set sv_pure 0 +set fs_game rage|+set r_fullscreen 0 +set r_mode 9 +set sv_pure 0|+set r_fullscreen 0 +set r_mode 11 +set sv_pure 0|</LocalDebuggerCommandArgumentsHistory>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Q4 Debug|x64'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Q4 Debug|x64'">
<LocalDebuggerCommand>D:\projects\Doom3\Quake4.exe</LocalDebuggerCommand> <LocalDebuggerCommand>D:\projects\Doom3\Quake4.exe</LocalDebuggerCommand>
+214 -9
View File
@@ -43,6 +43,7 @@ If you have questions concerning this license or the applicable additional terms
#include <stdio.h> #include <stdio.h>
#include <stdarg.h> #include <stdarg.h>
#include <assert.h> #include <assert.h>
#include <math.h>
#pragma comment(lib, "dxcompiler.lib") #pragma comment(lib, "dxcompiler.lib")
#pragma comment(lib, "d3dcompiler.lib") #pragma comment(lib, "d3dcompiler.lib")
@@ -2211,6 +2212,16 @@ void glRaytracingSetMeshAverageColor(glRaytracingMeshHandle_t meshHandle, float
glRaytracingLightingResetDenoiseHistory(); glRaytracingLightingResetDenoiseHistory();
} }
void glRaytracingSetMeshProcMetadata(glRaytracingMeshHandle_t meshHandle, uint32_t procFlags, float emissiveR, float emissiveG, float emissiveB, float emissivePower)
{
(void)meshHandle;
(void)procFlags;
(void)emissiveR;
(void)emissiveG;
(void)emissiveB;
(void)emissivePower;
}
void glRaytracingDeleteMesh(glRaytracingMeshHandle_t meshHandle) void glRaytracingDeleteMesh(glRaytracingMeshHandle_t meshHandle)
{ {
std::lock_guard<std::mutex> lock(g_glRaytracingMutex); std::lock_guard<std::mutex> lock(g_glRaytracingMutex);
@@ -2461,7 +2472,6 @@ struct glRaytracingLightingConstants_t
float denoisePhiNormal; float denoisePhiNormal;
float denoisePhiPosition; float denoisePhiPosition;
float bumpStrength; float bumpStrength;
}; };
struct glRaytracingMeshMetadata_t struct glRaytracingMeshMetadata_t
@@ -2530,6 +2540,10 @@ struct glRaytracingLightingState_t
DXGI_FORMAT iesFormats[GL_RAYTRACING_MAX_IES_TEXTURES]; DXGI_FORMAT iesFormats[GL_RAYTRACING_MAX_IES_TEXTURES];
bool uploadToCurrentFrameResource; bool uploadToCurrentFrameResource;
bool initialized; bool initialized;
glRaytracingSceneHandle_t lastProfileSceneHandle;
uint32_t lastProfileInstanceCount;
uint32_t lastProfileWidth;
uint32_t lastProfileHeight;
glRaytracingLightingState_t() glRaytracingLightingState_t()
{ {
@@ -2567,6 +2581,10 @@ struct glRaytracingLightingState_t
} }
uploadToCurrentFrameResource = false; uploadToCurrentFrameResource = false;
initialized = false; initialized = false;
lastProfileSceneHandle = 0;
lastProfileInstanceCount = 0;
lastProfileWidth = 0;
lastProfileHeight = 0;
} }
}; };
@@ -4787,6 +4805,29 @@ float3 EstimateFastBounceLight(float3 hitPos, float3 hitN, Light Lgt)
return 0.0; return 0.0;
} }
uint GetSecondaryBounceFastLightBudget()
{
if (gLightCount > 16u)
return 8u;
if (gLightCount > 10u)
return 7u;
if (gLightCount > 6u)
return 6u;
return gLightCount;
}
float GetSecondaryBounceFastLightScale(uint fastBudget)
{
if (fastBudget == 0u || fastBudget >= gLightCount)
return 1.0;
// The uploaded light list is CPU-sorted by broad importance. Use a small
// energy compensation for skipped low-importance lights without pretending
// the top few lights represent the entire room perfectly.
float fullScale = (float)gLightCount / (float)fastBudget;
return lerp(1.0, fullScale, 0.18);
}
float3 EstimateUnresolvedBounceRadiance(float3 hitPos, float3 hitN, float3 albedo) float3 EstimateUnresolvedBounceRadiance(float3 hitPos, float3 hitN, float3 albedo)
{ {
hitN = SafeNormalizeOr(hitN, float3(0.0, 0.0, 1.0)); hitN = SafeNormalizeOr(hitN, float3(0.0, 0.0, 1.0));
@@ -4796,11 +4837,14 @@ float3 EstimateUnresolvedBounceRadiance(float3 hitPos, float3 hitN, float3 albed
float3 lighting = gAmbientColor.rgb * (gAmbientColor.a * 0.025); float3 lighting = gAmbientColor.rgb * (gAmbientColor.a * 0.025);
lighting += GetSkyRadiance(hitN) * (0.035 + 0.035 * upness); lighting += GetSkyRadiance(hitN) * (0.035 + 0.035 * upness);
float3 fastAllLights = 0.0;
uint fastBudget = GetSecondaryBounceFastLightBudget();
[loop] [loop]
for (uint i = 0; i < gLightCount; ++i) for (uint i = 0; i < fastBudget; ++i)
{ {
lighting += EstimateFastBounceLight(hitPos, hitN, gLights[i]) * 0.35; fastAllLights += EstimateFastBounceLight(hitPos, hitN, gLights[i]);
} }
lighting += fastAllLights * (0.35 * GetSecondaryBounceFastLightScale(fastBudget));
return clamp(albedo * max(lighting, 0.0), 0.0, 6.0); return clamp(albedo * max(lighting, 0.0), 0.0, 6.0);
} }
@@ -4885,16 +4929,18 @@ float3 EstimateDirectLightingForBounceHit(uint2 hitPixel, float3 hitPos, float3
// direct visible/bloom-only effect until real material-space emissive lighting // direct visible/bloom-only effect until real material-space emissive lighting
// is implemented. // is implemented.
// Baseline: every light contributes to bounced radiance, so small dynamic // Baseline: secondary GI uses a capped important-light set. Primary direct
// lights do not vanish just because they were not chosen by the stochastic // lighting still evaluates every light, but bounce hits were multiplying the
// next-event-estimation budget. // full light list by every stochastic path depth.
float3 fastAllLights = 0.0; float3 fastAllLights = 0.0;
uint fastBudget = GetSecondaryBounceFastLightBudget();
[loop] [loop]
for (uint i = 0; i < gLightCount; ++i) for (uint i = 0; i < fastBudget; ++i)
{ {
fastAllLights += EstimateFastBounceLight(hitPos, hitN, gLights[i]); fastAllLights += EstimateFastBounceLight(hitPos, hitN, gLights[i]);
} }
lighting += fastAllLights; float fastLightScale = GetSecondaryBounceFastLightScale(fastBudget);
lighting += fastAllLights * fastLightScale;
// Visibility correction: replace a small stable subset of the unshadowed // Visibility correction: replace a small stable subset of the unshadowed
// baseline with real shadowed direct lighting. Keying this to the hit // baseline with real shadowed direct lighting. Keying this to the hit
@@ -4919,7 +4965,9 @@ float3 EstimateDirectLightingForBounceHit(uint2 hitPixel, float3 hitPos, float3
{ {
uint lightIndex = (start + c * stride) % gLightCount; uint lightIndex = (start + c * stride) % gLightCount;
Light Lgt = gLights[lightIndex]; Light Lgt = gLights[lightIndex];
float3 fast = EstimateFastBounceLight(hitPos, hitN, Lgt); float3 fast = (lightIndex < fastBudget)
? EstimateFastBounceLight(hitPos, hitN, Lgt) * fastLightScale
: 0.0;
float3 shadowed = EstimateShadowedBounceLight(hitPixel, hitPos, hitN, hitV, hitAlbedo, hitIsSkeletal, Lgt, lightingRng); float3 shadowed = EstimateShadowedBounceLight(hitPixel, hitPos, hitN, hitV, hitAlbedo, hitIsSkeletal, Lgt, lightingRng);
lighting += shadowed - fast; lighting += shadowed - fast;
} }
@@ -6584,6 +6632,38 @@ static void glRaytracingLightingUpdateConstants(void)
g_glRaytracingLighting.constants); g_glRaytracingLighting.constants);
} }
static float glRaytracingLightingEstimateLightImportance(const glRaytracingLight_t& light)
{
float colorPeak = light.color.x;
if (light.color.y > colorPeak) colorPeak = light.color.y;
if (light.color.z > colorPeak) colorPeak = light.color.z;
float radius = light.radius;
if (light.type == GL_RAYTRACING_LIGHT_TYPE_POINT)
{
radius = light.pointRadius.x;
if (light.pointRadius.y > radius) radius = light.pointRadius.y;
if (light.pointRadius.z > radius) radius = light.pointRadius.z;
}
else if (light.type == GL_RAYTRACING_LIGHT_TYPE_RECT)
{
radius = (light.halfWidth > light.halfHeight) ? light.halfWidth : light.halfHeight;
radius *= 6.0f;
}
if (radius < 1.0f)
radius = 1.0f;
float importance = colorPeak * light.intensity * sqrtf(radius);
if (light.samples != 0u)
importance *= 1.15f;
if (light.volumetricScattering > 0.0f)
importance *= 1.10f;
if (light.iesStrength > 0.0f)
importance *= 1.05f;
return importance;
}
static void glRaytracingLightingUpdateLights(void) static void glRaytracingLightingUpdateLights(void)
{ {
if (!g_glRaytracingLighting.uploadToCurrentFrameResource) if (!g_glRaytracingLighting.uploadToCurrentFrameResource)
@@ -6597,6 +6677,11 @@ static void glRaytracingLightingUpdateLights(void)
std::vector<glRaytracingLight_t>& uploadLights = g_glRaytracingLighting.uploadLights; std::vector<glRaytracingLight_t>& uploadLights = g_glRaytracingLighting.uploadLights;
uploadLights = g_glRaytracingLighting.cpuLights; uploadLights = g_glRaytracingLighting.cpuLights;
std::sort(uploadLights.begin(), uploadLights.end(),
[](const glRaytracingLight_t& a, const glRaytracingLight_t& b)
{
return glRaytracingLightingEstimateLightImportance(a) > glRaytracingLightingEstimateLightImportance(b);
});
for (size_t i = 0; i < uploadLights.size(); ++i) for (size_t i = 0; i < uploadLights.size(); ++i)
{ {
@@ -7840,6 +7925,12 @@ void glRaytracingLightingSetPathTracingOptions(uint32_t samplesPerPixel, uint32_
glRaytracingLightingUpdateConstants(); glRaytracingLightingUpdateConstants();
} }
void glRaytracingLightingSetSecondaryLightBudget(int budget, float compensation)
{
(void)budget;
(void)compensation;
}
void glRaytracingLightingSetDenoiseTuning(float phiColor, float phiNormal, float phiPosition) void glRaytracingLightingSetDenoiseTuning(float phiColor, float phiNormal, float phiPosition)
{ {
std::lock_guard<std::mutex> lock(g_glRaytracingMutex); std::lock_guard<std::mutex> lock(g_glRaytracingMutex);
@@ -7925,6 +8016,12 @@ bool glRaytracingLightingExecuteForScene(const glRaytracingLightingPassDesc_t* p
if (!topLevelAS) if (!topLevelAS)
return false; return false;
const glRaytracingRenderWorld_t* world = glRaytracingFindWorldConst(worldHandle);
g_glRaytracingLighting.lastProfileSceneHandle = worldHandle;
g_glRaytracingLighting.lastProfileInstanceCount = glRaytracingCountAliveInstances(world);
g_glRaytracingLighting.lastProfileWidth = pass ? pass->width : 0;
g_glRaytracingLighting.lastProfileHeight = pass ? pass->height : 0;
return glRaytracingLightingExecuteInternal(pass, topLevelAS); return glRaytracingLightingExecuteInternal(pass, topLevelAS);
} }
@@ -8169,6 +8266,114 @@ uint32_t glRaytracingLightingGetLightCount(void)
return (uint32_t)g_glRaytracingLighting.cpuLights.size(); return (uint32_t)g_glRaytracingLighting.cpuLights.size();
} }
bool glRaytracingLightingGetProfileCounters(glRaytracingProfileCounters_t* counters)
{
if (!counters)
return false;
std::lock_guard<std::mutex> lock(g_glRaytracingMutex);
memset(counters, 0, sizeof(*counters));
const glRaytracingLightingConstants_t& constants = g_glRaytracingLighting.constants;
const uint32_t lightCount = (uint32_t)g_glRaytracingLighting.cpuLights.size();
const uint32_t samplesPerPixel = constants.samplesPerPixel ? constants.samplesPerPixel : 1u;
const uint32_t maxBounces = constants.maxBounces ? constants.maxBounces : 1u;
uint32_t directLightSamples = 0;
uint32_t directShadowRays = 0;
uint32_t volumetricShadowRays = 0;
for (size_t i = 0; i < g_glRaytracingLighting.cpuLights.size(); ++i)
{
const glRaytracingLight_t& light = g_glRaytracingLighting.cpuLights[i];
const uint32_t sampleCount = glRaytracingClamp<uint32_t>(light.samples ? light.samples : 1u, 1u, 4u);
if (light.type == GL_RAYTRACING_LIGHT_TYPE_POINT)
++counters->pointLightCount;
else if (light.type == GL_RAYTRACING_LIGHT_TYPE_SPOT)
++counters->spotLightCount;
else if (light.type == GL_RAYTRACING_LIGHT_TYPE_RECT)
++counters->rectLightCount;
directLightSamples += sampleCount;
if (light.samples != 0u)
{
++counters->shadowCastingLightCount;
directShadowRays += sampleCount;
}
if (light.volumetricScattering > 0.0f &&
(light.type == GL_RAYTRACING_LIGHT_TYPE_POINT || light.type == GL_RAYTRACING_LIGHT_TYPE_SPOT))
{
++counters->volumetricLightCount;
volumetricShadowRays += glRaytracingClamp<uint32_t>(light.samples ? light.samples : 3u, 3u, 6u);
}
}
uint32_t meshCount = 0;
for (size_t i = 0; i < g_glRaytracingScene.meshes.size(); ++i)
{
if (g_glRaytracingScene.meshes[i].alive)
++meshCount;
}
uint32_t indirectDepth = 0;
if (maxBounces > 1u)
{
indirectDepth = glRaytracingClamp<uint32_t>(maxBounces - 1u, 0u, 3u);
if (samplesPerPixel <= 1u)
indirectDepth = glRaytracingClamp<uint32_t>(indirectDepth, 0u, 2u);
}
uint32_t correctionBudget = 0;
if (lightCount > 0u)
{
correctionBudget = (lightCount <= 3u) ? lightCount : 2u;
if (samplesPerPixel >= 4u)
correctionBudget = glRaytracingClamp<uint32_t>(correctionBudget + 1u, 0u, lightCount);
}
uint32_t fastBounceLightBudget = lightCount;
if (lightCount > 16u)
fastBounceLightBudget = 8u;
else if (lightCount > 10u)
fastBounceLightBudget = 7u;
else if (lightCount > 6u)
fastBounceLightBudget = 6u;
uint32_t gatherSamples = 0;
if (maxBounces > 1u)
{
gatherSamples = 3u;
if (lightCount > 4u)
gatherSamples = 2u;
if (lightCount > 10u)
gatherSamples = 1u;
if (samplesPerPixel >= 4u)
gatherSamples = glRaytracingClamp<uint32_t>(gatherSamples, 0u, 2u);
if (samplesPerPixel >= 6u)
gatherSamples = glRaytracingClamp<uint32_t>(gatherSamples, 0u, 1u);
}
counters->frameCounter = g_glRaytracingLighting.frameCounter;
counters->width = g_glRaytracingLighting.lastProfileWidth;
counters->height = g_glRaytracingLighting.lastProfileHeight;
counters->lightCount = lightCount;
counters->samplesPerPixel = samplesPerPixel;
counters->maxBounces = maxBounces;
counters->enableSpecular = constants.enableSpecular;
counters->enableDenoiser = constants.enableDenoiser;
counters->meshCount = meshCount;
counters->instanceCount = g_glRaytracingLighting.lastProfileInstanceCount;
counters->directLightSamplesPerPixel = directLightSamples;
counters->directShadowRaysPerPixel = directShadowRays;
counters->indirectBounceRaysPerPixel = samplesPerPixel * indirectDepth;
counters->indirectLightEvalsPerPixel = samplesPerPixel * indirectDepth * (fastBounceLightBudget + correctionBudget);
counters->finalGatherRaysPerPixel = gatherSamples;
counters->reflectionRaysPerPixel = (constants.enableSpecular != 0u && maxBounces > 1u) ? 1u : 0u;
counters->volumetricShadowRaysPerPixel = volumetricShadowRays;
counters->gpuMsec = com_pathTracingGpuMsec;
return true;
}
int glRaytracingSetInstanceVisibilityUnlocked( int glRaytracingSetInstanceVisibilityUnlocked(
glRaytracingRenderWorld_t* world, glRaytracingRenderWorld_t* world,
glRaytracingInstanceHandle_t instanceHandle, glRaytracingInstanceHandle_t instanceHandle,
+36
View File
@@ -1656,6 +1656,12 @@ typedef uint32_t glRaytracingInstanceHandle_t;
static const uint32_t GL_RAYTRACING_MAX_LIGHTS = 256; static const uint32_t GL_RAYTRACING_MAX_LIGHTS = 256;
static const uint32_t GL_RAYTRACING_PROC_SURFACE_EMISSIVE = 0x00000001u;
static const uint32_t GL_RAYTRACING_PROC_SURFACE_UNLIT = 0x00000002u;
static const uint32_t GL_RAYTRACING_PROC_SURFACE_SKY = 0x00000004u;
static const uint32_t GL_RAYTRACING_PROC_SURFACE_ALPHA_TESTED = 0x00000008u;
static const uint32_t GL_RAYTRACING_PROC_SURFACE_TWO_SIDED = 0x00000010u;
typedef struct glRaytracingVec3_s typedef struct glRaytracingVec3_s
{ {
float x, y, z; float x, y, z;
@@ -1732,6 +1738,33 @@ typedef struct glRaytracingLightingPassDesc_s
uint32_t height; uint32_t height;
} glRaytracingLightingPassDesc_t; } glRaytracingLightingPassDesc_t;
typedef struct glRaytracingProfileCounters_s
{
uint32_t frameCounter;
uint32_t width;
uint32_t height;
uint32_t lightCount;
uint32_t pointLightCount;
uint32_t spotLightCount;
uint32_t rectLightCount;
uint32_t shadowCastingLightCount;
uint32_t volumetricLightCount;
uint32_t samplesPerPixel;
uint32_t maxBounces;
uint32_t enableSpecular;
uint32_t enableDenoiser;
uint32_t meshCount;
uint32_t instanceCount;
uint32_t directLightSamplesPerPixel;
uint32_t directShadowRaysPerPixel;
uint32_t indirectBounceRaysPerPixel;
uint32_t indirectLightEvalsPerPixel;
uint32_t finalGatherRaysPerPixel;
uint32_t reflectionRaysPerPixel;
uint32_t volumetricShadowRaysPerPixel;
float gpuMsec;
} glRaytracingProfileCounters_t;
typedef struct glScreenSpaceDecal_s typedef struct glScreenSpaceDecal_s
{ {
glRaytracingVec3_t origin; glRaytracingVec3_t origin;
@@ -1848,6 +1881,7 @@ glRaytracingLight_t glRaytracingLightingMakeRectLight(
uint32_t twoSided); uint32_t twoSided);
uint32_t glRaytracingLightingGetLightCount(void); uint32_t glRaytracingLightingGetLightCount(void);
bool glRaytracingLightingGetProfileCounters(glRaytracingProfileCounters_t* counters);
void glLightScene(glRaytracingSceneHandle_t sceneHandle); void glLightScene(glRaytracingSceneHandle_t sceneHandle);
void glSetScreenSpaceDecalsQD3D12(const glScreenSpaceDecal_t* decals, uint32_t decalCount); void glSetScreenSpaceDecalsQD3D12(const glScreenSpaceDecal_t* decals, uint32_t decalCount);
@@ -2274,6 +2308,7 @@ void glUpdateTopLevelAceelStructure(
void glRaytracingLightingSetExternalDenoiser(int enable); void glRaytracingLightingSetExternalDenoiser(int enable);
void glRaytracingLightingUseExternalDenoiser(int enable); void glRaytracingLightingUseExternalDenoiser(int enable);
void glRaytracingLightingSetPathTracingOptions(uint32_t samplesPerPixel, uint32_t maxBounces, int enableDenoiser, float denoiseStrength); void glRaytracingLightingSetPathTracingOptions(uint32_t samplesPerPixel, uint32_t maxBounces, int enableDenoiser, float denoiseStrength);
void glRaytracingLightingSetSecondaryLightBudget(int budget, float compensation);
void QD3D12_SetPathTracingQuality(uint32_t samplesPerPixel, uint32_t maxBounces); void QD3D12_SetPathTracingQuality(uint32_t samplesPerPixel, uint32_t maxBounces);
void QD3D12_SetPathTracingFallbackSamples(uint32_t samplesPerPixel); void QD3D12_SetPathTracingFallbackSamples(uint32_t samplesPerPixel);
@@ -2310,6 +2345,7 @@ extern "C" {
void glRaytracingSetMeshMaterialFlags(glRaytracingMeshHandle_t meshHandle, uint32_t materialFlags); void glRaytracingSetMeshMaterialFlags(glRaytracingMeshHandle_t meshHandle, uint32_t materialFlags);
void glRaytracingSetMeshGlass(glRaytracingMeshHandle_t meshHandle, int isGlass); void glRaytracingSetMeshGlass(glRaytracingMeshHandle_t meshHandle, int isGlass);
void glRaytracingSetMeshAverageColor(glRaytracingMeshHandle_t meshHandle, float r, float g, float b, float a); void glRaytracingSetMeshAverageColor(glRaytracingMeshHandle_t meshHandle, float r, float g, float b, float a);
void glRaytracingSetMeshProcMetadata(glRaytracingMeshHandle_t meshHandle, uint32_t procFlags, float emissiveR, float emissiveG, float emissiveB, float emissivePower);
// For callers that create raytracing instances directly instead of using the // For callers that create raytracing instances directly instead of using the
// shim's glUpdateTopLevelAceelStructure() helper. Glass meshes must also use // shim's glUpdateTopLevelAceelStructure() helper. Glass meshes must also use
@@ -188,6 +188,12 @@ idCVar r_showEntityScissors( "r_showEntityScissors", "0", CVAR_RENDERER | CVAR_B
idCVar r_showInteractionFrustums( "r_showInteractionFrustums", "0", CVAR_RENDERER | CVAR_INTEGER, "1 = show a frustum for each interaction, 2 = also draw lines to light origin, 3 = also draw entity bbox", 0, 3, idCmdSystem::ArgCompletion_Integer<0,3> ); idCVar r_showInteractionFrustums( "r_showInteractionFrustums", "0", CVAR_RENDERER | CVAR_INTEGER, "1 = show a frustum for each interaction, 2 = also draw lines to light origin, 3 = also draw entity bbox", 0, 3, idCmdSystem::ArgCompletion_Integer<0,3> );
idCVar r_showInteractionScissors( "r_showInteractionScissors", "0", CVAR_RENDERER | CVAR_INTEGER, "1 = show screen rectangle which contains the interaction frustum, 2 = also draw construction lines", 0, 2, idCmdSystem::ArgCompletion_Integer<0,2> ); idCVar r_showInteractionScissors( "r_showInteractionScissors", "0", CVAR_RENDERER | CVAR_INTEGER, "1 = show screen rectangle which contains the interaction frustum, 2 = also draw construction lines", 0, 2, idCmdSystem::ArgCompletion_Integer<0,2> );
idCVar r_showLightCount( "r_showLightCount", "0", CVAR_RENDERER | CVAR_INTEGER, "1 = colors surfaces based on light count, 2 = also count everything through walls, 3 = also print overdraw", 0, 3, idCmdSystem::ArgCompletion_Integer<0,3> ); idCVar r_showLightCount( "r_showLightCount", "0", CVAR_RENDERER | CVAR_INTEGER, "1 = colors surfaces based on light count, 2 = also count everything through walls, 3 = also print overdraw", 0, 3, idCmdSystem::ArgCompletion_Integer<0,3> );
idCVar r_showPathTraceProfile( "r_showPathTraceProfile", "0", CVAR_RENDERER | CVAR_INTEGER, "report path tracer GPU and estimated ray workload, 1 = once per second, 2 = every frame", 0, 2, idCmdSystem::ArgCompletion_Integer<0,2> );
idCVar r_pathTraceSecondaryLightBudget( "r_pathTraceSecondaryLightBudget", "0", CVAR_RENDERER | CVAR_INTEGER, "secondary GI light budget, 0 = automatic, -1 = full light list" );
idCVar r_pathTraceSecondaryLightCompensation( "r_pathTraceSecondaryLightCompensation", "0.18", CVAR_RENDERER | CVAR_FLOAT, "energy compensation for capped secondary GI lights, 0 = none, 1 = full scale" );
idCVar r_pathTracePortalWorldCulling( "r_pathTracePortalWorldCulling", "0", CVAR_RENDERER | CVAR_BOOL, "use portal flood to hide/show static world ray tracing instances" );
idCVar r_pathTraceAreaLightCulling( "r_pathTraceAreaLightCulling", "1", CVAR_RENDERER | CVAR_BOOL, "use proc area graph to reduce uploaded path tracing lights" );
idCVar r_pathTraceAreaLightDepth( "r_pathTraceAreaLightDepth", "5", CVAR_RENDERER | CVAR_INTEGER, "proc area neighbor depth for path tracing lights", 0, 8, idCmdSystem::ArgCompletion_Integer<0,8> );
idCVar r_showViewEntitys( "r_showViewEntitys", "0", CVAR_RENDERER | CVAR_INTEGER, "1 = displays the bounding boxes of all view models, 2 = print index numbers" ); idCVar r_showViewEntitys( "r_showViewEntitys", "0", CVAR_RENDERER | CVAR_INTEGER, "1 = displays the bounding boxes of all view models, 2 = print index numbers" );
idCVar r_showTris( "r_showTris", "0", CVAR_RENDERER | CVAR_INTEGER, "enables wireframe rendering of the world, 1 = only draw visible ones, 2 = draw all front facing, 3 = draw all", 0, 3, idCmdSystem::ArgCompletion_Integer<0,3> ); idCVar r_showTris( "r_showTris", "0", CVAR_RENDERER | CVAR_INTEGER, "enables wireframe rendering of the world, 1 = only draw visible ones, 2 = draw all front facing, 3 = draw all", 0, 3, idCmdSystem::ArgCompletion_Integer<0,3> );
idCVar r_showSurfaceInfo( "r_showSurfaceInfo", "0", CVAR_RENDERER | CVAR_BOOL, "show surface material name under crosshair" ); idCVar r_showSurfaceInfo( "r_showSurfaceInfo", "0", CVAR_RENDERER | CVAR_BOOL, "show surface material name under crosshair" );
+2 -2
View File
@@ -62,8 +62,8 @@ class rvDeclMatType;
#else #else
#define PROC_FILE_EXT "proc" #define PROC_FILE_EXT "iceproc"
#define PROC_FILE_ID "mapProcFile003" #define PROC_FILE_ID "iceProcFile001"
#endif #endif
+187 -2
View File
@@ -43,11 +43,16 @@ void idRenderWorldLocal::FreeWorld() {
// this will free all the lightDefs and entityDefs // this will free all the lightDefs and entityDefs
FreeDefs(); FreeDefs();
// clear the dxr models. // A map reload is a hard boundary for path-tracing state. Clear any
glRaytracingClearScene(dxrWorldId); // persistent lights / temporal history before replacing proc geometry.
glRaytracingLightingClearLights(true);
// Delete proc-created DXR meshes before clearing the scene, so the ray
// tracing layer can invalidate any instances that still reference them.
for (i = 0; i < worldDXRmodels.Num(); i++) { for (i = 0; i < worldDXRmodels.Num(); i++) {
glRaytracingDeleteMesh(worldDXRmodels[i].dxrBottomAcel); glRaytracingDeleteMesh(worldDXRmodels[i].dxrBottomAcel);
} }
glRaytracingClearScene(dxrWorldId);
worldDXRmodels.Clear(); worldDXRmodels.Clear();
// free all the portals and check light/model references // free all the portals and check light/model references
@@ -84,6 +89,8 @@ void idRenderWorldLocal::FreeWorld() {
doublePortals = NULL; doublePortals = NULL;
numInterAreaPortals = 0; numInterAreaPortals = 0;
} }
portalHandleGroups.Clear();
pathTraceAreas.Clear();
if ( areaNodes ) { if ( areaNodes ) {
R_StaticFree( areaNodes ); R_StaticFree( areaNodes );
@@ -331,6 +338,74 @@ void idRenderWorldLocal::TouchWorldModels( void ) {
idRenderWorldLocal::ParseModel idRenderWorldLocal::ParseModel
================ ================
*/ */
typedef struct procRaytraceSurfaceMetadata_s {
bool valid;
uint32_t flags;
int areaNum;
float averageColor[4];
float emissiveColor[4];
idBounds bounds;
} procRaytraceSurfaceMetadata_t;
static void ClearProcRaytraceSurfaceMetadata( procRaytraceSurfaceMetadata_t &meta ) {
meta.valid = false;
meta.flags = 0;
meta.areaNum = -1;
meta.averageColor[0] = meta.averageColor[1] = meta.averageColor[2] = meta.averageColor[3] = 1.0f;
meta.emissiveColor[0] = meta.emissiveColor[1] = meta.emissiveColor[2] = meta.emissiveColor[3] = 0.0f;
meta.bounds.Clear();
}
static int ProcAreaNumFromModelName( const idStr &modelName ) {
if ( modelName.Icmpn( "_area", 5 ) != 0 ) {
return -1;
}
const char *areaText = modelName.c_str() + 5;
if ( *areaText < '0' || *areaText > '9' ) {
return -1;
}
return atoi( areaText );
}
static void ParseProcRaytraceSurfaceMetadata( idLexer *src, procRaytraceSurfaceMetadata_t &meta ) {
idToken token;
src->ExpectTokenString( "{" );
meta.valid = true;
while ( src->ReadToken( &token ) ) {
if ( token == "}" ) {
return;
}
if ( token == "flags" ) {
meta.flags = src->ParseInt();
continue;
}
if ( token == "area" ) {
meta.areaNum = src->ParseInt();
continue;
}
if ( token == "averageColor" ) {
src->Parse1DMatrix( 4, meta.averageColor );
continue;
}
if ( token == "emissive" ) {
src->Parse1DMatrix( 4, meta.emissiveColor );
continue;
}
if ( token == "bounds" ) {
float b[6];
src->Parse1DMatrix( 6, b );
meta.bounds[0].Set( b[0], b[1], b[2] );
meta.bounds[1].Set( b[3], b[4], b[5] );
continue;
}
src->Error( "R_ParseModel: bad raytraceSurface token \"%s\"", token.c_str() );
}
src->Error( "R_ParseModel: EOF in raytraceSurface" );
}
idRenderModel *idRenderWorldLocal::ParseModel( idLexer *src ) { idRenderModel *idRenderWorldLocal::ParseModel( idLexer *src ) {
idRenderModel *model; idRenderModel *model;
idToken token; idToken token;
@@ -342,9 +417,11 @@ idRenderModel *idRenderWorldLocal::ParseModel( idLexer *src ) {
// parse the name // parse the name
src->ExpectAnyToken( &token ); src->ExpectAnyToken( &token );
idStr modelName = token;
model = renderModelManager->AllocModel(); model = renderModelManager->AllocModel();
model->InitEmpty( token ); model->InitEmpty( token );
const int modelAreaNum = ProcAreaNumFromModelName( modelName );
int numSurfaces = src->ParseInt(); int numSurfaces = src->ParseInt();
if ( numSurfaces < 0 ) { if ( numSurfaces < 0 ) {
@@ -359,6 +436,10 @@ idRenderModel *idRenderWorldLocal::ParseModel( idLexer *src ) {
#endif #endif
for ( i = 0 ; i < numSurfaces ; i++ ) { for ( i = 0 ; i < numSurfaces ; i++ ) {
procRaytraceSurfaceMetadata_t raytraceMeta;
ClearProcRaytraceSurfaceMetadata( raytraceMeta );
raytraceMeta.areaNum = modelAreaNum;
src->ExpectTokenString( "{" ); src->ExpectTokenString( "{" );
src->ExpectAnyToken( &token ); src->ExpectAnyToken( &token );
@@ -424,6 +505,15 @@ idRenderModel *idRenderWorldLocal::ParseModel( idLexer *src ) {
for ( j = 0 ; j < tri->numIndexes ; j++ ) { for ( j = 0 ; j < tri->numIndexes ; j++ ) {
tri->indexes[j] = src->ParseInt(); tri->indexes[j] = src->ParseInt();
} }
while ( !src->PeekTokenString( "}" ) ) {
src->ExpectAnyToken( &token );
if ( token == "raytraceSurface" ) {
ParseProcRaytraceSurfaceMetadata( src, raytraceMeta );
continue;
}
src->Error( "R_ParseModel: bad surface token \"%s\"", token.c_str() );
}
src->ExpectTokenString( "}" ); src->ExpectTokenString( "}" );
// add the completed surface to the model // add the completed surface to the model
@@ -435,6 +525,21 @@ idRenderModel *idRenderWorldLocal::ParseModel( idLexer *src ) {
dxrWorldModel_t dxrModel; dxrWorldModel_t dxrModel;
dxrModel.tri = tri; dxrModel.tri = tri;
modelStatic->UpdateDXR(dxrModel.dxrBottomAcel, model->NumSurfaces() - 1); modelStatic->UpdateDXR(dxrModel.dxrBottomAcel, model->NumSurfaces() - 1);
if ( raytraceMeta.valid ) {
glRaytracingSetMeshAverageColor(
dxrModel.dxrBottomAcel,
raytraceMeta.averageColor[0],
raytraceMeta.averageColor[1],
raytraceMeta.averageColor[2],
raytraceMeta.averageColor[3] );
glRaytracingSetMeshProcMetadata(
dxrModel.dxrBottomAcel,
raytraceMeta.flags,
raytraceMeta.emissiveColor[0],
raytraceMeta.emissiveColor[1],
raytraceMeta.emissiveColor[2],
raytraceMeta.emissiveColor[3] );
}
glUpdateTopLevelAceelStructure(dxrWorldId, dxrModel.dxrBottomAcel, NULL, dxrModel.topAccelStruct); glUpdateTopLevelAceelStructure(dxrWorldId, dxrModel.dxrBottomAcel, NULL, dxrModel.topAccelStruct);
worldDXRmodels.Append(dxrModel); worldDXRmodels.Append(dxrModel);
} }
@@ -627,6 +732,78 @@ void idRenderWorldLocal::ParseNodes( idLexer *src ) {
src->ExpectTokenString( "}" ); src->ExpectTokenString( "}" );
} }
/*
================
idRenderWorldLocal::ParsePathTraceAreas
================
*/
void idRenderWorldLocal::ParsePathTraceAreas( idLexer *src ) {
int i, j;
src->ExpectTokenString( "{" );
const int numAreas = src->ParseInt();
if ( numAreas < 0 ) {
src->Error( "R_ParsePathTraceAreas: bad numAreas" );
return;
}
pathTraceAreas.Clear();
pathTraceAreas.SetNum( numAreas );
for ( i = 0 ; i < numAreas ; i++ ) {
pathTraceAreas[i].bounds.Clear();
pathTraceAreas[i].neighbors.Clear();
pathTraceAreas[i].staticLightNames.Clear();
pathTraceAreas[i].surfaceGroups = 0;
pathTraceAreas[i].valid = false;
}
for ( i = 0 ; i < numAreas ; i++ ) {
const int areaNum = src->ParseInt();
const int surfaceGroups = src->ParseInt();
float boundsVec[6];
src->Parse1DMatrix( 6, boundsVec );
const int neighborCount = src->ParseInt();
if ( areaNum < 0 || areaNum >= numAreas ) {
for ( j = 0 ; j < neighborCount ; j++ ) {
src->ParseInt();
}
const int lightCount = src->ParseInt();
for ( j = 0 ; j < lightCount ; j++ ) {
idToken lightName;
src->ExpectAnyToken( &lightName );
}
continue;
}
pathTraceArea_t &area = pathTraceAreas[areaNum];
area.bounds[0].Set( boundsVec[0], boundsVec[1], boundsVec[2] );
area.bounds[1].Set( boundsVec[3], boundsVec[4], boundsVec[5] );
area.surfaceGroups = surfaceGroups;
area.valid = true;
for ( j = 0 ; j < neighborCount ; j++ ) {
const int neighbor = src->ParseInt();
if ( neighbor >= 0 && neighbor < numAreas && area.neighbors.FindIndex( neighbor ) < 0 ) {
area.neighbors.Append( neighbor );
}
}
const int lightCount = src->ParseInt();
for ( j = 0 ; j < lightCount ; j++ ) {
idToken lightName;
src->ExpectAnyToken( &lightName );
if ( area.staticLightNames.Find( lightName ) == NULL ) {
area.staticLightNames.Append( lightName );
}
}
}
src->ExpectTokenString( "}" );
}
/* /*
================ ================
idRenderWorldLocal::CommonChildrenArea_r idRenderWorldLocal::CommonChildrenArea_r
@@ -671,6 +848,7 @@ Sets up for a single area world
================= =================
*/ */
void idRenderWorldLocal::ClearWorld() { void idRenderWorldLocal::ClearWorld() {
portalHandleGroups.Clear();
numPortalAreas = 1; numPortalAreas = 1;
portalAreas = (portalArea_t *)R_ClearedStaticAlloc( sizeof( portalAreas[0] ) ); portalAreas = (portalArea_t *)R_ClearedStaticAlloc( sizeof( portalAreas[0] ) );
areaScreenRect = (idScreenRect *) R_ClearedStaticAlloc( sizeof( idScreenRect ) ); areaScreenRect = (idScreenRect *) R_ClearedStaticAlloc( sizeof( idScreenRect ) );
@@ -736,6 +914,7 @@ bool idRenderWorldLocal::InitFromMap( const char *name ) {
// if this is an empty world, initialize manually // if this is an empty world, initialize manually
if ( !name || !name[0] ) { if ( !name || !name[0] ) {
FreeWorld(); FreeWorld();
glRaytracingLightingClearLights(true);
mapName.Clear(); mapName.Clear();
ClearWorld(); ClearWorld();
return true; return true;
@@ -753,6 +932,7 @@ bool idRenderWorldLocal::InitFromMap( const char *name ) {
if ( name == mapName ) { if ( name == mapName ) {
if ( currentTimeStamp != FILE_NOT_FOUND_TIMESTAMP && currentTimeStamp == mapTimeStamp ) { if ( currentTimeStamp != FILE_NOT_FOUND_TIMESTAMP && currentTimeStamp == mapTimeStamp ) {
common->Printf( "idRenderWorldLocal::InitFromMap: retaining existing map\n" ); common->Printf( "idRenderWorldLocal::InitFromMap: retaining existing map\n" );
glRaytracingLightingClearLights(true);
FreeDefs(); FreeDefs();
TouchWorldModels(); TouchWorldModels();
LoadWorldDecals(); LoadWorldDecals();
@@ -837,6 +1017,11 @@ bool idRenderWorldLocal::InitFromMap( const char *name ) {
continue; continue;
} }
if ( token == "pathTraceAreas" ) {
ParsePathTraceAreas( src );
continue;
}
src->Error( "idRenderWorldLocal::InitFromMap: bad token \"%s\"", token.c_str() ); src->Error( "idRenderWorldLocal::InitFromMap: bad token \"%s\"", token.c_str() );
} }
+17
View File
@@ -166,6 +166,21 @@ public:
doublePortal_t * doublePortals; doublePortal_t * doublePortals;
int numInterAreaPortals; int numInterAreaPortals;
struct portalHandleGroup_t {
idBounds bounds;
idList<int> portals;
};
mutable idList<portalHandleGroup_t> portalHandleGroups;
struct pathTraceArea_t {
idBounds bounds;
idList<int> neighbors;
idList<idStr> staticLightNames;
int surfaceGroups;
bool valid;
};
idList<pathTraceArea_t> pathTraceAreas;
idList<idRenderModel *> localModels; idList<idRenderModel *> localModels;
idList<renderWorldDecal_t> worldDecals; idList<renderWorldDecal_t> worldDecals;
@@ -183,6 +198,7 @@ public:
void SetupAreaRefs(); void SetupAreaRefs();
void ParseInterAreaPortals( idLexer *src ); void ParseInterAreaPortals( idLexer *src );
void ParseNodes( idLexer *src ); void ParseNodes( idLexer *src );
void ParsePathTraceAreas( idLexer *src );
int CommonChildrenArea_r( areaNode_t *node ); int CommonChildrenArea_r( areaNode_t *node );
void FreeWorld(); void FreeWorld();
void ClearWorld(); void ClearWorld();
@@ -211,6 +227,7 @@ public:
void AddAreaRefs( int areaNum, const struct portalStack_s *ps ); void AddAreaRefs( int areaNum, const struct portalStack_s *ps );
void BuildConnectedAreas_r( int areaNum ); void BuildConnectedAreas_r( int areaNum );
void BuildConnectedAreas( void ); void BuildConnectedAreas( void );
void RebuildConnectedAreasForAttribute( int portalAttributeIndex );
void FindViewLightsAndEntities( void ); void FindViewLightsAndEntities( void );
int NumPortals( void ) const; int NumPortals( void ) const;
+156 -11
View File
@@ -665,6 +665,44 @@ bool idRenderWorldLocal::PortalIsFoggedOut(const portal_t* p) {
return true; return true;
} }
static bool R_ScreenRectContains( const idScreenRect& outer, const idScreenRect& inner ) {
if ( inner.IsEmpty() ) {
return true;
}
if ( outer.IsEmpty() ) {
return false;
}
return outer.x1 <= inner.x1 && outer.y1 <= inner.y1 && outer.x2 >= inner.x2 && outer.y2 >= inner.y2;
}
static int R_ScreenRectPixelArea( const idScreenRect& rect ) {
if ( rect.IsEmpty() ) {
return 0;
}
return ( rect.x2 - rect.x1 + 1 ) * ( rect.y2 - rect.y1 + 1 );
}
static int R_ScreenRectExpansionArea( const idScreenRect& outer, const idScreenRect& inner ) {
if ( inner.IsEmpty() ) {
return 0;
}
if ( outer.IsEmpty() ) {
return R_ScreenRectPixelArea( inner );
}
idScreenRect expanded = outer;
expanded.Union( inner );
return R_ScreenRectPixelArea( expanded ) - R_ScreenRectPixelArea( outer );
}
static bool R_ScreenRectLightExpansionIsTiny( const idScreenRect& outer, const idScreenRect& inner ) {
const int expansionArea = R_ScreenRectExpansionArea( outer, inner );
const int coveredArea = R_ScreenRectPixelArea( outer );
return expansionArea <= Max( 1024, coveredArea / 24 );
}
static const int MAX_CONTAINED_AREA_REFLOODS = 2;
static byte* s_containedAreaRefloods = NULL;
/* /*
=================== ===================
FloodViewThroughArea_r FloodViewThroughArea_r
@@ -684,8 +722,28 @@ void idRenderWorldLocal::FloodViewThroughArea_r(const idVec3 origin, int areaNum
area = &portalAreas[areaNum]; area = &portalAreas[areaNum];
// cull models and lights to the current collection of planes const bool areaAlreadySeen = area->viewCount == tr.viewCount;
AddAreaRefs(areaNum, ps); const bool rectAlreadyCovered = areaAlreadySeen && R_ScreenRectContains( areaScreenRect[areaNum], ps->rect );
const bool tinyLightExpansion = areaAlreadySeen && !rectAlreadyCovered && R_ScreenRectLightExpansionIsTiny( areaScreenRect[areaNum], ps->rect );
// Synthetic newmap portals can create many equivalent paths into the same
// area. A contained rect still has a different plane stack, so let it add
// entities for correctness, but avoid repeatedly adding lights for duplicate
// covered screen space.
if ( rectAlreadyCovered ) {
AddAreaEntityRefs(areaNum, ps);
if ( !s_containedAreaRefloods || s_containedAreaRefloods[areaNum] >= MAX_CONTAINED_AREA_REFLOODS ) {
return;
}
s_containedAreaRefloods[areaNum]++;
} else if ( tinyLightExpansion ) {
AddAreaEntityRefs(areaNum, ps);
areaScreenRect[areaNum].Union(ps->rect);
return;
} else {
// cull models and lights to the current collection of planes
AddAreaRefs(areaNum, ps);
}
if (areaScreenRect[areaNum].IsEmpty()) { if (areaScreenRect[areaNum].IsEmpty()) {
areaScreenRect[areaNum] = ps->rect; areaScreenRect[areaNum] = ps->rect;
@@ -753,6 +811,7 @@ void idRenderWorldLocal::FloodViewThroughArea_r(const idVec3 origin, int areaNum
// find the screen pixel bounding box of the remaining portal // find the screen pixel bounding box of the remaining portal
// so we can scissor things outside it // so we can scissor things outside it
newStack.rect = ScreenRectFromWinding(&w, &tr.identitySpace); newStack.rect = ScreenRectFromWinding(&w, &tr.identitySpace);
newStack.rect.Expand();
// slop might have spread it a pixel outside, so trim it back // slop might have spread it a pixel outside, so trim it back
newStack.rect.Intersect(ps->rect); newStack.rect.Intersect(ps->rect);
@@ -819,6 +878,7 @@ void idRenderWorldLocal::FlowViewThroughPortals(const idVec3 origin, int numPlan
ps.rect = tr.viewDef->scissor; ps.rect = tr.viewDef->scissor;
if (tr.viewDef->areaNum < 0) { if (tr.viewDef->areaNum < 0) {
s_containedAreaRefloods = NULL;
for (i = 0; i < numPortalAreas; i++) { for (i = 0; i < numPortalAreas; i++) {
areaScreenRect[i] = tr.viewDef->scissor; areaScreenRect[i] = tr.viewDef->scissor;
@@ -831,6 +891,9 @@ void idRenderWorldLocal::FlowViewThroughPortals(const idVec3 origin, int numPlan
} }
else { else {
s_containedAreaRefloods = (byte*)R_FrameAlloc(numPortalAreas * sizeof(s_containedAreaRefloods[0]));
memset(s_containedAreaRefloods, 0, numPortalAreas * sizeof(s_containedAreaRefloods[0]));
for (i = 0; i < numPortalAreas; i++) { for (i = 0; i < numPortalAreas; i++) {
areaScreenRect[i].Clear(); areaScreenRect[i].Clear();
} }
@@ -1384,13 +1447,15 @@ void idRenderWorldLocal::FindViewLightsAndEntities(void) {
// light-behind-door culling // light-behind-door culling
BuildConnectedAreas(); BuildConnectedAreas();
// Reset DXR static world visibility for this view, then re-show static // The DXR static-world portal flood is useful, but it dirties many TLAS
// world geometry with a DXR-specific portal flood. This flood starts with // instances when crossing areas. Keep it opt-in until the update path is
// zero camera-FOV planes, so rays can hit geometry outside the camera FOV, // proven stable on all maps.
// but it still clips through actual portal windings so it does not make the if ( r_pathTracePortalWorldCulling.GetBool() ) {
// whole connected map visible. DXR_BeginWorldTopAccelStructVisibilityPass(this);
DXR_BeginWorldTopAccelStructVisibilityPass(this); DXR_FlowWorldTopAccelStructVisibilityThroughPortals(this);
//DXR_FlowWorldTopAccelStructVisibilityThroughPortals(this); } else {
DXR_ShowAllWorldTopAccelStructs(this);
}
// bump the view count, invalidating all // bump the view count, invalidating all
// visible areas // visible areas
@@ -1449,7 +1514,11 @@ qhandle_t idRenderWorldLocal::FindPortal(const idBounds& b) const {
idBounds wb; idBounds wb;
doublePortal_t* portal; doublePortal_t* portal;
idWinding* w; idWinding* w;
int firstPortal;
int numMatches;
firstPortal = 0;
numMatches = 0;
for (i = 0; i < numInterAreaPortals; i++) { for (i = 0; i < numInterAreaPortals; i++) {
portal = &doublePortals[i]; portal = &doublePortals[i];
w = portal->portals[0]->w; w = portal->portals[0]->w;
@@ -1459,11 +1528,40 @@ qhandle_t idRenderWorldLocal::FindPortal(const idBounds& b) const {
wb.AddPoint((*w)[j].ToVec3()); wb.AddPoint((*w)[j].ToVec3());
} }
if (wb.IntersectsBounds(b)) { if (wb.IntersectsBounds(b)) {
return i + 1; if ( firstPortal == 0 ) {
firstPortal = i + 1;
}
numMatches++;
} }
} }
return 0; if ( numMatches <= 1 ) {
return firstPortal;
}
for ( i = 0 ; i < portalHandleGroups.Num() ; i++ ) {
if ( portalHandleGroups[i].bounds.Compare( b, 0.1f ) ) {
return numInterAreaPortals + i + 1;
}
}
portalHandleGroup_t group;
group.bounds = b;
for ( i = 0 ; i < numInterAreaPortals ; i++ ) {
portal = &doublePortals[i];
w = portal->portals[0]->w;
wb.Clear();
for ( j = 0 ; j < w->GetNumPoints() ; j++ ) {
wb.AddPoint( ( *w )[j].ToVec3() );
}
if ( wb.IntersectsBounds( b ) ) {
group.portals.Append( i + 1 );
}
}
portalHandleGroups.Append( group );
common->Printf( "FindPortal grouped %i generated portals for bounds\n", group.portals.Num() );
return numInterAreaPortals + portalHandleGroups.Num();
} }
/* /*
@@ -1484,6 +1582,13 @@ void idRenderWorldLocal::FloodConnectedAreas(portalArea_t* area, int portalAttri
} }
} }
void idRenderWorldLocal::RebuildConnectedAreasForAttribute( int portalAttributeIndex ) {
for ( int i = 0 ; i < numPortalAreas ; i++ ) {
connectedAreaNum++;
FloodConnectedAreas( &portalAreas[i], portalAttributeIndex );
}
}
/* /*
============== ==============
AreasAreConnected AreasAreConnected
@@ -1526,6 +1631,38 @@ void idRenderWorldLocal::SetPortalState(qhandle_t portal, int blockTypes) {
return; return;
} }
if ( portal > numInterAreaPortals ) {
int groupIndex = portal - numInterAreaPortals - 1;
if ( groupIndex < 0 || groupIndex >= portalHandleGroups.Num() ) {
common->Error( "SetPortalState: bad grouped portal number %i", portal );
}
int changedBits = 0;
for ( int i = 0 ; i < portalHandleGroups[groupIndex].portals.Num() ; i++ ) {
int portalIndex = portalHandleGroups[groupIndex].portals[i] - 1;
int old = doublePortals[portalIndex].blockingBits;
if ( old == blockTypes ) {
continue;
}
changedBits |= old ^ blockTypes;
doublePortals[portalIndex].blockingBits = blockTypes;
}
for ( int i = 0 ; i < NUM_PORTAL_ATTRIBUTES ; i++ ) {
if ( changedBits & ( 1 << i ) ) {
RebuildConnectedAreasForAttribute( i );
}
}
if ( session->writeDemo ) {
session->writeDemo->WriteInt( DS_RENDER );
session->writeDemo->WriteInt( DC_SET_PORTAL_STATE );
session->writeDemo->WriteInt( portal );
session->writeDemo->WriteInt( blockTypes );
}
return;
}
if (portal < 1 || portal > numInterAreaPortals) { if (portal < 1 || portal > numInterAreaPortals) {
common->Error("SetPortalState: bad portal number %i", portal); common->Error("SetPortalState: bad portal number %i", portal);
} }
@@ -1562,6 +1699,14 @@ int idRenderWorldLocal::GetPortalState(qhandle_t portal) {
return 0; return 0;
} }
if ( portal > numInterAreaPortals ) {
int groupIndex = portal - numInterAreaPortals - 1;
if ( groupIndex < 0 || groupIndex >= portalHandleGroups.Num() || portalHandleGroups[groupIndex].portals.Num() == 0 ) {
common->Error( "GetPortalState: bad grouped portal number %i", portal );
}
return doublePortals[portalHandleGroups[groupIndex].portals[0] - 1].blockingBits;
}
if (portal < 1 || portal > numInterAreaPortals) { if (portal < 1 || portal > numInterAreaPortals) {
common->Error("GetPortalState: bad portal number %i", portal); common->Error("GetPortalState: bad portal number %i", portal);
} }
+126
View File
@@ -60,6 +60,52 @@ static idVec3 RB_DXRTransformLightVector(const idMat3& axis, const idVec3& v)
axis[0].z * v.x + axis[1].z * v.y + axis[2].z * v.z); axis[0].z * v.x + axis[1].z * v.y + axis[2].z * v.z);
} }
static void RB_DXRReportPathTraceProfile(void)
{
const int showProfile = r_showPathTraceProfile.GetInteger();
if (showProfile <= 0)
return;
static int lastPrintTime = 0;
if (showProfile == 1)
{
const int now = Sys_Milliseconds();
if (now - lastPrintTime < 1000)
return;
lastPrintTime = now;
}
glRaytracingProfileCounters_t profile;
if (!glRaytracingLightingGetProfileCounters(&profile))
return;
const uint32_t pixels = profile.width * profile.height;
common->Printf(
"pathTrace: %.2fms %ux%u px=%u lights=%u p/s/r=%u/%u/%u shadow=%u vol=%u spp=%u bounces=%u meshes=%u inst=%u rays/px direct=%u shadow=%u gi=%u giLight=%u gather=%u refl=%u volume=%u denoise=%u\n",
profile.gpuMsec,
profile.width,
profile.height,
pixels,
profile.lightCount,
profile.pointLightCount,
profile.spotLightCount,
profile.rectLightCount,
profile.shadowCastingLightCount,
profile.volumetricLightCount,
profile.samplesPerPixel,
profile.maxBounces,
profile.meshCount,
profile.instanceCount,
profile.directLightSamplesPerPixel,
profile.directShadowRaysPerPixel,
profile.indirectBounceRaysPerPixel,
profile.indirectLightEvalsPerPixel,
profile.finalGatherRaysPerPixel,
profile.reflectionRaysPerPixel,
profile.volumetricShadowRaysPerPixel,
profile.enableDenoiser);
}
static glRaytracingLight_t RB_DXRMakeSpotLightFromRenderLight( static glRaytracingLight_t RB_DXRMakeSpotLightFromRenderLight(
const renderLight_t& srcLight, const renderLight_t& srcLight,
const idVec3& worldOrigin, const idVec3& worldOrigin,
@@ -148,6 +194,76 @@ static glRaytracingLight_t RB_DXRMakeSpotLightFromRenderLight(
return light; return light;
} }
static void RB_DXRAddUniquePathTraceArea(idList<int>& areas, int areaNum)
{
if (areaNum < 0)
return;
if (areas.FindIndex(areaNum) >= 0)
return;
areas.Append(areaNum);
}
static bool RB_DXRBuildPathTraceLightAreaSet(idRenderWorldLocal* world, idList<int>& areas)
{
areas.Clear();
if (!r_pathTraceAreaLightCulling.GetBool())
return false;
if (!world || !backEnd.viewDef)
return false;
if (backEnd.viewDef->areaNum < 0)
return false;
if (world->pathTraceAreas.Num() != world->numPortalAreas)
return false;
const int depth = r_pathTraceAreaLightDepth.GetInteger();
RB_DXRAddUniquePathTraceArea(areas, backEnd.viewDef->areaNum);
int scanStart = 0;
for (int step = 0; step < depth; step++)
{
const int scanEnd = areas.Num();
for (int i = scanStart; i < scanEnd; i++)
{
const int areaNum = areas[i];
if (areaNum < 0 || areaNum >= world->pathTraceAreas.Num())
continue;
const idRenderWorldLocal::pathTraceArea_t& area = world->pathTraceAreas[areaNum];
if (!area.valid)
continue;
for (int neighborIndex = 0; neighborIndex < area.neighbors.Num(); neighborIndex++)
{
RB_DXRAddUniquePathTraceArea(areas, area.neighbors[neighborIndex]);
}
}
if (areas.Num() == scanEnd)
break;
scanStart = scanEnd;
}
return areas.Num() > 0;
}
static bool RB_DXRPathTraceLightTouchesAreaSet(const idRenderLightLocal* light, const idList<int>& areas)
{
if (!light)
return true;
if (light->areaNum >= 0 && areas.FindIndex(light->areaNum) >= 0)
return true;
for (const areaReference_t* ref = light->references; ref; ref = ref->ownerNext)
{
if (ref->area && areas.FindIndex(ref->area->areaNum) >= 0)
return true;
}
return false;
}
/* /*
==================== ====================
RB_DXDrawInteractions RB_DXDrawInteractions
@@ -161,6 +277,8 @@ void RB_DXDrawInteractions(void)
QD3D12_SetFrameGenerationMultiplier(r_frameGen.GetInteger()); QD3D12_SetFrameGenerationMultiplier(r_frameGen.GetInteger());
idList<glRaytracingLight_t> screenParticleLights; idList<glRaytracingLight_t> screenParticleLights;
idList<int> pathTraceLightAreas;
const bool usePathTraceLightAreas = RB_DXRBuildPathTraceLightAreaSet(backEnd.viewDef ? backEnd.viewDef->renderWorld : NULL, pathTraceLightAreas);
for (vLight = backEnd.viewDef->viewLights; vLight; vLight = vLight->next) for (vLight = backEnd.viewDef->viewLights; vLight; vLight = vLight->next)
{ {
@@ -179,6 +297,10 @@ void RB_DXDrawInteractions(void)
{ {
continue; continue;
} }
if (usePathTraceLightAreas && !RB_DXRPathTraceLightTouchesAreaSet(vLight->lightDef, pathTraceLightAreas))
{
continue;
}
const renderLight_t& srcLight = vLight->lightDef->parms; const renderLight_t& srcLight = vLight->lightDef->parms;
const float r = srcLight.shaderParms[SHADERPARM_RED]; const float r = srcLight.shaderParms[SHADERPARM_RED];
@@ -250,7 +372,11 @@ void RB_DXDrawInteractions(void)
{ {
backEnd.viewDef->renderWorld->SubmitWorldDecalsToScreenSpace(); backEnd.viewDef->renderWorld->SubmitWorldDecalsToScreenSpace();
glSetScreenSpaceParticleLightsQD3D12(screenParticleLights.Ptr(), screenParticleLights.Num()); glSetScreenSpaceParticleLightsQD3D12(screenParticleLights.Ptr(), screenParticleLights.Num());
glRaytracingLightingSetSecondaryLightBudget(
r_pathTraceSecondaryLightBudget.GetInteger(),
r_pathTraceSecondaryLightCompensation.GetFloat());
glLightScene(backEnd.viewDef->renderWorld->dxrWorldId); glLightScene(backEnd.viewDef->renderWorld->dxrWorldId);
RB_DXRReportPathTraceProfile();
glRaytracingLightingClearLights(false); glRaytracingLightingClearLights(false);
} }
} }
+6
View File
@@ -959,6 +959,12 @@ extern idCVar r_showLightScissors; // show light scissor rectangles
extern idCVar r_showEntityScissors; // show entity scissor rectangles extern idCVar r_showEntityScissors; // show entity scissor rectangles
extern idCVar r_showInteractionFrustums;// show a frustum for each interaction extern idCVar r_showInteractionFrustums;// show a frustum for each interaction
extern idCVar r_showInteractionScissors;// show screen rectangle which contains the interaction frustum extern idCVar r_showInteractionScissors;// show screen rectangle which contains the interaction frustum
extern idCVar r_showPathTraceProfile; // report path tracer GPU and estimated ray workload
extern idCVar r_pathTraceSecondaryLightBudget; // secondary GI light budget
extern idCVar r_pathTraceSecondaryLightCompensation; // secondary GI energy compensation
extern idCVar r_pathTracePortalWorldCulling; // portal cull static ray tracing world instances
extern idCVar r_pathTraceAreaLightCulling; // proc area light culling for path tracing
extern idCVar r_pathTraceAreaLightDepth; // proc area neighbor depth for path tracing lights
extern idCVar r_showMemory; // print frame memory utilization extern idCVar r_showMemory; // print frame memory utilization
extern idCVar r_showCull; // report sphere and box culling stats extern idCVar r_showCull; // report sphere and box culling stats
extern idCVar r_showInteractions; // report interaction generation activity extern idCVar r_showInteractions; // report interaction generation activity
+1
View File
@@ -709,6 +709,7 @@ public:
int listenerArea; int listenerArea;
idStr listenerAreaName; idStr listenerAreaName;
int listenerEnvironmentID; int listenerEnvironmentID;
idList<float> resolvePortalBestDist;
int gameMsec; int gameMsec;
int game44kHz; int game44kHz;
+23
View File
@@ -726,6 +726,26 @@ set at maxDistance
static const int MAX_PORTAL_TRACE_DEPTH = 10; static const int MAX_PORTAL_TRACE_DEPTH = 10;
void idSoundWorldLocal::ResolveOrigin( const int stackDepth, const soundPortalTrace_t *prevStack, const int soundArea, const float dist, const idVec3& soundOrigin, idSoundEmitterLocal *def ) { void idSoundWorldLocal::ResolveOrigin( const int stackDepth, const soundPortalTrace_t *prevStack, const int soundArea, const float dist, const idVec3& soundOrigin, idSoundEmitterLocal *def ) {
if ( !rw ) {
return;
}
if ( stackDepth == 0 ) {
int numAreas = rw->NumAreas();
resolvePortalBestDist.SetNum( numAreas );
for ( int i = 0 ; i < numAreas ; i++ ) {
resolvePortalBestDist[i] = idMath::INFINITY;
}
}
if ( soundArea < 0 || soundArea >= resolvePortalBestDist.Num() ) {
return;
}
if ( dist >= resolvePortalBestDist[soundArea] ) {
return;
}
resolvePortalBestDist[soundArea] = dist;
if ( dist >= def->distance ) { if ( dist >= def->distance ) {
// we can't possibly hear the sound through this chain of portals // we can't possibly hear the sound through this chain of portals
@@ -753,6 +773,9 @@ void idSoundWorldLocal::ResolveOrigin( const int stackDepth, const soundPortalTr
int numPortals = rw->NumPortalsInArea( soundArea ); int numPortals = rw->NumPortalsInArea( soundArea );
for( int p = 0; p < numPortals; p++ ) { for( int p = 0; p < numPortals; p++ ) {
exitPortal_t re = rw->GetPortal( soundArea, p ); exitPortal_t re = rw->GetPortal( soundArea, p );
if ( !re.w || re.w->GetNumPoints() < 3 || re.w->IsTiny() ) {
continue;
}
float occlusionDistance = 0; float occlusionDistance = 0;
+11
View File
@@ -151,6 +151,7 @@ void DmapHelp( void ) {
"Usage: dmap [options] mapfile\n" "Usage: dmap [options] mapfile\n"
"Options:\n" "Options:\n"
"noCurves = don't process curves\n" "noCurves = don't process curves\n"
"noAutoAreaRefine = don't add generated optimization portals inside areas\n"
"noCM = don't create collision map\n" "noCM = don't create collision map\n"
"noAAS = don't create AAS files\n" "noAAS = don't create AAS files\n"
@@ -163,6 +164,7 @@ ResetDmapGlobals
============ ============
*/ */
void ResetDmapGlobals( void ) { void ResetDmapGlobals( void ) {
ClearInterAreaPortals();
dmapGlobals.mapFileBase[0] = '\0'; dmapGlobals.mapFileBase[0] = '\0';
dmapGlobals.dmapFile = NULL; dmapGlobals.dmapFile = NULL;
dmapGlobals.mapPlanes.Clear(); dmapGlobals.mapPlanes.Clear();
@@ -180,6 +182,7 @@ void ResetDmapGlobals( void ) {
dmapGlobals.noTJunc = false; dmapGlobals.noTJunc = false;
dmapGlobals.nomerge = false; dmapGlobals.nomerge = false;
dmapGlobals.noFlood = false; dmapGlobals.noFlood = false;
dmapGlobals.autoAreaRefine = true;
dmapGlobals.noClipSides = false; dmapGlobals.noClipSides = false;
dmapGlobals.noLightCarve = false; dmapGlobals.noLightCarve = false;
dmapGlobals.noShadow = false; dmapGlobals.noShadow = false;
@@ -243,6 +246,12 @@ void Dmap( const idCmdArgs &args ) {
} else if ( !idStr::Icmp( s, "noFlood" ) ) { } else if ( !idStr::Icmp( s, "noFlood" ) ) {
common->Printf( "noFlood = true\n" ); common->Printf( "noFlood = true\n" );
dmapGlobals.noFlood = true; dmapGlobals.noFlood = true;
} else if ( !idStr::Icmp( s, "autoAreaRefine" ) ) {
common->Printf( "autoAreaRefine = true\n" );
dmapGlobals.autoAreaRefine = true;
} else if ( !idStr::Icmp( s, "noAutoAreaRefine" ) ) {
common->Printf( "autoAreaRefine = false\n" );
dmapGlobals.autoAreaRefine = false;
} else if ( !idStr::Icmp( s, "noLightCarve" ) ) { } else if ( !idStr::Icmp( s, "noLightCarve" ) ) {
common->Printf( "noLightCarve = true\n" ); common->Printf( "noLightCarve = true\n" );
dmapGlobals.noLightCarve = true; dmapGlobals.noLightCarve = true;
@@ -375,6 +384,8 @@ void Dmap( const idCmdArgs &args ) {
} }
} }
ClearInterAreaPortals();
// free the common .map representation // free the common .map representation
delete dmapGlobals.dmapFile; delete dmapGlobals.dmapFile;
+6
View File
@@ -153,6 +153,8 @@ typedef struct node_s {
// needed for FindSideForPortal // needed for FindSideForPortal
int area; // determined by flood filling up to areaportals int area; // determined by flood filling up to areaportals
int originalArea; // area before automatic refinement
int areaRefineFlood; // temporary flood marker for automatic refinement
int occupied; // 1 or greater can reach entity int occupied; // 1 or greater can reach entity
uEntity_t * occupant; // for leak file testing uEntity_t * occupant; // for leak file testing
@@ -256,6 +258,7 @@ typedef struct {
bool noTJunc; bool noTJunc;
bool nomerge; bool nomerge;
bool noFlood; bool noFlood;
bool autoAreaRefine; // split designer-authored areas with generated BSP portals
bool noClipSides; // don't cut sides by solid leafs, use the entire thing bool noClipSides; // don't cut sides by solid leafs, use the entire thing
bool noLightCarve; // extra triangle subdivision by light frustums bool noLightCarve; // extra triangle subdivision by light frustums
shadowOptLevel_t shadowOptLevel; shadowOptLevel_t shadowOptLevel;
@@ -339,6 +342,8 @@ void GLS_EndScene( void );
typedef struct { typedef struct {
int area0, area1; int area0, area1;
side_t *side; side_t *side;
idWinding *winding; // generated portals don't have a map brush side
bool generated;
} interAreaPortal_t; } interAreaPortal_t;
extern interAreaPortal_t interAreaPortals[MAX_INTER_AREA_PORTALS]; extern interAreaPortal_t interAreaPortals[MAX_INTER_AREA_PORTALS];
@@ -348,6 +353,7 @@ bool FloodEntities( tree_t *tree );
void FillOutside( uEntity_t *e ); void FillOutside( uEntity_t *e );
void FloodAreas( uEntity_t *e ); void FloodAreas( uEntity_t *e );
void MakeTreePortals( tree_t *tree ); void MakeTreePortals( tree_t *tree );
void ClearInterAreaPortals( void );
void FreePortal( uPortal_t *p ); void FreePortal( uPortal_t *p );
//============================================================================= //=============================================================================
+227 -2
View File
@@ -310,6 +310,134 @@ static void WriteUTriangles( const srfTriangles_t *uTris ) {
} }
} }
static bool GetImageAverageColorForProc( idImage *image, float averageColor[4] ) {
if ( !image ) {
return false;
}
byte *pic = NULL;
int width = 0;
int height = 0;
textureDepth_t depth = TD_DEFAULT;
// Do not call idImage::ActuallyLoadImage() from dmap. dmap can run inside
// the live game process, and ActuallyLoadImage() mutates GL/D3D texture
// objects. Read the source pixels directly so metadata generation is pure.
R_LoadImageProgram( image->imgName, &pic, &width, &height, NULL, &depth );
if ( !pic || width <= 0 || height <= 0 ) {
if ( pic ) {
R_StaticFree( pic );
}
return false;
}
uint64_t sum[4] = { 0, 0, 0, 0 };
const int pixelCount = width * height;
for ( int i = 0 ; i < pixelCount ; i++ ) {
const byte *rgba = pic + i * 4;
sum[0] += rgba[0];
sum[1] += rgba[1];
sum[2] += rgba[2];
sum[3] += rgba[3];
}
R_StaticFree( pic );
const float scale = 1.0f / ( 255.0f * (float)pixelCount );
averageColor[0] = idMath::ClampFloat( 0.0f, 1.0f, sum[0] * scale );
averageColor[1] = idMath::ClampFloat( 0.0f, 1.0f, sum[1] * scale );
averageColor[2] = idMath::ClampFloat( 0.0f, 1.0f, sum[2] * scale );
averageColor[3] = idMath::ClampFloat( 0.0f, 1.0f, sum[3] * scale );
return true;
}
static bool GetVertexAverageColorForProc( const srfTriangles_t *uTris, float averageColor[4] ) {
float sum[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
if ( !uTris || uTris->numVerts <= 0 ) {
return false;
}
for ( int i = 0 ; i < uTris->numVerts ; i++ ) {
sum[0] += uTris->verts[i].color[0] * ( 1.0f / 255.0f );
sum[1] += uTris->verts[i].color[1] * ( 1.0f / 255.0f );
sum[2] += uTris->verts[i].color[2] * ( 1.0f / 255.0f );
sum[3] += uTris->verts[i].color[3] * ( 1.0f / 255.0f );
}
const float invNumVerts = 1.0f / uTris->numVerts;
averageColor[0] = sum[0] * invNumVerts;
averageColor[1] = sum[1] * invNumVerts;
averageColor[2] = sum[2] * invNumVerts;
averageColor[3] = sum[3] * invNumVerts;
return averageColor[0] > 0.0f || averageColor[1] > 0.0f || averageColor[2] > 0.0f || averageColor[3] > 0.0f;
}
static void WriteRaytraceSurfaceMetadata( const idMaterial *material, const srfTriangles_t *uTris, int areaNum ) {
float averageColor[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
float emissiveColor[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
float bounds[6];
uint32_t flags = 0;
if ( material ) {
idImage *diffuseImage = material->GetDiffuseImage( NULL );
if ( !GetImageAverageColorForProc( diffuseImage, averageColor ) ) {
GetVertexAverageColorForProc( uTris, averageColor );
}
idImage *glowImage = material->GetGlowImage( NULL );
if ( !glowImage ) {
for ( int stageNum = 0 ; stageNum < material->GetNumStages() ; stageNum++ ) {
const shaderStage_t *stage = material->GetStage( stageNum );
if ( stage && stage->lighting == SL_GLOWMAP && stage->texture.image ) {
glowImage = stage->texture.image;
break;
}
}
}
if ( glowImage ) {
GetImageAverageColorForProc( glowImage, emissiveColor );
emissiveColor[3] = Max( Max( emissiveColor[0], emissiveColor[1] ), emissiveColor[2] ) > 0.01f ? 1.0f : 0.0f;
if ( emissiveColor[3] > 0.0f ) {
flags |= GL_RAYTRACING_PROC_SURFACE_EMISSIVE;
}
}
if ( !material->IsLitMaterial() ) {
flags |= GL_RAYTRACING_PROC_SURFACE_UNLIT;
}
if ( material->IsSky() ) {
flags |= GL_RAYTRACING_PROC_SURFACE_SKY;
}
if ( material->Coverage() == MC_PERFORATED ) {
flags |= GL_RAYTRACING_PROC_SURFACE_ALPHA_TESTED;
}
if ( material->GetCullType() == CT_TWO_SIDED ) {
flags |= GL_RAYTRACING_PROC_SURFACE_TWO_SIDED;
}
}
idBounds triBounds;
triBounds.Clear();
for ( int i = 0 ; i < uTris->numVerts ; i++ ) {
triBounds.AddPoint( uTris->verts[i].xyz );
}
bounds[0] = triBounds[0][0];
bounds[1] = triBounds[0][1];
bounds[2] = triBounds[0][2];
bounds[3] = triBounds[1][0];
bounds[4] = triBounds[1][1];
bounds[5] = triBounds[1][2];
procFile->WriteFloatString( "raytraceSurface { flags %u area %i averageColor ", flags, areaNum );
Write1DMatrix( procFile, 4, averageColor );
procFile->WriteFloatString( " emissive " );
Write1DMatrix( procFile, 4, emissiveColor );
procFile->WriteFloatString( " bounds " );
Write1DMatrix( procFile, 6, bounds );
procFile->WriteFloatString( " }\n" );
}
/* /*
==================== ====================
@@ -478,13 +606,15 @@ typedef struct interactionTris_s {
procFile->WriteFloatString( "/* surface %i */ { ", surfaceNum ); procFile->WriteFloatString( "/* surface %i */ { ", surfaceNum );
surfaceNum++; surfaceNum++;
procFile->WriteFloatString( "\"%s\" ", ambient->material->GetName() ); const idMaterial *surfaceMaterial = ambient->material;
procFile->WriteFloatString( "\"%s\" ", surfaceMaterial->GetName() );
uTri = ShareMapTriVerts( ambient ); uTri = ShareMapTriVerts( ambient );
FreeTriList( ambient ); FreeTriList( ambient );
CleanupUTriangles( uTri ); CleanupUTriangles( uTri );
WriteUTriangles( uTri ); WriteUTriangles( uTri );
WriteRaytraceSurfaceMetadata( surfaceMaterial, uTri, areaNum );
R_FreeStaticTriSurf( uTri ); R_FreeStaticTriSurf( uTri );
procFile->WriteFloatString( "}\n\n" ); procFile->WriteFloatString( "}\n\n" );
@@ -583,7 +713,16 @@ static void WriteOutputPortals( uEntity_t *e ) {
procFile->WriteFloatString( "/* interAreaPortal format is: numPoints positiveSideArea negativeSideArea ( point) ... */\n" ); procFile->WriteFloatString( "/* interAreaPortal format is: numPoints positiveSideArea negativeSideArea ( point) ... */\n" );
for ( i = 0 ; i < numInterAreaPortals ; i++ ) { for ( i = 0 ; i < numInterAreaPortals ; i++ ) {
iap = &interAreaPortals[i]; iap = &interAreaPortals[i];
w = iap->side->winding; if ( iap->winding ) {
w = iap->winding;
} else if ( iap->side && iap->side->visibleHull ) {
w = iap->side->visibleHull;
} else if ( iap->side ) {
w = iap->side->winding;
} else {
common->Error( "WriteOutputPortals: inter-area portal without a winding" );
continue;
}
procFile->WriteFloatString("/* iap %i */ %i %i %i ", i, w->GetNumPoints(), iap->area0, iap->area1 ); procFile->WriteFloatString("/* iap %i */ %i %i %i ", i, w->GetNumPoints(), iap->area0, iap->area1 );
for ( j = 0 ; j < w->GetNumPoints() ; j++ ) { for ( j = 0 ; j < w->GetNumPoints() ; j++ ) {
Write1DMatrix( procFile, 3, (*w)[j].ToFloatPtr() ); Write1DMatrix( procFile, 3, (*w)[j].ToFloatPtr() );
@@ -594,6 +733,88 @@ static void WriteOutputPortals( uEntity_t *e ) {
procFile->WriteFloatString( "}\n\n" ); procFile->WriteFloatString( "}\n\n" );
} }
/*
====================
WritePathTraceAreas
Writes deterministic per-area data for path-tracing light culling.
This is deliberately independent of authored light entities so dynamic lights
can use the same area table at runtime.
====================
*/
static void WritePathTraceAreas( uEntity_t *e ) {
procFile->WriteFloatString( "pathTraceAreas { /* numAreas = */ %i\n\n", e->numAreas );
procFile->WriteFloatString( "/* pathTraceArea format is: areaNum surfaceGroups ( bounds[6] ) neighborCount neighborArea ... lightCount \"lightName\" ... */\n" );
for ( int areaNum = 0 ; areaNum < e->numAreas ; areaNum++ ) {
uArea_t *area = &e->areas[areaNum];
idBounds bounds;
int surfaceGroups = 0;
idList<int> neighbors;
idList<mapLight_t *> lights;
bounds.Clear();
for ( optimizeGroup_t *group = area->groups ; group ; group = group->nextGroup ) {
if ( !group->triList ) {
continue;
}
surfaceGroups++;
bounds.AddPoint( group->bounds[0] );
bounds.AddPoint( group->bounds[1] );
for ( int lightNum = 0 ; lightNum < group->numGroupLights ; lightNum++ ) {
mapLight_t *light = group->groupLights[lightNum];
if ( light && lights.FindIndex( light ) < 0 ) {
lights.Append( light );
}
}
}
if ( bounds[0][0] > bounds[1][0] ) {
if ( e->tree ) {
bounds = e->tree->bounds;
} else {
bounds.Zero();
}
}
for ( int portalNum = 0 ; portalNum < numInterAreaPortals ; portalNum++ ) {
const interAreaPortal_t *iap = &interAreaPortals[portalNum];
int neighbor = -1;
if ( iap->area0 == areaNum ) {
neighbor = iap->area1;
} else if ( iap->area1 == areaNum ) {
neighbor = iap->area0;
}
if ( neighbor >= 0 && neighbors.FindIndex( neighbor ) < 0 ) {
neighbors.Append( neighbor );
}
}
float boundsVec[6] = {
bounds[0][0], bounds[0][1], bounds[0][2],
bounds[1][0], bounds[1][1], bounds[1][2]
};
procFile->WriteFloatString( "/* area %i */ %i %i ", areaNum, areaNum, surfaceGroups );
Write1DMatrix( procFile, 6, boundsVec );
procFile->WriteFloatString( "%i ", neighbors.Num() );
for ( int i = 0 ; i < neighbors.Num() ; i++ ) {
procFile->WriteFloatString( "%i ", neighbors[i] );
}
procFile->WriteFloatString( "%i ", lights.Num() );
for ( int i = 0 ; i < lights.Num() ; i++ ) {
procFile->WriteFloatString( "\"%s\" ", lights[i]->name );
}
procFile->WriteFloatString( "\n" );
}
procFile->WriteFloatString( "}\n\n" );
}
/* /*
==================== ====================
@@ -625,6 +846,10 @@ static void WriteOutputEntity( int entityNum ) {
// output the nodes // output the nodes
WriteOutputNodes( e->tree->headnode ); WriteOutputNodes( e->tree->headnode );
} }
if ( entityNum == 0 ) {
WritePathTraceAreas( e );
}
} }
+276 -1
View File
@@ -39,6 +39,33 @@ int numInterAreaPortals;
int c_active_portals; int c_active_portals;
int c_peak_portals; int c_peak_portals;
static int c_autoAreaRefineSplits;
static int c_autoAreaRefinePortals;
static int c_autoAreaRefineFlood;
#define AUTO_AREA_REFINE_MIN_LEAFS 12
#define AUTO_AREA_REFINE_MIN_SPLIT_LEAFS 4
#define AUTO_AREA_REFINE_MAX_SPLITS 256
#define AUTO_AREA_REFINE_MIN_PORTAL_AREA 64.0f
#define AUTO_AREA_REFINE_MAX_PORTAL_AREA 65536.0f
/*
=============
ClearInterAreaPortals
=============
*/
void ClearInterAreaPortals( void ) {
for ( int i = 0 ; i < numInterAreaPortals ; i++ ) {
if ( interAreaPortals[i].generated && interAreaPortals[i].winding ) {
delete interAreaPortals[i].winding;
}
interAreaPortals[i].side = NULL;
interAreaPortals[i].winding = NULL;
interAreaPortals[i].generated = false;
}
numInterAreaPortals = 0;
}
/* /*
=========== ===========
AllocPortal AllocPortal
@@ -824,10 +851,244 @@ void ClearAreas_r( node_t *node ) {
return; return;
} }
node->area = -1; node->area = -1;
node->originalArea = -1;
node->areaRefineFlood = 0;
} }
//============================================================= //=============================================================
static void MarkOriginalAreas_r( node_t *node ) {
if ( node->planenum != PLANENUM_LEAF ) {
MarkOriginalAreas_r( node->children[0] );
MarkOriginalAreas_r( node->children[1] );
return;
}
node->originalArea = node->area;
}
static void CollectAreaLeaves_r( node_t *node, int area, idList<node_t *> &leaves ) {
if ( node->planenum != PLANENUM_LEAF ) {
CollectAreaLeaves_r( node->children[0], area, leaves );
CollectAreaLeaves_r( node->children[1], area, leaves );
return;
}
if ( !node->opaque && node->area == area ) {
leaves.Append( node );
}
}
static void FloodAreaComponent_r( node_t *node, int area, const uPortal_t *blockedPortal, int floodNum, idList<node_t *> &component ) {
uPortal_t *p;
int s;
if ( node->planenum != PLANENUM_LEAF || node->opaque || node->area != area ) {
return;
}
if ( node->areaRefineFlood == floodNum ) {
return;
}
node->areaRefineFlood = floodNum;
component.Append( node );
for ( p = node->portals ; p ; p = p->next[s] ) {
s = ( p->nodes[1] == node );
if ( p == blockedPortal ) {
continue;
}
if ( !Portal_Passable( p ) ) {
continue;
}
FloodAreaComponent_r( p->nodes[!s], area, blockedPortal, floodNum, component );
}
}
static uPortal_t *FindBestAutoAreaPortal( int area, const idList<node_t *> &leaves ) {
uPortal_t *bestPortal;
float bestScore;
bestPortal = NULL;
bestScore = 0.0f;
for ( int i = 0 ; i < leaves.Num() ; i++ ) {
node_t *node = leaves[i];
int s;
for ( uPortal_t *p = node->portals ; p ; p = p->next[s] ) {
s = ( p->nodes[1] == node );
if ( p->nodes[0] != node ) {
continue; // evaluate each portal once
}
if ( !Portal_Passable( p ) ) {
continue;
}
if ( p->nodes[1]->area != area ) {
continue;
}
float portalArea = p->winding->GetArea();
if ( portalArea < AUTO_AREA_REFINE_MIN_PORTAL_AREA || portalArea > AUTO_AREA_REFINE_MAX_PORTAL_AREA ) {
continue;
}
idList<node_t *> component;
FloodAreaComponent_r( p->nodes[0], area, p, ++c_autoAreaRefineFlood, component );
int frontLeafs = component.Num();
int backLeafs = leaves.Num() - frontLeafs;
if ( frontLeafs < AUTO_AREA_REFINE_MIN_SPLIT_LEAFS || backLeafs < AUTO_AREA_REFINE_MIN_SPLIT_LEAFS ) {
continue;
}
int smaller = frontLeafs < backLeafs ? frontLeafs : backLeafs;
int larger = frontLeafs > backLeafs ? frontLeafs : backLeafs;
float balance = (float)smaller / (float)larger;
float score = balance * 100000.0f / portalArea;
if ( score > bestScore ) {
bestScore = score;
bestPortal = p;
}
}
}
return bestPortal;
}
static bool SplitAreaWithGeneratedPortal( uEntity_t *e, int area ) {
idList<node_t *> leaves;
idList<node_t *> component;
CollectAreaLeaves_r( e->tree->headnode, area, leaves );
if ( leaves.Num() < AUTO_AREA_REFINE_MIN_LEAFS ) {
return false;
}
uPortal_t *portal = FindBestAutoAreaPortal( area, leaves );
if ( !portal ) {
return false;
}
int floodNum = ++c_autoAreaRefineFlood;
FloodAreaComponent_r( portal->nodes[0], area, portal, floodNum, component );
if ( component.Num() <= 0 || component.Num() >= leaves.Num() ) {
return false;
}
int newArea = e->numAreas;
e->numAreas++;
// Keep the larger partition on the original area number so repeated
// refinement tends to continue from the broadest remaining space.
if ( component.Num() <= leaves.Num() / 2 ) {
for ( int i = 0 ; i < component.Num() ; i++ ) {
component[i]->area = newArea;
}
} else {
for ( int i = 0 ; i < leaves.Num() ; i++ ) {
if ( leaves[i]->areaRefineFlood != floodNum ) {
leaves[i]->area = newArea;
}
}
}
c_autoAreaRefineSplits++;
return true;
}
static void AutoRefineAreas( uEntity_t *e ) {
int startingAreas;
if ( !dmapGlobals.autoAreaRefine ) {
return;
}
if ( e != &dmapGlobals.uEntities[0] ) {
return;
}
startingAreas = e->numAreas;
c_autoAreaRefineSplits = 0;
c_autoAreaRefinePortals = 0;
c_autoAreaRefineFlood = 0;
for ( int area = 0 ; area < e->numAreas && c_autoAreaRefineSplits < AUTO_AREA_REFINE_MAX_SPLITS ; area++ ) {
while ( c_autoAreaRefineSplits < AUTO_AREA_REFINE_MAX_SPLITS ) {
if ( !SplitAreaWithGeneratedPortal( e, area ) ) {
break;
}
}
}
if ( c_autoAreaRefineSplits > 0 ) {
common->Printf( "%5i auto area refinement splits (%i -> %i areas)\n", c_autoAreaRefineSplits, startingAreas, e->numAreas );
} else {
common->Printf( "%5i auto area refinement splits\n", 0 );
}
}
static void AddGeneratedInterAreaPortal( uPortal_t *p ) {
if ( numInterAreaPortals >= MAX_INTER_AREA_PORTALS ) {
common->Warning( "MAX_INTER_AREA_PORTALS hit while adding generated area portals" );
return;
}
if ( !p->winding || p->winding->IsTiny() ) {
return;
}
interAreaPortal_t *iap = &interAreaPortals[numInterAreaPortals];
numInterAreaPortals++;
iap->area0 = p->nodes[0]->area;
iap->area1 = p->nodes[1]->area;
iap->side = NULL;
iap->winding = p->winding->Copy();
iap->generated = true;
c_autoAreaRefinePortals++;
}
static void FindGeneratedInterAreaPortals_r( node_t *node ) {
uPortal_t *p;
int s;
if ( node->planenum != PLANENUM_LEAF ) {
FindGeneratedInterAreaPortals_r( node->children[0] );
FindGeneratedInterAreaPortals_r( node->children[1] );
return;
}
if ( node->opaque ) {
return;
}
for ( p = node->portals ; p ; p = p->next[s] ) {
node_t *other;
s = ( p->nodes[1] == node );
other = p->nodes[!s];
if ( other->opaque ) {
continue;
}
if ( !Portal_Passable( p ) ) {
continue;
}
if ( other->area <= node->area ) {
continue;
}
if ( other->originalArea != node->originalArea ) {
continue; // authored areaportal boundary
}
if ( FindSideForPortal( p ) ) {
continue; // designer-authored portal, already emitted
}
AddGeneratedInterAreaPortal( p );
}
}
/* /*
================= =================
@@ -895,6 +1156,11 @@ static void FindInterAreaPortals_r( node_t *node ) {
continue; // already emited continue; // already emited
} }
if ( numInterAreaPortals >= MAX_INTER_AREA_PORTALS ) {
common->Warning( "MAX_INTER_AREA_PORTALS hit while adding designer area portals" );
continue;
}
iap = &interAreaPortals[numInterAreaPortals]; iap = &interAreaPortals[numInterAreaPortals];
numInterAreaPortals++; numInterAreaPortals++;
if ( side->planenum == p->onnode->planenum ) { if ( side->planenum == p->onnode->planenum ) {
@@ -905,6 +1171,8 @@ static void FindInterAreaPortals_r( node_t *node ) {
iap->area1 = p->nodes[0]->area; iap->area1 = p->nodes[0]->area;
} }
iap->side = side; iap->side = side;
iap->winding = NULL;
iap->generated = false;
} }
} }
@@ -934,13 +1202,20 @@ void FloodAreas( uEntity_t *e ) {
common->Printf ("%5i areas\n", c_areas); common->Printf ("%5i areas\n", c_areas);
e->numAreas = c_areas; e->numAreas = c_areas;
MarkOriginalAreas_r( e->tree->headnode );
AutoRefineAreas( e );
// make sure we got all of them // make sure we got all of them
CheckAreas_r( e->tree->headnode ); CheckAreas_r( e->tree->headnode );
// identify all portals between areas if this is the world // identify all portals between areas if this is the world
if ( e == &dmapGlobals.uEntities[0] ) { if ( e == &dmapGlobals.uEntities[0] ) {
numInterAreaPortals = 0; ClearInterAreaPortals();
FindInterAreaPortals_r( e->tree->headnode ); FindInterAreaPortals_r( e->tree->headnode );
if ( dmapGlobals.autoAreaRefine ) {
FindGeneratedInterAreaPortals_r( e->tree->headnode );
common->Printf( "%5i generated inter-area portals\n", c_autoAreaRefinePortals );
}
} }
} }
-6
View File
@@ -50,12 +50,6 @@ typedef struct {
int firstComponent; int firstComponent;
} jointAnimInfo_t; } jointAnimInfo_t;
typedef struct {
jointHandle_t num;
jointHandle_t parentNum;
int channel;
} jointInfo_t;
// //
// joint modifier modes. make sure to change script/doom_defs.script if you add any, or change their order. // joint modifier modes. make sure to change script/doom_defs.script if you add any, or change their order.
// //
+1 -1
View File
@@ -157,7 +157,7 @@ void idModelExport::LoadMayaDll( void ) {
#ifdef RV_UNIFIED_ALLOCATOR #ifdef RV_UNIFIED_ALLOCATOR
if ( !dllEntry( MD5_VERSION, common, sys, Memory::Allocate, Memory::Free, Memory::MSize ) ) { if ( !dllEntry( MD5_VERSION, common, sys, Memory::Allocate, Memory::Free, Memory::MSize ) ) {
#else #else
if ( !dllEntry( MD5_VERSION, common, sys ) ) { if ( !dllEntry( MD5_VERSION, common, sys, fileSystem ) ) {
#endif #endif
// RAVEN END // RAVEN END
// init failed // init failed