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

opengl各个坐标系理解与转换公式相关推荐

  1. OpenGL学习笔记(一):环境搭建、三维空间坐标系理解以及OpenGL的基本使用

    原博主博客地址:http://blog.csdn.net/qq21497936 本文章博客地址:http://blog.csdn.net/qq21497936/article/details/7866 ...

  2. OpenGL(5)深入理解Pipeline, State, Context

    OpenGL(5)深入理解Pipeline, State, Context Pipeline(管线/管道) 管线(pipeline),可以理解为渲染流水线.它的最终目的是将输入3D数据经过几个流程的处 ...

  3. opengl 坐标的理解

    [目标]:学习OpenGL中的坐标系统. [参考]: 1.<计算机图形学(OpenGL版) (第三版)> Francis著 (本文主要涉及第三章~第七章) 2.<计算机图形学(Ope ...

  4. OpenGL之坐标系以及单位

    1.1 OpenGL中默认的坐标系为右手坐标系,默认视点位置为原点,原点正好投影在投影窗口的中心,也正好投影在视口的中心. 1.2 在OpenGL中无绝对单位,只有相对的大小,相对于视锥体的大小来设定 ...

  5. OpenGL LookAt函数理解

    前言:记录OpenGL学习过程中的一些知识点,以个人理解为主. LookAt函数将顶点的世界空间坐标转换为观察空间坐标,实际上是以相机为原点重新定义的三维空间. glm::mat4 LookAt(gl ...

  6. Android Camera OpenGL FBO的理解

    背景概念: 首先,Android显示系统中,系统默认的渲染器是OpenGL,混合使用skia,各个厂商可能有不同的实现,大部分都是OpenGL. Android在系统启动时,经过BootLoader启 ...

  7. opengl微发展理解

    1.什么是OpenGL? 一种程序,可以与界面和图形硬件交互作用.一个开放的标准 2.软件管道 请看上图 - Apllication层     表示你的程序(调用渲染命令.如opengl API) - ...

  8. 【我的OpenGL学习进阶之旅】【持续更新】关于学习OpenGL的一些资料

    目录 一.相关书籍 OpenGL 方面 C方面 NDK 线性代数 二.相关博客 2.0 一些比较官方的链接 2.1 OpenGL着色器语言相关 2.2 [[yfan]](https://segment ...

  9. opengl中的glViewport,glOrtho,glFrustum 理解

    在刚使用opengl时,会遇到对opengles中的一些视角等理解,需要用到glViewport,glOrtho,glFrustum 等函数,下面针对这些函数做一些说明 viewport建立视口,是视 ...

最新文章

  1. 自动色阶、对比度、直方图均衡等算法的一些小改进
  2. 1048 采药 1049 装箱问题
  3. js事件(Event)知识整理
  4. 计算机保存的信息是模拟信号,信息技术考试样题(附解析).doc
  5. “远程办公扼杀了万亿美元的办公经济”
  6. ACM程序设计选修课——1024: 末位零(求末尾0的方法+可有可无的快速幂)
  7. 全国DEM下载教程 90米、30米、12.5米和5米等各种精度DEM数据
  8. 指数加权移动平均法(EWMA)
  9. qlistview 自定义控件_python – QListView中的自定义项
  10. Windows NT 架构
  11. VisualStudio各版本的安装与使用(持续更新)
  12. java登陆注册界面_java编写登陆注册页面(简单一点的,连接数据库)
  13. 张一鸣的大学四年收获及工作感悟
  14. 使用深度学习进行生存分析
  15. 用Python写一个任务管理器进行工作协调
  16. 王家卫入股的“导演合伙人制”,会给中国电影制造惊喜吗?
  17. 程序员的内功修炼指南
  18. 大端与小端字节数据详解
  19. Activiti7工作流+SpringBoot
  20. 寻回失落的“纸人李”——四川大学团队用3D技术平台重现传统纸人工艺

热门文章

  1. make_layers 作用
  2. 停一下,Maya建模师教你打造自己喜欢的游戏场景,赶紧学习啦
  3. 完美国际修改服务器经验倍率,吧主勿删,代码修改教程
  4. Piwigo 一款开源的图片管理系统PHP源码
  5. 智能园区三维可视化管理系统方案及优势开发
  6. python下载文件保存_Python根据URL地址下载文件并保存至对应目录的实现
  7. 使用Unity模拟人群疏散的资料整理
  8. 所谓的差分GPS似乎就是指RTK
  9. 计算机房应急灯标准,GB 51309 - 2018《消防应急照明和疏散指示系统技术标准》规范组官方答疑(四)...
  10. SQL注入的浅尝辄止