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 <iostream>
  4 #include <fstream>
  5 #include <glm\gtc\matrix_transform.hpp>
  6 #include <glm\gtx\transform.hpp>
  7 #include <ShapeGenerator.h>
  8 #include <Qt3DInput\qmouseevent.h>
  9 #include <Qt3DInput\qkeyevent.h>
 10
 11
 12 GLuint programID;
 13
 14
 15 GLuint VertexBufferID;
 16 GLuint IndexBufferID;
 17
 18 GLuint cubeVertexArrayObjectID;
 19 //立方体的索引数组长度
 20 GLuint cubeNumIndices;
 21
 22 GLuint tetraVertexArrayObjectID;
 23 //四面体的索引数组长度
 24 GLuint tetraNumIndices;
 25
 26 GLuint tetraIndexByteOffset;
 27
 28 GLuint fullTransformUniformLocation;
 29
 30
 31 void MyGlWindow::sendDataToOpenGL()
 32 {
 33     //创建Cube
 34     ShapeData cube = ShapeGenerator::makeCube();
 35     //创建四面体
 36     ShapeData tetra = ShapeGenerator::makeTetrahedron();
 37
 38     //创建和设置VertexBuffer
 39     glGenBuffers(1, &VertexBufferID);
 40     glBindBuffer(GL_ARRAY_BUFFER, VertexBufferID);
 41     glBufferData(GL_ARRAY_BUFFER, cube.vertexBufferSize() + tetra.vertexBufferSize(),0, GL_STATIC_DRAW);
 42     glBufferSubData(GL_ARRAY_BUFFER, 0, cube.vertexBufferSize(), cube.vertices);
 43     glBufferSubData(GL_ARRAY_BUFFER, cube.vertexBufferSize(), tetra.vertexBufferSize(), tetra.vertices);
 44
 45     //创建和设置IndexBuffer
 46     glGenBuffers(1, &IndexBufferID);
 47     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IndexBufferID);
 48     glBufferData(GL_ELEMENT_ARRAY_BUFFER, cube.indexBufferSize() + tetra.indexBufferSize() , 0, GL_STATIC_DRAW);
 49     glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, cube.indexBufferSize(), cube.indices);
 50     glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, cube.indexBufferSize(), tetra.indexBufferSize(), tetra.indices);
 51
 52
 53     cubeNumIndices = cube.numIndices;
 54     tetraNumIndices = tetra.numIndices;
 55
 56
 57
 58     //设置绘制Cube的VAO
 59     //生成VAO
 60     glGenVertexArrays(1, &cubeVertexArrayObjectID);
 61     //绑定VAO,后续的一系列状态和设置都会存储在这个VAO里。
 62     glBindVertexArray(cubeVertexArrayObjectID);
 63     //开启通道1(位置)
 64     glEnableVertexAttribArray(0);
 65     //开启通道2(颜色)
 66     glEnableVertexAttribArray(1);
 67     //绑定顶点数据ID到绑定点
 68     glBindBuffer(GL_ARRAY_BUFFER, VertexBufferID);
 69     //设置通道1如何获取数据
 70     glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 6, 0);
 71     //设置通道2如何获取数据
 72     glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 6, (void*)(sizeof(float) * 3));
 73     //绑定索引数据ID到绑定点
 74     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IndexBufferID);
 75
 76
 77     //设置绘制四面体的VAO
 78     glGenVertexArrays(1, &tetraVertexArrayObjectID);
 79     glBindVertexArray(tetraVertexArrayObjectID);
 80     //开启通道1(位置)
 81     glEnableVertexAttribArray(0);
 82     //开启通道2(颜色)
 83     glEnableVertexAttribArray(1);
 84     //绑定顶点数据ID到绑定点
 85     glBindBuffer(GL_ARRAY_BUFFER, VertexBufferID);
 86     //设置通道1如何获取数据
 87     glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 6, (void*)(cube.vertexBufferSize()));
 88     //设置通道2如何获取数据
 89     glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 6, (void*)(cube.vertexBufferSize() +sizeof(float) * 3));
 90     //绑定索引数据ID到绑定点
 91     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IndexBufferID);
 92
 93     tetraIndexByteOffset = cube.indexBufferSize();
 94
 95     cube.cleanUp();
 96     tetra.cleanUp();
 97 }
 98
 99 void MyGlWindow::installShaders()
