2、OpenGL – 坐标系

OpenGL - 坐标系

1、笛卡尔坐标

1.1、2D笛卡尔坐标系

平面坐标系,只有X 和 Y轴

1.2、3D笛卡尔坐标系

立体坐标系,有X Y轴还有Z 轴。形成立体3D图形

2、视口

在用户窗口中显示的大小,可以和原内容大小相同也可以不同

3、投影

  • 光源的发出点称为 投影中心
  • 投影中心与物体上各点的连线称为 投影线
  • 接受投影的面,称为 投影面
  • 过物体上各点的投影线与投影面的交点称为这些点的投影。
  • 投影分为 中心投影平行投影 两大类。
  • 所有投影线都交于投影中心点的投影称为 中心投影透视图 就是用这种投影方法绘制成的。
  • 所有的投影线都 互相平行 的投影称为平行投影。平行投影又分为 斜投影正投影 两种。当投影线倾斜于投影面时,称斜投影;投影线垂直于投影面时,称正投影 。

3.1、投影方式

透视投影属于中心投影。从一点观察物体。如下图,透视投影看到的投影面上的红球比黄球小,以为红球比黄球远。绿球看不到,因为不在投影面内。适合于立体图形

平面投影,投影面上红球和黄球的大小是一样的,看不出来远近,适合平面图形。

4、OpenGL ES中的坐标系

OpenGL ES坐标系统包括

  1. 视窗坐标
  2. 规格化设备坐标
  3. 裁剪坐标
  4. 视觉坐标
  5. 世界坐标
  6. 对象坐标

如下图一样是一个多层系统。

4.1.1、左手坐标系

左手坐标系:伸开左手,大拇指指向X轴正方向,食指指向Y轴正方向,其他三个手指指向Z轴正方向。

规范化设备坐标系用的是左手坐标系

4.2、右手坐标系

右手坐标系:伸开右手,大拇指指向X轴正方向,食指指向Y轴正方向,其他三个手指指向Z轴正方向。

世界坐标系视窗视觉、裁剪、对象右手坐标系

左手和右手坐标注系的区别在于两者Z轴的方向是相反的。

在高等数学中使用的三维空间是笛卡尔坐标系,如下:

笛卡尔坐标系其实就是右手坐标系,OpenGL中使用右手坐标注系,Direct3D使用的是左手坐标系。

4.1.3、左手旋转规则、右手旋转规则
左右手旋转规则用于判断当前坐标系中物体旋转时正方向的判定。在右手坐标系中,确定旋转轴后,右手握成拳头,拇指指向旋转轴的正方向,其余手指的弯曲方向即为旋转的正方向,跟手指弯曲方向一致的旋转记为正向,相反则为负向。左手坐标注系中判断旋转方向的正负使用左手,其他规则一样。

两者的示意图:

4.2、 视窗坐标系

视窗坐标也就是我们手机窗口对应的坐标系统,以左上角为原点,右下角对应我们手机的最大像素值的集合,如下图是一个像素为320*480的手机,那他右下角的坐标就是(320,480)。

4.3、 规格化设备坐标系

规格化设备坐标是以屏幕中心为原点,X轴朝右,Y轴朝上,所以左下角的坐标为(-1, -1),右上角的坐标为(1,1)。当然这是z轴为0时的显示,实际上我们的规格化设备坐标系统是要考虑z轴,所以由平面要转换成一个正方体,原点坐标为(0,0,0),也就是这个立方体的中心,而它左上角离我们最近的那个顶点的坐标就是(1,1,1),右下角离我们最远的那个顶点的坐标就是(-1,-1,-1)。

4.4、裁剪坐标系

裁剪坐标是执行矩阵变换透视投影之后,但在执行透视除法之前的坐标。超出裁剪空间的坐标会被丢弃。

4.5、视觉坐标系

视觉坐标系是从我们的眼睛出发朝我们的手机设备看过去所能看到的,会有一个z轴的最近距离和最远距离,也就是zNearzFar,只有在这两者之间并且也满足x轴和Y轴坐标在屏幕当中的坐标才会显示出来,越远的东西会显示得越小,产生透视的效果。

4.6、世界坐标系

世界坐标就是一个用户构造的固定的坐标系,方便描述这个坐标系下各种物体相对于原点的位置。

4.7、对象(或模型)坐标系

每个物体都有自己独立的坐标系。当物体旋转和移动的时候,这个坐标系也会发生相应的变化。

