mirror of
https://github.com/jmarshall23/DoomRTX.git
synced 2026-08-12 16:21:04 +02:00
420 lines
11 KiB
C++
420 lines
11 KiB
C++
#include "precompiled.h"
|
|
#pragma hdrstop
|
|
|
|
#include "tr_local.h"
|
|
#include <math.h>
|
|
|
|
static idVec3 RB_DXRMakeVec3(float x, float y, float z)
|
|
{
|
|
idVec3 v;
|
|
v.x = x;
|
|
v.y = y;
|
|
v.z = z;
|
|
return v;
|
|
}
|
|
|
|
static idVec3 RB_DXRSubVec3(const idVec3& a, const idVec3& b)
|
|
{
|
|
return RB_DXRMakeVec3(a.x - b.x, a.y - b.y, a.z - b.z);
|
|
}
|
|
|
|
static idVec3 RB_DXRScaleVec3(const idVec3& v, float s)
|
|
{
|
|
return RB_DXRMakeVec3(v.x * s, v.y * s, v.z * s);
|
|
}
|
|
|
|
static float RB_DXRDotVec3(const idVec3& a, const idVec3& b)
|
|
{
|
|
return a.x * b.x + a.y * b.y + a.z * b.z;
|
|
}
|
|
|
|
static idVec3 RB_DXRCrossVec3(const idVec3& a, const idVec3& b)
|
|
{
|
|
return RB_DXRMakeVec3(
|
|
a.y * b.z - a.z * b.y,
|
|
a.z * b.x - a.x * b.z,
|
|
a.x * b.y - a.y * b.x);
|
|
}
|
|
|
|
static float RB_DXRLengthVec3(const idVec3& v)
|
|
{
|
|
return sqrtf(v.x * v.x + v.y * v.y + v.z * v.z);
|
|
}
|
|
|
|
static idVec3 RB_DXRNormalizeVec3Safe(const idVec3& v, const idVec3& fallback)
|
|
{
|
|
const float len = RB_DXRLengthVec3(v);
|
|
if (len > 1e-20f)
|
|
{
|
|
const float invLen = 1.0f / len;
|
|
return RB_DXRMakeVec3(v.x * invLen, v.y * invLen, v.z * invLen);
|
|
}
|
|
return fallback;
|
|
}
|
|
|
|
static idVec3 RB_DXRTransformLightVector(const idMat3& axis, const idVec3& v)
|
|
{
|
|
return RB_DXRMakeVec3(
|
|
axis[0].x * v.x + axis[1].x * v.y + axis[2].x * v.z,
|
|
axis[0].y * v.x + axis[1].y * v.y + axis[2].y * 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(
|
|
const renderLight_t& srcLight,
|
|
const idVec3& worldOrigin,
|
|
float r, float g, float b,
|
|
float intensity)
|
|
{
|
|
const idVec3 targetW = RB_DXRTransformLightVector(srcLight.axis, srcLight.target);
|
|
const idVec3 rightW = RB_DXRTransformLightVector(srcLight.axis, srcLight.right);
|
|
const idVec3 upW = RB_DXRTransformLightVector(srcLight.axis, srcLight.up);
|
|
const idVec3 startW = RB_DXRTransformLightVector(srcLight.axis, srcLight.start);
|
|
const idVec3 endW = RB_DXRTransformLightVector(srcLight.axis, srcLight.end);
|
|
|
|
idVec3 fallbackDir = RB_DXRCrossVec3(rightW, upW);
|
|
fallbackDir = RB_DXRNormalizeVec3Safe(fallbackDir, RB_DXRMakeVec3(0.0f, 0.0f, -1.0f));
|
|
|
|
const idVec3 dir = RB_DXRNormalizeVec3Safe(targetW, fallbackDir);
|
|
|
|
float centerDepth = RB_DXRDotVec3(targetW, dir);
|
|
if (centerDepth <= 1e-4f)
|
|
{
|
|
centerDepth = RB_DXRLengthVec3(targetW);
|
|
}
|
|
if (centerDepth <= 1e-4f)
|
|
{
|
|
centerDepth = RB_DXRDotVec3(endW, dir);
|
|
}
|
|
if (centerDepth <= 1e-4f)
|
|
{
|
|
centerDepth = 64.0f;
|
|
}
|
|
|
|
const idVec3 rightPerp = RB_DXRSubVec3(
|
|
rightW,
|
|
RB_DXRScaleVec3(dir, RB_DXRDotVec3(rightW, dir)));
|
|
|
|
const idVec3 upPerp = RB_DXRSubVec3(
|
|
upW,
|
|
RB_DXRScaleVec3(dir, RB_DXRDotVec3(upW, dir)));
|
|
|
|
idVec3 axisU = RB_DXRCrossVec3(RB_DXRMakeVec3(0.0f, 0.0f, 1.0f), dir);
|
|
axisU = RB_DXRNormalizeVec3Safe(axisU, RB_DXRMakeVec3(1.0f, 0.0f, 0.0f));
|
|
axisU = RB_DXRNormalizeVec3Safe(rightPerp, axisU);
|
|
|
|
idVec3 axisV = RB_DXRCrossVec3(dir, axisU);
|
|
axisV = RB_DXRNormalizeVec3Safe(axisV, RB_DXRMakeVec3(0.0f, 1.0f, 0.0f));
|
|
if (RB_DXRDotVec3(axisV, upPerp) < 0.0f)
|
|
{
|
|
axisV = RB_DXRScaleVec3(axisV, -1.0f);
|
|
}
|
|
|
|
float tanHalfWidth = RB_DXRLengthVec3(rightPerp) / centerDepth;
|
|
float tanHalfHeight = RB_DXRLengthVec3(upPerp) / centerDepth;
|
|
|
|
float nearPlane = RB_DXRDotVec3(startW, dir);
|
|
if (nearPlane < 0.0f)
|
|
{
|
|
nearPlane = 0.0f;
|
|
}
|
|
|
|
float farPlane = RB_DXRDotVec3(endW, dir);
|
|
if (farPlane < centerDepth)
|
|
{
|
|
farPlane = centerDepth;
|
|
}
|
|
if (farPlane <= nearPlane)
|
|
{
|
|
farPlane = nearPlane + 64.0f;
|
|
}
|
|
|
|
glRaytracingLight_t light = glRaytracingLightingMakeSpotLight(
|
|
worldOrigin.x, worldOrigin.y, worldOrigin.z,
|
|
dir.x, dir.y, dir.z,
|
|
axisU.x, axisU.y, axisU.z,
|
|
axisV.x, axisV.y, axisV.z,
|
|
nearPlane,
|
|
farPlane,
|
|
tanHalfWidth,
|
|
tanHalfHeight,
|
|
r, g, b,
|
|
intensity,
|
|
1u);
|
|
|
|
light.samples = srcLight.noShadows ? 0u : 1u;
|
|
light.pointRadiusPad = srcLight.noSpecular ? 1.0f : 0.0f;
|
|
|
|
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 int RB_DXRSingleReferencedLightArea(const idRenderLightLocal* light)
|
|
{
|
|
if (!light)
|
|
return -1;
|
|
|
|
int singleArea = -1;
|
|
for (const areaReference_t* ref = light->references; ref; ref = ref->ownerNext)
|
|
{
|
|
if (!ref->area)
|
|
continue;
|
|
|
|
const int areaNum = ref->area->areaNum;
|
|
if (singleArea < 0)
|
|
{
|
|
singleArea = areaNum;
|
|
continue;
|
|
}
|
|
if (singleArea != areaNum)
|
|
{
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
return singleArea;
|
|
}
|
|
|
|
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
|
|
====================
|
|
*/
|
|
void RB_DXDrawInteractions(void)
|
|
{
|
|
viewLight_t* vLight;
|
|
|
|
QD3D12_SetToneMapBrightness(r_brightness.GetFloat());
|
|
QD3D12_SetFrameGenerationMultiplier(r_frameGen.GetInteger());
|
|
QD3D12_SetDepthOfField(
|
|
r_depthOfField.GetBool() ? 1 : 0,
|
|
r_dofFocusDistance.GetFloat(),
|
|
r_dofFocusRange.GetFloat(),
|
|
r_dofMaxBlur.GetFloat(),
|
|
r_dofAmount.GetFloat(),
|
|
r_dofDebug.GetBool() ? 1 : 0);
|
|
|
|
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)
|
|
{
|
|
backEnd.vLight = vLight;
|
|
|
|
// do fogging later
|
|
if (vLight->lightShader->IsFogLight())
|
|
{
|
|
continue;
|
|
}
|
|
if (vLight->lightShader->IsBlendLight())
|
|
{
|
|
continue;
|
|
}
|
|
if (!R_MaskedOcclusionCulling_LightIsVisible(backEnd.viewDef, vLight->lightDef))
|
|
{
|
|
continue;
|
|
}
|
|
if (usePathTraceLightAreas && !RB_DXRPathTraceLightTouchesAreaSet(vLight->lightDef, pathTraceLightAreas))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
const renderLight_t& srcLight = vLight->lightDef->parms;
|
|
const float r = srcLight.shaderParms[SHADERPARM_RED];
|
|
const float g = srcLight.shaderParms[SHADERPARM_GREEN];
|
|
const float b = srcLight.shaderParms[SHADERPARM_BLUE];
|
|
const float intensity = 6.0f;
|
|
|
|
glRaytracingLight_t light = {};
|
|
bool supported = true;
|
|
|
|
if (srcLight.pointLight)
|
|
{
|
|
light = glRaytracingLightingMakePointLight(
|
|
vLight->globalLightOrigin.x,
|
|
vLight->globalLightOrigin.y,
|
|
vLight->globalLightOrigin.z,
|
|
srcLight.lightRadius[0] * 1.15f,
|
|
srcLight.lightRadius[1] * 1.15f,
|
|
srcLight.lightRadius[2] * 1.5f,
|
|
r, g, b,
|
|
intensity);
|
|
|
|
light.samples = srcLight.noShadows ? 0u : 1u;
|
|
light.pointRadiusPad = srcLight.noSpecular ? 1.0f : 0.0f;
|
|
light.areaNum = RB_DXRSingleReferencedLightArea(vLight->lightDef);
|
|
|
|
const idVec3 axisU = RB_DXRNormalizeVec3Safe(RB_DXRTransformLightVector(srcLight.axis, RB_DXRMakeVec3(1.0f, 0.0f, 0.0f)), RB_DXRMakeVec3(1.0f, 0.0f, 0.0f));
|
|
const idVec3 axisV = RB_DXRNormalizeVec3Safe(RB_DXRTransformLightVector(srcLight.axis, RB_DXRMakeVec3(0.0f, 1.0f, 0.0f)), RB_DXRMakeVec3(0.0f, 1.0f, 0.0f));
|
|
const idVec3 axisW = RB_DXRNormalizeVec3Safe(RB_DXRTransformLightVector(srcLight.axis, RB_DXRMakeVec3(0.0f, 0.0f, 1.0f)), RB_DXRMakeVec3(0.0f, 0.0f, 1.0f));
|
|
light.axisU.x = axisU.x;
|
|
light.axisU.y = axisU.y;
|
|
light.axisU.z = axisU.z;
|
|
light.axisV.x = axisV.x;
|
|
light.axisV.y = axisV.y;
|
|
light.axisV.z = axisV.z;
|
|
light.normal.x = axisW.x;
|
|
light.normal.y = axisW.y;
|
|
light.normal.z = axisW.z;
|
|
}
|
|
else if (!srcLight.parallel)
|
|
{
|
|
light = RB_DXRMakeSpotLightFromRenderLight(
|
|
srcLight,
|
|
vLight->globalLightOrigin,
|
|
r, g, b,
|
|
intensity);
|
|
light.areaNum = RB_DXRSingleReferencedLightArea(vLight->lightDef);
|
|
}
|
|
else
|
|
{
|
|
// Parallel projected lights are not spot lights.
|
|
// Handle them in a separate directional/orthographic path.
|
|
supported = false;
|
|
common->Warning("Parallel lights are not needed with raytracing! Just place a skybox.");
|
|
}
|
|
|
|
if (supported) {
|
|
if (vLight->iesImage) {
|
|
vLight->iesImage->Bind();
|
|
if (vLight->iesImage->texnum != idImage::TEXTURE_NOT_LOADED) {
|
|
light.iesTextureId = vLight->iesImage->texnum;
|
|
light.iesStrength = 1.0f;
|
|
}
|
|
}
|
|
glRaytracingLightingAddLight(&light);
|
|
screenParticleLights.Append(light);
|
|
}
|
|
}
|
|
|
|
if (backEnd.viewDef->renderWorld)
|
|
{
|
|
backEnd.viewDef->renderWorld->SubmitWorldDecalsToScreenSpace();
|
|
glSetScreenSpaceParticleLightsQD3D12(screenParticleLights.Ptr(), screenParticleLights.Num());
|
|
glRaytracingLightingSetGIAmount(r_pathTraceGIAmount.GetFloat());
|
|
glRaytracingLightingSetWorldGrime(r_pathTraceWorldGrime.GetFloat());
|
|
glRaytracingLightingSetSecondaryLightBudget(
|
|
r_pathTraceSecondaryLightBudget.GetInteger(),
|
|
r_pathTraceSecondaryLightCompensation.GetFloat());
|
|
glLightScene(backEnd.viewDef->renderWorld->dxrWorldId);
|
|
RB_DXRReportPathTraceProfile();
|
|
glRaytracingLightingClearLights(false);
|
|
}
|
|
}
|