From 9d114ae4fec465baed381de7782ef42ca77e734b Mon Sep 17 00:00:00 2001 From: skal Date: Sun, 8 Mar 2026 09:13:57 +0100 Subject: fix(shaders): enforce y-up screen-space convention + document coordinate conventions - Add textureSampleYUp() helper to fullscreen_uv_vs.wgsl to correct y-flip when sampling WebGPU textures with y-up UV coordinates - Use textureSampleYUp() in passthrough, gaussian_blur, combined_postprocess - Fix skybox.wgsl: remove erroneous (1.0 - uv.y) flip (double-flip bug) - Document world/view/screen conventions in doc/3D.md, camera_common.wgsl, and fullscreen_uv_vs.wgsl Co-Authored-By: Claude Sonnet 4.6 --- src/shaders/render/fullscreen_uv_vs.wgsl | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) (limited to 'src/shaders/render/fullscreen_uv_vs.wgsl') diff --git a/src/shaders/render/fullscreen_uv_vs.wgsl b/src/shaders/render/fullscreen_uv_vs.wgsl index f9ae427..5f76160 100644 --- a/src/shaders/render/fullscreen_uv_vs.wgsl +++ b/src/shaders/render/fullscreen_uv_vs.wgsl @@ -1,15 +1,29 @@ // Common vertex shader for fullscreen post-processing effects. -// Draws a single triangle that covers the entire screen, with uv -// coordinates in [0..1] +// Draws a single triangle that covers the entire screen. +// +// Screen-space convention: Y-UP, origin at BOTTOM-LEFT +// uv in [0,1]: (0,0) = bottom-left, (1,1) = top-right +// st in [-1,1]: NDC directly, y-up +// +// WebGPU textures are Y-DOWN ((0,0) at top-left). +// Use textureSampleYUp() instead of textureSample() when sampling with uv. struct VertexOutput { - @builtin(position) position: vec4f, - @location(0) uv: vec2f, + @builtin(position) position: vec4f, // in pixel screen units + @location(0) uv: vec2f, // in [0, 1] + @location(1) st: vec2f, // in [-1, 1] }; @vertex fn vs_main(@builtin(vertex_index) i: u32) -> VertexOutput { - let pos = array(vec4f(-1, -1, 0, 1.), vec4f(3, -1, 2., 1.), vec4f(-1, 3, 0, -1)); + let pos = array(vec4f(-1, -1, 0, 0.), vec4f(3, -1, 2., 0.), vec4f(-1, 3, 0, 2.)); var out: VertexOutput; out.position = vec4f(pos[i].xy, 0.0, 1.0); out.uv = pos[i].zw; + out.st = pos[i].xy; return out; } + +// Sample a texture using y-up UV coordinates (uv.y=0 at bottom). +// Flips Y to match WebGPU texture convention (texel (0,0) at top-left). +fn textureSampleYUp(tex: texture_2d, s: sampler, uv: vec2f) -> vec4f { + return textureSample(tex, s, vec2f(uv.x, 1.0 - uv.y)); +} -- cgit v1.2.3