【问题标题】:OpenGL per-mesh material (shader)OpenGL per-mesh 材质(着色器)
【发布时间】:2019-03-01 23:53:15
【问题描述】:

所以,我正在使用 C++ 和 OpenGL 4 开发一个简单的游戏引擎。现在我正在努力渲染导入的模型。

我正在使用 FBX sdk 导入 fbx 模型,使用一种非常简单的方法:基本上我访问 fbx 的每个节点并将网格数据附加到一个稍后用于渲染的单个大结构中。但是,我希望能够为模型使用的每种材质指定不同的片段着色器(例如,为汽车轮辋和车灯指定不同的着色器)。

作为参考,UE4 有一个材质系统,允许用户使用类似蓝图的编辑器定义简单的着色器。

我想将类似的概念应用到我的引擎中,允许创建一个材质对象,该对象指定一段片段着色器代码和一组要使用的纹理。

我面临的问题是:

  1. 很明显,我必须为使用不同材料的每个模型部件分开绘制调用,因为我不能在绘制调用中间交换程序(可以吗?):在这一点上,最好有每个部分或单个部分都有单独的 vao/vbo/ebo,并跟踪一个部分的结束位置和下一个部分的开始位置? (我想这是最好的选择)
  2. 仅预编译着色器片段并将其附加到当前程序(即 glAttach + glLinkProgram + glUseProgram)是一种好习惯,还是为每种材质预链接整个程序更好,考虑到顶点着色器总是一样的吗?

【问题讨论】:

    标签: c++ opengl rendering game-engine fragment-shader


    【解决方案1】:
    1. 不,您不能在绘图调用过程中更改程序。根据您的数据布局,对于 GPU 的性能有不同的意见和测试。我的经验是,如果您不打算在第一次上传网格数据后修改它们,最有效的方法是拥有一个 VAO,有两个 VBO:一个用于索引,一个用于其余数据。发出绘图调用时,您会根据网格数据(您应该跟踪)偏移索引缓冲区,以及偏移着色器属性的配置。这种方法允许对缓存更友好和更有效的内存访问,因为内存块将是连续的。但是,正如我所提到的,在某些情况下这不是最有效的方法(尽管我相信它仍然足够有效)。这取决于您的硬件和驱动程序。

    2. 在启动渲染循环之前预编译和链接所有程序。这是最有效的方法

    另外,我建议您研究一下 UBER 着色器技术。该方法基于为不同的可能输入创建着色器,并创建一组defines 或子例程架构,允许您编译同一着色器的不同版本(例如,您可能有一个具有普通纹理的模型并且您可能想要应用凹凸贴图,但其他模型可能没有此纹理,因此执行完全相同的着色器将导致未定义的行为或崩溃)。

    【讨论】:

    • "您根据网格数据偏移索引缓冲区 *" 和 "*偏移着色器属性的配置" 为什么要这样做?不必这样做是glDrawElementsBaseVertex 及其同类的重点。
    • @NicolBolas 这就是我所指的。我并不是说他应该修改缓冲区中的索引或顶点位置,如果你不清楚的话我就不好了
    猜你喜欢
    • 2015-02-16
    • 1970-01-01
    • 2015-08-16
    • 2020-08-28
    • 2016-03-07
    • 2017-04-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多