OpenGL ES 入门之旅(6)--OpenGL 下的基础图元

·  阅读 1690

我们先来看一下OpenGL下的基础图元有哪些类型?

图元类型 枚举值 描述
GL_POINTS 每个顶点在屏幕上都是单独点
线 GL_LINES 每一对顶点定义一个线段
线带(不闭合) GL_LINE_STRIP 一个从第一个顶点依次经过每一个后续顶点而绘制成的线条
线环(闭合) GL_LINE_LOOP 一个从第一个顶点依次经过每一个后续顶点而绘制成的线条 ,同时将最后一个顶点和第一个顶点连接起来
三角形 GL_TRIANGLES 每三个顶点定义一个新的三角形
三角形带 GL_TRIANGLE_STRIP 共用一个条带上的顶点的一组三角形
三角形扇 GL_TRIANGLE_FAN 以一个圆点为中心呈扇形排列,共用相邻顶点的一组三角形

通过这张表,我们已经知道了OpenGL下的基础几何图元,以及它们形成的方式,它们所代表的枚举值。下面我们从更底层更基础的角度来学习OpenGL下的图元渲染。

基础图元

1.点

点是最基本的图元,也是最简单的图像。在OpenGL中,点称为顶点(Vertex),通常用一个形如(x, y, z)的三维坐标值表示。每个特定的顶点在屏幕上都仅仅是一个单独的点。一般情况 下,OpenGL 中的点将被画成单个的像素,实际上点还可以更小,虽然它可能足够小, 但并不会是无穷小,一个像素内可以描绘多个点,取决于对点大小的设定,默认一个点的大小为一个像素的大小。 设置点的大小的函数:

void glPointSize(GLfloat size);
复制代码

这是设置点的大小最简单最常用的方法 ,其中size 必须大于 0.0f,默认值为 1.0f,单位为“像素”。 具体实现如下:

1.设置点大小
glPointSize(5.0f); //设置点的大小为5像素

这里需要注意一下,OpenGL是一个状态机,如果把点的大小更改成5.0f之后,
那么在OpenGL的场景下面,它所有的点都会更改成5.0f,
所以我们在设置当前点完成之后,把它恢复原始状态1.0f.

2.设置点的大小范围和点与点之间的间隔
GLfloat sizes[2] = {2.0f,4.0f};
GLfloat step = 1.0f;  //设置2个范围2~4,间隔为1的点

3.获取点的大小范围和最小步长 ---所调用的方法
glGetFloatv(GL_POINT_SIZE_RANGE,sizes);
glGetFloatv(GL_POINT_GRAULARITY,&step);

4.通过使用程序点大小模式来设置点大小
glEnable(GL_PROGRAM_POINT_SIZE);

在这种模式下允许我们通过编程在顶点着色器和几何着色器中设置点的大小。
着色器内建变量:gl_PointSize; 并且可以直接在着色器源码写
 gl_PointSize = 5.0;
复制代码

2.线

比点更进一步的就是独立的线段了,线段是由两个顶点连接起来形成的图元。默认情况下,线段的宽度是一个像素,改变线段的唯一方式就是:glLineWidth设置线段宽度

glLineWidth(4.5f);  //设置独立线段的宽度为4.5f(像素);
复制代码

通过文章开始的基础图元列表我们已经知道,线段间的连接方式有三种: (1)独立线段:图元类型参数--GL_LINES (2)线段间首尾相连但最终不闭合:线带(折线),图元类型参数--GL_LINE_STRIP (3)线段间首尾相连最终封口闭合:线环(图形),图元类型参数--GL_LINE_LOOP 这三种连接方式所对应的图例如下图所示:

线段连接方式.png
线带是连续从一个顶点到下一个顶点绘制的线段,以形成一个真正连接的点的线段,为了把图形连接起来,每个连接的顶点会被选定两次,一次作为线段的终点,一次作为下一个线段的起点。 线环来说就是线带的一种扩展,在线带的基础上,额外增加一条线段将线带闭合起来。

3.三角形

3.1 绘制三角形

在基础图元中,最受欢迎的大概就是三角形了,同时,三角形也是最简单的实体多边形,它只有3个边。并且现在三角形已经是OpenGL中支持的唯一一种多边形,每三个顶点定义一个新的三角形,其他的多边形都可以由三角形构成。(光栅化硬件最受欢迎的也是三角形)。 如下是使用 GL_TRIANGLES 绘制的两个三角形:

绘制三角形.png
三角形的类型来自于顶点,并不是所有的三角形都是正三角形,如果顶点连接的顺序是顺时针的,那么就是顺三角形,如果顶点的连接顺序是逆时针的,那么就是逆三角形。

2.三角形的环绕方式

按照顶点指定的顺序和方向组合称为环绕。通过上面的图我们知道,上图的两个多边形是顺时针环绕的。我们可以通过改变顶点的顺序,从而改变环绕方向。我们把上图中左边的三角形的顶点v4和v5的顺序调换过来,然后从顶点V3开始绘制,则这个三角形的环绕方向为逆时针了。

