You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将global_invocation_id转换为裁剪空间坐标?(深度转世界坐标)

正确的GID到裁剪空间转换方案

结论:第三种方案是正确的,也是图形编程中像素索引转UV坐标的标准做法。

方案分析

1. 初步实现(存在偏移问题)

let uv = vec2f(gid.xy) / screen_size;
let clip_space = vec2(uv.x, 1.0 - uv.y) * 2.0 - 1.0;

该方案将像素索引直接作为坐标除以屏幕尺寸,得到的是像素左下角的UV坐标,而非像素中心。对于右下角像素(screen_width-1, screen_height-1),计算出的UV是((w-1)/w, (h-1)/h),转换到裁剪空间后无法匹配对应坐标系的右下角位置,且采样深度时会和深度缓冲区存储的像素中心深度值不匹配,导致坐标偏移。

2. 第二种方案(边缘错误+非中心对齐)

let uv = vec2f(gid.xy) / (screen_size - vec2f(1.0));

虽然该方案能让右下角像素的UV达到(1,1),但计算的是像素右下角的坐标,同样不是像素中心,会导致深度采样偏差。此外当屏幕尺寸为1时,会出现除以0的错误,存在兼容性隐患。

3. 第三种方案(正确的像素中心对齐)

let uv = (vec2f(gid.xy) + vec2f(0.5)) / screen_size;
let clip_space = vec2(uv.x, 1.0 - uv.y) * 2.0 - 1.0;

这是图形编程中的标准做法:

  • gid.xy是像素的索引,每个像素的中心坐标为gid.xy + 0.5
  • 除以屏幕尺寸后得到像素中心的UV坐标,与深度缓冲区中存储的每个texel对应的深度值完全匹配
  • 转换到裁剪空间后,左上角像素中心对应裁剪空间的(-1, 1),右下角像素中心对应(1, -1)(符合WebGPU的NDC坐标系规则),确保坐标转换的准确性

完整的深度转世界坐标代码

let depth = textureLoad(depth_buffer, gid.xy, 0);
let uv = (vec2f(gid.xy) + vec2f(0.5)) / screen_size;
let clip_space = vec2(uv.x, 1.0 - uv.y) * 2.0 - 1.0;
let world_space_hc = inverse_view_proj_matrix * vec4(clip_space, depth, 1.0);
let world_space = world_space_hc.xyz / world_space_hc.w;

内容的提问来源于stack exchange,提问作者Lukas Kalbertodt

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 17:53:19