美文网首页
OpenGL 中常见问题解析

OpenGL 中常见问题解析

作者: 远方竹叶 | 来源:发表于2020-07-22 15:40 被阅读0次

固定管线与可编程管线的区别

  • 管线: 可以理解为流水线.在课程里,我们学习到了图形渲染的流程. 这个过程就是流水线/管线

  • 固定管线: 大家可以想象一下在做iOS开发过程,苹果是不是经常将很多功能封装好,只需要由开发者设置参数就可以实现. 固定管线也是如此,OpenGL 将一些效果封装好,你只需要传递相关参数就可以实现

  • 可编程管线: 当固定管线不够实际开发中使用时,OpenGL 想到了一个办法,将2个着色器可以开发者借助于GLSL 语言自己编程:

    1. 顶点着色器: 处理顶点的变换.例如平移.旋转等
    2. 片元着色器: 处理光栅化后的像素点的颜色值处理. 最终将计算后的颜色填充到像素点

为什么坐标描述是正方形可是显示却不是正方形?

看如下代码:

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个元素呢?

  • 一般,我们常称为 "片元着色器"

  • 当然在看书/博客/与同行交流时,会有很多其他的名称.比如:"片段着色器","像素着色器"....

  • 就像别人给你一个昵称,和你的学名都是你本人一样

  • 那么片元着色器到底是做什么的?

  1. 主要用来处理你所渲染的图形或者图片的每一个像素点的颜值值
  2. 片元着色器是在使用GPU来帮助你计算颜色值
  3. 片元着色器每次只能处理1个像素点。所以如果你的图片占用了100个像素点,此时则要由GPU执行100次片元着色器
  4. 如此庞大的计算量,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);
}
  1. MultMatrix 函数中先获取 m (M3DMatrix44f)矩阵;
  2. 实现矩阵相乘(调用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 读取方式就可以了

持续更新。。。

相关文章

网友评论

      本文标题:OpenGL 中常见问题解析

      本文链接:https://www.haomeiwen.com/subject/hulxhktx.html