OpenGL:如何将顶点位置从几何着色器传递到片段着色器?

OpenGL: how to pass vertex pos from Geometry shader to fragment shader?

我目前正在学习 OpenGL 中的着色器,并完成了我的“drawText”几何着色器的编写,因此我可以绘制动态文本(每帧内容都会更改),而无需每帧重新创建 VBO。

它运行良好,但限制为 28 个字符,因为 GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS 限制等于 1024。

ATM 每个顶点有 6 个组件发出 vec4 pos 和 vec2 texCoord。 这给我 1024/6 = 170 个顶点用于我的三角形带。

我需要每个字符 6 个顶点(而不是第一个和最后一个字符)来显示每个字符的四边形和 2 个顶点以移动到具有退化三角形的下一个字符。 这给了我 170/6 = 28 个字符。

所以当我有一个长文本时,我将它分成 28 个字符的文本。

所以现在我尝试优化它并让我的几何着色器绘制超过 28 个字符。 所以因为我在 2D 中,所以我试图找到一种方法将 texCoord 存储在片段着色器的 pos.zw 中。并在我的几何着色器中删除 out vec2 texCoord。这将使我每个顶点仅发出 4 个组件,这将使我达到 42 个字符。

但是在阅读片段着色器文档和片段系统输入时,我不知道该由谁执行此操作。 那么,有什么办法可以实现吗?

我的代码供参考

顶点着色器

#version 330 core
layout (location = 0) in vec2 aPos;

uniform vec2    textPosition;
void main()
{
    gl_Position     = vec4(aPos ,0, 1) + vec4(textPosition, 0, 0);
}

片段着色器

#version 330 core

out     vec4        fragColor;
in      vec2        texCoord;

uniform vec4        textColor;
uniform sampler2D   outTexture;

void main()
{
    fragColor = texture(outTexture, texCoord) * textColor;
}

几何着色器

#version 330 core

layout (points) in;
layout (triangle_strip, max_vertices = 170) out; 
// max components and vertices are 1024
// vec4 pos and vec2 text coord per vertex, that 6 components per vertex, 1024 / 6 = 170

out     vec2    texCoord;

uniform float   screenRatio         = 1;
uniform float   fontRatio           = 1;
uniform float   fontInterval        = 0;        // distance between letters
uniform float   fontSize            = 0.025f;   // default value, screen coord range is -1f , 1f  
uniform int     textString[8];                  // limited to 28 chars . 170 vertices / 6 = 28, 28 / 4 = 7 ints.

void main() 
{    
    vec4 position = gl_in[0].gl_Position;

    float fsx   = fontSize * fontRatio * screenRatio;
    float fsy   = fontSize;
    float tsy    = 1.0f / 16.0f;                // fixed in a 16x16 chars bitmap
    float tsx    = tsy;
    float tw     = tsx * fontRatio;
    float to     = ( tsx - tw ) * 0.5f;

    vec4  ptl = position + vec4(0,0,0,0);     // top left
    vec4  ptr = position + vec4(fsx,0,0,0);   // top right
    vec4  pbl = position + vec4(0,fsy,0,0);   // bottom left
    vec4  pbr = position + vec4(fsx,fsy,0,0); // bottom right
    vec2  tt;                                 // tex coord top
    vec2  tb;                                 // tex coord bottom

    fsx += fontInterval;

    int i  = 0;                               // index in int array
    int si = 0;                               // sub index in int
    int ti = textString[0];
    int ch = 0;

    do
    {
        // unpack a char, 4 chars per int
        ch  = (ti >> si) & (0xFF);

        // string ends with [=12=] or end of array
        if ( ch == 0 || i >= 8)
            break;

        // compute row and col of char in bitmaps 16x16 chars
        int   r   = ch >> 4;
        int   c   = ch - ( r << 4 );

        // compute tex coord from row and column
        tb = vec2(c * tsx + to, 1.0f - r     * tsy);
        tt = vec2(tb.x        , tb.y - tsy);

        texCoord    = tt;
        gl_Position = ptl;
        EmitVertex();   
        EmitVertex();   
        texCoord    = tb;
        gl_Position = pbl;
        EmitVertex();

        tt.x += tw;
        tb.x += tw;

        texCoord    = tt;
        gl_Position = ptr;
        EmitVertex();   

        texCoord    = tb;
        gl_Position = pbr;
        EmitVertex();
        EmitVertex();

        // advance of 1 char
        ptl.x += fsx;
        ptr.x += fsx;
        pbl.x += fsx;
        pbr.x += fsx;

        si += 8;
        if ( si >= 32 )
        {
            si = 0;
            ++i;
            ti = textString[i];
        }
    }
    while ( true );

    EndPrimitive();
}  

要发送到光栅器的顶点位置,如通过 gl_Position 定义的,包含 4 个分量。总是。而这些组件的含义由光栅器和 OpenGL 渲染系统定义。

您无法绕过或绕过它。输出位置有 4 个分量,您不能在其中隐藏纹理坐标或其他任意数据。

如果您需要从 GS 输出更多内容,那么您需要更有效地使用 GS 的顶点输出。按照目前的情况,您在每个四边形之间输出退化条带。这意味着对于每 6 个顶点,只有 4 个是有意义的。您正在使用退化条带拆分四边形。

而不是这样做,你应该使用 EndPrimitive 来分割你的四边形。这将删除所有顶点输出的 1/3,从而为您提供更多组件以供实际使用。