一、着色器

1.单元着色器

  1. GLShaderManager::UserStockShader(GLT_SHADER_IDENTITY,GLfloat vColor[4]);
  2. 参数1: 存储着色器种类-单元着色器
  3. 参数2: 颜⾊
  4. 使用场景: 绘制默认OpenGL 坐标系(-1,1)下图形. 图形所有片段都会以一种颜色填充

2.平面着色器

  1. GLShaderManager::UserStockShader(GLT_SHADER_FLAT,GLfloat mvp[16],GLfloat vColor[4]);
  2. 参数1: 存储着⾊器种类-平面着色器
  3. 参数2: 允许变化的4*4矩阵
  4. 参数3: 颜⾊
  5. 使⽤用场景: 在绘制图形时, 可以应用变换(模型/投影变化).

3.上色着色器

  1. GLShaderManager::UserStockShader(GLT_SHADER_SHADED,GLfloat mvp[16]);
  2. 参数1: 存储着色器种类-上色着色器
  3. 参数2: 允许变化的4*4矩阵
  4. 使⽤用场景: 在绘制图形时, 可以应用变换(模型/投影变化) 颜色将会平滑地插入到顶点之间 称为平滑着色.

4.默认光源着色器(太阳光)

  1. GLShaderManager::UserStockShader(GLT_SHADER_DEFAULT_LIGHT,GLfloat mvMatrix[16],GLfloat pMatrix[16],GLfloat vColor[4]);
  2. 参数1: 存储着⾊器种类-默认光源着⾊器
  3. 参数2: 模型4*4矩阵
  4. 参数3: 投影4*4矩阵
  5. 参数4: 颜色值
  6. 使⽤场景: 在绘制图形时, 可以应用变换(模型/投影变化) 这种着⾊器会使绘制的图形产生阴影和光照的效果.

5.点光源着色器

  1. GLShaderManager::UserStockShader(GLT_SHADER_POINT_LIGHT_DIEF,GLfloat mvMatrix[16],GLfloat pMatrix[16],GLfloat vLightPos[3],GLfloat vColor[4]);
  2. 参数1: 存储着⾊器种类-点光源着⾊器
  3. 参数2: 模型4*4矩阵
  4. 参数3: 投影4*4矩阵
  5. 参数4: 点光源的位置
  6. 参数5: 颜⾊值
  7. 使用场景: 在绘制图形时, 可以应⽤变换(模型/投影变化) 这种着⾊器会使绘制的图形产⽣
  8. 阴影和光照的效果.它与默认光源着⾊器⾮常类似,区别只是光源位置可能是特定的.

6.纹理替换矩阵着色器

  1. GLShaderManager::UserStockShader(GLT_SHADER_TEXTURE_REPLACE,GLfloat mvMatrix[16],GLint nTextureUnit);
  2. 参数1: 存储着⾊器种类-纹理替换矩阵着⾊器
  3. 参数2: 模型4*4矩阵
  4. 参数3: 纹理单元
  5. 使用场景: 在绘制图形时, 可以应用变换(模型/投影变化)这种着⾊器通过给定的模型视图投影矩阵.
  6. 使用纹理单元来进行颜色填充.其中每个像素点的颜⾊是从纹理理中获取.

7.纹理调整着色器

  1. GLShaderManager::UserStockShader(GLT_SHADER_TEXTURE_MODULATE,GLfloat mvMatrix[16],GLfloat vColor[4],GLint nTextureUnit);
  2. 参数1: 存储着⾊器种类-纹理调整着⾊器
  3. 参数2: 模型4*4矩阵
  4. 参数3: 颜⾊值
  5. 参数4: 纹理单元
  6. 使用场景: 在绘制图形时, 可以应用变换(模型/投影变化)这种着⾊器通过给定的模型视图投影矩阵.
  7. 着⾊器将一个基本色乘以一个取自纹理单元nTextureUnit的纹理.将颜色与纹理进行颜色混合后才填充到片段中.

8.纹理光源着色器

  1. GLShaderManager::UserStockShader(GLT_SHADER_TEXTURE_POINT_LIGHT_DIEF,G Lfloat mvMatrix[16],GLfloat pMatrix[16],GLfloat vLightPos[3],GLfloat vBaseColor[4],GLint nTextureUnit);
  2. 参数1: 存储着⾊器种类-纹理光源着⾊器
  3. 参数2: 模型4*4矩阵
  4. 参数3: 投影4*4矩阵
  5. 参数4: 点光源位置
  6. 参数5: 颜色值(几何图形的基本色)
  7. 参数6: 纹理单元
  8. 使用场景: 在绘制图形时, 可以应用变换(模型/投影变化)这种着⾊器通过给定的模型视图投影矩阵.
  9. 着⾊器将⼀个纹理通过漫反射照明计算进行调整(相乘).

二、OpenGL 基本图元连接⽅式


image.png

