一、着色器
1.单元着色器
GLShaderManager::UserStockShader(GLT_SHADER_IDENTITY,GLfloat vColor[4]);参数1: 存储着色器种类-单元着色器参数2: 颜⾊使用场景: 绘制默认OpenGL 坐标系(-1,1)下图形. 图形所有片段都会以一种颜色填充
2.平面着色器
GLShaderManager::UserStockShader(GLT_SHADER_FLAT,GLfloat mvp[16],GLfloat vColor[4]);参数1: 存储着⾊器种类-平面着色器参数2: 允许变化的4*4矩阵参数3: 颜⾊使⽤用场景: 在绘制图形时, 可以应用变换(模型/投影变化).
3.上色着色器
GLShaderManager::UserStockShader(GLT_SHADER_SHADED,GLfloat mvp[16]);参数1: 存储着色器种类-上色着色器参数2: 允许变化的4*4矩阵使⽤用场景: 在绘制图形时, 可以应用变换(模型/投影变化) 颜色将会平滑地插入到顶点之间 称为平滑着色.
4.默认光源着色器(太阳光)
GLShaderManager::UserStockShader(GLT_SHADER_DEFAULT_LIGHT,GLfloat mvMatrix[16],GLfloat pMatrix[16],GLfloat vColor[4]);参数1: 存储着⾊器种类-默认光源着⾊器参数2: 模型4*4矩阵参数3: 投影4*4矩阵参数4: 颜色值使⽤场景: 在绘制图形时, 可以应用变换(模型/投影变化) 这种着⾊器会使绘制的图形产生阴影和光照的效果.
5.点光源着色器
GLShaderManager::UserStockShader(GLT_SHADER_POINT_LIGHT_DIEF,GLfloat mvMatrix[16],GLfloat pMatrix[16],GLfloat vLightPos[3],GLfloat vColor[4]);参数1: 存储着⾊器种类-点光源着⾊器参数2: 模型4*4矩阵参数3: 投影4*4矩阵参数4: 点光源的位置参数5: 颜⾊值使用场景: 在绘制图形时, 可以应⽤变换(模型/投影变化) 这种着⾊器会使绘制的图形产⽣阴影和光照的效果.它与默认光源着⾊器⾮常类似,区别只是光源位置可能是特定的.
6.纹理替换矩阵着色器
GLShaderManager::UserStockShader(GLT_SHADER_TEXTURE_REPLACE,GLfloat mvMatrix[16],GLint nTextureUnit);参数1: 存储着⾊器种类-纹理替换矩阵着⾊器参数2: 模型4*4矩阵参数3: 纹理单元使用场景: 在绘制图形时, 可以应用变换(模型/投影变化)这种着⾊器通过给定的模型视图投影矩阵.使用纹理单元来进行颜色填充.其中每个像素点的颜⾊是从纹理理中获取.
7.纹理调整着色器
GLShaderManager::UserStockShader(GLT_SHADER_TEXTURE_MODULATE,GLfloat mvMatrix[16],GLfloat vColor[4],GLint nTextureUnit);参数1: 存储着⾊器种类-纹理调整着⾊器参数2: 模型4*4矩阵参数3: 颜⾊值参数4: 纹理单元使用场景: 在绘制图形时, 可以应用变换(模型/投影变化)这种着⾊器通过给定的模型视图投影矩阵.着⾊器将一个基本色乘以一个取自纹理单元nTextureUnit的纹理.将颜色与纹理进行颜色混合后才填充到片段中.
8.纹理光源着色器
GLShaderManager::UserStockShader(GLT_SHADER_TEXTURE_POINT_LIGHT_DIEF,G Lfloat mvMatrix[16],GLfloat pMatrix[16],GLfloat vLightPos[3],GLfloat vBaseColor[4],GLint nTextureUnit);参数1: 存储着⾊器种类-纹理光源着⾊器参数2: 模型4*4矩阵参数3: 投影4*4矩阵参数4: 点光源位置参数5: 颜色值(几何图形的基本色)参数6: 纹理单元使用场景: 在绘制图形时, 可以应用变换(模型/投影变化)这种着⾊器通过给定的模型视图投影矩阵.着⾊器将⼀个纹理通过漫反射照明计算进行调整(相乘).
二、OpenGL 基本图元连接⽅式

