shader着色器变量gl_FragCoord 的含义

网友投稿 234 2022-09-22

shader着色器变量gl_FragCoord 的含义

版权:

​​liujing7256​​

前言

当我们编写shader着色器程序的时候,经常看到shader内置变量,gl_Position,gl_FragCoord,感觉一头雾水。

详解

1. gl_Position:

#version 330 corelayout (location = 0) in vec3 aPos; // 位置变量的属性位置值为0out vec4 vertexColor; // 为片段着色器指定一个颜色输出void main(){ gl_Position = vec4(aPos, 1.0); // 注意我们如何把一个vec3作为vec4的构造器的参数 vertexColor = vec4(0.5, 0.0, 0.0, 1.0); // 把输出变量设置为暗红色}

2. gl_FragCoord

gl_FragCoord 表示当前片元着色器处理的候选片元窗口相对坐标信息,是一个 vec4 类型的变量 (x, y, z, 1/w), 其中 x, y 是当前片元的窗口坐标,OpenGL 默认以窗口左下角为原点, 在 着色器中通过布局限定符可以重新设定原点,比如窗口左上角为原点 ​​origin_upper_left​​,窗口大小由 glViewport() 函数指定。x, y 默认是像素中心 而非 整数, 原点 的窗口坐标值为 (0.5, 0.5), 小数部分恒为 0.5, 当viewport 范围 为(0,0,800,600)时, x, y 的取值范围为(0.5, 0.5, 799.5, 599.5), 当在着色器中布局限定符设置为 pixel_center_integer 时, x, y 取值为整数。

第三个分量 z 表示的是当前片元的深度信息,由 vertex shader 处理过后系统插值得到, gl_FragCoord.z 的产生过程:

假设 OpenGL 变换的各坐标系统定义如下: world.xyzw 表示 世界坐标系的坐标, eye.xyzw 表示眼坐标系(也叫观察坐标系,还有叫相机坐标系,呃。。。) 的坐标, clip.xyzw 表示 裁剪坐标系的坐标 , ndc.xyzw 表示 规范化设备坐标系坐标, win.xyzw 表示 窗口坐标系坐标, OpenGL 一个完整的空间变换流水线如下:

world coordinate system --> eye coordinate system --> clip coordinate system --> normalized device coordinate system --> window device coordinate system。

gl_FragCoord.z 生成过程:

(1)世界坐标系内的坐标乘以观察矩阵变换到眼坐标空间 eye.xyzw = viewMatrix * world.xyzw;

(2)眼坐标系内的坐标通过乘上投影矩阵变换到裁剪空间 clip.xyzw = projectMatrix * eye.xyzw;

(3)裁剪坐标系内的坐标通过透视除法(也就是 w 为 1 化) 到 规范化设备坐标系 ndc.xyz = clip.xyz / clip.w;

(4)设备规范化坐标系到窗口坐标系 win.z = (dfar - dnear)/2 * ndc.z + (dfar+dnear)/2;

可以看出gl_FragCoord.z 是 win.z 。dnear ,dfar 是由 glDepthRange(dnear, dfar) 给定的,按openGL 默认值 (0,1) , win.z = ndc.z/2 + 0.5。

有时候我们需要在 shader 内反算 眼坐标系 或 世界坐标系 内的坐标, 这在后处理或延迟着色中很有用,不需要另外使用颜色缓存保留物体位置信息,减少带宽占用。

由窗口空间坐标反算规范化设备空间坐标:

ndc.xyzw = ( gl_FragCoord.xy/viewport.wh * 2.0 - 1.0, gl_FragCoord.z * 2.0 - 1.0, 1.0 );

这样我们只需向shader 中传入矩阵信息就可以获得该片元在指定空间内的坐标 ,例如

eye.xyzw = projectionMatrixInverse * ndc.xyzw;world.xyzw = modelViewProjectionMatrixInverse * ndc.xyzw

注意最终结果要除以 w 分量, eye.xyz = eye.xyz/eye.w;

第四个分量 gl_FragCoord.w

先看看透视投影矩阵的推导:

原文地址:​​OpenGL 投影矩阵​​

眼坐标空间到规范化设备坐标系空间

透视除法w的来源

gl_FragCoord.w 是裁剪空间 clip.w 的倒数即 1/clip.w , 由上面的透视投影矩阵的推导过程可以看出,为了凑透视除法, clip.w 值就是 眼坐标系 z 值的负数,也就是距离相机的距离。 取负数 是因为 眼坐标系 与 规范化设备坐标系 手向性不同, 眼坐标系是右手系, 规范化设备坐标系是左手系。这里暗示我们,对于透视投影, 由 gl_FragCoord.w 可以很方便的知道当前片元在眼坐标系中 距离相机的距离 : gl_FragCoord.w = - 1/Ze ----------> Ze = - 1/gl_FragCoord.w;

那么正交投影呢? 正交投影矩阵的 w 值 恒为 1, 还是乖乖的传矩阵做逆运算吧。当然 用逆矩阵反求 各坐标系的坐标 具有通用性。

总结:

gl_FragCoord 比较有用的是反求各坐标系的空间位置,减少带宽占用。 也可以方便的获取当前片元的窗口坐标和片元深度值。当深度测试开启时, 如果在片元着色器中没有定义 gl_FragDepth 的值, gl_FragCoord.z 即成为默认输出的深度值,并且gl_FragDepth 不会存在未定义输出的情况(因为不是用户定义的值就是系统给定的默认值)。

题外话, 给定一个矩阵,怎样判断投影矩阵 是 透视投影还是正交投影呢?

正交投影矩阵公式

透视投影矩阵公式

答案: 判断 projectionMatrix[3][2] 是否不等于 零。

最后给两个函数,在基于延迟着色的fragment shader 中 反求片元在 眼坐标系 或 世界坐标系的位置:

vec3 decodeCameraSpacePositionFromDepthBuffer(in vec2 texCoord){ vec4 clipSpaceLocation; clipSpaceLocation.xy = texCoord*2.0-1.0; clipSpaceLocation.z = texture(depthTexture, texCoord).r * 2.0-1.0; clipSpaceLocation.w = 1.0; vec4 homogenousLocation = projectionMatrixInverse * clipSpaceLocation; return homogenousLocation.xyz/homogenousLocation.w; } vec3 decodeWorldSpacePositionFromDepthBuffer(in vec2 texCoord){ vec4 clipSpaceLocation; clipSpaceLocation.xy = texCoord*2.0-1.0; clipSpaceLocation.z = texture(depthTexture, texCoord).r * 2.0-1.0; clipSpaceLocation.w = 1.0; vec4 homogenousLocation = viewProjectionMatrixInverse * clipSpaceLocation; return homogenousLocation.xyz/homogenousLocation.w; }

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:卢松松:QQ推出QID名片功能:赶紧抢注靓号ID!
下一篇:openGL中用Assimp库加载骨骼动画
相关文章

 发表评论

暂时没有评论,来抢沙发吧~