3D Computer Grapihcs Using OpenGL - 10 Color Buffer

本节我们将尝试利用三角形制作一个“走马灯”效果。

一个三角形如图示方式,从左向右依次移动。

先看一下代码:

MyGlWindow.cpp

 1 #include <gl\glew.h>
 2 #include "MyGlWindow.h"
 3 #include <iostream>
 4 #include <fstream>
 5
 6 float triangleWidth = 0.1f;
 7 float bytesPerTriangle = sizeof(GLfloat) * 18;
 8 uint triangleIndex = 0;
 9 uint maxTriangleCount = 20;
10
11 void MyGlWindow::sendDataToOpenGL()
12 {
13     //GLfloat verts[] =
14     //{
15     //    -1.0f, -1.0f, +0.5f,//Vertex 0
16     //    +1.0f, +0.0f, +0.0f,//Color  0
17     //    +0.0f, +1.0f, -0.5f,//Vertex 1
18     //    +0.0f, +1.0f, +0.0f,//Color  1
19     //    +1.0f, -1.0f, +0.5f,//Vertex 2
20     //    +0.0f, +0.0f, +1.0f,//Color  2
21
22     //    -1.0f, +1.0f, +0.5f,//Vertex 3
23     //    +0.5f, +0.3f, +0.1f,//Color  3
24     //    +0.0f, -1.0f, -0.5f,//Vertex 4
25     //    +0.1f, +0.4f, +0.2f,//Color  4
26     //    +1.0f, +1.0f, +0.5f,//Vertex 5
27     //    +1.0f, +0.5f, +0.2f,//Color  5
28     //};
29
30     GLuint vertexBufferID;
31     glGenBuffers(1, &vertexBufferID);
32     glBindBuffer(GL_ARRAY_BUFFER, vertexBufferID);
33     glBufferData(GL_ARRAY_BUFFER, maxTriangleCount * bytesPerTriangle, NULL, GL_STATIC_DRAW);
34
35     //GLushort indices[] =
36     //{
37     //    0,1,2,
38     //    3,4,5,
39     //};
40     //GLuint indexBufferID;
41     //glGenBuffers(1, &indexBufferID);
42     //glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBufferID);
43     //glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
44
45     glEnableVertexAttribArray(0);
46     glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 6, 0);
47
48     glEnableVertexAttribArray(1);
49     glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 6, (char*)(sizeof(GLfloat) * 3));
50 }
51
52 void MyGlWindow::installShaders()
53 {
54     //未修改,省略...
55 }
56
57 void MyGlWindow::initializeGL()
58 {
59     glewInit();
60     glEnable(GL_DEPTH_TEST);
61     sendDataToOpenGL();
62     installShaders();
63 }
64
65 void MyGlWindow::paintGL()
66 {
67     glClear(GL_DEPTH_BUFFER_BIT);
68     glViewport(0, 0, width(), height());
69     //glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, 0);
70     sendAnotherTriangle();
71     glDrawArrays(GL_TRIANGLES, (triangleIndex-1)*3, triangleIndex * bytesPerTriangle);
72 }
73
74 void MyGlWindow::sendAnotherTriangle()
75 {
76     if (triangleIndex == maxTriangleCount)
77         return;
78     GLfloat xVal = -1 + triangleIndex * triangleWidth;
79     GLfloat newTriangle[] =
80     {
81         xVal, 1.0f, 0.0f,
82         1.0f, 0.0f, 0.0f,
83
84         xVal + triangleWidth, 1.0f, 0.0f,
85         0.0f, 1.0f, 0.0f,
86
87         xVal, 0.0f, 0.0f,
88         0.0f, 0.0f, 1.0f,
89     };
90
91     glBufferSubData(GL_ARRAY_BUFFER, bytesPerTriangle * triangleIndex, bytesPerTriangle, newTriangle);
92
93     triangleIndex++;
94 }
95
96 std::string MyGlWindow::ReadShaderCode(const char* fileName)
97 {
98     //未修改,省略...
99 }

MyGlWindow.h

 1 #pragma once
 2 #include <QtOpenGL\qgl.h>
 3 #include <string>
 4 class MyGlWindow :public QGLWidget
 5 {
 6 protected:
 7     void sendDataToOpenGL();
 8     void installShaders();
 9     void initializeGL();
10     void paintGL();
11     std::string ReadShaderCode(const char* fileName);
12     void sendAnotherTriangle();
13 };

重点看cpp文件里的变化。

