1

我在概念化基于着色器的 OpenGL 程序中使用的工作流时遇到了一些麻烦。虽然我从未真正使用固定功能或基于着色器的管道完成任何重大项目,但我已经开始学习和试验,我很清楚着色器是要走的路。

但是,从直观的角度来看,固定功能管道对我来说更有意义。使用该方法渲染场景既简单又程序化——就像绘画一样。如果我想画一个盒子,我告诉显卡画一个盒子。如果我想要很多盒子,我会在一个循环中画出我的盒子。固定功能管道非常适合我既定的编程倾向。

这些似乎都与着色器一起消失了,这就是我遇到障碍的地方。许多基于着色器的教程展示了如何在屏幕上绘制三角形或立方体等,效果很好。但是,它们似乎根本没有涉及我将如何将这些概念应用到例如游戏中。如果我想绘制三个程序生成的三角形,我需要三个着色器吗?显然不是,因为那是不可行的。尽管如此,这显然不像将绘图代码粘贴在一个运行三遍的循环中那么简单。

因此,我想知道在游戏开发环境中使用着色器的“最佳实践”是什么。一个简单的游戏我应该有多少着色器?如何在它们之间切换并使用它们来渲染真实场景?

我不是在寻找细节,只是一般的理解。例如,如果我有一个渲染圆的着色器,我将如何重用该着色器在屏幕上的不同点绘制不同大小的圆?如果我希望每个圆圈都具有不同的颜色,如何将一些信息传递给每个圆圈的片段着色器?

4

2 回答 2

1

您没有绘制圆圈的着色器(好吧,您可能会使用正确的技巧,但我们现在暂时忘记它,因为它具有误导性并且具有非常罕见和特定的用途)。着色器是您编写的用于处理图形管道某些阶段的小程序,比“画一个圆”更具体。一般来说,每次进行绘图调用时,您都必须告诉 openGL 要使用哪些着色器(通过调用glUseProgram您必须至少使用顶点着色器和片段着色器。生成的管道将类似于

Vertex Shader:将为您要发送到openGL的每个顶点执行的代码。它将针对您在元素数组中发送的每个索引执行,并将使用相应的顶点属性作为输入数据,例如顶点位置、它的法线、它的 uv 坐标,也许是它的切线(如果你正在做法线映射) ,或者你发送给它的任何东西。通常你想在这里进行几何计算。您还可以访问为绘制调用设置的统一变量,这些变量是全局变量,不会因顶点而改变。您可能希望在顶点着色器中使用的典型统一变量是 PVM 矩阵。如果不使用曲面细分,顶点着色器将写入 gl_Position,即光栅化器将用于创建片段的位置。

Rasterization

Fragment Shader:将为每个片段执行的代码(如果更清楚,则为每个像素)。通常你在这里进行纹理采样和光照计算。您将使用来自顶点着色器和光栅器的数据,例如法线(用于评估漫反射和镜面反射项)和 uv 坐标(从纹理中获取正确的颜色)。纹理将是统一的,可能还有您正在评估的灯光参数。

深度测试,模板测试。(您可以使用早期片段优化( http://www.opengl.org/wiki/Early_Fragment_Test)在片段着色器之前移动

混合。

我建议你看看这个很好的程序来开发简单的着色器http://sourceforge.net/projects/quickshader/,它有很好的例子,还有一些你在每个教程中都找不到的更高级的东西。

于 2013-09-02T06:20:38.743 回答
1

固定功能流水线和可编程流水线在概念上确实没有区别。着色器引入的唯一东西是对管道的某些阶段进行编程的能力。

在当前的硬件上,您(大部分)可以控制顶点、图元组装、细分和片段阶段。在这些阶段之间和之后发生的一些操作仍然是固定功能的,例如深度/模板测试、混合、透视分割等。

因为着色器实际上只不过是您插入以定义特定阶段的输入和输出的程序,因此您应该将片段着色器的输入视为来自先前阶段之一的输出。in顶点输出在光栅化期间被插值,当您在片段着色器中有一个变量时,这些通常是您要处理的。

您还可以拥有程序范围的变量,称为制服。任何阶段都可以通过在每个阶段使用相同的名称来访问这些变量。它们不会随着着色器的调用而变化,因此称为统一。

现在您应该有足够的信息来弄清楚这个圆圈示例......您可以使用制服来缩放您的圆圈(可能是一个简单的缩放矩阵),您可以依赖每个顶点颜色或定义颜色的制服。

于 2013-09-02T02:50:04.293 回答