4.图元解析
OpenGL管线渲染流程
从客户端向服务端传递数据有3种形式:Texture Data、Uniforms、Attributes。每种形式都只是一种数据传递方式,并不限制传输数据类型
顶点着色器(Vertex Shader)接收Texture Data、Uniforms、Attributes,但是顶点着色器只会处理Uniforms、Attributes,对Texture Data只是起到传递作用
Texture Data、Uniforms都可以传递到顶点着色器和片元着色器,但是Attributes只能传递到顶点着色器,不能直接传递到片元着色器
Uniforms、Attributes使用区别:
比较通用型的用Uniforms,对每个顶点都可能要变化的用Attributes Attributes一般用来传递颜色、顶点数据、纹理坐标、光照法线等值, Uniforms一般用来传递旋转矩阵(顶点着色器用来旋转顶点数据)、颜色转换矩阵(片元着色器用来把YUV色值转化到RGB色值)。
注意Attributes变量不支持整数、布尔值、结构或者属性数组,不能在片段着色器中声明。
正投影
透视投影
固定管线(存储着色器)
使用存储着色器,我们可以简便的实现我们的需求,而不需要去进行太多自定义操作,只要根据需求选择合适的存储着色器就好。要是用固定管线,首先要先初始化着色器管理器。
GLShaderManager shaderManager;
shaderManager.InitializeStockShaders();
存储着色器
单元着色器
GLShaderManager::UserStockShader(GLT_SHADER_IDENTITY,GLfloat vColor[4]);
参数1:存储着色器类型-单元着色器
参数2:颜色
使用场景:绘制默认OpenGL坐标系(-1,1)下图形。图形所有片段都会以一种颜色填充
平面着色器
GLShaderManager::UserStockShader(GLT_SHADER_FLAT,GLfloat mvp[16],GLfloat vColor[4]);
参数1:存储着色器类型-平面着色器
参数2:允许变化的4x4矩阵
参数3:颜色
使用场景:在绘制图形时,可以应用变换(模型/投影变化)
上色着色器
GLShaderManager::UserStockShader(GLT_SHADER_SHADED,GLfloat mvp[16]);
参数1:存储着色器类型-上色着色器
参数2:允许变化的4x4矩阵
使用场景:在绘制图形时,可以应用变换(模型/投影变化),颜色将会平滑的插入到顶点之间称为平滑着色
默认光源着色器
GLShaderManager::UserStockShader(GLT_SHADER_DEFAULT_LIGHT,GLfloat mvMatrix[16],GLfloat pMatrix[16],GLfloat vColor[4]);
参数1:存储着色器类型-默认光源着色器
参数2:模型4x4矩阵
参数3:投影4x4矩阵
参数4:颜色(几何图形颜色)
使用场景:在绘制图形时,可以应用变换(模型/投影变化),这种着色器会使绘制的图形产生阴影和光照效果
点光源着色器
GLShaderManager::UserStockShader(GLT_SHADER_POINT_LIGHT_DIFF,GLfloat mvMatrix[16],GLfloat pMatrix[16],GLfloat vLightPos[3],GLfloat vColor[4]);
参数1:存储着色器类型-点光源着色器
参数2:模型4x4矩阵
参数3:投影4x4矩阵
参数4:点光源位置
参数5:漫反射颜色值
使用场景:在绘制图形时,可以应用变换(模型/投影变化),这种着色器会使绘制的图形产生阴影和光照的效果。它与默认光源着色器非常类似,区别只是光源位置可能是特定的。
纹理替换矩阵着色器
GLShaderManager::UserStockShader(GLT_SHADER_TEXTURE_REPLACE,GLfloat mvMatrix[16],GLint nTextureUnit);
参数1:存储着色器类型-纹理替换矩阵着色器
参数2:模型4x4矩阵
参数3:纹理单元
使用场景:在绘制图形时,可以应用变换(模型/投影变化),这种着色器通过给定的模型视图投影矩阵。使用纹理单元来进行颜色填充。其中每个像素点的颜色是从纹理中获取
纹理调整着色器
GLShaderManager::UserStockShader(GLT_SHADER_TEXTURE_MODULATE,GLfloat mvMatrix[16],GLfloat vColor[4],GLint nTextureUnit);
参数1:存储着色器-纹理调整着色器
参数2:模型4x4矩阵
参数3:颜色值
参数4:纹理单元
使用场景:在绘制图形时,可以应用变换(模型/投影变化)这种着色器通过给定的模型视图投影矩阵。着色器将一个基本色乘以一个取自纹理单元nTextureUnit的纹理,将颜色与纹理进行混合后才填充到片段中。
纹理光源着色器
GLShaderManager::UserStockShader(GLT_SHADER_TEXTURE_POINT_LIGHT_DIEF,GLfloat mvMatrix[16],GLfloat pMatrix[16],GLfloat vLightPos[3],GLfloat vBaseColor[4],GLint nTextureUnit);
参数1:存储着色器类型-纹理光源着色器
参数2:模型4x4矩阵
参数3:投影4x4矩阵
参数4:点光源位置
参数5:颜色值(几何图形的基本色)
参数6:纹理单元
使用场景:在绘制图形时,可以应用变换(模型/投影变化)。这种着色器通过给定的模型视图投影矩阵。着色器将一个纹理通过漫反射照明计算进行调整(相乘)。
基本图元
| 图元 | 描述 |
|---|---|
| GL_POINT | 每个顶点在屏幕上都是单独点 |
| GL_LINES | 每一对顶点定义一条线段 |
| GL_LINE_STRIP | 从第一个顶点依次经过后续每一个顶点绘制线条 |
| GL_LINE_LOOP | 从第一个顶点依次经过后续每一个顶点,再把最后一个顶点连接第一个顶点绘制一个环 |
| GL_TRIANGLES | 每3个顶点定义一个三角形 |
| GL_TRIANGLE_STRIP | 共用一个条带(strip)上的顶点的一组三角形 |
| GL_TRIANGLE_FAN | 以第一个点为中心呈扇形排列,共用相邻顶点的一组三角形 |
OpenGL 点/线/三角形
设置点的大小glPointSize(4.0f)
设置线宽度glLineWidth(2.5f)
OpenGL默认逆时针环绕的多边形为正面,我们也可以通过代码来自己配置:
glFrontFace(GL_CW)顺时针环绕的为正面
glFrontFace(GL_CCW)逆时针环绕的为正面
为什么三角形是OpenGL中最受欢迎的图元?
因为GL_TRIANGLE_STRIP(三角形带)和GL_TRIANGLE_FAN(三角形扇)图元时,前三个顶点指定1个三角形后,对接下来的一个三角形,只需要再指定一个顶底。需要绘制大量三角形的时候,采用这种方式可以节省大量的程序代码和数据存储空间。其次,还能够提升运算性能和节省带宽,更少的顶点意味着数据从内存传输到图形卡的速度更快,并且顶点着色器需要处理的次数也更少。
GLBatch
GLBatch是GLTools中包含的一个简单的容器类
- 开始填充数组
void GLBatch::Begin(GLenum primitive, GLuint nVerts, GLuint nTextureUnits = 0);
参数1:图元
参数2:顶点数
参数3:一组或者2组纹理坐标(可选) - 复制顶点数据(一个由3分量x,y,z顶点组成的数组)
void GLBatch::CopyVerterxData3f(GLfloat *vVerts); - 复制表面法线数据
void GLBatch::CopyNormalDataf(GLfloat *vNorms); - 复制颜色数据
void GLBatch::CopyColorData4f(GLfoat *vColors); - 复制纹理坐标数据
void GLBatch::CopyTexCoordData2f(GLfloat *vTex, GLuint uiTextureLayer) - 结束数据复制
void GLBatch::End(void) - 绘制图形
void GLBatch::Draw(void)
绘制可旋转的点/线/环/金字塔/雨伞/圆柱
main函数没什么特殊的,不过要注意,普通键位和特殊键位走的不是同一个回调函数
数据
GLMatrixStack 变化管线使用矩阵堆栈,构造函数允许指定堆栈的最大深度、默认的堆栈深度为64.这个矩阵堆在初始化时已经在堆栈中包含了单位矩阵。
初始化GLMatrixStack::GLMatrixStack(int iStackDepth = 64);
在堆栈顶部载入单位矩阵void GLMatrixStack::LoadIndentiy(void);
在堆栈顶部载入矩阵mvoid GLMatrixStack::LoadMatrix(const M3DMatrix44f m);
GLFrame 参考帧,可以表示世界坐标系中任意物体的位置与方向,涉及到的坐标系有两个:永远不变的世界坐标系,针对于自身的物体坐标系(即绘图坐标系)。可以用来产生模型视图矩阵,来产生位置的移动。
GLFrame的变化都是逆变化 例如:
GLFrame objectFrame
objectFrame.MoveRight(1)
看代码是向右移动1,实际上的效果是物体在画布上向左移动了1
GLFrustum 投影方式
用来设置投影方式和获取投影矩阵
GLGeometryTransform 进行几何变换的管道
渲染环境设置
开启深度测试
glEnable(GL_DEPTH_TEST);
设置矩阵堆栈,管理模型矩阵和投影矩阵transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);
观察者位置改变(世界坐标改变)cameraFrame.MoveForward(-15.0f);观察者向后移动15
重塑函数
透视投影设置
viewFrustum.SetPerspective(50, float(w)/float(h), 1.0f, 500.0f);
空格键点击监听(空格键值:32)
上下左右按键监听
参考帧旋转
objectFrame.RotateWorld(m3dDegToRad(-10.0f), 1.0, 0.0, 0.0);(m3dDegToRad:角度转弧度)
渲染函数
压栈出栈是为了使每次渲染相互独立,避免本次的设置影响后续设置,因为OpenGL是个状态机,每次操作都会记录的,所以要压栈出当前状态的复制,用这次复制来进行操作,操作完后把副本出栈,现在状态机里就的就还是本次操作之前的状态了
运行截图
代码资源见:Github