一个简单的显示三角形的源码示例
// Triangle.cpp
// Our first OpenGL program that will just draw a triangle on the screen.
#include
// OpenGL toolkit
#include
// Shader Manager Class
#ifdef __APPLE__
#include
// OS X version of GLUT
#else
#define FREEGLUT_STATIC
#include
// Windows FreeGlut equivalent
#endif
GLBatch triangleBatch;
GLShaderManager shaderManager;
///
// Window has changed size, or has just been created. In either case, we need
// to use the window dimensions to set the viewport and the projection matrix.
void ChangeSize(int w, int h)
{
glViewport(0, 0, w, h);
}
///
// This function does any needed initialization on the rendering context.
// This is the first opportunity to do any OpenGL related tasks.
void SetupRC()
{
// Blue background
glClearColor(0.0f, 0.0f, 1.0f, 1.0f );
shaderManager.InitializeStockShaders();
// Load up a triangle
GLfloat vVerts[] = { -0.5f, 0.0f, 0.0f,
0.5f, 0.0f, 0.0f,
0.0f, 0.5f, 0.0f };
triangleBatch.Begin(GL_TRIANGLES, 3);
triangleBatch.CopyVertexData3f(vVerts);
triangleBatch.End();
}
///
// Called to draw scene
void RenderScene(void)
{
// Clear the window with current clearing color
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
GLfloat vRed[] = { 1.0f, 0.0f, 0.0f, 1.0f };
shaderManager.UseStockShader(GLT_SHADER_IDENTITY, vRed);
triangleBatch.Draw();
// Perform the buffer swap to display back buffer
glutSwapBuffers();
}
///
// Main entry point for GLUT based programs
int main(int argc, char* argv[])
{
gltSetWorkingDirectory(argv[0]);
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GLUT_STENCIL);
glutInitWindowSize(800, 600);
glutCreateWindow("Triangle");
glutReshapeFunc(ChangeSize);
glutDisplayFunc(RenderScene);
GLenum err = glewInit();
if (GLEW_OK != err) {
fprintf(stderr, "GLEW Error: %s\n", glewGetErrorString(err));
return 1;
}
SetupRC();
glutMainLoop();
return 0;
}
一、先看头文件
GLTools.h头文件中包含了大部分GLTools中类似C语言的独立函数,而每个GLTools的C++类则有自己的头文件。例如在本示例中用到的GLBatch类型,在次GLTools.h包含了GLBatch.h,使用GLBatch类对顶点、颜色、法线等数据进行设置时,这些数据都是存储在CPU中。这个简单的封装类会将顶点等数据批次进行封装可下载GLTools源码查看其中的源文件,在学习过程中,慢慢介绍。
GLShaderManager.h移入了GLTools着色器管理器(Shader Manager)类。没有着色器,我们就不能在OpenGL(核心框架)中进行着色。
在Windows和Linux上,我们使用freeglut的静态库版本,所以在它前面添加FREEGLUT_STATIC处理器宏。
二、关键源码解析
1、int main(int argc, char* argv[])
在Win32中,我们可以从控制台应用程序建立图形窗口,GLUT库隐藏了这些细节。
glutInit(&argc, argv); 初始化GLUT库
标志一次表示:使用双缓冲窗口;RGBA颜色模式;支持深度缓冲区;支持模版缓冲区。
glutCreateWindow("Triangle");
初始化GLUT窗口的大小设置,并创建以“Triangle”为标题的窗口。
glutDisplayFunc(RenderScene);
为窗口改变大小设置的回调函数,以便能够设置视点;注册函数以包含OpenGL渲染代码。
if (GLEW_OK != err) {
fprintf(stderr, "GLEW Error: %s\n", glewGetErrorString(err));
return 1;
}
重新调用GLEW库初始化OpenGL驱动程序中所有丢失的入口点,以确保OpenGl API是完全可用的。
SetupRC();RC代表渲染环境(Rendering Context), 这是一个运行中的OpenGl状态机的句柄
glutMainLoop();
此函数被调用后,在主窗口被关闭之前都不回返回,负责处理所有操作系统特定的消息、按键动作等,直到我们关闭程序为止。
2、void ChangeSize(int w, int h) 在窗口大小改变是接受新的宽度和高度。
glViewport(0, 0, w, h); 参数0和0代表窗口中视口的左下角坐标,w和h代表宽度和高度是用像素表示的。OpenGL可以在这个区域中进行绘图的裁剪区域被映射到新的视口
3、void SetupRC() 在开始main函数中的GLUT主循环之前,我们先调用SetupRC,为程序做一些一次性的设置。
glClearColor(0.0f, 0.0f, 1.0f, 1.0f );
shaderManager.InitializeStockShaders();
用当前清除颜色来清除窗口,这个函数不会立即调用,而是设置在以后颜色缓冲区被清除时使用的颜色,并且清除颜色设置为蓝色;初始话渲染着色器;
GLfloat vVerts[] = { -0.5f, 0.0f, 0.0f,
0.5f, 0.0f, 0.0f,
0.0f, 0.5f, 0.0f };
triangleBatch.Begin(GL_TRIANGLES, 3);
triangleBatch.CopyVertexData3f(vVerts);
0.5f, 0.0f, 0.0f,
0.0f, 0.5f, 0.0f };
triangleBatch.Begin(GL_TRIANGLES, 3);
triangleBatch.CopyVertexData3f(vVerts);
triangleBatch.End();
设置顶点,包含3个顶点的x、y、z笛卡尔坐标对,由于显示的是2D图形,z坐标都设置为0;对批次进行初始化,告诉这个类它代表哪种图元,其中包括的顶点数,以及(可选)一组或两组纹理坐标;复制一个由3分量(x,y,z)顶点组成的数组;调用End来表明已经完成了数据的复制工作,并且将设置内部标记,以通知这个类包含哪些属性,一旦End函数被调用,就不能再添加新的属性了。
4、void RenderScene(void) 更新窗口,只要窗口发生最小化、恢复、最大化、覆盖或重新显示等变化,就会更新。
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
触发在SetupRC函数中的清除函数glClear(),清除一个或一组特定的缓冲区。缓冲区是一块存储图形信息的存储空间。(缓冲区后面继续学习!)
GLfloat vRed[] = { 1.0f, 0.0f, 0.0f, 1.0f };
shaderManager.UseStockShader(GLT_SHADER_IDENTITY, vRed);
triangleBatch.Draw();
shaderManager.UseStockShader(GLT_SHADER_IDENTITY, vRed);
triangleBatch.Draw();
设置渲染颜色;选择一个存储着色器并提供这个着色器的Uniform值(文章后面简单介绍这些着色器);指示将几何图形提交到着色器。
glutSwapBuffers();
在main函数开始时设置了双缓冲窗口,我们在后台缓冲区进行渲染,当在结束时交换到前台。这种形式能够防止观察者看到动画帧与动画帧之间闪烁的渲染过程。
OK!第一个实例代码就到这,下面简单学习一下着色器!
三、着色器简单学习
GLShaderManager::UseStackShader(GLenum shader,......);
在C语言(C++)中,.......表示函数接受一个可变的参数数量。就函数本身而言,它根据我们选择的着色器从堆栈中提取正确的参数,这些参数就是特定着色器要求的Uniform值
1、单位(Identity)着色器
只是简单地使用默认的笛卡尔坐标。只使用一个属性GLT_ATTRIBUTE_VERTEX,vColor参数包含了要求的颜色
GLShaderManager::UseStockShader(GLT_SHADER_IDENTITY,GLFloat vColor[4]);
2、平面(Flat)着色器
平面着色器将统一着色器进行了扩展,允许为几何图形变换指定一个4X4的变换矩阵。典型情况下是一种左乘模型视图矩阵和投影矩阵,通常称作“模型视图投影矩阵”。这种着色器只使用一个属性GLT_ATTRIBUTE_VERTEX。
GLSahderManager::UseStockShader(GLT_SHADER_FLAT,GLfloat mvp[16],GLfloat vColor[4]);
3、上色(Shaded)着色器
这种着色器唯一的Uniform值就是在几何图形中应用的变换矩阵。GLT_ATTRIBUTE_VERTEX和GLT_ATTRIBUTE_COLOR在这种着色器中都会使用。颜色值将被平滑地插入到顶点之间(称为平滑着色)。
GLSahderManager::UseStockShader(GLT_SHADER_SHADED,GLfloat mvp[16]);
4、默认光源着色器
本质上讲,这种着色器使对象产生阴影和光照的效果。需要模型视图矩阵、投影矩阵和作为基本色的颜色值等Uniform值。所需的属性有GLT_ATTRIBUTE_VERTEX和GLT_ATTRIBUTE_NORMAL。大多数光照着色器都需要正规矩阵作为Uniform值。
GLShaderManager::UseStock(GLT_DEFAULT_LIGHT,GLfloat mvMatrix[16],GLfloat pMaxtrix[16],GLfloat vColor[4]);
5、点光源着色器
光源位置可能是特定的。接受4个Uniform值,即模型视图矩阵、投影矩阵、视点坐标系中的光源位置和对象的基本漫反射颜色。所需的属性有GLT_ATTRIBUTE_VERTEX和GLT_ATTRIBUTE_NORMAL
GLShaderManager::UserStockShader(GLT_SHADER_POINT_LIGHT_DIFF,GLfloat mvMaxtrix[16],GLfloat pMaxtrix[16],GLflaoat vLightPos[3],GLfloat vColor[4]);
6、纹理替换矩阵
通过给定的模型视图投影矩阵,使用绑定到nTextureUnit指定的纹理单元的纹理对几何图形进行变换。片段颜色是直接从纹理样本中直接获取的。所需的属性有GLT_ATTRIBUTE_VERTEX和GLT_ATTRIBUTE_NORMAL。
GLShaderManager::UseStockShader(GLT_SHADER_TEXTURE_REPLACE,GLfloat mvpMatrix[16],GLint nTextureUnit);
7、纹理调整着色器
这种着色器将一个基本色乘以一个取自纹理单元nTextureUnit的纹理。所需的属性有GLT_ATTRIBUTE_VERTEX和GLT_ATTRIBUTE_TEXTURE0.
GLShaderManager::UseStockShader(GLT_SHADER_TEXTURE_MODULATE,GLfloat mvpMatrix[16],GLfloat vColor,GLint nTextureUnit);
8、纹理光源着色器
将一个纹理通过漫反射照明计算进行调整(相乘),光线在视觉空间中的位置是给定的。这种着色器接受5个Uniform值,即模型视图矩阵、投影矩阵、视觉空间中的光源位置、几何图形的基本色和将要使用的纹理单元。所需的属性有GLT_ATTRIBUTE_VERTEX、GLT_ATTRIBUTE_NORMAL和GLT_ATTRIBUTE_TEXTURE0.
GLShaderManager::UseStockShader(GLT_SHADER_TEXTURE_POINT_LIGHT_DIFF,
GLfloat mvMatrix,GLfloat pMatrix[16],GLfoat vLightPos[3],
GLfloat vBaseColor[4], GLint nTextureUnit);