From 60cdb871d246b081281436408e5f8859c8497da9 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Mon, 26 Feb 2024 17:00:28 +0100 Subject: [PATCH] Add light bounce --- .../rendering/vulkan/vk_lightmapper.cpp | 9 +++- src/common/rendering/vulkan/vk_lightmapper.h | 4 +- .../shaders/lightmap/frag_raytrace.glsl | 9 +++- .../static/shaders/lightmap/trace_bounce.glsl | 45 +++++++++++++++++++ .../static/shaders/lightmap/trace_light.glsl | 10 ++--- .../shaders/lightmap/trace_sunlight.glsl | 12 ++--- 6 files changed, 68 insertions(+), 21 deletions(-) create mode 100644 wadsrc/static/shaders/lightmap/trace_bounce.glsl diff --git a/src/common/rendering/vulkan/vk_lightmapper.cpp b/src/common/rendering/vulkan/vk_lightmapper.cpp index a67bda89b..d82c55425 100644 --- a/src/common/rendering/vulkan/vk_lightmapper.cpp +++ b/src/common/rendering/vulkan/vk_lightmapper.cpp @@ -28,6 +28,7 @@ CVAR(Bool, lm_ao, true, 0); CVAR(Bool, lm_softshadows, true, 0); CVAR(Bool, lm_sunlight, true, 0); CVAR(Bool, lm_blur, true, 0); +CVAR(Bool, lm_bounce, true, 0); VkLightmapper::VkLightmapper(VulkanRenderDevice* fb) : fb(fb) { @@ -523,7 +524,7 @@ void VkLightmapper::CreateShaders() .DebugName("VkLightmapper.VertCopy") .Create("VkLightmapper.VertCopy", fb->GetDevice()); - for (int i = 0; i < 8; i++) + for (int i = 0; i < 16; i++) { std::string defines = traceprefix; if (i & 1) @@ -532,6 +533,8 @@ void VkLightmapper::CreateShaders() defines += "#define USE_AO\n"; if (i & 4) defines += "#define USE_SUNLIGHT\n"; + if (i & 8) + defines += "#define USE_BOUNCE\n"; shaders.fragRaytrace[i] = ShaderBuilder() .Type(ShaderType::Fragment) @@ -589,6 +592,8 @@ int VkLightmapper::GetRaytracePipelineIndex() index |= 2; if (lm_sunlight && mesh->SunColor != FVector3(0.0f, 0.0f, 0.0f)) index |= 4; + if (lm_bounce) + index |= 8; return index; } @@ -688,7 +693,7 @@ void VkLightmapper::CreateRaytracePipeline() .DebugName("raytrace.renderPass") .Create(fb->GetDevice()); - for (int i = 0; i < 8; i++) + for (int i = 0; i < 16; i++) { raytrace.pipeline[i] = GraphicsPipelineBuilder() .Layout(raytrace.pipelineLayout.get()) diff --git a/src/common/rendering/vulkan/vk_lightmapper.h b/src/common/rendering/vulkan/vk_lightmapper.h index cf87c391c..c0812dfcd 100644 --- a/src/common/rendering/vulkan/vk_lightmapper.h +++ b/src/common/rendering/vulkan/vk_lightmapper.h @@ -183,7 +183,7 @@ private: std::unique_ptr vertRaytrace; std::unique_ptr vertScreenquad; std::unique_ptr vertCopy; - std::unique_ptr fragRaytrace[8]; + std::unique_ptr fragRaytrace[16]; std::unique_ptr fragResolve; std::unique_ptr fragBlur[2]; std::unique_ptr fragCopy; @@ -194,7 +194,7 @@ private: std::unique_ptr descriptorSetLayout0; std::unique_ptr descriptorSetLayout1; std::unique_ptr pipelineLayout; - std::unique_ptr pipeline[8]; + std::unique_ptr pipeline[16]; std::unique_ptr renderPass; std::unique_ptr descriptorPool0; std::unique_ptr descriptorPool1; diff --git a/wadsrc/static/shaders/lightmap/frag_raytrace.glsl b/wadsrc/static/shaders/lightmap/frag_raytrace.glsl index 0250ab273..dbb682152 100644 --- a/wadsrc/static/shaders/lightmap/frag_raytrace.glsl +++ b/wadsrc/static/shaders/lightmap/frag_raytrace.glsl @@ -7,6 +7,7 @@ #include #include #include +#include layout(location = 0) centroid in vec3 worldpos; layout(location = 1) in flat int InstanceIndex; @@ -23,16 +24,20 @@ void main() vec3 origin = worldpos + normal * 0.01; #if defined(USE_SUNLIGHT) - vec3 incoming = TraceSunLight(origin, normal, SurfaceIndex); + vec3 incoming = TraceSunLight(origin, normal); #else vec3 incoming = vec3(0.0); #endif for (uint j = LightStart; j < LightEnd; j++) { - incoming += TraceLight(origin, normal, lights[lightIndexes[j]], SurfaceIndex); + incoming += TraceLight(origin, normal, lights[lightIndexes[j]], 0.0); } +#if defined(USE_BOUNCE) + incoming += TraceBounceLight(origin, normal); +#endif + #if defined(USE_AO) incoming.rgb *= TraceAmbientOcclusion(origin, normal); #endif diff --git a/wadsrc/static/shaders/lightmap/trace_bounce.glsl b/wadsrc/static/shaders/lightmap/trace_bounce.glsl new file mode 100644 index 000000000..09b14b310 --- /dev/null +++ b/wadsrc/static/shaders/lightmap/trace_bounce.glsl @@ -0,0 +1,45 @@ + +#include + +vec3 TraceBounceLight(vec3 origin, vec3 normal) +{ + const float minDistance = 0.01; + const float maxDistance = 1000.0; + const int SampleCount = 8; + + vec3 N = normal; + vec3 up = abs(N.x) < abs(N.y) ? vec3(1.0, 0.0, 0.0) : vec3(0.0, 1.0, 0.0); + vec3 tangent = normalize(cross(up, N)); + vec3 bitangent = cross(N, tangent); + vec3 incoming = vec3(0.0); + + for (uint i = 0; i < SampleCount; i++) + { + vec2 Xi = Hammersley(i, SampleCount); + vec3 H = normalize(vec3(Xi.x * 2.0f - 1.0f, Xi.y * 2.0f - 1.0f, 1.5 - length(Xi))); + vec3 L = H.x * tangent + H.y * bitangent + H.z * N; + + TraceResult result = TraceFirstHit(origin, minDistance, L, maxDistance); + + // We hit nothing. + if (result.primitiveIndex == -1) + continue; + + SurfaceInfo surface = GetSurface(result.primitiveIndex); + uint LightStart = surface.LightStart; + uint LightEnd = surface.LightEnd; + vec3 surfacepos = origin + L * result.t; + + float angleAttenuation = max(dot(normal, L), 0.0); + +#if defined(USE_SUNLIGHT) + incoming += TraceSunLight(surfacepos, surface.Normal) * angleAttenuation; +#endif + + for (uint j = LightStart; j < LightEnd; j++) + { + incoming += TraceLight(surfacepos, surface.Normal, lights[lightIndexes[j]], result.t) * angleAttenuation; + } + } + return incoming / float(SampleCount); +} diff --git a/wadsrc/static/shaders/lightmap/trace_light.glsl b/wadsrc/static/shaders/lightmap/trace_light.glsl index 6ab51fc01..aa8980eb4 100644 --- a/wadsrc/static/shaders/lightmap/trace_light.glsl +++ b/wadsrc/static/shaders/lightmap/trace_light.glsl @@ -3,21 +3,17 @@ vec4 TracePointLightRay(vec3 origin, vec3 lightpos, float tmin, vec4 rayColor); -vec3 TraceLight(vec3 origin, vec3 normal, LightInfo light, int surfaceIndex) +vec3 TraceLight(vec3 origin, vec3 normal, LightInfo light, float extraDistance) { const float minDistance = 0.01; vec3 incoming = vec3(0.0); - float dist = distance(light.RelativeOrigin, origin); + float dist = distance(light.RelativeOrigin, origin) + extraDistance; if (dist > minDistance && dist < light.Radius) { vec3 dir = normalize(light.RelativeOrigin - origin); float distAttenuation = max(1.0 - (dist / light.Radius), 0.0); - float angleAttenuation = 1.0f; - if (surfaceIndex >= 0) - { - angleAttenuation = max(dot(normal, dir), 0.0); - } + float angleAttenuation = max(dot(normal, dir), 0.0); float spotAttenuation = 1.0; if (light.OuterAngleCos > -1.0) { diff --git a/wadsrc/static/shaders/lightmap/trace_sunlight.glsl b/wadsrc/static/shaders/lightmap/trace_sunlight.glsl index 01fed131c..727196807 100644 --- a/wadsrc/static/shaders/lightmap/trace_sunlight.glsl +++ b/wadsrc/static/shaders/lightmap/trace_sunlight.glsl @@ -3,15 +3,11 @@ vec4 TraceSunRay(vec3 origin, float tmin, vec3 dir, float tmax, vec4 rayColor); -vec3 TraceSunLight(vec3 origin, vec3 normal, int surfaceIndex) +vec3 TraceSunLight(vec3 origin, vec3 normal) { - float angleAttenuation = 1.0f; - if (surfaceIndex >= 0) - { - angleAttenuation = max(dot(normal, SunDir), 0.0); - if (angleAttenuation == 0.0) - return vec3(0.0); - } + float angleAttenuation = max(dot(normal, SunDir), 0.0); + if (angleAttenuation == 0.0) + return vec3(0.0); const float minDistance = 0.01; vec3 incoming = vec3(0.0);