我试图了解顶点和片段着色器如何在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);
}
使用这些着色器的程序绘制一个带纹理(图像)的简单2D矩形。首先,它将矩形的顶点和纹理坐标传递给带有属性的顶点着色器。然后顶点着色器将纹理坐标传递给片段着色器。
令我困惑的是,矢量vPosition,a_texCoord和v_texCoord只能保存1点,但需要保存4个不同的点。我在某处读到了为每个顶点调用顶点着色器的地方。这是否意味着对于我想要绘制的每个图像,顶点和片段着色器将被处理4次?当我定义属性(glVertexAttribPointer)时我使用的是一个有4个点的数组,着色器如何在一个只能存储1个点的变量中保存4个点?
我想使用制服而不是属性,我读得更好。我也不需要变量变量。我想这样:
顶点着色器:
// 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);
}
这可能吗?我还能将所需的所有点传递给着色器吗?这是个好主意吗?
答案 0 :(得分:1)
不,您不能将每个顶点数据存储到制服中。均匀设计为每个绘制调用,顶点属性设计为每个顶点。使用制服的顶点位置的唯一方法是绘制点,因为它只使用1个坐标。
关于顶点和处理:是的,如果使用4个顶点绘制,那么对于要处理的顶点,将至少有4次调用顶点着色器。你没有什么可担心的,想象一下,使用4个顶点绘制一个100x100的图像,将有4个调用顶点着色器和10000个(100x100)调用片段着色器。这就是GPU的设计目标,它非常有效。
您可以查看一些完整的openGL管道图表,以便更好地了解所有内容,但只是为了让您了解在调用openGL绘制时发生的事情:
现在我再次介绍了这个管道,但是对于你提出的问题,这些管道最为有趣。
尝试理解着色器只是长固定管道的一部分,现在可以被覆盖,你不应该问自己,至少它们被调用了多少次,而不是像你正在做的简单操作那样。如果需要优化这些调用的次数,则很可能需要在CPU上进行优化。例如,如果你要绘制几千个相互重叠的大矩形,你可以想到算法减少绘制一个矩形所需的大小,这个矩形大多与其他矩形重叠,或者如果完全重叠则根本不绘制它。 / p>
所以要了解你发布的着色器发生了什么:如果你正在绘制一个纹理矩形,你将有4或6个调用顶点着色器(6个使用两个三角形)。顶点着色器将接收所有已启用的属性,在您的情况下是位置和纹理坐标。这两个值没有做任何事情,但在这一点上向前传递。然后位置是自动的(您不需要另外的变化参数来传递它),但纹理坐标被分配给您称为v_texCoord
的变化属性。这意味着将为要绘制的每个像素插值纹理坐标,然后在片段着色器中接收这些值。这就是为什么你可以实际看到绘制的纹理的原因,因为每个像素都具有从纹理中获取的不同颜色,并且片段着色器接收到不同的插值坐标。因此,用统一替换属性会破坏所有这些,不会发生插值,所有像素看起来都完全一样。