100 {
101     //...
102 }
103
104 void MyGlWindow::initializeGL()
105 {
106     glewInit();
107     glEnable(GL_DEPTH_TEST);
108     sendDataToOpenGL();
109     installShaders();
110 }
111
112 void MyGlWindow::paintGL()
113 {
114     glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
115     glViewport(0, 0, width(), height());
116
117     //绑定cube的VAO,下面绘制的都是立方体--------------------------------------
118     glBindVertexArray(cubeVertexArrayObjectID);
119
120     glm::mat4 fullTransformMatrix;
121     glm::mat4 viewToProjectionMatrix = glm::perspective(30.0f, ((float)width()) / height(), 0.1f, 10.0f);
122     glm::mat4 worldToViewMatrix = camera.getWorldToViewMatrix();
123     glm::mat4 worldToProjectionMatrix = viewToProjectionMatrix * worldToViewMatrix;
124
125     //绘制Cube1
126     glm::mat4 cube1ModelToWorldMatrix =
127         glm::translate(glm::vec3(-1.0f, 0.0f, -3.0f))*
128         glm::rotate(36.0f, glm::vec3(1.0f, 0.0f, 0.0f));
129
130     fullTransformMatrix = worldToProjectionMatrix * cube1ModelToWorldMatrix;
131     glUniformMatrix4fv(fullTransformUniformLocation, 1, GL_FALSE, &fullTransformMatrix[0][0]);
132     glDrawElements(GL_TRIANGLES, cubeNumIndices, GL_UNSIGNED_SHORT, 0);
133
134     //绘制Cube2
135     glm::mat4 cube2ModelToWorldMatrix =
136         glm::translate(glm::vec3(1.0f, 0.0f, -3.75f))*
137         glm::rotate(36.0f, glm::vec3(0.0f, 1.0f, 0.0f));
138     fullTransformMatrix = worldToProjectionMatrix * cube2ModelToWorldMatrix;
139     glUniformMatrix4fv(fullTransformUniformLocation, 1, GL_FALSE, &fullTransformMatrix[0][0]);
140     glDrawElements(GL_TRIANGLES, cubeNumIndices, GL_UNSIGNED_SHORT, 0);
141
142     //绑定Tetra的VAO,下面绘制的都是四面体--------------------------------------
143     glBindVertexArray(tetraVertexArrayObjectID);
144
145     //绘制Tetra1
146     glm::mat4 tetra1ModelToWorldMatrix =
147         glm::translate(glm::vec3(1.0f, -2.0f, -3.75f))*
148         glm::rotate(36.0f, glm::vec3(0.0f, 1.0f, 0.0f));
149     fullTransformMatrix = worldToProjectionMatrix * tetra1ModelToWorldMatrix;
150     glUniformMatrix4fv(fullTransformUniformLocation, 1, GL_FALSE, &fullTransformMatrix[0][0]);
151     glDrawElements(GL_TRIANGLES, tetraNumIndices, GL_UNSIGNED_SHORT, (void*)tetraIndexByteOffset);
152
153     glm::mat4 tetra2ModelToWorldMatrix =
154         glm::translate(glm::vec3(-3.0f, -2.0f, -3.75f))*
155         glm::rotate(36.0f, glm::vec3(1.0f, 1.0f, 0.0f));
156     fullTransformMatrix = worldToProjectionMatrix * tetra2ModelToWorldMatrix;
157     glUniformMatrix4fv(fullTransformUniformLocation, 1, GL_FALSE, &fullTransformMatrix[0][0]);
158     glDrawElements(GL_TRIANGLES, tetraNumIndices, GL_UNSIGNED_SHORT, (void*)tetraIndexByteOffset);
159 }
160
161
162 std::string MyGlWindow::ReadShaderCode(const char* fileName)
163 {
164     //...
165 }
166
167 void MyGlWindow::mouseMoveEvent(QMouseEvent * e)
168 {
169     //...
170 }
171
172 void MyGlWindow::keyPressEvent(QKeyEvent * e)
173 {
174     //...
175 }

注意:为了方便起见,我们把原先setupVertexArray函数的内容全部移动到sendDataToOpenGL函数中了。

