diff --git a/src/common/rendering/hwrenderer/data/hw_lightmaptile.h b/src/common/rendering/hwrenderer/data/hw_lightmaptile.h index ae56a1a2f..dbfdb7dd9 100644 --- a/src/common/rendering/hwrenderer/data/hw_lightmaptile.h +++ b/src/common/rendering/hwrenderer/data/hw_lightmaptile.h @@ -48,6 +48,14 @@ struct LightmapTile FVector3 ProjLocalToV = { 0.0f, 0.0f, 0.0f }; } Transform; + // Calculate world coordinates from UV coordinates + struct + { + FVector3 WorldOrigin; + FVector3 WorldU; + FVector3 WorldV; + } InverseTransform; + int UseCount = 0; bool AddedThisFrame = false; @@ -180,14 +188,43 @@ struct LightmapTile height = textureSize; } - Transform.TranslateWorldToLocal.X = uvMin.X * SampleDimension + 0.1f; - Transform.TranslateWorldToLocal.Y = uvMin.Y * SampleDimension + 0.1f; - Transform.TranslateWorldToLocal.Z = uvMin.Z * SampleDimension + 0.1f; + uvMin *= (float)SampleDimension; + uvMax *= (float)SampleDimension; + + Transform.TranslateWorldToLocal.X = uvMin.X + 0.1f; + Transform.TranslateWorldToLocal.Y = uvMin.Y + 0.1f; + Transform.TranslateWorldToLocal.Z = uvMin.Z + 0.1f; Transform.ProjLocalToU = tCoords[0]; Transform.ProjLocalToV = tCoords[1]; + switch (planeAxis) + { + default: + case AXIS_YZ: + InverseTransform.WorldOrigin = PointAtYZ(uvMin.Y, uvMin.Z); + InverseTransform.WorldU = PointAtYZ(uvMax.Y, uvMin.Z); + InverseTransform.WorldV = PointAtYZ(uvMin.Y, uvMax.Z); + break; + + case AXIS_XZ: + InverseTransform.WorldOrigin = PointAtXZ(uvMin.X, uvMin.Z); + InverseTransform.WorldU = PointAtXZ(uvMax.X, uvMin.Z); + InverseTransform.WorldV = PointAtXZ(uvMin.X, uvMax.Z); + break; + + case AXIS_XY: + InverseTransform.WorldOrigin = PointAtXY(uvMin.X, uvMin.Y); + InverseTransform.WorldU = PointAtXY(uvMax.X, uvMin.Y); + InverseTransform.WorldV = PointAtXY(uvMin.X, uvMax.Y); + break; + } + AtlasLocation.Width = width; AtlasLocation.Height = height; } + + FVector3 PointAtYZ(float y, float z) const { return FVector3(-(Plane.Y * y + Plane.Z * z + Plane.W) / Plane.X, y, z); } + FVector3 PointAtXZ(float x, float z) const { return FVector3(x, -(Plane.X * x + Plane.Z * z + Plane.W) / Plane.Y, z); } + FVector3 PointAtXY(float x, float y) const { return FVector3(x, y, -(Plane.X * x + Plane.Y * y + Plane.W) / Plane.Z); } }; diff --git a/src/common/rendering/vulkan/vk_lightmapper.cpp b/src/common/rendering/vulkan/vk_lightmapper.cpp index e8bdc1f4b..a748ee5e5 100644 --- a/src/common/rendering/vulkan/vk_lightmapper.cpp +++ b/src/common/rendering/vulkan/vk_lightmapper.cpp @@ -414,7 +414,10 @@ void VkLightmapper::CopyResult() for (unsigned int i = 0, count = copylists.Size(); i < count; i++) { if (copylists[i].Size() > 0) + { barrier0.AddImage(destTexture[i].Light.Image.get(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_ACCESS_SHADER_READ_BIT, VK_ACCESS_COLOR_ATTACHMENT_READ_BIT, VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1); + barrier0.AddImage(destTexture[i].Probe.Image.get(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_ACCESS_SHADER_READ_BIT, VK_ACCESS_COLOR_ATTACHMENT_READ_BIT, VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1); + } } barrier0.Execute(cmdbuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); @@ -433,20 +436,31 @@ void VkLightmapper::CopyResult() auto& framebuffer = destTexture[i].Light.LMFramebuffer; if (!framebuffer) { - auto& view = destTexture[i].Light.LMView; - if (!view) + auto& lightView = destTexture[i].Light.LMView; + if (!lightView) { - view = ImageViewBuilder() + lightView = ImageViewBuilder() .Type(VK_IMAGE_VIEW_TYPE_2D) .Image(destTexture[i].Light.Image.get(), VK_FORMAT_R16G16B16A16_SFLOAT, VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1, 1) - .DebugName("LMView") + .DebugName("LMLightView") + .Create(fb->GetDevice()); + } + + auto& probeView = destTexture[i].Probe.LMView; + if (!probeView) + { + probeView = ImageViewBuilder() + .Type(VK_IMAGE_VIEW_TYPE_2D) + .Image(destTexture[i].Probe.Image.get(), VK_FORMAT_R16_UINT, VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1, 1) + .DebugName("LMProbeView") .Create(fb->GetDevice()); } framebuffer = FramebufferBuilder() .RenderPass(copy.renderPass.get()) .Size(destSize, destSize) - .AddAttachment(view.get()) + .AddAttachment(lightView.get()) + .AddAttachment(probeView.get()) .DebugName("LMFramebuffer") .Create(fb->GetDevice()); } @@ -464,6 +478,9 @@ void VkLightmapper::CopyResult() copyinfo->DestPosY = tile->AtlasLocation.Y; copyinfo->TileWidth = tile->AtlasLocation.Width; copyinfo->TileHeight = tile->AtlasLocation.Height; + copyinfo->WorldOrigin = tile->InverseTransform.WorldOrigin; + copyinfo->WorldU = tile->InverseTransform.WorldU; + copyinfo->WorldV = tile->InverseTransform.WorldV; } // Draw the tiles. One instance per tile. @@ -499,7 +516,10 @@ void VkLightmapper::CopyResult() for (unsigned int i = 0, count = copylists.Size(); i < count; i++) { if (copylists[i].Size() > 0) + { barrier1.AddImage(destTexture[i].Light.Image.get(), VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT, VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1); + barrier1.AddImage(destTexture[i].Probe.Image.get(), VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT, VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1); + } } barrier1.Execute(cmdbuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); @@ -883,8 +903,16 @@ void VkLightmapper::CreateCopyPipeline() VK_ATTACHMENT_STORE_OP_STORE, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) + .AddAttachment( + VK_FORMAT_R16_UINT, + VK_SAMPLE_COUNT_1_BIT, + VK_ATTACHMENT_LOAD_OP_LOAD, + VK_ATTACHMENT_STORE_OP_STORE, + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) .AddSubpass() .AddSubpassColorAttachmentRef(0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) + .AddSubpassColorAttachmentRef(1, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) .AddExternalSubpassDependency( VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, @@ -900,6 +928,8 @@ void VkLightmapper::CreateCopyPipeline() .AddFragmentShader(shaders.fragCopy) .Topology(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP) .AddDynamicState(VK_DYNAMIC_STATE_VIEWPORT) + .AddColorBlendAttachment(ColorBlendAttachmentBuilder().Create()) + .AddColorBlendAttachment(ColorBlendAttachmentBuilder().Create()) .Viewport(0.0f, 0.0f, 0.0f, 0.0f) .Scissor(0, 0, 4096, 4096) .DebugName("copy.pipeline") diff --git a/src/common/rendering/vulkan/vk_lightmapper.h b/src/common/rendering/vulkan/vk_lightmapper.h index 88f68ed45..ce762fc3d 100644 --- a/src/common/rendering/vulkan/vk_lightmapper.h +++ b/src/common/rendering/vulkan/vk_lightmapper.h @@ -95,10 +95,14 @@ struct CopyTileInfo int TileHeight; int Padding1; int Padding2; + FVector3 WorldOrigin; + float Padding3; + FVector3 WorldU; + float Padding4; + FVector3 WorldV; + float Padding5; }; -static_assert(sizeof(CopyTileInfo) == sizeof(int32_t) * 8); - class VkLightmapper { public: diff --git a/wadsrc/static/shaders/lightmap/frag_copy.glsl b/wadsrc/static/shaders/lightmap/frag_copy.glsl index 77f683bab..53f7834b3 100644 --- a/wadsrc/static/shaders/lightmap/frag_copy.glsl +++ b/wadsrc/static/shaders/lightmap/frag_copy.glsl @@ -2,9 +2,15 @@ layout(set = 0, binding = 0) uniform sampler2D Tex; layout(location = 0) in vec2 TexCoord; +layout(location = 1) in vec3 WorldPos; + layout(location = 0) out vec4 FragColor; +layout(location = 1) out uvec4 FragProbe; void main() { + uint probeIndex = 0; + FragColor = texture(Tex, TexCoord); + FragProbe.x = probeIndex; } diff --git a/wadsrc/static/shaders/lightmap/vert_copy.glsl b/wadsrc/static/shaders/lightmap/vert_copy.glsl index c73b6b6de..966dedcf0 100644 --- a/wadsrc/static/shaders/lightmap/vert_copy.glsl +++ b/wadsrc/static/shaders/lightmap/vert_copy.glsl @@ -13,6 +13,12 @@ struct TileCopy ivec2 DestPos; ivec2 TileSize; int Padding1, Padding2; + vec3 WorldOrigin; + float Padding3; + vec3 WorldU; + float Padding4; + vec3 WorldV; + float Padding5; }; layout(std430, set = 0, binding = 1) buffer readonly CopyBuffer @@ -21,6 +27,7 @@ layout(std430, set = 0, binding = 1) buffer readonly CopyBuffer }; layout(location = 0) out vec2 TexCoord; +layout(location = 1) out vec3 WorldPos; vec2 positions[4] = vec2[]( vec2(0.0, 0.0), @@ -38,4 +45,5 @@ void main() gl_Position = vec4(dest * 2.0 - 1.0, 0.0, 1.0); TexCoord = src; + WorldPos = tile.WorldOrigin + tile.WorldU * uv.x + tile.WorldV * uv.y; } diff --git a/wadsrc/static/shaders/scene/binding_textures.glsl b/wadsrc/static/shaders/scene/binding_textures.glsl index 4f89e3609..95e976ae0 100644 --- a/wadsrc/static/shaders/scene/binding_textures.glsl +++ b/wadsrc/static/shaders/scene/binding_textures.glsl @@ -1,6 +1,7 @@ layout(set = 2, binding = 0) uniform sampler2D textures[]; layout(set = 2, binding = 0) uniform samplerCube cubeTextures[]; +layout(set = 2, binding = 0) uniform usampler2D uintTextures[]; const int tex = 0; const int texture2 = 1; diff --git a/wadsrc/static/shaders/scene/lightmodel_pbr.glsl b/wadsrc/static/shaders/scene/lightmodel_pbr.glsl index e21091d81..ac882eb2b 100644 --- a/wadsrc/static/shaders/scene/lightmodel_pbr.glsl +++ b/wadsrc/static/shaders/scene/lightmodel_pbr.glsl @@ -176,11 +176,11 @@ vec3 ProcessMaterialLight(Material material, vec3 ambientLight, float sunlightAt vec3 irradiance, prefilteredColor; - /*if (vLightmapIndex != -1) + if (vLightmapIndex != -1) { uvec4 probeIndexes = textureGather(uintTextures[nonuniformEXT(vLightmapIndex + 1)], vLightmap.xy); - vec2 t = frac(vLightmap.xy); + vec2 t = fract(vLightmap.xy); vec2 invt = 1.0 - t; float t00 = invt.x * invt.y; float t10 = t.x * invt.y; @@ -200,7 +200,7 @@ vec3 ProcessMaterialLight(Material material, vec3 ambientLight, float sunlightAt irradiance = irradiance0 * t00 + irradiance1 * t10 + irradiance2 * t01 + irradiance3 * t11; prefilteredColor = prefilteredColor0 * t00 + prefilteredColor1 * t10 + prefilteredColor2 * t01 + prefilteredColor3 * t11; } - else*/ + else { irradiance = texture(cubeTextures[uLightProbeIndex], N).rgb; prefilteredColor = textureLod(cubeTextures[uLightProbeIndex + 1], R, roughness * MAX_REFLECTION_LOD).rgb;