openGL学习(二)

来源:互联网 发布:亚洲人讲英语 知乎 编辑:程序博客网 时间:2024/05/22 08:26

openGL学习(二)

主要学习openGL利用着色器绘制3D形状

  1. 摄像机的设置(视角选择)。要显示一个物体首先需要确定在什么地方以什么视角观看。
  2. 着色器。openGL绘制都是先定义定点数组(vertex array objects),然后到顶点缓冲(vertex buffer objects)完成绘制。
  3. 利用索引绘制。利用索引去除重复点的定义。

摄像机的设置

简单来说相机的设置就是在什么位置朝什么方向以多大的视角看物体。在glm数学库中有2个函数计算。
观察矩阵:

 mat4 lookAt(vec3 const & eye, vec3 const & center, vec3 const & up);

其中:第一个参数为相机的位置,第二个参数为视线方向,第三个参数为向上方向。 可以简单理解为一个人和他的眼睛,如果他需要看某个物体,首先需要走到物体附近(位置),然后转动头去看(视线)。比如在xy平面有个三角形:
这里写图片描述
设置函数为:glm::lookAt(glm::vec3(0.0f, 0.0f, 1.0f), glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 1.0f, 0.0f));
表示在位置(0, 0, 1)朝着(0, 0, 0)方向观察,y轴为向上方向。则显示如下:
这里写图片描述

如果设置为:glm::lookAt(glm::vec3(1.0f, 0.0f, 1.0f), glm::vec3(1.0f, 0.0f, 0.0f), glm::vec3(0.0f, 1.0f, 0.0f));显示为:
这里写图片描述

注意 第二个参数只表示方向,其大小不影响显示。

为了增加控制的交互性,比如使用鼠标控制视角的移动和旋转,这需要对相机矩阵进行计算。

相机的旋转:
水平旋转角度为h,竖直旋转角度为v,如图所示
相机选装
计算相机视角的方向,其x轴坐标为cos(v)*sin(h),y轴坐标为sin(v),z轴坐标为cos(v)*cos(h),图中显示了其原理。

投影矩阵:

 mat4 perspective(T fovy, T aspect, T zNear, T zFar);

第一个参数表示视角范围,第二个表示长宽比,第三个为近裁剪平面,第四个为远裁剪平面。

在现实世界中,如果你在远处一个房子的后面,现在需要观察房子的正面,则你需要首先走到房子的正面,然后使用眼睛观看,这样就观察到房子的正面。在openGL中则变换世界坐标系完成视角变换问题。分为4步:物体坐标系->世界坐标系->相机坐标系->屏幕显示。
这里写图片描述

利用数学矩阵实现为:P*V*M。

着色器

着色器有2个,顶点着色器 (vertex shader) 和片段着色器 (fragment shader) 。其具体的怎么使用教程中都有。我的理解是:由于openGL所有的数据都定义为缓冲(buffer),然后通过着色器传递给openGL进行绘制。顶点着色器可以看成数据的读入,把定义物体的顶点数据和颜色数据传入着色器,然后通过片段着色器进行绘制。

这里说明下openGL的绘制: openGL只能绘制三角形,其绘制函数glDrawArrays (GLenum mode, GLint first, GLsizei count); 其中model有GL_TRIANGLE 和 GL_TRIANGLE_STRIP。
GL_TRIANGLE_STRIP 表示三个点进行一次绘制,每次推进一个点。比如有A, B, C, D 四个点定义一个矩形,如果定点定义顺序为A->B->C->D, 则glDrawArrays(GL_TRIANGLE_STRIP, 0, 3); 表示绘制ABC构成的三角形,如下(最后一个参数小于3将无法绘制,不构成三角形):
这里写图片描述

如果最后一位改为4 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);则表示先绘制ABC。然后绘制BCD,一次向后推进一个定点,结果如下:
这里写图片描述

GL_TRIANGLE则表示3个点绘制一次,绘制一个矩形需要6个点。

因此,定点的定义顺序十分重要

使用索引进行绘制

在绘制复杂的图形时需要定义每个定点(每次绘制一个三角形),而许多定点会重复使用,比如:
这里写图片描述

图中,中间一行的定点都定义了2次,使用索引对每个点进行映射,可以达到数据的重复使用,节约大量空间。比如定义定点数据为:

static const GLfloat g_vertex_buffer_data[] = {        0.0f, 0.0f, 0.0f,        1.0f, 1.0f, 0.0f,        2.0f, 0.0f, 0.0f,        0.0f, 0.0f, 1.0f,        1.0f, 3.0f, 1.0f,        2.0f, 0.0f, 1.0f,        0.0f, 0.0f, 2.0f,        1.0f, 4.0f, 2.0f,        2.0f, 0.0f, 2.0f,    };

其中一行表示一个点。
其索引可以为:

int iIndices[] =    {         0, 3, 1, 4, 2, 5, 9, // First row, then restart         3, 6, 4, 7, 5, 8, 9,  // Second row, then restart    };

在定义数据点的使用只定义了9个点,索引的建立使用了12个点,(2和7, 4和8, 7和9使用相同索引)。
注意由于使用GL_TRIANGLE_STRIP参数进行绘制,使用连续的顶点进行绘制需,有时需要进行切分(重新绘制),比如在上次中第一行的矩形与第二行的矩形需要分开,则在索引中每一行的最后一个表示进行切分,其值为索引最后一位的下一个。

0 0
原创粉丝点击