了解OpenGL中的着色器工作流?

了解OpenGL中的着色器工作流?,opengl,shader,Opengl,Shader,我在概念化基于着色器的OpenGL程序中使用的工作流时遇到了一点困难。虽然我从来没有真正使用固定函数或基于着色器的管道完成过任何重大项目,但我已经开始学习和实验,我很清楚着色器是一条可行之路 然而,从直观的角度来看,固定功能管道对我来说更有意义。使用该方法渲染场景与绘制图片一样简单且程序化。如果我想画一个盒子,我会告诉图形卡画一个盒子。如果我想要很多盒子,我会把盒子画成一个圈。固定函数管道非常适合我既定的编程趋势 这些似乎都是通过着色器进行的,这就是我遇到的障碍。许多基于着色器的教程演示了如何在

我在概念化基于着色器的OpenGL程序中使用的工作流时遇到了一点困难。虽然我从来没有真正使用固定函数或基于着色器的管道完成过任何重大项目,但我已经开始学习和实验,我很清楚着色器是一条可行之路

然而,从直观的角度来看,固定功能管道对我来说更有意义。使用该方法渲染场景与绘制图片一样简单且程序化。如果我想画一个盒子,我会告诉图形卡画一个盒子。如果我想要很多盒子,我会把盒子画成一个圈。固定函数管道非常适合我既定的编程趋势

这些似乎都是通过着色器进行的,这就是我遇到的障碍。许多基于着色器的教程演示了如何在屏幕上绘制三角形或立方体,效果很好。然而,他们似乎根本没有讨论我如何将这些概念应用到游戏中。如果我想画三个程序生成的三角形,我需要三个着色器吗?显然不是,因为那是不可行的。不过,这显然不像将绘图代码粘贴在一个运行三次的循环中那么简单

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


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

固定函数管道和可编程管道之间在概念上没有区别。着色器引入的唯一功能是对管道的某些阶段进行编程

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

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

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


现在你应该有足够的信息来理解这个圆的例子。。。您可以使用统一来缩放圆(可能是一个简单的缩放矩阵),也可以使用逐顶点颜色或定义颜色的统一。

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

顶点着色器
:将为要发送到openGL的每个顶点执行的代码。它将为元素数组中发送的每个索引执行,并将相应的顶点属性(例如顶点位置、其法线、其uv坐标,可能是其切线)用作输入数据(如果正在进行法线贴图),或发送给它的任何内容。通常,您希望在此处进行几何计算。您还可以访问为绘制调用设置的统一变量,这些变量是全局变量,每个顶点都不会更改。在顶点着色器中,您可能需要使用的一个典型统一变量是PVM矩阵。如果不使用细分,顶点着色器将写入gl_位置,光栅化器将使用该位置创建碎片。您还可以让顶点输出不同的内容(如uv坐标和处理thieri几何体后的法线),将它们提供给光栅化器,以便稍后使用

光栅化

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

深度测试,模具测试。(可以使用早期片段优化()将其移动到片段着色器之前)

混合


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

“许多基于着色器的教程演示了如何在屏幕上绘制三角形或立方体,效果很好。”大多数教程都不止一页,因此不仅仅是“画一个对象”。有。我同意NB。阅读教程,找本书,或者找一些简单的游戏英语