顶点着色器的输入是如何工作的?

huangapple go评论79阅读模式
英文:

How does the input for vertex shader work?

问题

总结一下,我有以下的顶点缓冲区:

GLfloat _vertices[] = {
    -1.0f, -1.0f,
    1.0f, -1.0f,
    -1.0f, 1.0f,
    1.0f, -1.0f,
    1.0f, 1.0f,
    -1.0f, 1.0f
};

然后我设置了顶点并进行绘制如下:

glViewport(0, 0, w, h);
glEnableVertexAttribArray(0);
glDisable(GL_BLEND);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, _vertices);
glDrawArrays(GL_TRIANGLES, 0, 6);

我的顶点着色器如下:

#version 320 es
layout(location = 0) in vec2 vertPos;

out vec2 fragPos;
out float theLength;
void main()
{
    fragPos = vertPos;
    theLength = length(fragPos);
    gl_Position = vec4(vertPos.xy, 1.0, 1.0);
}

片段着色器如下:

#version 320 es
precision mediump float;

in vec2 fragPos;
in float theLength;

out vec4 fragColor;

void main()
{
    vec4 color = vec4(0.0);
    float d = length(fragPos);

    fragColor = vec4(d, 0.0, 0.0, 1.0);
}

使用上述片段着色器,我得到了以下图像:

顶点着色器的输入是如何工作的?

如果我将这一行 fragColor = vec4(d, 0.0, 0.0, 1.0); 更改为 fragColor = vec4(theLength, 0.0, 0.0, 1.0);,我得到:

顶点着色器的输入是如何工作的?

为什么我得到不同的结果?我期望得到一个红色的正方形。
我在SDL中使用了glsl着色器。也许SDL在后台实现了几何着色器?

谢谢。

英文:

In summary, I have the following vertices buffer:

GLfloat _vertices[] = {
    -1.0f, -1.0f,
    1.0f, -1.0f,
    -1.0f, 1.0f,
    1.0f, -1.0f,
    1.0f, 1.0f,
    -1.0f, 1.0f };

I then set the vertices and call draw like this:

glViewport(0, 0, w, h);
glEnableVertexAttribArray(0);
glDisable(GL_BLEND);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, _vertices);
glDrawArrays(GL_TRIANGLES, 0, 6);

My Vertex shader is as:

#version 320 es
layout(location = 0) in vec2 vertPos;

out vec2 fragPos;
out float theLength;
void main()
{
    fragPos = vertPos;
    theLength = length(fragPos);
    gl_Position = vec4(vertPos.xy, 1.0, 1.0);
}

And the fragment is:

#version 320 es
precision mediump float;

in vec2 fragPos;
in float theLength;

out vec4 fragColor;

void main()
{
    vec4 color = vec4(0.0);
    float d = length(fragPos);

    fragColor = vec4(d, 0.0, 0.0, 1.0);
}

With the fragment like the one above I have the following image:
顶点着色器的输入是如何工作的?

If I change the line fragColor = vec4(d, 0.0, 0.0, 1.0); to fragColor = vec4(theLength, 0.0, 0.0, 1.0); I got:

顶点着色器的输入是如何工作的?

Why do I obtain different results? I was expecting to have a red square.
I'm using glsl shaders within SDL. Maybe SDL is implementing a Geometry Shader in the background?

Thank you.

答案1

得分: 7

使用fragColor = vec4(theLength, 0.0, 0.0, 1.0);,只在每个顶点上计算长度,然后对顶点的长度结果进行插值。

由于所有顶点的长度相同(可能是sqrt(2)),在这些值之间的所有插值都产生相同的结果。

在原始版本中,长度是分别计算每个像素(片段)的。这导致中心部分具有较小的值。

重要的区别在于哪些值被插值。在第一个版本中,插值的是位置(在顶点之间变化)。例如,对于第一行像素:fragPos.x从-1插值到1(其中所有值都在之间)。fragPos.y是恒定的-1。当然,当您然后计算距离时,每个片段都会得到不同的值。

在第二个版本中,被插值的是长度,长度不变。

英文:

With fragColor = vec4(theLength, 0.0, 0.0, 1.0);, the length is only calculated on each vertex, then the length results for the vertices are interpolated.

Since all vertices have the same length (probably sqrt(2)), all interpolations between those values yield the same result.

In the original version, the length is calculated for each pixel (fragment) separately. This leads to having smaller values towards the center.

The important difference is which values get interpolated. In the first version, it's the position (which varies between vertices). Example for the first pixel row: fragPos.x is interpolated from -1 to 1 (with all values inbetween). fragPos.y is constant -1. When you then calculate the distance, you get different value for each fragment.

In the second version, it's the length which doesn't vary.

答案2

得分: 6

默认情况下,行为如下(省略了与深度缓冲区、模板缓冲区等无关的部分):

  1. 对于每个顶点,顶点着色器评估out变量
  2. 对于每个面(三角形),根据重心坐标插值三个顶点的out变量,这种插值对属于三角形的每个片段(像素)都是独立的
  3. 片段着色器对每个这样的片段执行,接收插值值到in参数中

对于fragPos,每个顶点都不同,因此自然会得到具有不同向量的插值,这些向量的长度与距离中心的距离成正比,因为您的四边形在范围-1到1之间

对于length,对于每个顶点,长度计算为sqrt(2),因此对于每个片段,这些插值是恒定的

顶点着色器的输入是如何工作的?

英文:

By default the behavior is as follows (omiting work with depth buffer, stencil buffer other things unrelated here):

  1. For every vertex, vertex shader evaluates out variables
  2. For every face (triangle), the out variables for 3 its vertices are interpolated according to barycentric coordinates, this interpolation is separate for every fragment (pixel) belonging to the triangle
  3. The fragment shader is executed for each such fragment, receiving interpolated values into in arguments

In the case of fragPos, it is different for every vertex, thus naturally you get interpolations with varying vectors, and length of those are proportional to the distance from the center, since your quad is in range -1 to 1

In the case of length, for every vertex the length evaluates to sqrt(2), thus interpolation over those is constant for every fragment

顶点着色器的输入是如何工作的?

答案3

得分: 4

顶点着色器被每个顶点调用 - 三角形需要调用3次。
片段着色器被每个片段调用 - 大致上可以理解为每个像素都会调用。

每个uniform变量都可以有一个插值修饰符 - smoothflatnoperspective,描述了如何将顶点着色器中的3个值分配给片段着色器的每个调用。

如果修饰符是flat,那么对于每个基元(例如三角形),都有一个主要的顶点,其值用于属于该基元的所有片段。

smooth会取三个值,对于三角形的每个顶点,进行插值。尝试将theLength设置为例如顶点的.x坐标,亲自观察一下。

但是,它永远不会按照你想要的方式工作,因为在顶点着色器中没有足够的信息。

英文:

Vertex shader is invoked for each vertex - 3 invocations for a triangle.
Fragment shader is invoked for each fragment - invoked for each pixel(roughly).

Each uniform variable can have a interpolation qualifier - smooth, flat, or noperspective describing how to distribute the 3 values from the vertex shader to each invocation for the fragment shader.

If the qualifier is flat, then for each primitive there is a main vertex from which are the values of variables used for all fragments belonging to that primitive.

smooth would take the three values, for each vertex of the triangle, and interpolate between them. Try setting theLength to e.g. .x coordinate of the vertex and see for yourself.

It will never work with the pattern you want though as there is simply not enough information in the vertex shader.

huangapple
  • 本文由 发表于 2023年6月22日 19:28:17
  • 转载请务必保留本文链接:https://go.coder-hub.com/76531406.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定