OpenGL的主要作用就是讲图形渲染到帧缓冲当中。为了实现这一要求,需要将复杂的物体分解成图元的形式(包括点、线、以及三角形),当它们的分布密度足够高时,就可以表达为2D以及3D物体的形态。OpenGL可以支持很多种不同的图元类型。不过它们最后都可以归结为三种类型的一种,即点、线或者三角形。线和三角形图元类型可以再组合为条带、循环体(线),或扇面(三角形)。这些图元类型通过OpenGL的枚举量来进行表达,并且作为渲染函数的输入参数。下图为图元类型与OpenGL枚举量之间的对应关系。
我们利用三角形图元渲染出一个彩色的立方体,而是是利用索引绘制方式。也从篇开始,着色编程添加打印错误日志。代码主要代码如下:
void MyQGLWidget::initShader()
{
glGenVertexArrays(NumVAOs, VAOs);
glBindVertexArray(VAOs[Triangles]);
// create a cube
// v6----- v5
// /| /|
// v1------v0|
// | | | |
// | |v7---|-|v4
// |/ |/
// v2------v3
GLfloat vertices[] = {
// position // color
0.5, 0.5, 0.5, 1.0, 1.0, 1.0, // v0 White
-0.5, 0.5, 0.5, 1.0, 0.0, 1.0, // v1 Magenta
-0.5, -0.5, 0.5, 1.0, 0.0, 0.0, // v2 Red
0.5, -0.5, 0.5, 1.0, 1.0, 0.0, // v3 Yellow
0.5, -0.5, -0.5, 0.0, 1.0, 0.0, // v4 Green
0.5, 0.5, -0.5, 0.0, 1.0, 1.0, // v5 Cyan
-0.5, 0.5, -0.5, 0.0, 0.0, 1.0, // v6 Blue
-0.5, -0.5, -0.5, 0.0, 0.0, 0.0 // v7 Black
};
//vertex index
GLushort indices[36] = {
0, 1, 2, 0, 2, 3, // front
0, 3, 4, 0, 4, 5, // right
0, 5, 6, 0, 6, 1, // up
1, 6, 7, 1, 7, 2, // right
7, 4, 3, 7, 3, 2, // down
4, 7, 6, 4, 6, 5 // back
};
glGenBuffers(NumBuffers, Buffers);
glBindBuffer(GL_ARRAY_BUFFER, Buffers[ArrayBuffer]);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glEnableVertexAttribArray(vPosition);
glVertexAttribPointer(vPosition, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)0);
glEnableVertexAttribArray(vColor);
glVertexAttribPointer(vColor, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)(3* sizeof(GLfloat)));
GLuint indexBufferID;
glGenBuffers(1, &indexBufferID);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBufferID);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
const char* vertexShaderCode =
"#version 430 \n"
""
"layout(location = 0) in vec3 vPosition;"
"layout(location = 1) in vec3 color;"
"out vec3 myColor;"
""
"void main()"
"{"
" mat4 rotatey = mat4(0.5, 0.0, 0.866, 0.0, 0.0,1.0,0.0,0.0, -0.866,0.0,0.5,0.0, 0.0,0.0, 0.0,1.0);"
" mat4 rotatex = mat4(1.0, 0.0, 0.0, 0.0, 0.0,0.707,-0.707,0.0, 0.0,0.707,0.707,0.0, 0.0,0.0, 0.0,1.0);"
" gl_Position = rotatex *rotatey* vec4(vPosition, 1.0);"
" myColor = color;"
"}";
const char* fragmentShaderCode =
"#version 430 \r \n"
""
"in vec3 myColor;"
"out vec4 fColor;"
""
"void main()"
"{"
" fColor = vec4(myColor, 1.0f);"
"}";
GLuint vertexShaderID = glCreateShader(GL_VERTEX_SHADER);
GLuint fragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER);
const char* adapter[1];
adapter[0] = vertexShaderCode;
glShaderSource(vertexShaderID, 1, adapter, 0);
adapter[0] = fragmentShaderCode;
glShaderSource(fragmentShaderID, 1, adapter, 0);
glCompileShader(vertexShaderID);
GLint compiled;
glGetShaderiv(vertexShaderID, GL_COMPILE_STATUS, &compiled );
if (!compiled)
{
std::cout<<"vertexShaderID";
GLsizei len;
glGetShaderiv( vertexShaderID, GL_INFO_LOG_LENGTH, &len );
GLchar* log = new GLchar[len+1];
glGetShaderInfoLog( vertexShaderID, len, &len, log );
std::cerr << "Shader compilation failed: " << log << std::endl;
delete [] log;
}
glCompileShader(fragmentShaderID);
glGetShaderiv(fragmentShaderID, GL_COMPILE_STATUS, &compiled );
if (!compiled)
{
std::cout<<"fragmentShaderID";
GLsizei len;
glGetShaderiv( fragmentShaderID, GL_INFO_LOG_LENGTH, &len );
GLchar* log = new GLchar[len+1];
glGetShaderInfoLog( fragmentShaderID, len, &len, log );
std::cerr << "Shader compilation failed: " << log << std::endl;
delete [] log;
}
GLuint programID = glCreateProgram();
glAttachShader(programID, vertexShaderID);
glAttachShader(programID, fragmentShaderID);
glLinkProgram(programID);
GLint linked;
glGetProgramiv( programID, GL_LINK_STATUS, &linked );
if (!linked)
std::cout<<"Error";
glUseProgram(programID);
}
大部分OpenGL绘制命令都是以Draw这个单词开始的。绘制命令大致可以分为两个部分:索引形式和非索引形式的绘制。索引形式的绘制需要用到绑定GL_ELEMENT_ARRAY_BUFFER的缓存对象中存储的索引数组,它可以用来间接地对已经启用的顶点数组进行索引。而我们之前的渲染都是用非索引的绘制。什么时候应用索引绘制?索引绘制能够节省存储空间,共享顶点属性数据,但存在的限制时共享的数据的属性时相同的。当我们需要为同一个顶点指定不同的属性,例如颜色和法向量时,索引绘制无法满足需求,这时候需要使用顶点数组为同一个顶点指定不同属性。最基本的索引形式的绘制命令是glDrawElements。
void glDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices);
使用count个元素来定义一个系列几何图元,而元素的索引值保存在GL_ELEMENT_ARRAY_BUFFER的缓存中。
model定义了图元类型,它必须是图元类型标识符中一个。
代码下载
OpenGL学习系列导航