Add tile world position information to lightmapper copy pass

This commit is contained in:
Magnus Norddahl 2025-07-19 02:28:19 +02:00
commit 1efa5b19cd
7 changed files with 99 additions and 13 deletions

View file

@ -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); }
};

View file

@ -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")

View file

@ -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:

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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;

View file

@ -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;