4.8、惯性坐标系

惯性坐标系是指世界坐标系和物体坐标系转换的中间产物。惯性坐标系的原点和物体坐标系的原点重合,但惯性坐标系的轴和世界坐标系的轴平行。

为什么要引入惯性坐标系?因为物体坐标系转换到惯性坐标系只需要旋转,从惯性坐标系转换到世界坐标系只需要平移。

5. OpenGL中的坐标变换

OpenGL最终渲染到屏幕上是2D的,所以我们需要将3D坐标进行一系列的变换为2D坐标,整个过程如下图所示。

OpenGL中只定义了裁剪坐标系、规范化设备坐标系和屏幕坐标系。而局部坐标系(模型坐标系)、世界坐标系和相机坐标系都是为了方便用户设计而自定义的坐标系,他们的关系如下图所示。

  • 模型变换、视变换、投影变换由用户在顶点着色器中完成。
  • 透视除法、视口变换OpenGL在顶点着色器处理之后完成。

开发中,从局部坐标系(模型坐标系)到裁剪坐标系的转变是通过矩阵运算得到的。这三个矩阵就是MVP矩阵:模型矩阵(M)、观察矩阵(V)和投影矩阵(P)

1
V_clip = M_pro * M_view * M_model * V_local

5.1 、模型变换

模型变换的目的是通过变换,使得用顶点定义或3D模型软件构造的模型,能够按照需要,通过缩小、平移、旋转等操作放置到场景中合适的位置。

通过模型变换后,物体的位置在全局的世界坐标系下,世界坐标系是所有物体交互的一个公共坐标系。

5.2、 视变换

视变换是为了方便观察场景中的物体、方便计算而设立的坐标系。相机坐标系中的坐标,是从相机的角度来解释世界坐标系中的位置。

6、OpenGL中 模型变换

在OpenGL中,对物体的移动、缩放、旋转操作要使用模型变换,有三个模型变换函数:

  • glTranslatef 平移
  • glRotatef 旋转
  • glScalef 缩放

6.1、平移:

glTranslatef (GLfloat x, GLfloat y, GLfloat z);

x,y,z分别表示物体在xyz方向上的平移,举例来说,glTransLatef(-5.0f,4.0f,-3.0f)表示物体沿x轴负方向移 动5,y正方向移动4,z负方向移动3。

6.2、旋转:

glRotatef (GLfloat angle, GLfloat x, GLfloat y, GLfloat z);

第一个参数是旋转角度,后三个参数定义了旋转轴,这个旋转轴是由地当前坐标系的原点和点(x,y,z)的直 线。正方向是原点指向点(xyz)。如果要定义不经过原点的旋转轴,则需要先把物体的旋转轴平移到过原 点,旋转之后,再经过平移的逆变换平移回去。

6.3、缩放:

glScalef (GLfloat x, GLfloat y, GLfloat z);

三个参数分别是物体在xyz三个方向上的缩放比例。

举例如下,原始图像:

平移:

旋转:

缩放:

坐标变换完整代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include <glut.h>
#include <iostream>
 
using namespace std;
 
void myDisplay(void)    
{
    glClearColor(1,1,0.8,1);
    glClear(GL_COLOR_BUFFER_BIT);
 
    //加载单位矩阵,在做坐标变换之前都要加载一下这个单位矩阵
    //glLoadIdentity();
 
    //将变换矩阵与当前矩阵相乘,之后所有的点都会左乘上该平移矩阵
    glTranslatef(0.6,0,0);
    glRotatef(45,0,0,1);
    glScalef(0.5,0.5,0.5);
    glColor3f(1,0,1);
    glBegin(GL_POLYGON);  //绘制一个多边形
    {
        glVertex2f(-0.4,-0.4);
        glVertex2f(-0.4,0.4);
        glVertex2f(0.4,0.4);
        glVertex2f(0.4,-0.4);
    }
    glEnd();
    glFlush();
}  
 
int main(int argc, char *argv[])    
{    
    glutInit(&argc, argv);   //初始化GLUT
    glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE);  
    glutInitWindowPosition(500, 200);    
    glutInitWindowSize(400, 400);    
    glutCreateWindow("OpenGL");  
    glutDisplayFunc(&myDisplay);   //回调函数
    glutMainLoop();    //持续显示,当窗口改变会重新绘制图形
    return 0;    
}