From 961e74e0fa3740868686089146a2f37423015bd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Lu=C3=ADs=20Vaz=20Silva?= Date: Sun, 16 Feb 2025 04:08:53 -0300 Subject: [PATCH] add camera-facing midtexture shadows to dynamic lights, off by default due to fps hit --- .../rendering/hwrenderer/data/hw_cvars.cpp | 2 + .../rendering/hwrenderer/data/hw_cvars.h | 1 + .../rendering/vulkan/shaders/vk_shader.cpp | 1 + .../rendering/vulkan/shaders/vk_shader.h | 3 +- .../rendering/vulkan/vk_renderstate.cpp | 2 + wadsrc/static/menudef.txt | 1 + .../shaders/lightmap/polyfill_rayquery.glsl | 38 +++++++ wadsrc/static/shaders/scene/light_trace.glsl | 105 ++++++++++++++++-- 8 files changed, 141 insertions(+), 12 deletions(-) diff --git a/src/common/rendering/hwrenderer/data/hw_cvars.cpp b/src/common/rendering/hwrenderer/data/hw_cvars.cpp index 0c110f2e6..88a8d9ca3 100644 --- a/src/common/rendering/hwrenderer/data/hw_cvars.cpp +++ b/src/common/rendering/hwrenderer/data/hw_cvars.cpp @@ -182,3 +182,5 @@ int get_gl_spritelight() CVARD(Bool, gl_fakemodellight, true, CVAR_GLOBALCONFIG | CVAR_ARCHIVE, "adds a fake sunlight on models to improve contrast") CVARD(Float, gl_fakemodellightintensity, 0.05, CVAR_GLOBALCONFIG | CVAR_ARCHIVE, "fake sunlight intensity (brightness)") + +CVARD(Bool, gl_precise_midtextures_trace, false, CVAR_GLOBALCONFIG | CVAR_ARCHIVE, "trace midtextures facing towards camera, only needed for maps that don't use midtextures 'evenly', roughly doubles the cost of ray-traced lights") \ No newline at end of file diff --git a/src/common/rendering/hwrenderer/data/hw_cvars.h b/src/common/rendering/hwrenderer/data/hw_cvars.h index a056860b9..11b5a2d90 100644 --- a/src/common/rendering/hwrenderer/data/hw_cvars.h +++ b/src/common/rendering/hwrenderer/data/hw_cvars.h @@ -67,3 +67,4 @@ int get_gl_spritelight(); EXTERN_CVAR(Bool, gl_fakemodellight) EXTERN_CVAR(Float, gl_fakemodellightintensity) +EXTERN_CVAR(Bool, gl_precise_midtextures_trace) diff --git a/src/common/rendering/vulkan/shaders/vk_shader.cpp b/src/common/rendering/vulkan/shaders/vk_shader.cpp index 686e2f27d..a2412e46b 100644 --- a/src/common/rendering/vulkan/shaders/vk_shader.cpp +++ b/src/common/rendering/vulkan/shaders/vk_shader.cpp @@ -391,6 +391,7 @@ void VkShaderManager::BuildDefinesBlock(FString &definesBlock, const char *defin if (key.UseRaytrace) definesBlock << "#define USE_RAYTRACE\n"; if (key.UseRaytracePrecise) definesBlock << "#define USE_RAYTRACE_PRECISE\n"; + if (key.PreciseMidtextureTrace) definesBlock << "#define PRECISE_MIDTEXTURES\n"; definesBlock << "#define SHADOWMAP_FILTER "; definesBlock << std::to_string(key.ShadowmapFilter).c_str(); diff --git a/src/common/rendering/vulkan/shaders/vk_shader.h b/src/common/rendering/vulkan/shaders/vk_shader.h index 1accd8373..2c774b625 100644 --- a/src/common/rendering/vulkan/shaders/vk_shader.h +++ b/src/common/rendering/vulkan/shaders/vk_shader.h @@ -111,7 +111,8 @@ public: uint64_t ShadeVertex : 1; // SHADE_VERTEX uint64_t LightNoNormals : 1; // LIGHT_NONORMALS uint64_t UseSpriteCenter : 1; // USE_SPRITE_CENTER - uint64_t Unused : 27; + uint64_t PreciseMidtextureTrace : 1; // PRECISE_MIDTEXTURES + uint64_t Unused : 26; }; uint64_t AsQWORD = 0; }; diff --git a/src/common/rendering/vulkan/vk_renderstate.cpp b/src/common/rendering/vulkan/vk_renderstate.cpp index cca6eb7a4..ad66bcf15 100644 --- a/src/common/rendering/vulkan/vk_renderstate.cpp +++ b/src/common/rendering/vulkan/vk_renderstate.cpp @@ -336,6 +336,7 @@ void VkRenderState::ApplyRenderPass(int dt) pipelineKey.ShaderKey.UseShadowmap = gl_light_shadows == 1; pipelineKey.ShaderKey.UseRaytrace = gl_light_shadows >= 2; pipelineKey.ShaderKey.UseRaytracePrecise = gl_light_shadows >= 3; + pipelineKey.ShaderKey.PreciseMidtextureTrace = gl_precise_midtextures_trace; pipelineKey.ShaderKey.ShadowmapFilter = std::clamp(int(gl_light_shadow_filter), 0, 15); pipelineKey.ShaderKey.GBufferPass = mRenderTarget.DrawBuffers > 1; @@ -1091,6 +1092,7 @@ void VkRenderState::ApplyLevelMeshPipeline(VulkanCommandBuffer* cmdbuffer, VkPip pipelineKey.ShaderKey.UseShadowmap = gl_light_shadows == 1; pipelineKey.ShaderKey.UseRaytrace = gl_light_shadows >= 2; pipelineKey.ShaderKey.UseRaytracePrecise = gl_light_shadows >= 3; + pipelineKey.ShaderKey.PreciseMidtextureTrace = gl_precise_midtextures_trace; pipelineKey.ShaderKey.ShadowmapFilter = std::clamp(int(gl_light_shadow_filter), 0, 15); pipelineKey.ShaderKey.GBufferPass = mRenderTarget.DrawBuffers > 1; diff --git a/wadsrc/static/menudef.txt b/wadsrc/static/menudef.txt index c0d6a4a7d..4cc10316b 100644 --- a/wadsrc/static/menudef.txt +++ b/wadsrc/static/menudef.txt @@ -1070,6 +1070,7 @@ OptionMenu "LightOptions" protected Option "$GLLIGHTMNU_LIGHTSHADOWS", gl_light_shadows, "ShadowMode" Option "$GLLIGHTMNU_LIGHTSHADOWFILTER", gl_light_shadow_filter, "ShadowFilter" Option "$GLLIGHTMNU_LIGHTSHADOWMAPQUALITY", gl_shadowmap_quality, "ShadowMapQuality" + Option "$GLLIGHTMNU_PRECISEMIDTEXTRACE", gl_precise_midtextures_trace, "YesNo" StaticText " " Option "$GLPREFMNU_SWLMBANDED", gl_bandedswlight, "OnOff" Option "$GLPREFMNU_FOGFORCEFULLBRIGHT", gl_brightfog, "YesNo" diff --git a/wadsrc/static/shaders/lightmap/polyfill_rayquery.glsl b/wadsrc/static/shaders/lightmap/polyfill_rayquery.glsl index 27faf72a6..1446903e9 100644 --- a/wadsrc/static/shaders/lightmap/polyfill_rayquery.glsl +++ b/wadsrc/static/shaders/lightmap/polyfill_rayquery.glsl @@ -43,6 +43,41 @@ TraceResult TraceFirstHit(vec3 origin, float tmin, vec3 dir, float tmax) return result; } +TraceResult TraceFirstHitReverse(vec3 origin, float tmin, vec3 dir, float tmax) +{ + TraceResult result; + + rayQueryEXT rayQuery; + rayQueryInitializeEXT(rayQuery, acc, gl_RayFlagsCullFrontFacingTrianglesEXT, 0xFF, origin, tmin, dir, tmax); + + while(rayQueryProceedEXT(rayQuery)) + { + if (rayQueryGetIntersectionTypeEXT(rayQuery, false) == gl_RayQueryCommittedIntersectionTriangleEXT) + { + rayQueryConfirmIntersectionEXT(rayQuery); + } + } + + if (rayQueryGetIntersectionTypeEXT(rayQuery, true) == gl_RayQueryCommittedIntersectionTriangleEXT) + { + result.t = rayQueryGetIntersectionTEXT(rayQuery, true); + + result.primitiveWeights.xy = rayQueryGetIntersectionBarycentricsEXT(rayQuery, true); + result.primitiveWeights.z = 1.0 - result.primitiveWeights.x - result.primitiveWeights.y; + + result.primitiveIndex = + rayQueryGetIntersectionInstanceCustomIndexEXT(rayQuery, true) + + rayQueryGetIntersectionPrimitiveIndexEXT(rayQuery, true); + } + else + { + result.t = tmax; + result.primitiveIndex = -1; + } + + return result; +} + bool TraceAnyHit(vec3 origin, float tmin, vec3 dir, float tmax) { rayQueryEXT rayQuery; @@ -276,4 +311,7 @@ TraceResult TraceFirstHit(vec3 origin, float tmin, vec3 dir, float tmax) return result; } +//no nice tracing for you sorry +#define TraceFirstHitReverse TraceFirstHit + #endif diff --git a/wadsrc/static/shaders/scene/light_trace.glsl b/wadsrc/static/shaders/scene/light_trace.glsl index f483b8506..2f5aa85e0 100644 --- a/wadsrc/static/shaders/scene/light_trace.glsl +++ b/wadsrc/static/shaders/scene/light_trace.glsl @@ -3,26 +3,109 @@ #include #include +bool TraceHitIsFacing(vec3 hitPos, SurfaceInfo hitSurface) +{ + vec3 target = uCameraPos.xyz - hitPos; + return dot(hitSurface.Normal, target) < 0; +} + float TraceDynLightRay(vec3 origin, float tmin, vec3 direction, float dist) { float alpha = 1.0; for (int i = 0; i < 3; i++) { - TraceResult result = TraceFirstHit(origin, tmin, direction, dist); + #ifdef PRECISE_MIDTEXTURES + TraceResult result; + SurfaceInfo surface; + bool skip = true; - // Stop if we hit nothing - the point light is visible. - if (result.primitiveIndex == -1) - return alpha; + { + TraceResult frontResult = TraceFirstHit(origin, tmin, direction, dist); + TraceResult backResult = TraceFirstHitReverse(origin, tmin, direction, dist); + + if(frontResult.primitiveIndex != -1 && backResult.primitiveIndex != -1) + { + //both hit + SurfaceInfo frontSurface = GetSurface(frontResult.primitiveIndex); + SurfaceInfo backSurface = GetSurface(backResult.primitiveIndex); + + bool frontFacing = TraceHitIsFacing(origin + direction * frontResult.t, frontSurface); + bool backFacing = TraceHitIsFacing(origin + direction * backResult.t, backSurface); - SurfaceInfo surface = GetSurface(result.primitiveIndex); + //bool frontFacing = dot(frontSurface.Normal, uCameraNormal) > 0; + //bool backFacing = dot(backSurface.Normal, uCameraNormal) > 0; + + if(frontFacing && frontFacing == backFacing) + { + skip = false; + if(frontResult.t < backResult.t) + { + result = frontResult; + surface = frontSurface; + } + else + { + result = backResult; + surface = backSurface; + } + } + else if(backFacing) + { + skip = false; + result = backResult; + surface = backSurface; + } + else + { + skip = !frontFacing; + result = frontResult; + surface = frontSurface; + } + } + else if(frontResult.primitiveIndex != -1) + { + result = frontResult; + surface = GetSurface(frontResult.primitiveIndex); + skip = TraceHitIsFacing(origin + direction * result.t, surface);//dot(surface.Normal, uCameraNormal) < 0; + } + else if(backResult.primitiveIndex != -1) + { + result = backResult; + surface = GetSurface(backResult.primitiveIndex); + skip = TraceHitIsFacing(origin + direction * result.t, surface);//dot(surface.Normal, uCameraNormal) < 0; + } + else + { + // neither hit + return alpha; + } + } + + if(!skip) + { + alpha = PassRayThroughSurfaceDynLight(surface, GetSurfaceUV(result.primitiveIndex, result.primitiveWeights), alpha); + + // Stop if there is no light left + if (alpha <= 0.0) + return 0.0; + } + #else + TraceResult result = TraceFirstHit(origin, tmin, direction, dist); + + // Stop if we hit nothing - the point light is visible. + if (result.primitiveIndex == -1) + return alpha; + + SurfaceInfo surface = GetSurface(result.primitiveIndex); - // Pass through surface texture - alpha = PassRayThroughSurfaceDynLight(surface, GetSurfaceUV(result.primitiveIndex, result.primitiveWeights), alpha); - - // Stop if there is no light left - if (alpha <= 0.0) - return 0.0; + // Pass through surface texture + alpha = PassRayThroughSurfaceDynLight(surface, GetSurfaceUV(result.primitiveIndex, result.primitiveWeights), alpha); + + // Stop if there is no light left + if (alpha <= 0.0) + return 0.0; + #endif // Move to surface hit point origin += direction * result.t;