dmap now contains path tracing optimizations stored in iceproc files.
|
Before Width: | Height: | Size: 1.0 MiB After Width: | Height: | Size: 1.0 MiB |
|
Before Width: | Height: | Size: 1.0 MiB After Width: | Height: | Size: 1.0 MiB |
|
Before Width: | Height: | Size: 256 KiB After Width: | Height: | Size: 1.0 MiB |
|
Before Width: | Height: | Size: 1.0 MiB After Width: | Height: | Size: 1.0 MiB |
|
Before Width: | Height: | Size: 1.0 MiB After Width: | Height: | Size: 1.0 MiB |
|
Before Width: | Height: | Size: 1.0 MiB After Width: | Height: | Size: 1.0 MiB |
|
Before Width: | Height: | Size: 1.0 MiB After Width: | Height: | Size: 1.0 MiB |
|
Before Width: | Height: | Size: 1.0 MiB After Width: | Height: | Size: 1.0 MiB |
|
Before Width: | Height: | Size: 1.0 MiB After Width: | Height: | Size: 1.0 MiB |
|
Before Width: | Height: | Size: 256 KiB After Width: | Height: | Size: 1.0 MiB |
|
Before Width: | Height: | Size: 256 KiB After Width: | Height: | Size: 1.0 MiB |
|
Before Width: | Height: | Size: 256 KiB After Width: | Height: | Size: 1.0 MiB |
|
Before Width: | Height: | Size: 1.0 MiB After Width: | Height: | Size: 1.0 MiB |
|
Before Width: | Height: | Size: 1.0 MiB After Width: | Height: | Size: 1.0 MiB |
|
Before Width: | Height: | Size: 1.0 MiB After Width: | Height: | Size: 1.0 MiB |
|
Before Width: | Height: | Size: 1.0 MiB After Width: | Height: | Size: 1.0 MiB |
|
Before Width: | Height: | Size: 1.0 MiB After Width: | Height: | Size: 1.0 MiB |
|
Before Width: | Height: | Size: 1.0 MiB After Width: | Height: | Size: 1.0 MiB |
|
Before Width: | Height: | Size: 1.0 MiB After Width: | Height: | Size: 1.0 MiB |
|
Before Width: | Height: | Size: 1.0 MiB After Width: | Height: | Size: 1.0 MiB |
|
Before Width: | Height: | Size: 1.0 MiB After Width: | Height: | Size: 1.0 MiB |
|
Before Width: | Height: | Size: 1.0 MiB After Width: | Height: | Size: 1.0 MiB |
|
Before Width: | Height: | Size: 1.0 MiB After Width: | Height: | Size: 1.0 MiB |
|
Before Width: | Height: | Size: 1.0 MiB After Width: | Height: | Size: 1.0 MiB |
@@ -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 },
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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" );
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
@@ -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 );
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
|
|||||||
@@ -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 );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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 );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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.
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||