先定义了几个变量(其实也可以定义成常量),方便后面使用,他们分别是:

  • float triangleWidth = 0.1f 表示三角形的宽度
  • float bytesPerTriangle = sizeof(GLfloat) * 18 表示每个三角形包含的顶点信息数据字节数,一个三角形使用了3个顶点,每个顶点有6个GLfloat类型数据
  • uint triangleIndex = 0 表示当前绘制的三角形的索引
  • uint maxTriangleCount = 20 “走马灯”最多有多少个三角形

此前我们是在sendDataToOpenGL()函数中创建一个verts数组,把所有的数据一次性发送到OpenGL中进行绘制,本次我们需要动态改变绘制的内容,所以就不事先将数据一次性发送了。首先删除掉sendDataToOpenGL函数中的verts数组。(13-28行)

另外也不需要所以数组了,也把索引数组相关的内容删除掉。(35-43行以及69行)

33行也做了修改,首先我们要给VertexArrayBuffer分配足够的空间,所以第二个参数改成了maxTriangleCount * bytesPerTriangle,提供20个三角形需要的空间。而我们在这个阶段不需要提供任何数据(后面会讲如何提供),所以第三个参数直接给个空值NULL。

在71行绘制Array之前,我们调用了一个新添加的函数sendAnotherTriangle(),这个函数的前半部分(78-89行)是准备数据,准备每次走马灯要绘制的三角形的数据,由数据内容也能看出来,主要区别就是位置向右移动了。

重点是91行的函数

glBufferSubData(GL_ARRAY_BUFFER, bytesPerTriangle * triangleIndex, bytesPerTriangle, newTriangle);

glBufferSubData 这个OpenGL函数的作用是“部分填充” Array Buffer。可以对比观察33行的glBufferData(一次性全部填充), 名字只是多了一个Sub,但是两者的参数还是有些区别的。

  • 第一个参数和glBufferData是一样的,表示设置哪个绑定点的数据。
  • 第二个参数是一个绘制的起始位置,因为我们右了一个三角形的索引triangleIndex,所以起始值就是它乘以每个三角形的字节数。
  • 第三个参数表示每个元素的长度,正好使用我们一开始定义的每个三角形的字节数 bytesPerTriangle
  • 第四个参数是数据本身

71行绘制Array Buffer, 注意第二个参数是每个三角形的起始点。

完成后编译运行,发现画面并没有变化,主要原因是画面没有重绘,为了激活重绘,最简单的办法就是让窗口失去焦点和得到焦点,也就是可以在opengl窗口和其他任意窗口之间点击切换。

但是看到的效果仍然不是我们期望的。效果如下:

这是什么原因呢?

原因是OpenGL使用了双重缓存。一个Front Buffer, 一个Back Buffer。

绘制工作都是在Back Buffer上进行的,以免用户看到绘制的过程,绘制好以后,会和Front Buffer进行一次交换。这就是为什么我们看到了似乎有两副不同的图在反复切换。

另外,我们明确指定了每次只绘制一个三角形,但是为什么之前的三角形都保存下来了?

原因是我们没有进行一次“清理”。

找到MyGlWindow.cpp的67行,我们对它进行如下修改:

glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);

既然要清理Depth Buffer,我们顺便使用一个"位或" 运算符把 Color Buffer也添加上。

这样修改以后,就可以实现"走马灯"效果了!(效果就不截图了,动图太难弄了)

原文地址:https://www.cnblogs.com/AnKen/p/8343895.html

时间: 2024-10-14 20:11:25

3D Computer Grapihcs Using OpenGL - 10 Color Buffer的相关文章

3D Computer Grapihcs Using OpenGL - 20 结合Buffer

在上一节的案例中,我们使用了四个Buffer Object,立方体的VertexBuffer,立方体的索引Buffer,四面体的VertexBuffer,四面体的索引Buffer. 我们这节尝试把两个图形的Vertex Buffer结合,两个图形的索引Buffer结合,形成两个Buffer,让程序更加简化. 先看最终代码: MyGlWindow.cpp: 1 #include <gl\glew.h> 2 #include "MyGlWindow.h" 3 #include

3D Computer Grapihcs Using OpenGL - 05 EBO

本节将采用两种方法绘制两个三角形. 先看第一种方法的代码 MyGlWindow.cpp 1 #include <gl\glew.h> 2 #include "MyGlWindow.h" 3 4 void MyGlWindow::initializeGL() 5 { 6 glewInit(); 7 8 GLfloat verts[] = 9 { 10 +0.0f, +0.0f, 11 +1.0f, +1.0f, 12 -1.0f, +1.0f, 13 14 +0.0f, +0

