固定管线与可编程管线的区别
-
管线: 可以理解为流水线.在课程里,我们学习到了图形渲染的流程. 这个过程就是流水线/管线
-
固定管线: 大家可以想象一下在做iOS开发过程,苹果是不是经常将很多功能封装好,只需要由开发者设置参数就可以实现. 固定管线也是如此,OpenGL 将一些效果封装好,你只需要传递相关参数就可以实现
-
可编程管线: 当固定管线不够实际开发中使用时,OpenGL 想到了一个办法,将2个着色器可以开发者借助于GLSL 语言自己编程:
- 顶点着色器: 处理顶点的变换.例如平移.旋转等
- 片元着色器: 处理光栅化后的像素点的颜色值处理. 最终将计算后的颜色填充到像素点
为什么坐标描述是正方形可是显示却不是正方形?
看如下代码:
GLfloat verts[] = {
-0.2f, -0.2f, 0,
0.2f, -0.2f, 0,
0.2f, 0.2f, 0,
-0.2f, 0.2f, 0
};
pyramidBatch.Begin(GL_TRIANGLE_FAN, 4);
pyramidBatch.CopyVertexData3f(verts);
pyramidBatch.End();
正常情况下,看到这一步时,你肯定会想结果是个正方形,但是,结果是这样的

😄,这是为什么呢?
- 因为标准 NDC 坐标系显示到屏幕上要与窗口是映射关系
- 你映射的窗口是(600,800)所以不是正方形
- 将你映射的窗口大小改成(600,600).即可
// glutInitWindowSize(600, 800);
glutInitWindowSize(600, 600);

片元着色器
在 OpenGL 开发中,我们说的片元着色器,片段着色器,像素着色器是同一个概念。那么片元=片段=像素? 一个片元是否只有1个元素呢?
-
一般,我们常称为 "片元着色器"
-
当然在看书/博客/与同行交流时,会有很多其他的名称.比如:"片段着色器","像素着色器"....
-
就像别人给你一个昵称,和你的学名都是你本人一样
-
那么片元着色器到底是做什么的?
- 主要用来处理你所渲染的图形或者图片的每一个像素点的颜值值
- 片元着色器是在使用GPU来帮助你计算颜色值
- 片元着色器每次只能处理1个像素点。所以如果你的图片占用了100个像素点,此时则要由GPU执行100次片元着色器
- 如此庞大的计算量,CPU是无法完成这么大量的并行运算的,而GPU 擅长如此
渲染流程同样适用固定管线下吗?
-
首先,不管你是要固定着色器还是可编程管线。都是对图形的顶点和像素点进行处理
-
固定管线其实就把关于对顶点和像素点处理,根据需求不同封装起来而已
-
固定着色器封装下,它的内部还是要对顶点和像素点来处理
固定着色器是如何和绘制联系起来的?
shaderManager.UseStockShader(GLT_SHADER_IDENTITY, vRed);
这里面设置使用的是哪种固定着色器
pyramidBatch.Draw();
这个批次容器里面存放了 图元连接方式以及顶点数据,那么着色器和批次容器是怎么关联绑定的呢?
-
需要千万记住的是OpenGL 是状态机。设置固定着色器,是针对整个OpenGL 环境来设置的。也就是说当你不改变固定着色器,在整个案例里,你都是用一种固定着色器来渲染的
-
通俗的说,例如你设置点的大小 glPointSize = 4.0 时,如果你改变,那么你整个 OpenGL 环境里绘制的图像的点大小都会为 4.0
-
那么怎么修改了? 在渲染不同图像改用不同固定着色器?
shaderManager.UseStockShader(GLT_SHADER_IDENTITY, vRed);
redBatch.Draw();
shaderManager.UseStockShader(GLT_SHADER_IDENTITY, vGreen);
greenBatch.Draw();
shaderManager.UseStockShader(GLT_SHADER_IDENTITY, vBlue);
blueBatch.Draw();
矩阵堆栈
- 在绘图时,可以不用矩阵堆栈吗?
如果绘制比较多,没有 push&pop 是不行的,否则别的变化都作用在 modelViewMatrix 上了,modelViewMatrix 是全局的,本来不是你的也被影响了,push 的意思就是,我先占用,需要等我绘制完了,pop 是把我的变化从全局的 modelViewMatrix 的剔除掉,保持原来的模样,否则就乱套了。push&pop 就是为了把变化绘制了,还不影响整体环境,如果你不用 push 或者 pop,那你自己精细算 modelViewMatrix 的数据也是可以的,如果简单的图形计算起来可以,但是如果遇到复杂无规律可循的图形,计算量是很大的,而且相互之间还不能有影响。这些 push&pop 就可以搞定了,何乐而不为呢?😄
- ModelViewProjectionMatrix 矩阵在堆栈中充当什么样角色?
modelViewMatrix 只有一个,是全局的,大家都在用,如果你某个图形 A,他要有bcdefg变化,那么 push -> modelViewMatrix ✖️b✖️c✖️d✖️e✖️f✖️g -> pop modelViewMatrix,这时候物体 B 有个一个abc*999-366的变化,push -> modelViewMatrix✖️abc✖️999-366 ->pop -> modelViewMatrix, A 和 B 都是要有自己的变化,比如 A 必须要 bcdefg 都叉乘了才可作为 A 的最后的 modelViewMatrix 渲染,B 也是同理,你把 A 的modelViewMatrix ✖️b✖️c✖️d✖️e✖️f✖️g✖️abc✖️999-366 给 B,那就乱套了,你要的最终变化给你就行了,别人的不要管。
MultMatrix(GLFrame &frame) 和 MultMatrix(M3DMatrix44f mMatrix)
参数为 GLFrame 时
inline void MultMatrix(GLFrame& frame) {
M3DMatrix44f m;
frame.GetMatrix(m);
MultMatrix(m);
}
- MultMatrix 函数中先获取 m (M3DMatrix44f)矩阵;
- 实现矩阵相乘(调用MultMatrix(M3DMatrix44f mMatrix));
参数为 M3DMatrix44f 时
inline void MultMatrix(const M3DMatrix44f mMatrix) {
M3DMatrix44f mTemp;
m3dCopyMatrix44(mTemp, pStack[stackPointer]);
m3dMatrixMultiply44(pStack[stackPointer], mTemp, mMatrix);
}
即可实现矩阵相乘。
颜色填充与纹理填充
纹理是图片,那么没有图片,只有颜色,就不是纹理了吗?
- OpenGL 图形绘制有3种方式填充:1. 线框填充;2. 颜色填充;3. 纹理填充。
- 一般如果是使用颜色填充,就不需要去使用一张位图来完成。直接设置颜色会比较节省性能。
顶点坐标和纹理坐标指定时顺序问题
在 OpenGL 纹理绘制时,会遇到如下代码:
pyramidBatch.MultiTexCoord2f(0, 0, 0);
pyramidBatch.Vertex3f(1.0f, -1.0f, 2.0f);
为什么要先指定纹理坐标再指定顶点坐标呢?
-
原则上是先指定顶点坐标还是先指定纹理坐标,这个是没有先后顺序的,都可以
-
但是! 在OpenGL 固定管线下,使用批次类时,需要先指定纹理坐标,再指定顶点坐标。这个应该是由三角形批次类导致的
-
不过,在OpenGL ES 自定义管线中,是没有这个问题的。我们会将顶点数据和纹理坐标数据存储一个数组中,指定OpenGL 读取方式就可以了
持续更新。。。
网友评论