opengl各个坐标系理解与转换公式

1、标准化设备坐标(Normalized Device Coordinates, NDC)

 顶点坐标已经在顶点着色器中处理过,它们就应该是标准化设备坐标了,标准化设备坐标是一个x、y和z值在-1.0到1.0的一小段空间。任何落在范围外的坐标都会被丢弃/裁剪,不会显示在你的屏幕上。

2、UV坐标系

UV坐标系一般以左下角为原点(0,0),经常用于贴图上面。范围为0-1.

 

OpenGL 一个完整的空间变换流水线如下:

model coordinate system(模型坐标系)->world coordinate system(世界坐标系) --> eye coordinate system(相机坐标系) --> clip coordinate system(裁减平面坐标系) --> normalized device coordinate system(标准设备坐标系NDC) --> window device coordinate system(屏幕坐标系)。

 

 

  1. 模型变换观察变换,使将物体的坐标从模型空间,通过旋转移动等复合变换,转换到了以摄像机为原点的观察空间坐标系下。在观察空间下,z轴上的数据表示了物体距离摄像机的远近,即深度,此时的深度值还是线性的。(观察空间使用的是右手坐标系,即 -z轴才是摄像机的正前方)
  2.  观察空间中,只有位于视锥体内的物体才会被摄像机渲染并且可见,所以需要将范围外的顶点剔除。但是视锥体是一个金字塔形状,由六个锥平面构成。使用六个锥平面直接进行裁剪判断会很麻烦; 因此,有一种更加方便的方法是:通过一个透视投影矩阵把顶点从观察空间转换到一个裁剪空间下,转换的过程实际是对x,y,z分量都进行了不同程度的缩放和平移。使x,y,z值满足:直接用w分量作为裁剪的范围值,如果变换后的x,y,z分量都位于[-w,w]这个范围内,就说明该顶点位于裁剪空间内,反之会被剔除。 以下是推导出的透视投影矩阵和顶点相乘后的坐标点(这里不做推导过程):

    Near:近裁剪平面距离
    Far:远裁剪平面距离
    FOV:锥体竖直方向的张开角度
    Aspect:摄像机的横纵比

  3. 在上一步操作中,我们可以得到裁剪空间下的 z 和 w 分量:

  4. 经过透视投影变换,坐标系转换到了裁剪空间下。紧接着,我们可以通过判断当前的 x,y,z 分量是否处于 [-w,w] 范围内,来判断坐标点是否处于视锥体内,并将视锥体外的坐标点剔除。在观察空间,世界空间,模型空间下,坐标点的w分量一直都是1,所以说,经过剔除后的裁剪空间下的坐标点的范围值为 [-1,1]
  5. 当完成所有的裁剪工作后,就要进行真正的投影了,即把视锥体投影到屏幕空间中,从而得到真正的二维像素坐标。 期间需要进行两步操作,齐次除法映射输出
  6. 齐次除法:用齐次坐标系的 w 分量去除以x,y,z分量。以z轴分量为例:

    经过齐次除法后,坐标系由裁剪空间转换到了NDC(归一化的设备坐标,Normalized Device Coordinates)下,此时的x,y,z分量的范围值为[-1,1]。
  7. 映射输出:NDC下的x和y的坐标范围是[-1,1],而屏幕空间左下角像素坐标是(0,0),右上角的像素坐标是(pixelWidth,pixelHeight),因此x和y会先除以2再加1/2,映射到[0,1],然后再分别乘以pixelWidth和pixelHeight:

    上面的式子对x,y值做了处理,而z分量会直接被用于深度缓冲(Zbuffer),当然这个也不一定,会根据硬件选取合适的存储格式。 除此之外,为了能将z值存储到深度图中,需要将其范围映射到 [0,1]:

    此时的 d 值就是 Unity 中深度图存储的数据。因为d是关于z_ndc的函数,z_ndc是关于1/z_visw的函数,因此 d 自然不是线性的了。 (z_ndc:ndc空间下的z值;z_visw:观察空间下的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;

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; 
}

 

  • 6
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

XR风云

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值