计算机图形学-预告3
首先先声明,代码是来自www.cs.unm.edu/~angel。在下这里指示添加一些注释或者说明以及把里面的English翻译成Chinese。有部分是参考其他博客。
这一部分主要是讲公共使用的文件的。
InitShader.cpp
// 读取文件,并且返回指针
static char* readShaderSource(const char* shaderFile)
{
FILE* fp = fopen(shaderFile, "r");
if ( fp == NULL )
{
return NULL;
}
fseek(fp, 0L, SEEK_END);
long size = ftell(fp);
fseek(fp, 0L, SEEK_SET);
char* buf = new char[size + 1];
fread(buf, 1, size, fp);
buf[size] = '\0';
fclose(fp);
return buf;
}
//根据vShaderFile和fShaderFile创建GLSL program 对象
GLuint InitShader(const char* vShaderFile, const char* fShaderFile)
{
//查看GLSL和OpenGL的版本
const GLubyte *renderer = glGetString( GL_RENDERER );
const GLubyte *vendor = glGetString( GL_VENDOR );
const GLubyte *version = glGetString( GL_VERSION );
const GLubyte *glslVersion =
glGetString( GL_SHADING_LANGUAGE_VERSION );
GLint major, minor;
glGetIntegerv(GL_MAJOR_VERSION, &major);
glGetIntegerv(GL_MINOR_VERSION, &minor);
std::cout << "GL Vendor :" << vendor << std::endl;
std::cout << "GL Renderer : " << renderer << std::endl;
std::cout << "GL Version (string) : " << version << std::endl;
std::cout << "GL Version (integer) : " << major << "." << minor << std::endl;
std::cout << "GLSL Version : " << glslVersion << std::endl;
//构建信息数组
struct Shader
{
const char* filename;
GLenum type;
GLchar* source;
} shaders[2] =
{
{ vShaderFile, GL_VERTEX_SHADER, NULL },
{ fShaderFile, GL_FRAGMENT_SHADER, NULL }
};
//创建着色器程序
GLuint program = glCreateProgram();
for ( int i = 0; i < 2; ++i )
{
Shader& s = shaders[i];
s.source = readShaderSource( s.filename );
if ( shaders[i].source == NULL )//文件读取失败
{
std::cerr << "Failed to read " << s.filename << std::endl;
exit( EXIT_FAILURE );
}
//创建着色器对象:(片段着色器/顶点着色器)
GLuint shader = glCreateShader( s.type );
//把着色器源代码和着色器对象相关联
glShaderSource( shader, 1, (const GLchar**) &s.source, NULL );
//编译着色器对象
glCompileShader( shader );
GLint compiled;
//检查编译是否成功
glGetShaderiv( shader, GL_COMPILE_STATUS, &compiled );
if ( !compiled )
{
std::cerr << s.filename << " failed to compile:" << std::endl;
GLint logSize;
//得到编译日志长度
glGetShaderiv( shader, GL_INFO_LOG_LENGTH, &logSize );
char* logMsg = new char[logSize];
//得到日志信息并输出
glGetShaderInfoLog( shader, logSize, NULL, logMsg );
std::cerr << logMsg << std::endl;
delete [] logMsg;
exit( EXIT_FAILURE );
}
delete [] s.source;
//将着色器程序链接到所创建的程序中
glAttachShader( program, shader );
}
//将这些对象链接成一个可执行程序
glLinkProgram(program);
GLint linked;
//查询链接的结果
glGetProgramiv( program, GL_LINK_STATUS, &linked );
if ( !linked )//链接失败
{
std::cerr << "Shader program failed to link" << std::endl;
GLint logSize;
//得到链接日志长度
glGetProgramiv( program, GL_INFO_LOG_LENGTH, &logSize);
char* logMsg = new char[logSize];
//得到日志信息并输出
glGetProgramInfoLog( program, logSize, NULL, logMsg );
std::cerr << logMsg << std::endl;
delete [] logMsg;
exit( EXIT_FAILURE );
}
//链接成功,在OpenGL管线中使用渲染程序
glUseProgram(program);
return program;
}
关于VAO和VBO
- VAO(顶点数组对象 Vertex Array Object)是一个包含一个或数个顶点缓冲区对象,一般存储一个可渲染物体的所有信息
- VBO(缓冲区对象 Vertex Buffer Object)是指显卡内存中的一块高速内存缓冲区,用来存储顶点的所有信息
VBO是Vertex Buffer Object, VAO是Vertex Array Object。 VAO是OpenGL 3.0以后才引入的新东西,但是在2.0版本中做为扩展接口。
VBO其实就是显卡中的显存,为了提高渲染速度,可以将要绘制的顶点数据缓存在显存中,这样就不需要将要绘制的顶点数据重复从CPU发送到GPU, 浪费带宽资源。
而VAO则是一个容器,可以包括多个VBO, 它类似于以前的call list, 由于它进一步将VBO容于其中,所以绘制效率将在VBO的基础上更进一步。
一般在初始化数据的时候,会接触到。代码片段解释。
// @{ 创建定点数组对象(初始化VAO)
GLuint vao;
glGenVertexArrays( 1, &vao );// 生成一个未用的VAO ID,存于变量vao中
glBindVertexArray( vao ); // 创建id为vao的VAO,并绑定为当前VAO
// }@
// @{ 创建和初始化缓冲对象(生成VBO)
GLuint buffer;
glGenBuffers( 1, &buffer );// 生成一个未用的缓冲区对象ID,存于变量buffer中
glBindBuffer( GL_ARRAY_BUFFER, buffer );// 创建id为buffer的Array Buffer对象,并绑定为当前Array Buffer对象
// 为Buffer对象在GPU端申请空间,并提供数据
glBufferData(
GL_ARRAY_BUFFER,// Buffer类型
sizeof(points),// 申请空间大小
points,// 提供数据
GL_STATIC_DRAW // 表明将如何使用Buffer的标志(GL_STATIC_DRAW含义是一次提供数据,多遍绘制)
);
// }@
// Load shaders and use the resulting shader program
GLuint program = InitShader( "vshader.glsl", "fshader.glsl" );
glUseProgram( program ); // 使用该shader程序
// 初始化着色器里面的顶点位置的变量
// 获取shader程序中属性变量的位置(索引)
GLuint loc = glGetAttribLocation( program, "vPosition" );
// 启用顶点属性数组
glEnableVertexAttribArray( loc );
//事实上连接属性引索和缓冲区的方法
// 为顶点属性数组提供数据(数据存放在之前buffer对象中)
glVertexAttribPointer(
loc,//属性变量引索
2,//每个顶点属性的分量个数
GL_FLOAT,//数组数据类型
GL_FALSE,//是否进行归一化处理
0,//在数组中相邻属性成员间的间隔(以字节为单位)
BUFFER_OFFSET(0) // 第一个属性值在buffer中的偏移量
);
具体关于VAO、VBO的数据传输,可以参考:
http://blog.csdn.net/qweewqpkn/article/details/46365405
http://blog.csdn.net/wanglang3081/article/details/8750358
http://blog.csdn.net/candycat1992/article/details/39676669
http://blog.csdn.net/csxiaoshui/article/details/23935079