【问题标题】:How vertex and fragment shaders communicate in OpenGL?顶点和片段着色器如何在 OpenGL 中通信?
【发布时间】:2015-04-04 15:53:25
【问题描述】:

我真的不明白片段着色器是如何工作的。

我知道

  • 顶点着色器每个顶点运行一次
  • 片段着色器每个片段运行一次

由于片段着色器不是按顶点工作,而是按片段工作,它如何将数据发送到片段着色器?顶点数量和碎片数量不相等。

它如何决定哪个片段属于哪个顶点?

【问题讨论】:

    标签: opengl graphics glsl fragment-shader vertex-shader


    【解决方案1】:

    要理解这一点,您需要考虑整个渲染管道。顶点着色器的输出(除了特殊输出gl_Position)作为顶点的“关联数据”传递到管道中的下一个阶段。

    虽然顶点着色器一次只在一个顶点上工作,根本不关心基元,但管道的进一步阶段确实会考虑基元类型(和顶点连接信息)。这就是通常所说的“原始装配”。现在,我们仍然拥有由 VS 生成的具有关联数据的单个顶点,但我们也知道哪些顶点被组合在一起以定义基本图元,例如点(1 个顶点)、线(2 个顶点)或三角形(3顶点)。

    在光栅化过程中,为输出像素光栅中属于图元的每个像素位置生成片段。这样做时,定义图元的顶点的关联数据可以在整个图元中插值。在一条线上,这相当简单:完成了线性插值。让我们用一些相关的输出向量 v 来调用端点 A 和 B,这样我们就有了 v_A 和 v_B。越过这条线,我们在每个端点处得到 v 的插值作为 v(x)=(1-x) * v_A + x * v_B,其中 x 在 0(在点 A)到 1(在点乙)。对于三角形,使用所有 3 个顶点的数据之间的重心插值。因此,虽然顶点和片段之间没有 1:1 映射,但 VS 的输出仍然定义了 FS 的相应输入的值,只是不是以直接方式,而是通过使用的原始类型的插值间接地定义。

    到目前为止我给出的公式有点简化。实际上,默认情况下,应用透视校正,通过修改公式以考虑透视的失真影响。这仅仅意味着插值应该像在对象空间中线性应用一样起作用(在应用投影失真之前)。例如,如果您有透视投影和一些不平行于图像平面的图元,则在屏幕空间中向右移动 1 个像素确实意味着在真实对象上移动可变距离,具体取决于实际点到的距离相机平面。

    您可以通过对 GLSL 中的 in/out 变量使用 noperspective 限定符来禁用透视校正。然后,按照我的描述使用线性/重心插值。

    您还可以使用flat 限定符,它将完全禁用插值。在这种情况下,只有一个顶点(所谓的“激发顶点”)的值用于整个图元的所有片段。整数数据永远不能由 GL 自动插值,并且在发送到片段着色器时必须限定为 flat

    【讨论】:

    • 所以我想我们也可以将这个公式应用到 uv 坐标上进行纹理处理。
    • 好吧。基本原理适用于所有输出变量,uv 坐标只是一个例子。我扩展了我的答案以解决插值的透视校正问题。
    【解决方案2】:

    答案是他们没有——至少不是直接的。还有一个叫做“光栅化器”的东西,它位于管道中的顶点处理器和片段处理器之间。光栅化器负责收集来自顶点着色器的顶点,将它们重新组装成图元(通常是三角形),将这些三角形分解为(部分)覆盖像素的“光栅”,并将这些片段发送到片段着色器。

    这是(大部分)固定功能的硬件,您不能直接编程。您可以进行一些配置调整,这些调整会影响它作为基元处理的内容以及作为片段生成的内容,但在大多数情况下,它只是在顶点着色器和片段着色器之间进行操作。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-11-24
      • 2023-03-25
      • 2019-01-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-05-20
      相关资源
      最近更新 更多