diff --git a/base/maps/game/mars_city1/textures/objective1.tga b/base/maps/game/mars_city1/textures/objective1.tga index 87280f32..03dad0cd 100644 Binary files a/base/maps/game/mars_city1/textures/objective1.tga and b/base/maps/game/mars_city1/textures/objective1.tga differ diff --git a/base/maps/game/mars_city1/textures/objective2.tga b/base/maps/game/mars_city1/textures/objective2.tga index edbb61be..37dbcfe3 100644 Binary files a/base/maps/game/mars_city1/textures/objective2.tga and b/base/maps/game/mars_city1/textures/objective2.tga differ diff --git a/base/maps/game/mars_city2/textures/objective1.tga b/base/maps/game/mars_city2/textures/objective1.tga index f37d6e40..42a55d86 100644 Binary files a/base/maps/game/mars_city2/textures/objective1.tga and b/base/maps/game/mars_city2/textures/objective1.tga differ diff --git a/base/maps/game/mars_city2/textures/objective2.tga b/base/maps/game/mars_city2/textures/objective2.tga index 2730baa0..c0287b5e 100644 Binary files a/base/maps/game/mars_city2/textures/objective2.tga and b/base/maps/game/mars_city2/textures/objective2.tga differ diff --git a/base/maps/game/mars_city2/textures/objective3.tga b/base/maps/game/mars_city2/textures/objective3.tga index 72dcebe5..dced765f 100644 Binary files a/base/maps/game/mars_city2/textures/objective3.tga and b/base/maps/game/mars_city2/textures/objective3.tga differ diff --git a/neo/engine/opengl/gl_d3d12shim.cpp b/neo/engine/opengl/gl_d3d12shim.cpp index 5e22d6e0..d51410b7 100644 --- a/neo/engine/opengl/gl_d3d12shim.cpp +++ b/neo/engine/opengl/gl_d3d12shim.cpp @@ -349,6 +349,7 @@ void QD3D12_SetUpscalerQuality(int quality); void QD3D12_SetUpscalerSharpness(float sharpness); void QD3D12_SetToneMapBrightness(float brightness); float QD3D12_GetToneMapBrightness(void); +void QD3D12_SetDepthOfField(int enabled, float focusDistance, float focusRange, float maxBlur, float amount, int debugMask); void QD3D12_SetFrameGenerationMultiplier(int multiplier); int QD3D12_GetFrameGenerationMultiplier(void); int QD3D12_GetActiveFrameGenerationMultiplier(void); @@ -1820,6 +1821,7 @@ struct GLState ComPtr postRootSig; ComPtr postCopyPSO; ComPtr postSharpenPSO; + ComPtr postDepthOfFieldPSO; ComPtr postToneMapPSO; ComPtr postToneMapTileMaxPSO; ComPtr postToneMapFinalMaxPSO; @@ -1847,6 +1849,7 @@ struct GLState ComPtr postVsBlob; ComPtr postPsCopyBlob; ComPtr postPsSharpenBlob; + ComPtr postPsDepthOfFieldBlob; ComPtr postPsToneMapBlob; ComPtr postPsToneMapTileMaxBlob; ComPtr postPsToneMapFinalMaxBlob; @@ -1866,6 +1869,12 @@ struct GLState GLenum defaultMagFilter = GL_LINEAR; GLenum defaultWrapS = GL_REPEAT; GLenum defaultWrapT = GL_REPEAT; + bool depthOfFieldEnabled = true; + float dofFocusDistance = 0.0f; + float dofFocusRange = 96.0f; + float dofMaxBlur = 8.0f; + float dofAmount = 1.0f; + bool dofDebugMask = false; GLState() { @@ -4968,6 +4977,11 @@ cbuffer PostCB : register(b0) #define gSkyCloudCoverage gSkyCloudParams.y #define gSkyCloudDensity gSkyCloudParams.z #define gSkyCloudSeed gSkyCloudParams.w +#define gDofFocusDistance gSkyCloudParams.x +#define gDofFocusRange gSkyCloudParams.y +#define gDofMaxBlur gSkyCloudParams.z +#define gDofAmount gSkyCloudParams.w +#define gDofDebugMask gSkyCloudTanY #define gSkyHorizonFogColor gPostParams2.rgb #define gSkyHorizonFogHeight gPostParams2.w #define gSkyHorizonFogPower gPostParams3.x @@ -5309,7 +5323,8 @@ float4 PSCopy(VSOut i) : SV_Target0 { return QD3D12_ApplyPostFog(gTex0.Sample(gSamp0, i.uv), i.uv); } - +)HLSL" +R"HLSL( float QD3D12_SkyCloudFade(float t) { t = saturate(t); @@ -5482,6 +5497,96 @@ float4 PSSharpen(VSOut i) : SV_Target0 return QD3D12_ApplyPostFog(float4(saturate(sharp), center.a), i.uv); } +float QD3D12_DepthOfFieldCoc(float2 uv) +{ + float amount = saturate(gDofAmount); + float maxBlur = max(gDofMaxBlur, 0.0); + if (amount <= 0.0001 || maxBlur <= 0.0001) + return 0.0; + + float sceneDepth = gFogDepth.SampleLevel(gSamp0, uv, 0.0); + if (sceneDepth >= 0.99999) + return 0.0; + + float coc = 0.0; + if (gPostFogCameraValid > 0.5) + { + float3 worldPos = gFogPosition.SampleLevel(gSamp0, uv, 0.0).xyz; + float sceneDistance = length(worldPos - gPostFogCameraWorldPos.xyz); + float focusDistance = gDofFocusDistance; + if (focusDistance <= 0.5) + { + float centerDepth = gFogDepth.SampleLevel(gSamp0, float2(0.5, 0.5), 0.0); + if (centerDepth < 0.99999) + { + float3 centerWorld = gFogPosition.SampleLevel(gSamp0, float2(0.5, 0.5), 0.0).xyz; + focusDistance = length(centerWorld - gPostFogCameraWorldPos.xyz); + } + else + { + focusDistance = 256.0; + } + } + focusDistance = max(focusDistance, 1.0); + float focusRange = max(gDofFocusRange, 1.0); + float focusDelta = abs(sceneDistance - focusDistance); + coc = saturate((focusDelta - focusRange * 0.20) / focusRange); + coc *= (sceneDistance < focusDistance) ? 1.15 : 1.0; + } + else + { + float focusDepth = gFogDepth.SampleLevel(gSamp0, float2(0.5, 0.5), 0.0); + if (focusDepth >= 0.99999) + focusDepth = 0.5; + + // Fallback for paths that have not published camera constants: use raw + // hardware depth so the post pass remains visibly active. + coc = saturate(abs(sceneDepth - focusDepth) * 260.0 - 0.02); + } + + return saturate(coc) * amount; +} + +float3 QD3D12_DepthOfFieldBlur(float2 uv, float3 centerRgb) +{ + float coc = QD3D12_DepthOfFieldCoc(uv); + if (coc <= 0.001) + return centerRgb; + float maxBlur = max(gDofMaxBlur, 0.0); + + uint srcW, srcH; + gTex0.GetDimensions(srcW, srcH); + float2 texel = 1.0 / max(float2((float)srcW, (float)srcH), float2(1.0, 1.0)); + float2 r = texel * (maxBlur * coc); + + float3 blur = centerRgb * 0.22; + blur += gTex0.Sample(gSamp0, saturate(uv + r * float2( 1.0, 0.0))).rgb * 0.10; + blur += gTex0.Sample(gSamp0, saturate(uv + r * float2(-1.0, 0.0))).rgb * 0.10; + blur += gTex0.Sample(gSamp0, saturate(uv + r * float2( 0.0, 1.0))).rgb * 0.10; + blur += gTex0.Sample(gSamp0, saturate(uv + r * float2( 0.0, -1.0))).rgb * 0.10; + blur += gTex0.Sample(gSamp0, saturate(uv + r * float2( 0.707, 0.707))).rgb * 0.085; + blur += gTex0.Sample(gSamp0, saturate(uv + r * float2(-0.707, 0.707))).rgb * 0.085; + blur += gTex0.Sample(gSamp0, saturate(uv + r * float2( 0.707, -0.707))).rgb * 0.085; + blur += gTex0.Sample(gSamp0, saturate(uv + r * float2(-0.707, -0.707))).rgb * 0.085; + blur += gTex0.Sample(gSamp0, saturate(uv + r * float2( 1.7, 0.45))).rgb * 0.025; + blur += gTex0.Sample(gSamp0, saturate(uv + r * float2(-1.7, -0.45))).rgb * 0.025; + + float blend = smoothstep(0.05, 1.0, coc); + return lerp(centerRgb, blur, blend); +} + +float4 PSDepthOfField(VSOut i) : SV_Target0 +{ + float4 center = gTex0.Sample(gSamp0, i.uv); + if (gDofDebugMask > 0.5) + { + float coc = QD3D12_DepthOfFieldCoc(i.uv); + return float4(coc.xxx, 1.0); + } + float3 color = QD3D12_DepthOfFieldBlur(i.uv, center.rgb); + return QD3D12_ApplyPostFog(float4(saturate(color), center.a), i.uv); +} + float QD3D12_ToneMapBrightness(float3 rgb) { @@ -5596,12 +5701,19 @@ float4 PSToneMap(VSOut i) : SV_Target0 { float4 center = gTex0.Sample(gSamp0, i.uv); + if (gDofDebugMask > 0.5) + { + float coc = QD3D12_DepthOfFieldCoc(i.uv); + return float4(coc.xxx, 1.0); + } + // Root table t7 is the 1x1 brightest-pixel reduction for this shader. It is // also used as TAA history by PSTAA, but those entries are never active in the // same PSO. float whitePoint = max(gTaaHistory.SampleLevel(gSamp0, float2(0.5, 0.5), 0.0).r, 1.0); - float3 hdr = QD3D12_PostSharpenHDR(i.uv, max(center.rgb, 0.0)); + float3 hdr = max(center.rgb, 0.0); + hdr = (gDofAmount > 0.0001) ? max(QD3D12_DepthOfFieldBlur(i.uv, hdr), float3(0.0, 0.0, 0.0)) : QD3D12_PostSharpenHDR(i.uv, hdr); float3 mapped = QD3D12_ExtendedReinhard(hdr, whitePoint); // Do not apply a gamma pow here. This shim's swap chain and scene buffers are @@ -9024,6 +9136,11 @@ static void QD3D12_SetPostConstants( constants[25] = screenParticleOutputMode; constants[26] = screenParticleDepthScaleX; constants[27] = screenParticleDepthScaleY; + constants[44] = g_gl.dofFocusDistance; + constants[45] = g_gl.dofFocusRange; + constants[46] = g_gl.dofMaxBlur; + constants[47] = ( g_gl.depthOfFieldEnabled && forceCameraPosition ) ? g_gl.dofAmount : 0.0f; + constants[43] = g_gl.dofDebugMask ? 1.0f : 0.0f; if (skyClouds) { constants[7] = skyClouds->fogOpacity; @@ -9064,7 +9181,7 @@ static void QD3D12_SetPostConstants( cl->SetGraphicsRoot32BitConstants(QD3D12_PostRootConstants, QD3D12_PostConstantDwords, constants, 0); } -static void QD3D12_BindPostFogResources(ID3D12GraphicsCommandList* cl, QD3D12Window& w, bool applySceneFog) +static void QD3D12_BindPostFogResources(ID3D12GraphicsCommandList* cl, QD3D12Window& w, bool applySceneFog, bool bindSceneDepthResources = false) { if (!cl) return; @@ -9075,7 +9192,8 @@ static void QD3D12_BindPostFogResources(ID3D12GraphicsCommandList* cl, QD3D12Win cl->SetGraphicsRootDescriptorTable(11, w.sceneColorSrvGpu[w.frameIndex]); } - if (!applySceneFog || !g_gl.sceneFogValidThisFrame) + const bool needSceneDepthResources = bindSceneDepthResources || (applySceneFog && g_gl.sceneFogValidThisFrame); + if (!needSceneDepthResources) return; if (!w.positionBuffers[w.frameIndex] || !w.depthBuffer) return; @@ -9086,6 +9204,19 @@ static void QD3D12_BindPostFogResources(ID3D12GraphicsCommandList* cl, QD3D12Win cl->SetGraphicsRootDescriptorTable(10, w.depthSrvGpu); } +static bool QD3D12_DepthOfFieldActive(const QD3D12Window& w) +{ + const UINT frame = w.frameIndex; + return g_gl.depthOfFieldEnabled && + g_gl.dofAmount > 0.0001f && + g_gl.dofMaxBlur > 0.0001f && + !w.isPbuffer && + w.positionBuffers[frame] && + w.depthBuffer && + w.positionSrvIndex[frame] != UINT_MAX && + w.depthSrvIndex != UINT_MAX; +} + static bool QD3D12_EnsureScreenSpaceDecalBuffer() { if (!g_gl.device || !g_gl.srvHeap) @@ -9255,7 +9386,9 @@ static void QD3D12_PostFullscreenPass(ID3D12GraphicsCommandList* cl, const D3D12_RECT& scissor, float sharpnessOverride = -1.0f, bool applySceneFog = false, - QD3D12Window* fogWindow = nullptr) + QD3D12Window* fogWindow = nullptr, + bool forceCameraPosition = false, + bool bindSceneDepthResources = false) { if (!cl || !pso) return; @@ -9264,7 +9397,7 @@ static void QD3D12_PostFullscreenPass(ID3D12GraphicsCommandList* cl, cl->SetDescriptorHeaps(_countof(heaps), heaps); cl->SetGraphicsRootSignature(g_gl.postRootSig.Get()); const float passSharpness = (sharpnessOverride >= 0.0f) ? sharpnessOverride : g_gl.upscalerSharpness; - QD3D12_SetPostConstants(cl, passSharpness, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, applySceneFog); + QD3D12_SetPostConstants(cl, passSharpness, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, applySceneFog, 0.0f, 0.0f, forceCameraPosition); cl->SetPipelineState(pso); cl->OMSetRenderTargets(1, &outputRtv, FALSE, nullptr); cl->RSSetViewports(1, &viewport); @@ -9272,7 +9405,7 @@ static void QD3D12_PostFullscreenPass(ID3D12GraphicsCommandList* cl, cl->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST); cl->SetGraphicsRootDescriptorTable(0, inputSrv); if (fogWindow) - QD3D12_BindPostFogResources(cl, *fogWindow, applySceneFog); + QD3D12_BindPostFogResources(cl, *fogWindow, applySceneFog, bindSceneDepthResources); cl->DrawInstanced(3, 1, 0, 0); } @@ -9383,7 +9516,8 @@ static bool QD3D12_ToneMapFullscreenPass( cl->SetDescriptorHeaps(_countof(heaps), heaps); cl->SetGraphicsRootSignature(g_gl.postRootSig.Get()); const float passSharpness = (sharpnessOverride >= 0.0f) ? sharpnessOverride : g_gl.upscalerSharpness; - QD3D12_SetPostConstants(cl, passSharpness, 0.0f, 1.0f, 1.0f, 1.0f, g_gl.toneMapBrightness, applySceneFog); + const bool dofActive = QD3D12_DepthOfFieldActive(w); + QD3D12_SetPostConstants(cl, passSharpness, 0.0f, 1.0f, 1.0f, 1.0f, g_gl.toneMapBrightness, applySceneFog, 0.0f, 0.0f, dofActive); cl->SetPipelineState(g_gl.postToneMapPSO.Get()); cl->OMSetRenderTargets(1, &outputRtv, FALSE, nullptr); cl->RSSetViewports(1, &viewport); @@ -9396,7 +9530,7 @@ static bool QD3D12_ToneMapFullscreenPass( QD3D12_TransitionResource(cl, w.sceneColorBuffers[frame].Get(), w.sceneColorState[frame], D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE); cl->SetGraphicsRootDescriptorTable(11, w.sceneColorSrvGpu[frame]); } - QD3D12_BindPostFogResources(cl, w, applySceneFog); + QD3D12_BindPostFogResources(cl, w, applySceneFog, dofActive); cl->DrawInstanced(3, 1, 0, 0); return true; } @@ -9855,6 +9989,9 @@ static bool QD3D12_FinalBlitToBackBuffer( ID3D12PipelineState* finalPso = (g_gl.upscalerSharpness > 0.0001f && g_gl.postSharpenPSO) ? g_gl.postSharpenPSO.Get() : g_gl.postCopyPSO.Get(); + const bool dofActive = QD3D12_DepthOfFieldActive(w); + if (dofActive) + finalPso = g_gl.postDepthOfFieldPSO.Get(); // This is the only final sharpen point. All temporal work (internal TAA, // DLSS/DLSS-RR, or FSR) has already completed before this fullscreen pass. @@ -9867,7 +10004,9 @@ static bool QD3D12_FinalBlitToBackBuffer( outputScissor, -1.0f, true, - &w); + &w, + dofActive, + dofActive); return true; } @@ -11320,6 +11459,7 @@ static void QD3D12_CompileShaders() g_gl.postVsBlob = CompileShaderSourceVariant(kQD3D12PostHLSL, "VSMain", "vs_6_0"); g_gl.postPsCopyBlob = CompileShaderSourceVariant(kQD3D12PostHLSL, "PSCopy", "ps_6_0"); g_gl.postPsSharpenBlob = CompileShaderSourceVariant(kQD3D12PostHLSL, "PSSharpen", "ps_6_0"); + g_gl.postPsDepthOfFieldBlob = CompileShaderSourceVariant(kQD3D12PostHLSL, "PSDepthOfField", "ps_6_0"); g_gl.postPsToneMapBlob = CompileShaderSourceVariant(kQD3D12PostHLSL, "PSToneMap", "ps_6_0"); g_gl.postPsToneMapTileMaxBlob = CompileShaderSourceVariant(kQD3D12PostHLSL, "PSToneMapTileMax", "ps_6_0"); g_gl.postPsToneMapFinalMaxBlob = CompileShaderSourceVariant(kQD3D12PostHLSL, "PSToneMapFinalMax", "ps_6_0"); @@ -11526,6 +11666,9 @@ static void QD3D12_CreatePSOs() d.PS = { g_gl.postPsSharpenBlob->GetBufferPointer(), g_gl.postPsSharpenBlob->GetBufferSize() }; QD3D12_CHECK(g_gl.device->CreateGraphicsPipelineState(&d, IID_PPV_ARGS(&g_gl.postSharpenPSO))); + d.PS = { g_gl.postPsDepthOfFieldBlob->GetBufferPointer(), g_gl.postPsDepthOfFieldBlob->GetBufferSize() }; + QD3D12_CHECK(g_gl.device->CreateGraphicsPipelineState(&d, IID_PPV_ARGS(&g_gl.postDepthOfFieldPSO))); + d.PS = { g_gl.postPsToneMapBlob->GetBufferPointer(), g_gl.postPsToneMapBlob->GetBufferSize() }; QD3D12_CHECK(g_gl.device->CreateGraphicsPipelineState(&d, IID_PPV_ARGS(&g_gl.postToneMapPSO))); @@ -19785,6 +19928,23 @@ float QD3D12_GetToneMapBrightness(void) return g_gl.toneMapBrightness; } +static float QD3D12_ClampFinite(float value, float fallback, float minValue, float maxValue) +{ + if (!std::isfinite(value)) + return fallback; + return ClampValue(value, minValue, maxValue); +} + +void QD3D12_SetDepthOfField(int enabled, float focusDistance, float focusRange, float maxBlur, float amount, int debugMask) +{ + g_gl.depthOfFieldEnabled = enabled != 0; + g_gl.dofFocusDistance = QD3D12_ClampFinite(focusDistance, 0.0f, 0.0f, 8192.0f); + g_gl.dofFocusRange = QD3D12_ClampFinite(focusRange, 96.0f, 1.0f, 8192.0f); + g_gl.dofMaxBlur = QD3D12_ClampFinite(maxBlur, 8.0f, 0.0f, 16.0f); + g_gl.dofAmount = g_gl.depthOfFieldEnabled ? QD3D12_ClampFinite(amount, 1.0f, 0.0f, 1.0f) : 0.0f; + g_gl.dofDebugMask = debugMask != 0; +} + void APIENTRY glToneMapBrightnessQD3D12(GLfloat brightness) { QD3D12_SetToneMapBrightness(brightness); diff --git a/neo/engine/opengl/opengl.h b/neo/engine/opengl/opengl.h index f114dc8f..75d2d09e 100644 --- a/neo/engine/opengl/opengl.h +++ b/neo/engine/opengl/opengl.h @@ -2446,6 +2446,7 @@ void APIENTRY glShowAllTopLevelAccelStructures( void QD3D12_SetUpscalerSharpness(float sharpness); void QD3D12_SetToneMapBrightness(float brightness); +void QD3D12_SetDepthOfField(int enabled, float focusDistance, float focusRange, float maxBlur, float amount, int debugMask); void QD3D12_SetFrameGenerationMultiplier(int multiplier); int QD3D12_GetFrameGenerationMultiplier(void); int QD3D12_GetActiveFrameGenerationMultiplier(void); diff --git a/neo/engine/renderer/RenderSystem.cpp b/neo/engine/renderer/RenderSystem.cpp index 9396bc2b..72cad280 100644 --- a/neo/engine/renderer/RenderSystem.cpp +++ b/neo/engine/renderer/RenderSystem.cpp @@ -285,6 +285,15 @@ static void R_CheckCvars( void ) { r_frameGen.ClearModified(); QD3D12_SetFrameGenerationMultiplier( r_frameGen.GetInteger() ); } + if ( r_depthOfField.IsModified() || r_dofFocusDistance.IsModified() || r_dofFocusRange.IsModified() || r_dofMaxBlur.IsModified() || r_dofAmount.IsModified() || r_dofDebug.IsModified() ) { + r_depthOfField.ClearModified(); + r_dofFocusDistance.ClearModified(); + r_dofFocusRange.ClearModified(); + r_dofMaxBlur.ClearModified(); + r_dofAmount.ClearModified(); + r_dofDebug.ClearModified(); + QD3D12_SetDepthOfField( r_depthOfField.GetBool() ? 1 : 0, r_dofFocusDistance.GetFloat(), r_dofFocusRange.GetFloat(), r_dofMaxBlur.GetFloat(), r_dofAmount.GetFloat(), r_dofDebug.GetBool() ? 1 : 0 ); + } // check for changes to logging state // GLimp_EnableLogging( r_logFile.GetInteger() != 0 ); diff --git a/neo/engine/renderer/RenderSystem_init.cpp b/neo/engine/renderer/RenderSystem_init.cpp index 92cde900..9ca4a7c4 100644 --- a/neo/engine/renderer/RenderSystem_init.cpp +++ b/neo/engine/renderer/RenderSystem_init.cpp @@ -82,6 +82,12 @@ idCVar r_ignoreGLErrors( "r_ignoreGLErrors", "1", CVAR_RENDERER | CVAR_BOOL, "ig idCVar r_finish( "r_finish", "0", CVAR_RENDERER | CVAR_BOOL, "force a call to glFinish() every frame" ); idCVar r_swapInterval( "r_swapInterval", "0", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_INTEGER, "changes wglSwapIntarval" ); idCVar r_frameGen( "r_frameGen", "0", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_INTEGER, "DLSS frame generation multiplier: 0/1 = off, 2 = 2x, 3 = 3x, 4 = 4x", 0, 4, idCmdSystem::ArgCompletion_Integer<0,4> ); +idCVar r_depthOfField( "r_depthOfField", "1", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_BOOL, "cheap cinematic depth of field" ); +idCVar r_dofFocusDistance( "r_dofFocusDistance", "256", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_FLOAT, "depth of field focal distance in world units, 0 = center-screen autofocus", 0.0f, 8192.0f ); +idCVar r_dofFocusRange( "r_dofFocusRange", "600", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_FLOAT, "depth of field in-focus range in world units", 1.0f, 8192.0f ); +idCVar r_dofMaxBlur( "r_dofMaxBlur", "2", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_FLOAT, "maximum depth of field blur radius in pixels", 0.0f, 16.0f ); +idCVar r_dofAmount( "r_dofAmount", "1", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_FLOAT, "depth of field blend amount", 0.0f, 1.0f ); +idCVar r_dofDebug( "r_dofDebug", "0", CVAR_RENDERER | CVAR_BOOL, "show depth of field blur mask" ); idCVar r_gamma( "r_gamma", "1", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_FLOAT, "changes gamma tables", 0.5f, 3.0f ); idCVar r_brightness( "r_brightnesspt", "1.5", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_FLOAT, "changes gamma tables", 0.5f, 2.0f ); diff --git a/neo/engine/renderer/draw_dx.cpp b/neo/engine/renderer/draw_dx.cpp index a38e1714..90ee30bb 100644 --- a/neo/engine/renderer/draw_dx.cpp +++ b/neo/engine/renderer/draw_dx.cpp @@ -301,6 +301,13 @@ void RB_DXDrawInteractions(void) 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 screenParticleLights; idList pathTraceLightAreas; diff --git a/neo/engine/renderer/tr_local.h b/neo/engine/renderer/tr_local.h index ac289e36..e5343af8 100644 --- a/neo/engine/renderer/tr_local.h +++ b/neo/engine/renderer/tr_local.h @@ -839,6 +839,12 @@ extern idCVar r_finish; // force a call to glFinish() every frame extern idCVar r_frontBuffer; // draw to front buffer for debugging extern idCVar r_swapInterval; // changes wglSwapIntarval extern idCVar r_frameGen; // DLSS frame generation multiplier +extern idCVar r_depthOfField; // cheap cinematic depth of field +extern idCVar r_dofFocusDistance; // depth of field focal distance in world units +extern idCVar r_dofFocusRange; // depth of field in-focus range in world units +extern idCVar r_dofMaxBlur; // maximum depth of field blur radius in pixels +extern idCVar r_dofAmount; // depth of field blend amount +extern idCVar r_dofDebug; // show depth of field blur mask extern idCVar r_offsetFactor; // polygon offset parameter extern idCVar r_offsetUnits; // polygon offset parameter extern idCVar r_singleTriangle; // only draw a single triangle per primitive