OpenGL 编程/GLStart/Tut3
基本图形是你可以轻松绘制的基本形状。它可以是三角形、正方形,甚至是一个点。在本课中,我们将学习如何绘制一些基本图形,包括:点、三角形和不同的多边形。
在 OpenGL 中进行绘制的最简单方法是使用即时模式。为此,你使用 glBegin() 函数,它接受一个参数“模式”,即你想要绘制的对象类型。
以下是可能的模式及其含义的列表
GL_POINTS | 在屏幕上绘制点。每个指定的顶点都是一个点。 |
---|---|
GL_LINES | 在屏幕上绘制线条。每两个指定的顶点组成一条线。 |
GL_LINE_STRIP | 在屏幕上绘制连接的线条。每个指定的顶点在指定的第一个和第二个顶点之后都会连接。 |
GL_LINE_LOOP | 在屏幕上绘制连接的线条。最后一个指定的顶点与第一个指定的顶点相连。 |
GL_TRIANGLES | 在屏幕上绘制三角形。每三个指定的顶点组成一个三角形。 |
GL_TRIANGLE_STRIP | 在屏幕上绘制连接的三角形。在指定的前三个顶点之后,每个指定的顶点都会创建一个三角形。 |
GL_TRIANGLE_FAN | 像 GL_TRIANGLE_STRIP 一样绘制连接的三角形,但以扇形形状绘制三角形。 |
GL_QUADS | 在屏幕上绘制四边形(四边形)。每四个指定的顶点组成一个四边形。 |
GL_QUAD_STRIP | 在屏幕上绘制连接的四边形。在指定的第一个四个顶点之后,每两个指定的顶点都会组成一个连接的四边形。 |
GL_POLYGON | 在屏幕上绘制多边形。多边形可以由任意数量的边组成。 |
当你完成绘制特定基本图形的所有顶点后,在下一行放置 glEnd() 函数,该函数结束该基本图形的绘制。
让我们用最简单的模式 GL_POINTS 做一个例子。在使用 OpenGL 绘制点时,点的默认大小为 1 像素宽和高。当你运行程序时,这将非常难以看到。要编辑要绘制的点的大小,可以使用 glPointSize() 函数,它接受一个参数,即你想要的点的大小。
现在在 Render() 函数中,在你编写 glBegin() 代码之前,我们将设置点的大小为 10 像素。
glPointSize(10.0f);
之后,任何点的绘制都将以 10 像素宽和高绘制。现在用 GL_POINTS 模式参数编写 glBegin() 函数。然后在此之后,使用 glVertex3f() 函数指定要使用的顶点。对于这个例子,我们希望屏幕的右上角 (1.0,1.0,0.0) 和左下角 (-1.0,-1.0,0.0) 有一个点。绘制完这两个点后,确保使用 glEnd() 函数结束绘制。
glBegin(GL_POINTS); //starts drawing of points glVertex3f(1.0f,1.0f,0.0f);//upper-right corner glVertex3f(-1.0f,-1.0f,0.0f);//lower-left corner glEnd();//end drawing of points
以下是你的参考的整个渲染函数以及示例输出。本教程此部分的完整代码可以在可下载文件中找到。这个例子叫做“points”
void Render() { //clear color and depth buffer glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glLoadIdentity();//load identity matrix glTranslatef(0.0f,0.0f,-4.0f);//move forward 4 units glColor3f(0.0f,0.0f,1.0f); //blue color glPointSize(10.0f);//set point size to 10 pixels glBegin(GL_POINTS); //starts drawing of points glVertex3f(1.0f,1.0f,0.0f);//upper-right corner glVertex3f(-1.0f,-1.0f,0.0f);//lower-left corner glEnd();//end drawing of points }
我想要涵盖 glBegin() 函数中的每一种模式,但这会占用太多时间和空间。因此,我将涵盖高级模式,并在需要时最有可能涵盖其他模式。
线段环至少需要两个顶点。之后指定的每个顶点都与之前指定的顶点和第一个指定的顶点相连。因此,如果我们在窗口左侧、窗口右侧、顶部和底部放置一个顶点,我们将得到一个旋转的正方形。
让我们在 OpenGL 中完成这个图。首先,我们使用 glBegin() 函数并传递 GL_LINE_LOOP 参数,告诉 OpenGL 我们要开始绘制线段环。然后,我们传递四个顶点来创建旋转的正方形。第一个顶点位于窗口左侧 (-1.0f,0.0f,0.0f),第二个顶点位于窗口底部 (0.0f,-1.0f,0.0f),第三个顶点位于窗口右侧 (1.0f,0.0f,0.0f),第四个也是最后一个顶点位于窗口顶部 (0.0f,1.0f,0.0f)。然后,我们确保放入 glEnd() 以告诉 OpenGL 我们已经完成绘制线段环。
glBegin(GL_LINE_LOOP);//start drawing a line loop glVertex3f(-1.0f,0.0f,0.0f);//left of window glVertex3f(0.0f,-1.0f,0.0f);//bottom of window glVertex3f(1.0f,0.0f,0.0f);//right of window glVertex3f(0.0f,1.0f,0.0f);//top of window glEnd();//end drawing of line loop
以下是完整的 Render() 函数以及示例输出。在本章的可下载文件中查找名为“lineLoop”的项目文件。
void Render() { //clear color and depth buffer glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glLoadIdentity();//load identity matrix glTranslatef(0.0f,0.0f,-4.0f);//move forward 4 units glColor3f(0.0f,0.0f,1.0f); //blue color glBegin(GL_LINE_LOOP);//start drawing a line loop glVertex3f(-1.0f,0.0f,0.0f);//left of window glVertex3f(0.0f,-1.0f,0.0f);//bottom of window glVertex3f(1.0f,0.0f,0.0f);//right of window glVertex3f(0.0f,1.0f,0.0f);//top of window glEnd();//end drawing of line loop }
三角形由三个顶点组成。对于这个例子,我们将使用常规的 GL_TRIANGLES 模式来绘制两个并排的三角形。
首先,我们要在左侧绘制一个三角形。因此,我们需要在左侧绘制三个顶点来表示一个三角形,并在窗口右侧绘制三个顶点来表示第二个三角形。请注意,你不需要两个 glBegin() 函数来绘制两个三角形。由于 GL_TRIANGLES 是复数(意味着单词末尾没有“S”),它可以在一个 glBegin() 和 glEnd() 函数调用之间处理多个三角形。
请注意,我在图的右下角写下了顶点的坐标。以下是绘制这两个三角形的代码。
glBegin(GL_TRIANGLES);//start drawing triangles glVertex3f(-1.0f,-0.1f,0.0f);//triangle one first vertex glVertex3f(-0.5f,-0.25f,0.0f);//triangle one second vertex glVertex3f(-0.75f,0.25f,0.0f);//triangle one third vertex //drawing a new triangle glVertex3f(0.5f,-0.25f,0.0f);//triangle two first vertex glVertex3f(1.0f,-0.25f,0.0f);//triangle two second vertex glVertex3f(0.75f,0.25f,0.0f);//triangle two third vertex glEnd();//end drawing of triangles
以下是此例子的完整 Render() 函数以及示例输出。要查看完整代码,请参见可下载文件中的“triangle”项目文件夹。
void Render() { //clear color and depth buffer glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glLoadIdentity();//load identity matrix glTranslatef(0.0f,0.0f,-4.0f);//move forward 4 units glColor3f(0.0f,0.0f,1.0f); //blue color glBegin(GL_TRIANGLES);//start drawing triangles glVertex3f(-1.0f,-0.25f,0.0f);//triangle one first vertex glVertex3f(-0.5f,-0.25f,0.0f);//triangle one second vertex glVertex3f(-0.75f,0.25f,0.0f);//triangle one third vertex //drawing a new triangle glVertex3f(0.5f,-0.25f,0.0f);//triangle two first vertex glVertex3f(1.0f,-0.25f,0.0f);//triangle two second vertex glVertex3f(0.75f,0.25f,0.0f);//triangle two third vertex glEnd();//end drawing of triangles }
多边形由至少三个顶点组成,这些顶点连接在一起形成一个形状。在这个例子中,我们将使用 GL_POLYGON 模式来绘制一个六边形。
GL_POLYGON 模式允许你绘制任意数量边形的形状。由于 GL_POLYGON 是一个单数词(意味着单词末尾没有“S”),你只能在一个 glBegin() 和 glEnd() 函数调用之间绘制一个多边形。另外,你指定的最后一个顶点会自动连接到第一个指定的顶点。当然,由于多边形是一个封闭的形状,就像三角形一样,形状将用你指定的颜色填充(目前为蓝色)。以下是我们的六边形的图。
(注意:这不能用于 凹多边形)
以下是绘制这个多边形的代码
glBegin(GL_POLYGON);//begin drawing of polygon glVertex3f(-0.5f,0.5f,0.0f);//first vertex glVertex3f(0.5f,0.5f,0.0f);//second vertex glVertex3f(1.0f,0.0f,0.0f);//third vertex glVertex3f(0.5f,-0.5f,0.0f);//fourth vertex glVertex3f(-0.5f,-0.5f,0.0f);//fifth vertex glVertex3f(-1.0f,0.0f,0.0f);//sixth vertex glEnd();//end drawing of polygon
以下是完整的 Render() 函数以及示例输出。在包含的可下载文件中查找“polygon”项目文件夹中的完整代码。
void Render() { //clear color and depth buffer glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glLoadIdentity();//load identity matrix glTranslatef(0.0f,0.0f,-4.0f);//move forward 4 units glColor3f(0.0f,0.0f,1.0f); //blue color glBegin(GL_POLYGON);//begin drawing of polygon glVertex3f(-0.5f,0.5f,0.0f);//first vertex glVertex3f(0.5f,0.5f,0.0f);//second vertex glVertex3f(1.0f,0.0f,0.0f);//third vertex glVertex3f(0.5f,-0.5f,0.0f);//fourth vertex glVertex3f(-0.5f,-0.5f,0.0f);//fifth vertex glVertex3f(-1.0f,0.0f,0.0f);//sixth vertex glEnd();//end drawing of polygon }
使用 OpenGL 即时模式有一些缺点。例如,顶点数据必须在绘制时动态传输到图形内存。这可以通过使用显示列表来改进。显示列表本质上是采用 glBegin()/glEnd() 命令序列并以有效的方式将其存储在图形卡侧。
(待办事项:稍后详细说明,请参阅 [1] 以获取一些信息 - glGenLists(), glNewList(), glEndList(), glCallList(), glDeleteLists())
显示列表也有一些缺点。一旦编译,显示列表就是静态的,无法更改。此外,由多个基本图形共享的顶点在绘制时仍然需要多次表示和变换。这非常低效。
顶点数组和顶点缓冲区解决了这些问题。思路很简单,就是使用数组存储顶点数据。使用 glDrawArrays(),可以使用这些顶点绘制基本图形。
为了在视频内存中存储数据,可以使用顶点缓冲区(glGenBuffer()、glBindBuffer()、glBufferData()、glDeleteBuffers())。 顶点缓冲区存在两种类型。
- GL_ARRAY_BUFFER 用于保存实际的顶点数据。
- GL_ELEMENT_ARRAY_BUFFER 用于保存指向存储在独立的 GL_ARRAY_BUFFER 中的顶点的索引,从而允许在多个图元中重用顶点。
(待办事项:稍后详细说明,举例)