OpenGL是一种可以对图形硬件设备特性进行访问的软件库,它的1.0版本发布于1994年7月,主要用于计算机图形学。随着AR和VR的发展,计算机图形学算法会变的日益重要,比如光线追踪[RayTracing]。
一.编译源码
使用CLion打开OGLPG-9th-Edition源码[1],在根目录下创建build文件夹,然后cd build,执行命令cmake …,报错如下所示:
解决方法是注释CMakeLists.txt文件中的92-94行代码:
二.遇到问题
遇到无法打开文件glfw3_d.lib问题时,需要编译OGLPG-9th-Edition\lib\glfw源码[3]:
编译解决方案,在OGLPG-9th-Edition\lib\glfw\build\src\Debug中可以找到glfw3.lib和glfw3.pdb文件:
将glfw3.lib和glfw3.pdb重命名为glfw3_d.lib和glfw3_d.pdb后,拷贝到OGLPG-9th-Edition\lib目录下面:
三.运行例子
运行例子01-keypress.cpp如下所示:
运行例子01-triangles.cpp如下所示:
四.01-triangles.cpp源码分析
(1)顶点着色器和片元着色器
GLFW库是什么呢?GLFW是用来创建OpenGL上下文以及操作窗口的一个第三方库。那Glew库又是什么呢?由于各个平台和显卡厂家的OpenGL的API都有区别,Glew[OpenGL Extension Wrangler Library]就是把这些个API整合起来的一个库。顶点着色(包括细分和几何着色)决定了一个图元应该位于屏幕的什么位置,而片元着色使用这些信息来决定某个片元的颜色应该是什么。
(2)OpenGL和C数据类型对应关系
后缀 | 数据类型 | C语言数据类型 | 对应的OpenGL类型 |
---|---|---|---|
b | 8位整型 | signed char | GLbyte |
s | 16位整型 | signed short | GLshort |
i | 32位整型 | int | GLint、GLsizei |
f | 32位浮点型 | float | GLfloat、GLclampf |
d | 64位浮点型 | double | GLdouble、GLclampd |
ub | 8位无符号整型 | unsigned char | GLubyte |
us | 16位无符号整型 | unsigned short | GLushort |
ui | 32位无符号整型 | unsigned int | GLuint、GLenum、GLbitfield |
(3)01-triangles.cpp文件源码和注释
#include "vgl.h"
#include "LoadShaders.h"
enum VAO_IDs { Triangles, NumVAOs };
enum Buffer_IDs { ArrayBuffer, NumBuffers };
enum Attrib_IDs { vPosition = 0 };
GLuint VAOs[NumVAOs];
GLuint Buffers[NumBuffers];
const GLuint NumVertices = 6;
void init( void )
{
// n:指定要生成的顶点数组对象名字的数量
// arrays:指定生成的顶点数组对象名字要存储的数组
// 分配顶点数组对象:返回n个未使用的对象名到数组arrays中,用作顶点数组对象
glGenVertexArrays( NumVAOs, VAOs );
// array:指定绑定的顶点数组的名字
// 创建并绑定一个顶点数组对象
glBindVertexArray( VAOs[Triangles] );
GLfloat vertices[NumVertices][2] = {
{ -0.90f, -0.90f }, { 0.85f, -0.90f }, { -0.90f, 0.85f }, // Triangle 1
{ 0.90f, -0.85f }, { 0.90f, 0.90f }, { -0.85f, 0.90f } // Triangle 2
};
// void glCreateBuffers(GLsizei n, GLuint* buffers);
// 返回n个当前未使用的缓存对象名称(每个都表示一个新创建的缓存对象),并保存到buffers数组中
glCreateBuffers( NumBuffers, Buffers );
// void glBindBuffer(GLenum target, GLuint buffer);
// 将名称为buffer的缓存对象绑定到target所指定的缓存结合点。target必须是OpenGL支持的缓存绑定目标之一,buffer必须是通过glCreateBuffers()分配的名称。
// 如果buffer是第一次被绑定,那么它所对应的缓存对象也将同时被创建。
glBindBuffer( GL_ARRAY_BUFFER, Buffers[ArrayBuffer] );
// void glBufferStorage(GLenum target, GLsizeiptr size, const void * data, GLbitfield flags);
// glBufferStorage为当前绑定到目标缓冲区对象创建新的不可变数据存储
glBufferStorage( GL_ARRAY_BUFFER, sizeof(vertices), vertices, 0);
ShaderInfo shaders[] =
{
{ GL_VERTEX_SHADER, "media/shaders/triangles/triangles.vert" },
{ GL_FRAGMENT_SHADER, "media/shaders/triangles/triangles.frag" },
{ GL_NONE, NULL }
};
GLuint program = LoadShaders( shaders );
glUseProgram( program );
// glVertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *pointer);
// index:着色器中的属性位置
// size:表示每个顶点需要更新的分量数目,可以是1、2、3、4或GL_BGRA
// type:指定数组中每个元素的数据类型
// normalized:设置顶点数据在存储前是否需要进行归一化
// stride:数组中每两个元素之间的大小偏移值
// pointer:表示缓存对象中,从起始位置开始计算的数组数据的偏移值,使用基本的系统单位byte
glVertexAttribPointer( vPosition, 2, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0) );
glEnableVertexAttribArray( vPosition );
}
void display( void )
{
static const float black[] = { 0.0f, 0.0f, 0.0f, 0.0f };
// 清除帧缓存中的数据再进行渲染
// GL_COLOR:清除的缓存类型
// 0:设置要清除的缓存索引
// back:设置清除缓存之后的颜色
glClearBufferfv(GL_COLOR, 0, black);
// 选择作为顶点数据使用的顶点数组
glBindVertexArray( VAOs[Triangles] );
// 请求渲染几何图元
glDrawArrays( GL_TRIANGLES, 0, NumVertices );
}
int main( int argc, char** argv )
{
// glfw初始化和配置
glfwInit();
// 同时创建渲染窗口换个一个新的OpenGL环境,用来执行渲染指令
GLFWwindow* window = glfwCreateWindow(800, 600, "Triangles", NULL, NULL);
// 设置window中的窗口所关联的OpenGL环境为当前环境
glfwMakeContextCurrent(window);
// 初始化GL3W库,创建OpenGL环境前,这个方向必须调用一次
gl3wInit();
// 设置程序中用到的数据
init();
while (!glfwWindowShouldClose(window))
{
// 渲染工作
display();
// 交换该窗口前端和后端的缓存,重回内容并且显示出来
glfwSwapBuffers(window);
// 处理所有的等待事件,检查操作系统返回的任何信息
glfwPollEvents();
}
// 销毁指定窗口和它的上下文环境,判断是否需要关闭窗口
glfwDestroyWindow(window);
// 关闭GLFW库
glfwTerminate();
}
(4)顶点着色器triangles.vert文件代码和注释
#version 400 core //OpenGL着色语言版本
layout( location = 0 ) in vec4 vPosition; //保存顶点位置信息
void main()
{
gl_Position = vPosition; //将输入顶点位置复制到顶点着色器的指定输出位置
}
(5)片元着色器文件代码和注释
#version 450 core
out vec4 fColor; //片元所对应的颜色值
void main()
{
fColor = vec4(0.5, 0.4, 0.8, 1.0);
}
参考文献:
[1]The OpenGL Programming Guide 9th Edition:http://www.opengl-redbook.com/
[2]OpenGL Red Book Example Code:https://github.com/openglredbook/examples
[3]GLFW源码下载-编译-使用:http://t.zoukankan.com/Doyoung-p-13690602.html
[4]OpenGL编程指南[第9版]