fix: move light data from UBO to push constants — fixes std140 layout issue

Root cause: GLSL std140 layout adds padding after mat4 for vec4 fields,
causing light data to be read at wrong offsets → NaN/artifacts.

Fix:
- UBO back to 64 bytes (mat4 vp only)
- Light data (pos + color, 32 bytes) sent via push constants at offset 64
- Two push constant ranges: Vertex (0-64, model) + Fragment (64-96, light)
- Both vertex and fragment shaders read from same push_constant block
- PBR shader fully restored with Cook-Torrance BRDF
- Dynamic point light follows physics ball
This commit is contained in:
emil28092005
2026-06-18 19:53:45 +03:00
parent ad8a14a4f7
commit 1dde764342
7 changed files with 110 additions and 24 deletions
+12 -9
View File
@@ -100,14 +100,10 @@ internal sealed unsafe class VulkanRenderer : IRenderer, Engine.Graphics.IScreen
});
}
// Pack UBO: mat4 vp (64 bytes) + vec4 lightPos (16) + vec4 lightColor (16) = 96 bytes
var uboData = stackalloc byte[128];
// Pack UBO: just mat4 vp (64 bytes)
var uboData = stackalloc byte[64];
var vpCopy = vp;
System.Buffer.MemoryCopy(&vpCopy, uboData, 64, 64);
var lpCopy = lightPos;
System.Buffer.MemoryCopy(&lpCopy, uboData + 64, 16, 16);
var lcCopy = lightColor;
System.Buffer.MemoryCopy(&lcCopy, uboData + 80, 16, 16);
var drawCalls = new List<(VkBuffer vertexBuf, VkBuffer indexBuf, uint indexCount, Matrix4x4 model)>();
@@ -127,10 +123,10 @@ internal sealed unsafe class VulkanRenderer : IRenderer, Engine.Graphics.IScreen
drawCalls.Add((entry.vb.Buffer, entry.ib.Buffer, entry.indexCount, t.GetMatrix()));
});
Render(vp, drawCalls, uboData);
Render(vp, drawCalls, uboData, lightPos, lightColor);
}
private void Render(Matrix4x4 vp, List<(VkBuffer vertexBuf, VkBuffer indexBuf, uint indexCount, Matrix4x4 model)> drawCalls, byte* uboData)
private void Render(Matrix4x4 vp, List<(VkBuffer vertexBuf, VkBuffer indexBuf, uint indexCount, Matrix4x4 model)> drawCalls, byte* uboData, Vector4 lightPos, Vector4 lightColor)
{
_frameResources.WaitFrame(_frameIndex);
@@ -142,7 +138,7 @@ internal sealed unsafe class VulkanRenderer : IRenderer, Engine.Graphics.IScreen
{
_swapchain.Recreate(_ctx.SurfaceExtent.Width == 0 ? 1280 : (int)_ctx.SurfaceExtent.Width,
_ctx.SurfaceExtent.Height == 0 ? 720 : (int)_ctx.SurfaceExtent.Height);
Render(vp, drawCalls, uboData);
Render(vp, drawCalls, uboData, lightPos, lightColor);
return;
}
@@ -250,6 +246,13 @@ internal sealed unsafe class VulkanRenderer : IRenderer, Engine.Graphics.IScreen
var model = dc.model;
Vk.vkCmdPushConstants(cmd, _pipeline.PipelineLayout, VkShaderStageFlags.Vertex, 0, 64, &model);
// Light data as push constants at offset 64 (fragment stage)
var lpCopy = lightPos;
Vk.vkCmdPushConstants(cmd, _pipeline.PipelineLayout, VkShaderStageFlags.Fragment, 64, 16, &lpCopy);
var lcCopy = lightColor;
Vk.vkCmdPushConstants(cmd, _pipeline.PipelineLayout, VkShaderStageFlags.Fragment, 80, 16, &lcCopy);
Vk.vkCmdDrawIndexed(cmd, dc.indexCount, 1, 0, 0, 0);
}