【问题标题】:Setting vectors in shaders, How does it work? OpenGL GLSL在着色器中设置向量,它是如何工作的? OpenGL GLSL
【发布时间】:2015-05-02 14:39:08
【问题描述】:

我正在尝试了解顶点和片段着色器在 OpenGL ES 2.0 中的工作原理。

我的着色器如下所示:

顶点着色器:

// source code for the vertex shader
attribute vec4 vPosition
attribute vec2 a_texCoord;
varying vec2 v_texCoord;

void main() {
    gl_Position = vPosition;
    v_texCoord = a_texCoord;
}

片段着色器:

// source code for the fragment shader
precision mediump float;
uniform sampler2D s_texture;
varying vec2 v_texCoord;

void main() {
    gl_FragColor = texture2D(s_texture, v_texCoord);
}

使用这些着色器的程序绘制一个带有纹理(图像)的简单二维矩形。首先,它将矩形的顶点和纹理坐标传递给带有属性的顶点着色器。然后顶点着色器将带有变量的纹理坐标传递给片段着色器。

让我困惑的是向量 vPosition、a_texCoord 和 v_texCoord 只能保存 1 个 Point,但需要保存 4 个不同的 Point。我在某处读到将为每个顶点调用顶点着色器。这是否意味着对于我要绘制的每个图像,顶点和片段着色器将被处理 4 次?当我定义属性(glVertexAttribPointer)时,我使用的是一个有 4 个点的数组,着色器如何将 4 个点保存在一个只能存储 1 个点的变量中?

我想使用制服而不是属性,我读得更好。我也不需要可变变量。我想要这样:

顶点着色器:

// source code for the vertex shader
uniform vec4 vPosition;

void main() {
    gl_Position = vPosition;
}

片段着色器:

// source code for the fragment shader
precision mediump float;
uniform sampler2D s_texture;
uniform vec2 v_texCoord;

void main() {
    gl_FragColor = texture2D(s_texture, v_texCoord);
}

这可能吗?我仍然可以将我需要的所有点传递给着色器吗?这是个好主意吗?

【问题讨论】:

    标签: android opengl-es glsl opengl-es-2.0 glsles


    【解决方案1】:

    不,您不能将每个顶点的数据存储到制服中。制服被设计为每个绘制调用,顶点属性被设计为每个顶点。您可以将顶点位置与制服一起使用的唯一方法是绘制一个点,因为它仅使用 1 个坐标。

    关于顶点和处理:是的,如果您使用 4 个顶点进行绘制,将至少调用 4 次顶点着色器来处理这些顶点。您无需担心这一点,想象一下使用 4 个顶点绘制 100x100 图像,将调用 4 次顶点着色器和 10000(100x100) 次片段着色器调用。这就是 GPU 的设计目的,它非常高效。

    您可以查看一些完整的 openGL 管道图表以更好地了解所有内容,但只是为了让您了解调用 openGL 进行绘图时发生的情况:

    • 根据您正在绘制的形状(例如三角形),将在顶点着色器中获取和处理一些点,这包括所有属性,例如位置、纹理坐标、法线...
    • 接下来将进行光栅化,此时将确定缓冲区上的所有像素都将被绘制到,并为每个像素分配一个片段着色器。
    • 然后片段着色器发生,它将接收所有内插值和所需的固定制服,并刷新您当前正在使用的每个附加缓冲区中的单个特定像素(颜色、深度...)。

    现在,这条管道还有很多我描述的内容,但这些对于您提出的问题来说是最有趣的。

    试着理解着色器只是一个长的固定管道的一部分,现在可以被覆盖,你不应该问自己它们被调用了多少次,至少不是因为你正在做的简单操作。如果您需要优化这些调用的数量,您很可能需要在 CPU 上进行优化。例如,如果您正在绘制数千个相互重叠的大矩形,您可以考虑使用算法来减少绘制一个大部分重叠的矩形所需的大小,或者如果它完全重叠,甚至根本不绘制它。

    所以要了解您发布的着色器发生了什么:如果您正在绘制一个带纹理的矩形,您将有 4 或 6 次调用顶点着色器(6 次使用两个三角形)。顶点着色器将接收所有启用的属性,在您的情况下是位置和纹理坐标。这两个值没有做任何事情,而是在这一点上向前传递。然后位置是自动的(您不需要另一个可变参数来传递它),但是纹理坐标被分配给您称为v_texCoord 的可变属性。这意味着将为将要绘制的每个像素插入纹理坐标,然后在片段着色器中接收这些值。这就是为什么您实际上可以看到绘制的纹理的原因,因为每个像素都具有从纹理中获取的不同颜色,并且片段着色器接收到不同的插值坐标。所以用统一替换属性会破坏这一切,不会发生插值,所有像素看起来都完全相同。

    【讨论】:

    • 非常感谢您的详细回答
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-05-08
    • 2011-03-14
    • 1970-01-01
    • 1970-01-01
    • 2022-10-14
    • 1970-01-01
    • 2013-12-11
    相关资源
    最近更新 更多