逆时针和顺时针绘制.png
在默认情况下,OpenGL默认是逆时针环绕方向为正方向,即逆时针环绕的三角形为正面。上图左边的三角形,显示的是正面,而右边的显示的是反面。(逆就是正,顺就是反)环绕方向是多边形一个非常有用的性质,可以用于消除不必要的面。

那么,为什么会有正反面这一说法呢?举个栗子:如果有一张特别薄的正方形便签纸,我们可以认为这是一个正方形,那么这张纸仍然会存在两面,纸的正面和反面。如果我们用同大小6张正方形便签纸片围成一个正方体,那么正方体的任何一个面都是一个正方形,而且这个正方形是有正反面,假设朝外的你能看到的部分是正面,那么朝内的看不到的那部分就是反面。

在OpenGL中也需要区分正反面,我们也可以通过函数glFrontFace(GL_CW),来告诉OpenGL按顶点设置顺序顺时针环绕的多边形是反面,通过函数glFrontFace(GL_CCW),来告诉OpenGL按顶点设置顺序逆时针环绕的多边形是正面。

设置这个的原因是,在默认情况下,OpenGL绘制三维物体时正反两面都会绘制,而实际上我们在观察物体的时候,很多面我们是看不到的,比如物体朝内方向的多边形,还有一些物体间遮挡的情况导致有些多边形是不可见的,因此为了提高性能,我们需要剔除这些不必要的绘制。

glEnable(GL_CULL_FACE); //来启动剔除功能
glCullFace(); //参数可以是GL_FRONT、GL_BACK、GL_FRONT_AND_BACK,
复制代码

3.三角形带

我们可以绘制多个三角形连起来形成多个面或者多边形。使用GL_TRIANGLE_STRIP图元,可以绘制一串相连的多边形,来节省大量的时间。

三角形带.png
由上图可以看到,多边形的边的绘制顺序并不是完全按照我们指定的顶点顺序的。而是按照OpenGL指定的顺序逆时针方向绘制的。

使用三角形带而不是分别指定每个三角形的顶点的优势: 1.用前面三个顶点指定一个三角形后,只需再指定一个顶点就能画出第二个三角形。这样在绘制大量的三角形时,这种绘制方法可以节省代码以及数据存储空间 2.运算性能的提高和带宽的节省。更少的顶点,从内存传输的显卡的时间更快,以及参与变换的顶点更少。

4.三角形扇

对于很多表面或者形状而言,我们会需要绘制几个相连的三角形,这时我们可以使用GL_TRIANGLE_FAN图元绘制一组围绕一个中心点相连的三角形,即三角形扇。

三角形扇.png

5.绘制方式

由以上内容我们知道,从三维的角度来看,每一个多边形都具有两个面(正面和反面)。每一个面都可以设置不同的绘制方式:常用的多边形绘制模式有:填充式(GL_FILL)、轮廓线式(GL_LINE)、顶点式(GL_POINT)和镂空图案填充式(最后一种比较特殊),在OpenGL中默认的绘制方式是:填充式。 我们使用glPolygonMode()函数来指定模式:

void glPolygonMode(GLenum face,GLenum mode);
//该函数要求说明是对多边形哪一个面是定face设置模式
在设置绘制模式时可以为两个面分别设置不同的方式:
glPolygonMode(GL_FRONT, GL_FILL);            // 设置正面为填充方式
glPolygonMode(GL_BACK, GL_LINE);             // 设置反面为边缘绘制方式
glPolygonMode(GL_FRONT_AND_BACK, GL_POINT); // 设置两面均为顶点绘制方式
复制代码

4.一个工具类(容器)GLBatch

GLTools库中包含一个简单的容器类,叫做GLBatch,这个工具类可以作为最常用的7种基本图元的简单批次容器使用,而且它知道在使用GL_ShaderManager支持的任意存储着色器时如何对图元进行渲染。

void GLBatch::Begain(GLeunm primitive,GLuint nVerts,GLuint nTexttureUnints = 0);
参数1:图元
参数2:顶点数
参数3:一组或者两组纹理坐标(可选)

//复制顶点数据(一个由3分量x,y,z顶点组成的数组)
void GLBatch::CopyVerterxData3f(GLfloat *vVerts)

//复制表面法线数据
void GLBatch::CopyNormalDataf(GLfloat *vNorms);

//复制颜色数据void GLBatch::CopyColorData4f(GLfloat *vColors);

//复制纹理坐标数据
void GLBatch::CopyTexCoordData2f(GLFloat *vTextCoords,GLuint u iTextureLayer);

//结束数据绘制
void GLBatch::End(void);
复制代码
分类:
阅读
标签:
收藏成功!
已添加到「」, 点击更改