OpenGL之Clip Space 和 NDC透视除法(Perspective Division)

转自:容易混淆的Clip Space vs NDC,透视除法 - 知乎

Clip Space是一个顶点乘以MVP矩阵之后所在的空间,Vertex Shader的输出就是在Clip Space上(划重点),接着由GPU自己做透视除法将顶点转到NDC。 

透视除法将Clip Space顶点的4个分量都除以w分量,就从Clip Space转换到了NDC了。

而NDC是一个长宽高取值范围为[-1,1]的立方体,超过这个范围的顶点,会被GPU剪裁。

:在DirectX里面,NDC的z方向取值范围是[0,1],在Unity中可以用UNITY_NEAR_CLIP_VALUE获取z方向近平面的值,在openGL环境下是-1.0,DirectX中是0.0。本文以OpenGL坐标系为准,D3D坐标系会有一些差异。

Fragment Shader的输入是在什么空间?

Vertex Shader的输出在Clip Space,那Fragment Shader的输入在什么空间?不是NDC,而是屏幕空间Screen Space

我们前面说到Vertex Shader的输出在Clip Space,接着GPU会做透视除法变到NDC。这之后GPU还有一步,应用视口变换,转换到Window Space(Screen Space),输入给Fragment Shader:

(Vertex Shader) => Clip Space => (透视除法) => NDC => (视口变换) => Window Space => (Fragment Shader)

视口变换的计算方法也很简单,假设视口的原点为(x,y),长宽为(width,height)。

以x轴为例,变换只是将NDC的[-1,1] 线性映射到[x, x+width]范围内。

z轴则会从NDC的[-1,1]映射到[nearVal, farVal]内(默认near=0,far=1)。

width, height, near, far 等参数可以通过如下函数指定:

void glViewport(GLint *x*, GLint *y*, GLsizei *width*, GLsizei *height*);
void glDepthRangef(GLfloat *nearVal*, GLfloat *farVal*);

SV_Position和gl_FragCoord的w分量

前面提到了Fragment Shader的输入是经过视口变换后的坐标,Shader中访问的方法是:OpenGL中通过gl_FragCoord来访问,D3D中则通过SV_Position语义访问。

此输入参数的xy分量表示Screen Space的坐标,z表示写入到深度缓冲中的值,那么w分量表示什么呢?

透视除法的时候,(x,y,z,w) => (x/w, y/w, z/w, w/w)。会发现最后一个分量变成了1没什么意义,所以不如存点有用的数据,对于SV_Position来说,最后一个分量存的就是w,也即View Space的Z。

对于gl_FragCoord来说,存的是1/w。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值