一、着色器
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;
//照相机 Frame
GLFrame cameraFrame;
//模型 Frame
GLFrame 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 color
glClear(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 |