如何在片元着色器中计算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; }
你之前方法的问题分析
Khronos文章方法错误点:
- 误用了
gl_FragCoord.z:全屏正交渲染的片元深度值并非场景的真实深度,导致转换后的眼空间方向错误。 - 缺少逆视图矩阵转换:仅通过逆投影得到的是眼空间方向,未转换到世界空间,因此相机旋转时天空无变化。
- 未处理Vulkan Y轴差异:Vulkan的窗口坐标Y轴与标准NDC方向相反,未翻转会导致窗口缩放时天空拉伸。
- 误用了
相机坐标系转换方法错误点:
- 未应用投影矩阵的FOV缩放:直接通过轴向量组合的方向未考虑视场角带来的像素方向畸变,导致不支持FOV调整。
- 轴映射逻辑错误:你的坐标系以Z为向上轴,但代码中使用
forward * p.y等组合方式与Godot的Y向上、-Z向前的坐标系不匹配,导致天空转动时扭曲翻转。
Godot 4的EYEDIR原理
Godot 4中用于天空渲染的视图方向向量(对应你的EYEDIR),核心逻辑与上述实现一致:
- 将屏幕像素坐标转换为NDC空间,处理平台相关的轴方向差异。
- 通过逆投影矩阵将NDC向量转换为眼空间的射线方向。
- 通过相机的世界变换矩阵(即逆视图矩阵)将眼空间方向转换为世界空间方向,确保与场景渲染的相机姿态、投影参数完全匹配。
内容的提问来源于stack exchange,提问作者Tristan367
相关产品推荐
相关产品推荐

