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. java数组排序之冒泡排序
  2. python3 日志检索异常抛出异常 raise KeyError(key),KeyError: 'formatters'
  3. Matlab中legend位置
  4. vb.net2019- 机器学习ml.net情绪分析(2)
  5. 【深度学习】你不知道的车牌识别系统
  6. Linux使用lvresize扩展或缩减LV逻辑卷大小
  7. Bigtable的些许重点
  8. 自动挡跑高速用S挡还是D挡? 回答
  9. WORD的POI处理与原理
  10. 移植u-boot.2012.04.01
  11. python基于tornade的高并发接口编程实战学习
  12. 深度置信网络学习总结
  13. vscode 弹窗报错~/AppData\LocalPrograms\Microsavs Code\unins000.exe
  14. linux制作虚拟机镜像,为OpenStack制作CoreOS虚拟机镜像(基于CoreOS官方提供镜像)
  15. python简单编程--ATM银行管理系统
  16. 无线局域网和蜂窝移动网络_干货!无线AP覆盖系统解决方案
  17. 电商网站后台九大功能模块详解
  18. word在另外计算机格式不对,为什么同一个word文档在两台电脑上打开里面的格式不一样...
  19. IntelliJ IDEA 13 皮肤/编辑器字体设置
  20. 五、Hive数据仓库(完整版)

热门文章

  1. 如何从 Github 中删除提交
  2. 中国拼图游戏市场现状研究分析与发展前景预测报告(2022)
  3. 最新版Win11系统22H2跳过联网验机-亲测可用
  4. vivox9怎么和计算机共享,vivo手机怎么分享软件给别人(共享软件的操作步骤)...
  5. JavaScript实战之简单的抽签器
  6. 考研英语前缀总结·十六
  7. 菜鸟的树莓派Raspberry Pi学习之旅(一)——认识树莓派硬件篇
  8. 2022亚马逊云科技re:Invent,与合作伙伴描绘宏伟蓝图
  9. 新版JESD625C 和 JESD625B 条款之间的区别变更说明
  10. PCNN 脉冲耦合神经网络整理