| 图元 | 描述 |
|---|---|
| GL_POINTS | 每个顶点在屏幕上都是单独点 |
| GL_LINES | 每⼀对顶点定义⼀个线段 |
| GL_LINE_STRIP | 一个从第⼀个顶点依次经过每⼀个后续顶点而绘制的线条 |
| GL_LINE_LOOP | 和GL_LINE_STRIP相同,但是最后⼀个顶点和第⼀个顶点连接起来了 |
| GL_TRIANGLES | 每3个顶点定义⼀个新的三角形 |
| GL_TRIANGLE_STRIP | 共⽤一个条带(strip)上的顶点的一组三⻆形 |
| GL_TRIANGLE_FAN | 以⼀个圆点为中⼼呈扇形排列,共⽤相邻顶点的⼀组三⻆形 |
GL_TRIANGLE_STRIP优点:
- 用前3个顶点指定第1个三角形之后,接下来的每⼀个三⻆形,只需要再指定1个顶点。需要绘制⼤量的三⻆形时,采⽤这种⽅法可以节省⼤大量的程序代码和数据存储空间。
- 提供运算性能和节省带宽。更少的顶点意味着数据从内存传输到图形卡的速度更快,并且顶点着⾊器需要处理的次数也更少。
OpenGL三⻆形环绕⽅式
在默认情况下,OpenGL认为具有逆时针⽅向环绕的多边形为正⾯。
GL_CW: 顺时针环绕的多边形为正⾯GL_CCW:逆时针环绕的多边形为正⾯// 手动指定那个面为正面,一般不做修改glFrontFace(GL_CW);
三、图元的渲染
1.导入相关的头文件
// GLTool.h头文件包含了大部分GLTool中类似C语言的独立函数#include "GLTools.h"// 矩阵工具类.可以利用GLMatrixStack加载 单元矩阵/矩阵/矩阵相乘/压栈/出栈/缩放/平移/旋转#include "GLMatrixStack.h"// 矩阵⼯具类,表示位置.设置vOrigin, vForward ,vUp等#include "GLFrame.h"// 矩阵工具类,用来快速设置正/透视投影矩阵.完成坐标从3D->2D映射过程#include "GLFrustum.h"// 三角形批次类,帮助类,利用它可以传输顶点/光照/纹理/颜色数据到存储着⾊器中#include "GLBatch.h"// 变换管道类,⽤来快速在代码中传输视图矩阵/投影矩阵/视图投影变换矩阵等.#include "GLGeometryTransform.h"// 数学库#include <math.h>// 在Mac 系统下,`#include<glut/glut.h>`在Windows 和 Linux上,我们使用freeglut的静态库版本并且需要添加⼀一个宏#ifdef __APPLE__#include <glut/glut.h>#else#define FREEGLUT_STATIC#include <GL/glut.h>#endif
2.定义相关变量
// 着色器管理类GLShaderManager shaderManager;//模型视图矩阵堆栈GLMatrixStack modelViewMatrix;//投影矩阵堆栈GLMatrixStack projectionMatrix;//照相机 FrameGLFrame cameraFrame;//模型 FrameGLFrame objectFrame;//投影矩阵GLFrustum viewFrustum;//容器类(7种不同的图元对应7种容器对象)GLBatch pointBatch;GLBatch lineBatch;GLBatch lineStripBatch;GLBatch lineLoopBatch;GLBatch triangleBatch;GLBatch triangleStripBatch;GLBatch triangleFanBatch;//几何变换的管道GLGeometryTransform transformPipeline;GLfloat vGreen[] = { 0.0f, 1.0f, 0.0f, 1.0f };GLfloat vBlack[] = { 0.0f, 0.0f, 0.0f, 1.0f };// 跟踪效果步骤int nStep = 0;
3.changeSize函数
changeSize:通过glutReshaperFunc(函数名)注册为重塑函数,当屏幕大小发生变化/或者第一次创建窗口时,会调用该函数调整窗口⼤小/视口⼤小,主要在该方法中使用窗口维度设置视口和投影矩阵
// 使用窗口维度设置视口和投影矩阵.void changeSize(int w, int h) {glViewport(0, 0, w, h);//创建投影矩阵,并将它载入投影矩阵堆栈中 下面是透视投影viewFrustum.SetPerspective(35.0f, float(w) / float(h), 1.0f, 500.0f);projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());//将单元矩阵载入模型视图矩阵堆栈modelViewMatrix.LoadIdentity();//设置变换管线以使用两个矩阵堆栈transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);}
GLFrustum类通过setPerspective 方法为我们构建一个平截头体。
GLFrustum::SetPerspective(float fFov , float fAspect ,float fNear ,float fFar);fFov:垂直方向上的视场角度fAspect:窗口的宽度与高度的纵横比 宽(w)/⾼(h)fNear:近裁剪面距离fFar:远裁剪面距离
4.renderScene函数
renderScene:⾃定义函数.通过glutDisplayFunc(函数名)注册为显示渲染函数.当屏幕发生变化/或者开发者主动渲染会调用此函数,用来实现数据->渲染过程
void RenderScene(void) {// Clear the window with current clearing colorglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);//压栈modelViewMatrix.PushMatrix();M3DMatrix44f mCamera;cameraFrame.GetCameraMatrix(mCamera);//矩阵乘以堆栈的顶部矩阵,相乘的结果随后简存储在堆栈的顶部modelViewMatrix.MultMatrix(mCamera);M3DMatrix44f mObjectFrame;//只要使用 GetMatrix 函数就可以获取矩阵堆栈顶部的值,这个函数可以进行2次重载。用来使用GLShaderManager 的使用。或者是获取顶部矩阵的顶点副本数据objectFrame.GetMatrix(mObjectFrame);//矩阵乘以矩阵堆栈的顶部矩阵,相乘的结果随后简存储在堆栈的顶部modelViewMatrix.MultMatrix(mObjectFrame);shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vBlack);switch(nStep) {case 0://设置点的大小glPointSize(4.0f);pointBatch.Draw();glPointSize(1.0f);break;case 1://设置线的宽度glLineWidth(2.0f);lineBatch.Draw();glLineWidth(1.0f);break;case 2:glLineWidth(2.0f);lineStripBatch.Draw();glLineWidth(1.0f);break;case 3:glLineWidth(2.0f);lineLoopBatch.Draw();glLineWidth(1.0f);break;}//还原到以前的模型视图矩阵(单位矩阵)modelViewMatrix.PopMatrix();// 进行缓冲区交换glutSwapBuffers();}
这里主要通过模型视图堆栈,做了一系列的矩阵计算,从而得到一个新的模型视图堆栈。最后通过渲染管线获取到模型视图矩阵以及投影矩阵,作为固定着色器中几何图形变换的变换矩阵。
变换管道通过get可获得的矩阵有4种
| 方法 | 说明 |
|---|---|
| GetProjectionMatrix() | 投影矩阵 |
| GetNormalMatrix() | 法线矩阵 |
| GetModelViewMatrix() | 模型视图矩阵,简称mv |
| GetModelViewProjectionMatrix() | 模型视图投影矩阵,简称mvp |
4.1、PushMatrix()
压栈: 和数据结构中的栈类似,调用这个方法的时候,若传入一个矩阵,则将该矩阵压入栈顶;若不传入参数,则默认copy一份当前栈顶矩阵,压入栈顶,主要作用就是记录状态,保存当时的临时结果。
4.2、MultMatrix(x)
矩阵相乘:将栈顶元素copy一份,并与矩阵相乘,得到的结果赋值给矩阵堆栈的栈顶矩阵。
4.3、PopMatrix()
矩阵出栈:将栈顶矩阵出栈,恢复为原始的矩阵堆栈。
在使用完该栈之后,这个方法必须调用。原因就是,之前有提到,OpenGL上下文本身就是一个巨大的状态机,若在这里不将栈顶矩阵出栈,对于在其他使用到该矩阵堆栈的地方来说,矩阵数据就会错乱。
5.setupRC函数
setupRC:在main方法中手动调用,且只执行一次,主要是做着色器初始化、窗口背景初始化、顶点数据的准备等工作
void setupRC() {// 灰色的背景glClearColor(0.7f, 0.7f, 0.7f, 1.0f );// 初始化着色器管理类shaderManager.InitializeStockShaders();// 开启深度测试glEnable(GL_DEPTH_TEST);//设置变换管线以使用两个矩阵堆栈 changeSize中已经写了// transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);移动相机,也可以移动物体 objectFrame.MoveForward(15.0f);cameraFrame.MoveForward(-15.0f);//定义一些点,三角形形状。GLfloat vCoast[9] = {3,3,0,0,3,0,3,0,0};//用点的形式pointBatch.Begin(GL_POINTS, 3);pointBatch.CopyVertexData3f(vCoast);pointBatch.End();//通过线的形式lineBatch.Begin(GL_LINES, 3);lineBatch.CopyVertexData3f(vCoast);lineBatch.End();//通过线段的形式lineStripBatch.Begin(GL_LINE_STRIP, 3);lineStripBatch.CopyVertexData3f(vCoast);lineStripBatch.End();//通过线环的形式lineLoopBatch.Begin(GL_LINE_LOOP, 3);lineLoopBatch.CopyVertexData3f(vCoast);lineLoopBatch.End();...}
void GLBatch::Begin(GLenum primitive,GLuint nVerts,GLuint nTextureUnits = 0);参数1:表示使用的图元参数2:顶点数参数3:纹理坐标(可选)//负责顶点坐标void GLBatch::CopyVertexData3f(GLFloat *vNorms);//结束,表示已经完成数据复制工作void GLBatch::End(void);
观察者或者物体位置的设置有三种
| 方法 | 说明 |
|---|---|
| void MoveForward(float fDelta) | 向外移动的像素点,修改z |
| void MoveUp(float fDelta) | 向上移动的像素点,修改y |
| void MoveRight(float fDelta) | 向右移动的像素点,修改x |