图元 描述
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认为具有逆时针⽅向环绕的多边形为正⾯。

  1. GL_CW 顺时针环绕的多边形为正⾯
  2. GL_CCW:逆时针环绕的多边形为正⾯
  3. // 手动指定那个面为正面,一般不做修改
  4. glFrontFace(GL_CW);

三、图元的渲染

1.导入相关的头文件

  1. // GLTool.h头文件包含了大部分GLTool中类似C语言的独立函数
  2. #include "GLTools.h"
  3. // 矩阵工具类.可以利用GLMatrixStack加载 单元矩阵/矩阵/矩阵相乘/压栈/出栈/缩放/平移/旋转
  4. #include "GLMatrixStack.h"
  5. // 矩阵⼯具类,表示位置.设置vOrigin, vForward ,vUp等
  6. #include "GLFrame.h"
  7. // 矩阵工具类,用来快速设置正/透视投影矩阵.完成坐标从3D->2D映射过程
  8. #include "GLFrustum.h"
  9. // 三角形批次类,帮助类,利用它可以传输顶点/光照/纹理/颜色数据到存储着⾊器中
  10. #include "GLBatch.h"
  11. // 变换管道类,⽤来快速在代码中传输视图矩阵/投影矩阵/视图投影变换矩阵等.
  12. #include "GLGeometryTransform.h"
  13. // 数学库
  14. #include <math.h>
  15. // 在Mac 系统下,`#include<glut/glut.h>`在Windows 和 Linux上,我们使用freeglut的静态库版本并且需要添加⼀一个宏
  16. #ifdef __APPLE__
  17. #include <glut/glut.h>
  18. #else
  19. #define FREEGLUT_STATIC
  20. #include <GL/glut.h>
  21. #endif

2.定义相关变量

  1. // 着色器管理类
  2. GLShaderManager shaderManager;
  3. //模型视图矩阵堆栈
  4. GLMatrixStack modelViewMatrix;
  5. //投影矩阵堆栈
  6. GLMatrixStack projectionMatrix;
  7. //照相机 Frame
  8. GLFrame cameraFrame;
  9. //模型 Frame
  10. GLFrame objectFrame;
  11. //投影矩阵
  12. GLFrustum viewFrustum;
  13. //容器类(7种不同的图元对应7种容器对象)
  14. GLBatch pointBatch;
  15. GLBatch lineBatch;
  16. GLBatch lineStripBatch;
  17. GLBatch lineLoopBatch;
  18. GLBatch triangleBatch;
  19. GLBatch triangleStripBatch;
  20. GLBatch triangleFanBatch;
  21. //几何变换的管道
  22. GLGeometryTransform transformPipeline;
  23. GLfloat vGreen[] = { 0.0f, 1.0f, 0.0f, 1.0f };
  24. GLfloat vBlack[] = { 0.0f, 0.0f, 0.0f, 1.0f };
  25. // 跟踪效果步骤
  26. int nStep = 0;

3.changeSize函数

changeSize:通过glutReshaperFunc(函数名)注册为重塑函数,当屏幕大小发生变化/或者第一次创建窗口时,会调用该函数调整窗口⼤小/视口⼤小,主要在该方法中使用窗口维度设置视口和投影矩阵

  1. // 使用窗口维度设置视口和投影矩阵.
  2. void changeSize(int w, int h) {
  3. glViewport(0, 0, w, h);
  4. //创建投影矩阵,并将它载入投影矩阵堆栈中 下面是透视投影
  5. viewFrustum.SetPerspective(35.0f, float(w) / float(h), 1.0f, 500.0f);
  6. projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
  7. //将单元矩阵载入模型视图矩阵堆栈
  8. modelViewMatrix.LoadIdentity();
  9. //设置变换管线以使用两个矩阵堆栈
  10. transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);
  11. }

GLFrustum类通过setPerspective 方法为我们构建一个平截头体。

  1. GLFrustum::SetPerspective(float fFov , float fAspect ,float fNear ,float fFar);
  2. fFov:垂直方向上的视场角度
  3. fAspect:窗口的宽度与高度的纵横比 宽(w)/⾼(h)
  4. fNear:近裁剪面距离
  5. fFar:远裁剪面距离

4.renderScene函数