下面详解改动的过程:

  • 首先合并了两个顶点数组和两个索引数组, cubeVertexBufferID + tetraVertexBufferID -> VertexBufferID, cubeIndexBufferID + tetraIndexBufferID -> IndexBufferID。
  • 在sendDataToOpenGL()函数的一开始,我们先定义好两个图形。
  • 合并了顶点数组和索引数组以后,在初始化时候就要初始化足够的长度,在41行我们指定VertexBuffer的长度为: cube.vertexBufferSize() + tetra.vertexBufferSize(),正好容纳两个顶点数组,而数组内容暂时为空(第三个参数为0)。
  • 然后使用两个glBufferSubData函数分块给顶点数组填充内容,42,43行分别给VertexBuffer的第一部分和第二部分填充了数据,注意第二个和第三个参数,分别指定了开始的偏移值和数组的长度。这也是为什么42行的第二个参数为0,而43行的第二个参数为cube.vertexBuffer()的原因。
  • 顶点数组设定好以后,下面就设定索引数组(46-50),其设定方法和顶点数组类似,就不赘述了。
  • 我们把sendDataToOpenGL函数和setupVertexArray函数合并,并且把cube.cleanUp()和tetra.cleanUp()放在了最后,原因是后面还需要使用到cube对象的相关属性
  • 58-91行中只改动了87和89行的最后一个参数。这里的改动主要是针对VertexBuffer的,因为VertexBuffer发生了变化,所以四面体的位置和颜色信息在数组中都要往后整体偏移cube.vertexBufferSize()个位置。
  • 93行我们定义了一个tetraIndexByteOffset成员,用来记录立方体的索引Buffer的长度(绘制的时候要用)
  • 在绘制函数中,内容同样基本没变,只是改变了151行和158行的最后一个参数,这里是针对IndexBuffer的,因为glDrawElements()函数的最后一个参数是说明索引Buffer数组的偏移值的(顶点Buffer在前面已经用glVertexAttribPointer函数设置过了),因此,在绘制四面体时候需要向后偏移上一步我们记录的tetraIndexByteOffset个单位。绘制立方体则不需要偏移,因为它们仍处在数组的开头。

修改完成后,运行,结果和上节一样,但是逻辑上我们已经把四个数组简化成2个数组了。

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

时间: 2024-08-07 19:35:28

3D Computer Grapihcs Using OpenGL - 20 结合Buffer的相关文章

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

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

一步步学OpenGL(20) -《点光源》

教程 20 点光源 原文: http://ogldev.atspace.co.uk/www/tutorial20/tutorial20.html CSDN完整版专栏: http://blog.csdn.net/column/details/13062.html 背景 之前已经学习了三个基本的光照模型(环境光,漫射光和镜面反射光),这三种模型都是基于平行光的.平行光只是通过一个向量来表示,没有光源起点,因此它不会随着距离的增大而衰减(实际上没有起点根本无法定义光源和某个物体的距离).现在我们再来看

【一步步学OpenGL 20】 -《点光源》

教程 20 点光源 原文: http://ogldev.atspace.co.uk/www/tutorial20/tutorial20.html CSDN完整版专栏: http://blog.csdn.net/column/details/13062.html 背景 之前已经学习了三个主要的光照模型(环境光,漫射光和镜面反射光),这三种模型都是基于平行光的.平行光仅仅是通过一个向量来表示,没有光源起点,因此它不会随着距离的增大而衰减(实际上没有起点根本无法定义光源和某个物体的距离). 如今我们再

20个不可思议的 WebGL 示例和演示

WebGL 是一项在网页浏览器呈现3D画面的技术,有别于过去需要安装浏览器插件,通过 WebGL 的技术,只需要编写网页代码即可实现3D图像的展示.WebGL 可以为 Canvas 提供硬件3D加速渲染,这样 Web 开发人员就可以借助系统显卡来在浏览器里更流畅地展示3D场景和模型了.在这篇文章中20个不可思议的 WebGL 示例来增强你对于这个新技术的理解. 1. Aquarium Image Source:www.webglsamples.org Created by Greggman an

&lt;转载&gt; OpenGL Projection Matrix

原文 OpenGL Projection Matrix Related Topics: OpenGL Transformation Overview Perspective Projection Orthographic Projection Updates: The MathML version is available here. Overview A computer monitor is a 2D surface. A 3D scene rendered by OpenGL must b

OpenGL学习之路(一)

1 引子 虽然是计算机科班出身,但从小对几何方面的东西就不太感冒,空间想象能力也较差,所以从本科到研究生,基本没接触过<计算机图形学>.为什么说基本没学过呢?因为好奇(尤其是惊叹于三维游戏的逼真,如魔兽世界.极品飞车),在研究生阶段还专门选修计算机图形学,但也只是听了几堂课,知道了有帧缓存.齐次坐标等零零散散的概念,之后读了一篇论文并上台作报告(压根没读懂).总之,当时只是觉得计算机图形学或三维渲染很牛,甚至问我什么是渲染都不知道,更不知道如何将3维几何体显示到2维屏幕上.令我现在想来非常可笑