在前面的文章中我们有了解到,opengl的顶点坐标要求是介于-1.0到1.0之间的NDC(标准化设备坐标)。但是我们日常使用到的坐标可能有多种不同的坐标系统,比如针对对象本身有一套坐标系统,描述对象内部各个组件的坐标关系。对象与对象之间有一套坐标系统,描述对象间的坐标关系等等。opengl针对不同的情况提供了不同的坐标系统,并且基于一定的转换将不同坐标系统下的坐标转换为标准化的设备坐标(NDC)。

  

Android OpenGL默认坐标 opengl坐标范围_设备坐标

 

 

   上面这张图片,描述了在opengl中我们主要会用到的坐标系统,和坐标系统的转换流程。

LOCAL SPACE,MODEL MATRIX

  局部空间,描述的是对象内部的坐标系统。比如一张图片,我们默认左下角是坐标原点(0,0),如果图片长度为1,右上角我们会用(1,1)表述。局部空间坐标通过模型矩阵(MODEL MATRIX)转换为世界空间坐标,模型矩阵的转换包含对象的位移、旋转、缩放操作。

WORDL SPACE,VIEW MATRIX

  世界空间,描述的是对象与对象间的坐标关系,比如对象A坐标(0,0,0),对象B坐标(2,0,0),渲染的时候对象B就会在对象A的左边,隔着两个单位。默认每个对象的世界坐标是(0,0,0),如果没有设置对象的世界坐标,那么渲染效果就是所有的对象都叠在一起了。世界空间坐标通过视图矩阵(VIEW MATRIX)可以转换为视图空间坐标,视图矩阵主要是通过一系列的旋转,位移计算,将对象描述到视图空间内,相当于将对象摆放到我们眼睛前、摄像机前的合适位置。

  后面视图空间中会提到摄像机的概念,我们对摄像机的不同操作,如移动、旋转,也是为了生成不同的视图矩阵(VIEW MATRIX)

VIEW SPACE,PROJECTION MATRIX

  视图空间,也可以称之为摄像机空间或者视觉空间,描述的是基于用户眼睛的角度所生成的坐标关系。即从我们的眼睛出发,描述对象是在我们的前面、左边、右边?视图空间(VIEW SPACE)也相当于摄像机拍摄到的空间。视图空间坐标通过投射矩阵(PROJECTION MATRIX)可以转换为裁剪空间坐标,投射矩阵将视图坐标转换为-1到1间的标准设备坐标(NDC),另外根据投射方式的不同可以分为正射投影(orthographic projection)和透视投影(perspective projection)。在视觉表现上,透视投影描述的我们眼睛看到的世界:离我们近的看的更大,离我们远的看的更小;而正射投影则没有远近的差异,直接将对象的坐标映射到屏幕上而已。

CLIP SPACE

  裁剪空间,描述一个-1到1的坐标系统,在这个范围内的对象会被渲染出来,没有的就过滤掉。也是在这个空间内,将对象坐标最终转换为标准化设备坐标(NDC)。裁剪空间坐标通过视图转换,将裁剪空间坐标(NDC)装换为屏幕空间坐标。

SCREEN SPACE

  屏幕空间,即我们通过glViewport定义的屏幕宽高所对应的坐标系统。

  opengl提供多种坐标系统,也是为了方便我们在不同的场景下有合适的坐标体系,在不同场景下有方便的转换方式。而我们常见到的MVP转换,就是从对象空间装换到裁剪空间的组合。另外我们之前也了解过,顶点着色器主要处理的是对象顶点的坐标,所以我们的MVP转换也是在顶点着色器内处理。

  以常用的透视投影为例,我们描述一个在我们眼睛前面3个单位,右边1个单位对象的MVP矩阵转换过程

// model matrix
glm::mat4 model = glm::mat4(1.0f);
model = glm::translate(model, glm::vec3(1.0f, 0.0f, 0.0f);
// view matrix
glm::mat4 view = glm::mat4(1.0f);
view = glm::translate(view, glm::vec3(0.0f, 0.0f, -3.0f);
// projection matrix
glm::mat4 projection = glm::perspective(glm::radians(45.0f), 800.0f / 600.0f, 0.1f, 100.0f);
// 传递给shader
// u_model = model; u_view = view; u_projection = projection;
...
... vertex shader
uniform mat4 u_model;
uniform mat4 u_view;
uniform mat4 u_projection;
void main(){
    gl_Position = u_projection * u_view * u_model * vec4(aPos, 1.0f);  
}

  模型矩阵我们提到了是对象位移、旋转、缩放操作的转换;视图矩阵我们可以引入摄像机概念进行更为复杂的效果表现;投射矩阵比较固定,设定哪种投射方式,屏幕的宽高,远近参数的设定等。