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

如何在片元着色器中计算Godot 4风格的EYEDIR像素方向?

解决全屏天空着色器的EYEDIR(世界空间像素方向)计算问题

核心思路

全屏天空的本质是计算从相机位置出发,指向当前片元的世界空间方向向量,该向量需要完全匹配相机的投影参数(FOV、宽高比)与姿态(旋转),步骤为:窗口坐标 → NDC空间 → 逆投影转眼空间方向 → 逆视图转世界空间方向。

正确实现代码(适配Vulkan)

需要传入以下Uniform变量:

  • mat4 invProj:相机投影矩阵的逆矩阵
  • mat4 invView:相机视图矩阵的逆矩阵(即相机的世界变换矩阵)
  • vec2 screenSize:当前窗口的分辨率(宽、高)
vec3 getWorldSpaceEyeDir() {
    // 1. 将窗口坐标转换为NDC空间(处理Vulkan Y轴翻转:Vulkan的gl_FragCoord.y从底部到顶部,需转为标准NDC的Y轴方向)
    vec2 ndc = (2.0 * gl_FragCoord.xy) / screenSize - 1.0;
    ndc.y = -ndc.y;

    // 2. 构造NDC空间的无限远射线方向(z取-1.0对应眼空间的远平面方向,w=1.0确保投影转换正确)
    vec4 ndcRay = vec4(ndc, -1.0, 1.0);

    // 3. 通过逆投影矩阵转换为眼空间方向向量(w设为0.0消除平移影响)
    vec4 eyeRay = invProj * ndcRay;
    eyeRay.w = 0.0;
    vec3 eyeDir = normalize(eyeRay.xyz);

    // 4. 通过逆视图矩阵转换为世界空间方向向量
    vec4 worldRay = invView * vec4(eyeDir, 0.0);
    vec3 worldDir = normalize(worldRay.xyz);

    return worldDir;
}

你之前方法的问题分析

  1. Khronos文章方法错误点:

    • 误用了gl_FragCoord.z:全屏正交渲染的片元深度值并非场景的真实深度,导致转换后的眼空间方向错误。
    • 缺少逆视图矩阵转换:仅通过逆投影得到的是眼空间方向,未转换到世界空间,因此相机旋转时天空无变化。
    • 未处理Vulkan Y轴差异:Vulkan的窗口坐标Y轴与标准NDC方向相反,未翻转会导致窗口缩放时天空拉伸。
  2. 相机坐标系转换方法错误点:

    • 未应用投影矩阵的FOV缩放:直接通过轴向量组合的方向未考虑视场角带来的像素方向畸变,导致不支持FOV调整。
    • 轴映射逻辑错误:你的坐标系以Z为向上轴,但代码中使用forward * p.y等组合方式与Godot的Y向上、-Z向前的坐标系不匹配,导致天空转动时扭曲翻转。

Godot 4的EYEDIR原理

Godot 4中用于天空渲染的视图方向向量(对应你的EYEDIR),核心逻辑与上述实现一致:

  1. 将屏幕像素坐标转换为NDC空间,处理平台相关的轴方向差异。
  2. 通过逆投影矩阵将NDC向量转换为眼空间的射线方向。
  3. 通过相机的世界变换矩阵(即逆视图矩阵)将眼空间方向转换为世界空间方向,确保与场景渲染的相机姿态、投影参数完全匹配。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 09:32:11