在片元着色器中获取顶点位置

6

出于某种原因,我需要在片元着色器中获取形成基本图形(三角形)的所有顶点的位置。

有三种方法可以做到这一点:使用额外属性、uniform变量和几何着色器。

属性:

// vertex shader
in vec3 vPosition;
in vec3 vposA;
in vec3 vposB;
in vec3 vposC;
out vec3 posA;
out vec3 posB;
out vec3 posC;

void main() {
    // ....
    posA = vposA;
    posB = vposB;
    posC = vposC;
}

问题在于我需要发送额外属性,这意味着需要在VBOs中使用更多的内存。
统一变量:
// fragment shader
uniform vec3 posA;
uniform vec3 posB;
uniform vec3 posC;

void main() {
    // ...
}

主要缺点显然是需要为绘制的每个三角形绑定一次uniform,因此我只能在每次绘制调用中绘制一个三角形。

GS(几何着色器)

layout(triangles) in;
layout(triangle_strip, max_vertices = 3) out;

out vec3 posA;
out vec3 posB;
out vec3 posC;

void main()
{
    posA = gl_in[0].gl_Position.xyz;
    posB = gl_in[1].gl_Position.xyz;
    posC = gl_in[2].gl_Position.xyz;

    gl_Position = gl_in[0].gl_Position;
    EmitVertex();
    gl_Position = gl_in[1].gl_Position;
    EmitVertex();
    gl_Position = gl_in[2].gl_Position;
    EmitVertex();
    EndPrimitive();
}

使用GS时,我不需要在内存中存储任何东西,可以绘制任意数量的三角形,但问题是整个新的着色器阶段被使用。

我也考虑过使用flat关键字,但这里行不通。

问题是,是否有其他选项,有什么我可能遗漏的吗?

谢谢。

1个回答

3

几何着色器是最实用的方法,但通常不适用于WebGL。

你可以考虑采用可编程顶点拉取的方法,其中实际顶点数据存储在缓冲纹理中,您使用索引来查找位置值。我无法评论性能,但这样做需要每个顶点 显著 较少的存储空间。

这是您原始基于属性的尝试的修改版本:

// vertex shader
in int vIdxA; // Index of vtx 0 in current triangle
in int vIdxB; // Index of vtx 1 in current triangle
in int vIdxC; // Index of vtx 2 in current triangle

out vec3 posA;
out vec3 posB;
out vec3 posC;

uniform samplerBuffer vtx_buf; // Actual vertex position array, as a buffer texture

void main() {
    int vtx = gl_VertexID % 3;

    // ....
    posA = texelFetch (vtx_buf, vIdxA);
    posB = texelFetch (vtx_buf, vIdxB);
    posC = texelFetch (vtx_buf, vIdxC);

    if (vtx == 0)
        gl_Position = posA;
    else if (vtx == 1)
        gl_Position = posB;
    else
        gl_Position = posC;
}

按照目前的实现方式,这也将排除WebGL,但是采用这种方法来适应OpenGL ES应该会更容易,而不是基于几何着色器的方法。


3
看起来你可以使用属性(attribute)代替gl_VertexID,并且在WebGL中也可以这样做。这里有一个在纹理(texture)中放置顶点数据的WebGL示例 - gman
1
@gman:我对这个细节并不是太担心,因为在WebGL中,texelFetch和缓冲纹理也需要扩展才能工作。您将不得不归一化纹理坐标并消除整数顶点属性。这基本上是我能想到的最简单的示例,它使用现有的着色器代码作为基础,在每个顶点的基础上执行几何着色器(获取和发出3个顶点)的工作。 我最担心的是让posAposBposC对于三角形中的所有顶点保持一致,以便变化的插值不会搞砸事情。 - Andon M. Coleman
屏幕空间的AABB(轴对齐边界框)是为原始图形计算的,然后测试这些片段是否包含在三角形内,对吗?不完全正确。片段着色器确实需要知道顶点,但是在实际着色器运行之前进行了先前的测试。如果我错了,请纠正我。 - Dragan Okanovic
@gman:重点是,为什么要在概念示例中加入必须使其在WebGL中工作的细节呢?我可以规范化纹理坐标,消除对gl_VertexID的依赖等等,但这将需要更多的代码来解释,并且这样做没有任何好处。 - Andon M. Coleman
@AbstractAlgorithm:正确,覆盖率是在片段着色器运行之前计算的。但生成它的数据并没有被保留下来。光栅化后,剩下的只有你插值的变量 :-\ 大多数情况下,在片段着色器中工作时,你只需要插值变量或变量的变化率。 - Andon M. Coleman
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接