From d1c6fbe61f6312f45d60e83466d7d1d641b9fbd7 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Tue, 24 Jun 2025 15:04:16 +0200 Subject: [PATCH] Misc lightmapper adjustments --- .../hwrenderer/data/hw_lightmaptile.h | 14 +++--- .../rendering/vulkan/vk_lightmapper.cpp | 43 +++++++++---------- src/common/rendering/vulkan/vk_lightmapper.h | 1 + src/rendering/hwrenderer/doom_levelmesh.cpp | 6 +++ wadsrc/static/shaders/lightmap/frag_blur.glsl | 25 +++++++---- 5 files changed, 53 insertions(+), 36 deletions(-) diff --git a/src/common/rendering/hwrenderer/data/hw_lightmaptile.h b/src/common/rendering/hwrenderer/data/hw_lightmaptile.h index fc06953aa..925bf4589 100644 --- a/src/common/rendering/hwrenderer/data/hw_lightmaptile.h +++ b/src/common/rendering/hwrenderer/data/hw_lightmaptile.h @@ -57,6 +57,9 @@ struct LightmapTile uint16_t SampleDimension = 0; FVector4 Plane = FVector4(0.0f, 0.0f, 1.0f, 0.0f); + // Flats must always use XY axis (slopes may change rapidly in a way that causes artifacts otherwise) + bool UseXYAxis = false; + // Initial tile for surfaces that can be baked in the background bool NeedsInitialBake = false; @@ -69,20 +72,20 @@ struct LightmapTile // Used to track if tile has already been added to the VisibleTiles list for this scene int LastSeen = 0; - FVector2 ToUV(const FVector3& vert) const + /*FVector2 ToUV(const FVector3& vert) const { FVector3 localPos = vert - Transform.TranslateWorldToLocal; float u = (localPos | Transform.ProjLocalToU) / AtlasLocation.Width; float v = (localPos | Transform.ProjLocalToV) / AtlasLocation.Height; return FVector2(u, v); - } + }*/ FVector2 ToUV(const FVector3& vert, float textureSize) const { // Clamp in case the wall moved outside the tile (happens if a lift moves with a static lightmap on it) FVector3 localPos = vert - Transform.TranslateWorldToLocal; - float u = std::max(std::min(localPos | Transform.ProjLocalToU, (float)AtlasLocation.Width), 0.0f); - float v = std::max(std::min(localPos | Transform.ProjLocalToV, (float)AtlasLocation.Height), 0.0f); + float u = std::max(std::min(localPos | Transform.ProjLocalToU, (float)AtlasLocation.Width - 2.0f), 1.0f); + float v = std::max(std::min(localPos | Transform.ProjLocalToV, (float)AtlasLocation.Height - 2.0f), 1.0f); u = (AtlasLocation.X + u) / textureSize; v = (AtlasLocation.Y + v) / textureSize; return FVector2(u, v); @@ -133,7 +136,8 @@ struct LightmapTile FVector3 tCoords[2] = { FVector3(0.0f, 0.0f, 0.0f), FVector3(0.0f, 0.0f, 0.0f) }; int width, height; - switch (BestAxis(Plane)) + PlaneAxis planeAxis = UseXYAxis ? AXIS_XY : BestAxis(Plane); + switch (planeAxis) { default: case AXIS_YZ: diff --git a/src/common/rendering/vulkan/vk_lightmapper.cpp b/src/common/rendering/vulkan/vk_lightmapper.cpp index e9f3b3e36..cd364af99 100644 --- a/src/common/rendering/vulkan/vk_lightmapper.cpp +++ b/src/common/rendering/vulkan/vk_lightmapper.cpp @@ -112,12 +112,13 @@ void VkLightmapper::Raytrace(const TArray& tiles) Blur(); CopyResult(); - if (drawindexed.Pos == drawindexed.BufferSize || copytiles.Pos == drawindexed.BufferSize) + if (drawindexed.IsFull || copytiles.Pos == drawindexed.BufferSize) { fb->GetCommands()->PopGroup(fb->GetCommands()->GetTransferCommands()); fb->WaitForCommands(false); fb->GetCommands()->PushGroup(fb->GetCommands()->GetTransferCommands(), "lightmap.total"); drawindexed.Pos = 0; + drawindexed.IsFull = false; copytiles.Pos = 0; } } @@ -218,12 +219,23 @@ void VkLightmapper::Render() pc.ProjLocalToU = SwapYZ(targetTile->Transform.ProjLocalToU); pc.ProjLocalToV = SwapYZ(targetTile->Transform.ProjLocalToV); - bool buffersFull = false; - // Paint all surfaces visible in the tile visibleSurfaces.Clear(); mesh->GetVisibleSurfaces(targetTile, visibleSurfaces); + + if (drawindexed.Pos + (int)visibleSurfaces.Size() >= drawindexed.BufferSize) + { + // Our indirect draw buffer is full. Mark the remaining tiles as not rendered + while (i < count) + { + selectedTiles[i].Tile->ReceivedNewLight = true; + i++; + } + drawindexed.IsFull = true; + break; + } + for (int surfaceIndex : visibleSurfaces) { LevelMeshSurface* surface = &mesh->Mesh.Surfaces[surfaceIndex]; @@ -238,29 +250,13 @@ void VkLightmapper::Render() drawindexed.Constants[drawindexed.Pos] = pc; drawindexed.Commands[drawindexed.Pos] = cmd; drawindexed.Pos++; - - if (drawindexed.Pos == drawindexed.BufferSize) - { - // Our indirect draw buffer is full. Postpone the rest. - buffersFull = true; - break; - } - } - - if (buffersFull) - { - while (i < count) - { - selectedTiles[i].Tile->ReceivedNewLight = true; - i++; - } - break; } selectedTile.Rendered = true; } - cmdbuffer->drawIndexedIndirect(drawindexed.CommandsBuffer->buffer, startPos * sizeof(VkDrawIndexedIndirectCommand), drawindexed.Pos - startPos, sizeof(VkDrawIndexedIndirectCommand)); + if (drawindexed.Pos > startPos) + cmdbuffer->drawIndexedIndirect(drawindexed.CommandsBuffer->buffer, startPos * sizeof(VkDrawIndexedIndirectCommand), drawindexed.Pos - startPos, sizeof(VkDrawIndexedIndirectCommand)); cmdbuffer->endRenderPass(); @@ -922,6 +918,9 @@ void VkLightmapper::CreateCopyPipeline() .Create(fb->GetDevice()); copy.sampler = SamplerBuilder() + .MinFilter(VK_FILTER_NEAREST) + .MagFilter(VK_FILTER_NEAREST) + .MipmapMode(VK_SAMPLER_MIPMAP_MODE_NEAREST) .DebugName("copy.Sampler") .Create(fb->GetDevice()); } @@ -1006,7 +1005,7 @@ void VkLightmapper::CreateBakeImage() .AddCombinedImageSampler(bakeImage.resolve.DescriptorSet.get(), 0, bakeImage.raytrace.View.get(), resolve.sampler.get(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) .AddCombinedImageSampler(bakeImage.blur.DescriptorSet[0].get(), 0, bakeImage.resolve.View.get(), blur.sampler.get(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) .AddCombinedImageSampler(bakeImage.blur.DescriptorSet[1].get(), 0, bakeImage.blur.View.get(), blur.sampler.get(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) - .AddCombinedImageSampler(bakeImage.copy.DescriptorSet.get(), 0, bakeImage.resolve.View.get(), blur.sampler.get(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) + .AddCombinedImageSampler(bakeImage.copy.DescriptorSet.get(), 0, bakeImage.resolve.View.get(), copy.sampler.get(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) .AddBuffer(bakeImage.copy.DescriptorSet.get(), 1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, copytiles.Buffer.get()) .Execute(fb->GetDevice()); } diff --git a/src/common/rendering/vulkan/vk_lightmapper.h b/src/common/rendering/vulkan/vk_lightmapper.h index f8f674123..88f68ed45 100644 --- a/src/common/rendering/vulkan/vk_lightmapper.h +++ b/src/common/rendering/vulkan/vk_lightmapper.h @@ -175,6 +175,7 @@ private: VkDrawIndexedIndirectCommand* Commands = nullptr; LightmapRaytracePC* Constants = nullptr; int Pos = 0; + bool IsFull = false; } drawindexed; struct diff --git a/src/rendering/hwrenderer/doom_levelmesh.cpp b/src/rendering/hwrenderer/doom_levelmesh.cpp index cb002d1cf..83a39537f 100644 --- a/src/rendering/hwrenderer/doom_levelmesh.cpp +++ b/src/rendering/hwrenderer/doom_levelmesh.cpp @@ -515,6 +515,7 @@ void DoomLevelMesh::BuildSubsectorVisibilityLists(FLevelLocals& doomMap) // Always bake the subsector VisibleSubsectors[i].Push(i); + sub->validcount = validcount; stack.Push(sub); @@ -1465,6 +1466,10 @@ void DoomLevelMesh::CreateFlat(FLevelLocals& doomMap, unsigned int sectorIndex) sinfo.NextSubsectorSurface = SubsectorSurfaces[subsectorIndex]; SubsectorSurfaces[subsectorIndex] = surf; } + else + { + sinfo.NextSubsectorSurface = -1; + } surf = sinfo.NextSurface; } } @@ -1749,6 +1754,7 @@ int DoomLevelMesh::AddSurfaceToTile(const DoomSurfaceInfo& info, const LevelMesh tile.Plane = surf.Plane; tile.SampleDimension = GetSampleDimension(sampleDimension); tile.UseCount = 1; + tile.UseXYAxis = (info.Type == ST_CEILING || info.Type == ST_FLOOR); int index = AllocTile(tile); Lightmap.AddedTiles.Push(index); diff --git a/wadsrc/static/shaders/lightmap/frag_blur.glsl b/wadsrc/static/shaders/lightmap/frag_blur.glsl index 26c96bf82..b46290ad8 100644 --- a/wadsrc/static/shaders/lightmap/frag_blur.glsl +++ b/wadsrc/static/shaders/lightmap/frag_blur.glsl @@ -8,7 +8,7 @@ vec4 centerFragColor; vec4 clampedSample(vec4 f) { - return f != vec4(0, 0, 0, 0) ? f : centerFragColor; + return f.a != 0.0 ? f : centerFragColor; } void main() @@ -18,15 +18,22 @@ void main() centerFragColor = textureOffset(tex, texCoord, ivec2(0, 0)); + if (centerFragColor.a != 0.0) + { #if defined(BLUR_HORIZONTAL) - fragcolor = - centerFragColor * 0.5 + - clampedSample(textureOffset(tex, texCoord, ivec2( 1, 0))) * 0.25 + - clampedSample(textureOffset(tex, texCoord, ivec2(-1, 0))) * 0.25; + fragcolor = + centerFragColor * 0.5 + + clampedSample(textureOffset(tex, texCoord, ivec2( 1, 0))) * 0.25 + + clampedSample(textureOffset(tex, texCoord, ivec2(-1, 0))) * 0.25; #else - fragcolor = - centerFragColor * 0.5 + - clampedSample(textureOffset(tex, texCoord, ivec2(0, 1))) * 0.25 + - clampedSample(textureOffset(tex, texCoord, ivec2(0,-1))) * 0.25; + fragcolor = + centerFragColor * 0.5 + + clampedSample(textureOffset(tex, texCoord, ivec2(0, 1))) * 0.25 + + clampedSample(textureOffset(tex, texCoord, ivec2(0,-1))) * 0.25; #endif + } + else + { + fragcolor = centerFragColor; + } }