OpenGL:如何将顶点POS从几何着色器传递到碎片着色器?
我目前正在学习 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 中。并删除几何着色器中的 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 \0 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();
}
I am currently learning shaders in OpenGL and finished writing my "drawText" geometry shader, so I can draw dynamic text ( content change every frame ), without recreating VBO every frame.
It's working nicely but it's limited to 28 chars, because of the GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS limitations that is equal 1024.
ATM I have 6 components per vertex emitted vec4 pos and vec2 texCoord.
Which give me 1024/6 = 170 vertices to use for my triangle strip.
I need 6 vertices per char ( instead first and last char ) to display a quad per char and 2 vertices to move to next char with degenerated triangle.
That gives me 170/6 = 28 chars.
So when I have a long text, I split it into text of 28 chars.
So now I try to optimize that and get my geometry shader to draw more than 28 chars.
So because I am in 2D, I was trying to find a way to store the texCoord in the pos.zw for the fragment shader. and remove the out vec2 texCoord in my geometry shader. Which will make me emit only 4 components per vertex, which would bring me to 42 chars.
But reading the fragment shader doc and fragment systems input I don't see who to do this.
So, is there a way to achieve that?
My code for reference
Vertex Shader
#version 330 core
layout (location = 0) in vec2 aPos;
uniform vec2 textPosition;
void main()
{
gl_Position = vec4(aPos ,0, 1) + vec4(textPosition, 0, 0);
}
Fragment Shader
#version 330 core
out vec4 fragColor;
in vec2 texCoord;
uniform vec4 textColor;
uniform sampler2D outTexture;
void main()
{
fragColor = texture(outTexture, texCoord) * textColor;
}
Geometry Shader
#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 \0 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();
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
通过
gl_position
定义的顶点的位置包含4个组件。总是。这些组件的含义由Rasterizer和OpenGL渲染系统定义。您不能绕过或以其他方式解决它。输出位置具有4个组件,并且您无法在其中隐藏纹理坐标或其他任意数据。
如果您需要从GS输出更多内容,则需要更有效地使用GS的顶点输出。就目前而言,您可以在每个四方之间输出退化条。这意味着,对于每6个顶点,其中只有4个是有意义的。您正在使用简并条进行拆分。
您应该使用
最终启动
将四边形拆分。这将删除所有顶点输出的1/3,从而为您提供更多的组件,以实现实际利用。The position of a vertex to be sent to the rasterizer, as defined through
gl_Position
, contains 4 components. Always. And the meaning of those components is defined by the rasterizer and the OpenGL rendering system.You cannot bypass or otherwise get around it. The output position has 4 components, and you cannot hide texture coordinates or other arbitrary data within them.
If you need to output more stuff from the GS, then you need to more efficiently use your GS's vertex output. As it currently stands, you output degenerate strips between each quad. This means that for every 6 vertices, only 4 of them are meaningful. You're using degenerate strips to split quads.
Instead of doing that, you should use
EndPrimitive
to split your quads. That will remove 1/3rd of all of your vertex output, giving you more components to put to actual good use.