renderScene:⾃定义函数.通过glutDisplayFunc(函数名)注册为显示渲染函数.当屏幕发生变化/或者开发者主动渲染会调用此函数,用来实现数据->渲染过程

  1. void RenderScene(void) {
  2. // Clear the window with current clearing color
  3. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
  4. //压栈
  5. modelViewMatrix.PushMatrix();
  6. M3DMatrix44f mCamera;
  7. cameraFrame.GetCameraMatrix(mCamera);
  8. //矩阵乘以堆栈的顶部矩阵,相乘的结果随后简存储在堆栈的顶部
  9. modelViewMatrix.MultMatrix(mCamera);
  10. M3DMatrix44f mObjectFrame;
  11. //只要使用 GetMatrix 函数就可以获取矩阵堆栈顶部的值,这个函数可以进行2次重载。用来使用GLShaderManager 的使用。或者是获取顶部矩阵的顶点副本数据
  12. objectFrame.GetMatrix(mObjectFrame);
  13. //矩阵乘以矩阵堆栈的顶部矩阵,相乘的结果随后简存储在堆栈的顶部
  14. modelViewMatrix.MultMatrix(mObjectFrame);
  15. shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vBlack);
  16. switch(nStep) {
  17. case 0:
  18. //设置点的大小
  19. glPointSize(4.0f);
  20. pointBatch.Draw();
  21. glPointSize(1.0f);
  22. break;
  23. case 1:
  24. //设置线的宽度
  25. glLineWidth(2.0f);
  26. lineBatch.Draw();
  27. glLineWidth(1.0f);
  28. break;
  29. case 2:
  30. glLineWidth(2.0f);
  31. lineStripBatch.Draw();
  32. glLineWidth(1.0f);
  33. break;
  34. case 3:
  35. glLineWidth(2.0f);
  36. lineLoopBatch.Draw();
  37. glLineWidth(1.0f);
  38. break;
  39. }
  40. //还原到以前的模型视图矩阵(单位矩阵)
  41. modelViewMatrix.PopMatrix();
  42. // 进行缓冲区交换
  43. glutSwapBuffers();
  44. }

这里主要通过模型视图堆栈,做了一系列的矩阵计算,从而得到一个新的模型视图堆栈。最后通过渲染管线获取到模型视图矩阵以及投影矩阵,作为固定着色器中几何图形变换的变换矩阵。

变换管道通过get可获得的矩阵有4种

方法 说明
GetProjectionMatrix() 投影矩阵
GetNormalMatrix() 法线矩阵
GetModelViewMatrix() 模型视图矩阵,简称mv
GetModelViewProjectionMatrix() 模型视图投影矩阵,简称mvp

4.1、PushMatrix()

压栈: 和数据结构中的栈类似,调用这个方法的时候,若传入一个矩阵,则将该矩阵压入栈顶;若不传入参数,则默认copy一份当前栈顶矩阵,压入栈顶,主要作用就是记录状态,保存当时的临时结果。

4.2、MultMatrix(x)

矩阵相乘:将栈顶元素copy一份,并与矩阵相乘,得到的结果赋值给矩阵堆栈的栈顶矩阵。

4.3、PopMatrix()

矩阵出栈:将栈顶矩阵出栈,恢复为原始的矩阵堆栈。
在使用完该栈之后,这个方法必须调用。原因就是,之前有提到,OpenGL上下文本身就是一个巨大的状态机,若在这里不将栈顶矩阵出栈,对于在其他使用到该矩阵堆栈的地方来说,矩阵数据就会错乱。
image.png

5.setupRC函数

setupRC:在main方法中手动调用,且只执行一次,主要是做着色器初始化、窗口背景初始化、顶点数据的准备等工作

  1. void setupRC() {
  2. // 灰色的背景
  3. glClearColor(0.7f, 0.7f, 0.7f, 1.0f );
  4. // 初始化着色器管理类
  5. shaderManager.InitializeStockShaders();
  6. // 开启深度测试
  7. glEnable(GL_DEPTH_TEST);
  8. //设置变换管线以使用两个矩阵堆栈 changeSize中已经写了
  9. // transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);
  10. 移动相机,也可以移动物体 objectFrame.MoveForward(15.0f);
  11. cameraFrame.MoveForward(-15.0f);
  12. //定义一些点,三角形形状。
  13. GLfloat vCoast[9] = {
  14. 3,3,0,0,3,0,3,0,0
  15. };
  16. //用点的形式
  17. pointBatch.Begin(GL_POINTS, 3);
  18. pointBatch.CopyVertexData3f(vCoast);
  19. pointBatch.End();
  20. //通过线的形式
  21. lineBatch.Begin(GL_LINES, 3);
  22. lineBatch.CopyVertexData3f(vCoast);
  23. lineBatch.End();
  24. //通过线段的形式
  25. lineStripBatch.Begin(GL_LINE_STRIP, 3);
  26. lineStripBatch.CopyVertexData3f(vCoast);
  27. lineStripBatch.End();
  28. //通过线环的形式
  29. lineLoopBatch.Begin(GL_LINE_LOOP, 3);
  30. lineLoopBatch.CopyVertexData3f(vCoast);
  31. lineLoopBatch.End();
  32. ...
  33. }
  1. void GLBatch::Begin(GLenum primitive,GLuint nVerts,GLuint nTextureUnits = 0);
  2. 参数1:表示使用的图元
  3. 参数2:顶点数
  4. 参数3:纹理坐标(可选)
  5. //负责顶点坐标
  6. void GLBatch::CopyVertexData3f(GLFloat *vNorms);
  7. //结束,表示已经完成数据复制工作
  8. void GLBatch::End(void);


观察者或者物体位置的设置有三种

方法 说明
void MoveForward(float fDelta) 向外移动的像素点,修改z
void MoveUp(float fDelta) 向上移动的像素点,修改y
void MoveRight(float fDelta) 向右移动的像素点,修改x