diff --git a/src/AcDream.App/Rendering/Shaders/spv/shaders.manifest.json b/src/AcDream.App/Rendering/Shaders/spv/shaders.manifest.json index 277e5146..0bd707cb 100644 --- a/src/AcDream.App/Rendering/Shaders/spv/shaders.manifest.json +++ b/src/AcDream.App/Rendering/Shaders/spv/shaders.manifest.json @@ -105,9 +105,8 @@ "stages": [ { "stage": "vert", - "sourceSha256": "4de580ce11b8d755d3558dc49bf7ebccec54d307595d91c38b5c5d552d645c7e", - "compiled": false, - "message": "terrain_modern.vert:221: error: \u0027uProjection\u0027 : undeclared identifier" + "sourceSha256": "336880b293e95c9ba13dce7a616a15e941191afec8bdaabe04a4993182eb6811", + "compiled": true }, { "stage": "frag", diff --git a/src/AcDream.App/Rendering/Shaders/terrain_modern.vert b/src/AcDream.App/Rendering/Shaders/terrain_modern.vert index db8224ef..254b948e 100644 --- a/src/AcDream.App/Rendering/Shaders/terrain_modern.vert +++ b/src/AcDream.App/Rendering/Shaders/terrain_modern.vert @@ -13,8 +13,16 @@ layout(location = 3) in uvec4 aPacked1; layout(location = 4) in uvec4 aPacked2; layout(location = 5) in uvec4 aPacked3; -uniform mat4 uView; -uniform mat4 uProjection; +// Campaign V slice V6f-1: uView/uProjection converged into the single +// uViewProjection that GpuPushConstants already carries, so terrain can be +// expressed in Vulkan GLSL at all — two loose mat4 uniforms are 128 bytes and +// cannot both fit the pinned 96-byte push block, and Vulkan GLSL has no default +// uniform block to hold them loose. The product is now formed on the CPU +// (camera.View * camera.Projection) instead of per vertex here; the two are the +// same transform, and System.Numerics' row-vector layout uploaded untransposed +// reads in GLSL as the transpose, so (View*Proj)^T == Proj^T * View^T is exactly +// the uProjection * uView this replaced. +uniform mat4 uViewProjection; struct Light { vec4 posAndKind; @@ -165,7 +173,7 @@ void main() { // the un-nudged heightmap via TerrainSurface.SampleZ. // Closes issue #100; supersedes the hiddenTerrainCells cell-collapse hack. vec3 terrainPos = vec3(aPos.xy, aPos.z - 0.01); - gl_Position = uProjection * uView * vec4(terrainPos, 1.0); + gl_Position = uViewProjection * vec4(terrainPos, 1.0); // Phase U.3: terrain clip gate against the single OutsideView region. With // uTerrainClipCount == 0 (U.3 default) the first loop is skipped and the diff --git a/src/AcDream.App/Rendering/TerrainModernRenderer.cs b/src/AcDream.App/Rendering/TerrainModernRenderer.cs index 643a2d1a..1308248f 100644 --- a/src/AcDream.App/Rendering/TerrainModernRenderer.cs +++ b/src/AcDream.App/Rendering/TerrainModernRenderer.cs @@ -494,15 +494,18 @@ public sealed unsafe class TerrainModernRenderer : IDisposable // Bind shader + uniforms + atlas handles. // Verified Phase W Stage 4 (T4.2): terrain projects from the camera view-proj; - // no separate landscape viewpoint to sync. Both uView and uProjection derive - // from the ICamera passed into this method — the same camera used for all other + // no separate landscape viewpoint to sync. uViewProjection derives from + // the ICamera passed into this method — the same camera used for all other // renderers in the unified pipeline. Retail's LScape::update_viewpoint // pre-positions terrain to the outdoor landcell, but acdream uses the // unified camera matrix everywhere, so no separate viewpoint divergence can occur. _shader.Use(); UploadTextureTilingOnce(); - _shader.SetMatrix4("uView", camera.View); - _shader.SetMatrix4("uProjection", camera.Projection); + // Campaign V slice V6f-1: one uViewProjection, matching the field + // GpuPushConstants already carries, instead of the separate uView and + // uProjection the shader used to combine per vertex. viewProjection is + // the same product the visibility pass above already computed. + _shader.SetMatrix4("uViewProjection", viewProjection); var (terrainHandle, alphaHandle) = _atlas.GetBindlessHandles(); // Campaign V slice V2b: pass each handle's binding=9 table slot