3D Computer Grapihcs Using OpenGL - 07 Passing Data from Vertex to Fragment Shader

上节的最后我们实现了两个绿色的三角形,而绿色是直接在Fragment Shader中指定的. 这节我们将为这两个三角形进行更加自由的着色--五个顶点各自使用不同的颜色. 要实现这个目的,我们分两步进行,首先 在顶点数组里增加数据用来表示颜色 修改sendDataToOpenGL()函数中的verts数组: 1 GLfloat verts[] = 2 { 3 +0.0f, +0.0f, //Vertex 0 4 +1.0, +0.0, +0.0f, //Color 0 5 +1.0f, +1.0f

3D Computer Grapihcs Using OpenGL - 08 Text File Shaders

使用之前的方法写Shader是一件很痛苦的事情,把Shader代码直接卸载C++文件中,需要使用很多引号来包裹,既不美观也不方便. 我们这节的目的是使用纯文本文件保存Shader. 首先在工程中创建两个文件,分别命名为VertexShaderCode.glsl 和 FragmentShaderCode.glsl,后缀名可以自己随意指定,不一定非要是glsl. 然后把上节的Shader代码拷贝到两个文件中去. VertexShaderCode.glsl 1 #version 430 2 3 in

Bentley.ProSteel.3D.v18.0.Rev.8.10.0.9结构软件.

Delft3D 3.23 (河口海岸数值模拟) Delft3D,V3.23,最好的水数值模拟软件\ FastCAM.v6.0-ISO 1CD(数控切割编程套料软件)\ Flow2000 v5.3 1CD(最好的高聚物挤出过程分析软件)\ Flow2000 v6.2 1CD(最好的高聚物挤出过程分析软件) \ maxsurf 中文教程手册\ PROFILE_MASTER_2000_CAM-DUCT_v2.26.050 风管展开软体 pm2000\ PVelite 2006 压力容器设计和分析软件

【原创】Linux环境下的图形系统和AMD R600显卡编程(10)——R600显卡的3D引擎编程

3D图形处理流水线需要流经多个硬件单元才能得到最后的渲染结果,流水线上的所有的硬件单元必须被正确编程,才能得到正确的结果. 总体上看,从图形处理流水线的源头开始,需要准备好vertex和index,在立即模式下,index可以直接编程在命令中,通过配置寄存器告诉GPU vertex buffer的位置,在启动GPU流水线之前,还需要将vertex shader程序和pixel shader程序加载到vram 中,并通过配置寄存器告示GPU shader程序的位置,在vertex shader和p

OpenGL学习脚印: 帧缓冲对象(Frame Buffer Object)

写在前面 一直以来,我们在使用OpenGL渲染时,最终的目的地是默认的帧缓冲区,实际上OpenGL也允许我们创建自定义的帧缓冲区.使用自定义的帧缓冲区,可以实现镜面,离屏渲染,以及很酷的后处理效果.本节将学习帧缓存的使用,文中示例代码均可以在我的github下载. 本节内容整理自 1.OpenGL Frame Buffer Object (FBO) 2.www.learnopengl.com Framebuffers FBO概念 在OpenGL中,渲染管线中的顶点.纹理等经过一系列处理后,最终显

3D OpenGL ES

什么是OpenGL ES? OpenGL ES (为OpenGL for Embedded System的缩写) 为适用于嵌入式系统的一个免费二维和三维图形库. 为桌面版本OpenGL 的一个子集. OpenGL ES管道(Pipeline) OpenGL ES 1.x 的工序是固定的,称为Fix-Function Pipeline,可以想象一个带有很多控制开关的机器,尽管加工的工序是固定的,但是可以通过打开或关闭开关来设置参数或者打开关闭某些功能.OpenGL ES 2.0 允许提供编程来控制

OpenGL ES 3.0之Fragment buffer objects(FBO)详解(一)

片段操作图 这篇文章将介绍从写入帧缓冲和读取帧缓冲的方式. Buffers(缓冲) OpenGL ES支持三种缓冲: OpenGL ES •• Color buffer颜色缓冲 •• Depth buffer深度缓冲 •• Stencil buffer模板缓冲 创建缓冲区 OpenGL ES 是一个交互式的渲染系统,假设每帧的开始,你希望初始化所有缓冲区中数据的默认值.调用glClear 函数来清除缓冲区内容,参数mask 指定清除的缓冲区. 你可能不要求清除每一个缓冲区,不在同时清除它们.但如