【问题标题】:Get vertex positions in fragment shader在片段着色器中获取顶点位置
【发布时间】:2015-02-11 04:13:42
【问题描述】:

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

我可以通过三种方式做到这一点:附加属性、制服和通过几何着色器。

属性

// 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;
}

问题是我需要发送额外的属性,这意味着在 VBO 中使用了额外的内存。

制服

// fragment shader
uniform vec3 posA;
uniform vec3 posB;
uniform vec3 posC;

void main() {
    // ...
}

主要缺点显然是需要为每个正在绘制的三角形绑定制服,所以我每次绘制调用只能绘制一个三角形。

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 关键字,但在这里不行。

问题是,是否还有其他选择,我可能会遗漏一些东西?

谢谢。

【问题讨论】:

    标签: opengl opengl-es glsl webgl


    【解决方案1】:

    几何着色器是最实用的方法,但这通常会排除 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 应该比基于几何着色器的方法更容易。

    【讨论】:

    • 您似乎可以使用属性而不是使用gl_VertexID,您可以在WebGL 中做同样的事情吗? Here's a WebGL example putting vertex data in textures.
    • @gman:我不太关心这个细节,因为texelFetch 和缓冲区纹理在没有扩展的情况下也无法在 WebGL 中工作。您必须标准化纹理坐标并消除整数顶点属性。这基本上是我能想到的最简单的例子,它使用现有的着色器代码作为基础,在每个顶点的基础上完成几何着色器的工作(获取并发出 3 个顶点)。我最担心的是让posAposBposC 对三角形中的所有顶点保持一致,这样不同的插值就不会搞砸了。
    • 在我看来,可能有一些预定义的变量可能会将顶点的信息传递给片段,因为在光栅化期间,每个片段都在测试自己是否包含在图元中,所以无论如何它都会得到顶点的位置。感谢@AndonM.Coleman 的想法。
    • @AbstractAlgorithm:你有点倒退了。在光栅化过程中,会生成一组被基元覆盖的片段。您可能会在现代硬件上找到每个片段的唯一内容是插值变量和偏导数dFdxdFdy(WebGL 中的扩展),片段着色器不必知道实际的顶点位置。我不知道您需要知道什么顶点位置,但插值坐标的偏导数有时同样有用;例如,您可以使用它计算三角形的法线。
    • "Screen-space AABB" 计算基元,然后测试这些片段是否包含在三角形内,对吗?并不完全是片段着色器需要知道顶点,而是在实际着色器运行之前完成的先前测试。如果我错了,请纠正我。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-24
    • 2011-05-24
    • 1970-01-01
    • 2017-05-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多