【问题标题】:glsl fragment shader calculate texture positionglsl片段着色器计算纹理位置
【发布时间】:2024-01-21 08:10:01
【问题描述】:

我正在编写一个片段着色器,用于将包含任意字节数组的一维纹理渲染为一种条形码。 我的想法是将每个字节编码为对角线划分的正方形(因此 4 个三角形中的每一个代表 2 位),如下所示:

 _____
|\ A /|  each byte encoded as binary is DDCCBBAA,
| \ / |  the colors are: Red   if 11
|D X B|                  Green if 10
| / \ |                  Blue  if 01
|/ C \|                  Black if 00
 ¯¯¯¯¯   so color can be calculated as: [(H & L), (H & !L), (!H & L)]

so for example: 198 == 11 00 01 10 would be:
 _____                 DD CC BB AA
|\ G /| 
| \ / | A=10=Green
|R X B| B=01=Blue
| / \ | C=00=Black
|/ b \| D=11=Red
 ¯¯¯¯¯  (B=Blue, b=Black)

到目前为止,我得到的是一个将 2 个布尔值(示例符号中的 H,L)编码为 vec3 颜色的函数,以及一个用于编码字节和“角索引”(A/B/C/D 在示例)进入颜色:

#version 400
out vec4 gl_FragColor; // the output fragment
in vec2 vf_texcoord; // normalized texture coords, 0/0=top/left
uniform isampler1D uf_texture; // the input data
uniform int uf_texLen; // the input data's byte count
vec3 encodeColor(bool H, bool L){
  return vec3(H&&L,H&&!L,!H&&L);
}
vec3 encodeByte(int data,int corner){
  int maskL = 1 << corner;
  int maskH = maskL << 1;
  int shiftL = corner/2;
  int shiftH = shiftL+1;
  bool H=bool((data&maskH)>>shiftH);
  bool L=bool((data&maskL)>>shiftL);
  return encodeColor(H,L);
}
void main(void) {

  // the part I can't figure out

  gl_FragColor.rgb=encodeByte(/* some stuff calculated by the part above*/);
  gl_FragColor.a=1;
}

问题是我不知道如何计算要编码的字节以及当前片段在哪个“角落”。

【问题讨论】:

  • “4 个三角形中的每一个都代表 2 个字节?”你的意思是比特吗?
  • 假设您实际上正在绘制所有几何图形,为什么不使用“要编码的字节”和“角”为每个三角形指定两个统一值?
  • 如果这个彩色方块代表一个字节,但您的原始数据包含多个字节,您将需要以某种方式显示多个方块,目前尚不清楚您打算如何做到这一点。您是将每个正方形绘制为单独的 GL 基元(例如三角形扇形),还是使用 GL 绘制单个矩形并依靠片段着色器在其中显示不同颜色的正方形?
  • @RogerAllen 因为我提到的两个“三角形”不是几何GL_TRIANGLES,但整个事物被渲染为一个大矩形(作为 2 个三角形的 VBO)。我在问题中提到的三角形只是代表正方形的每个字节的上/下/左/右四分之一。
  • @Wyzard 我将整个字符串渲染为一个大矩形,因此计算每个片段要处理的字符串的哪个字节取决于片段着色器。

标签: opengl glsl fragment-shader


【解决方案1】:

(注意,这里的代码是我头脑中的,未经测试,我也没有写很多 GLSL。变量名很草率,我可能犯了一些愚蠢的语法错误,但它应该足以传达这个想法。)

您需要做的第一件事是将纹理坐标转换为数据索引(显示颜色的正方形)和一组修改后的纹理坐标,这些坐标代表在该正方形内的位置。

对于水平排列,您可以执行以下操作:

float temp = vf_texcoord.x * uf_texLen;
float temp2 = floor(temp);
int dataIndex = temp2;
vec2 squareTexcoord = { temp2 - temp, vf_texcoord.y };

然后你会使用squareTexcoord 来决定你在正方形的哪个象限:

int corner;
vec2 squareTexcoord2 = squareTexcoord - { 0.5, 0.5 }
if (abs(squareTexcoord2.x) > abs(squareTexcoord2.y)) {  // Left or right triangle
    if (squareTexcoord2.x > 0) {  // Right triangle
        corner = 0;
    }
    else {  // Left triangle
        corner = 1;
    }
}
else {  // Top or bottom triangle
    if (squareTexcoord2.y > 0) {  // Bottom triangle
        corner = 2;
    }
    else {  // Top triangle
        corner = 3;
    }
}

现在您已经拥有了着色所需的一切:

gl_FragColor = { encodeByte(int(texelFetch(uf_texture,dataIndex,0).r), corner), 1.0 };

【讨论】:

  • 我不太明白abs(squareTexcoord2.x) &gt; abs(squareTexcoord2.y) 行。据我所知,这会检查我们是否在广场的右下半部分?
  • 它检查点是在左边还是右边,而不是在顶部或底部,它告诉你它是在正方形的“领结”还是“沙漏”部分。
  • 顺便说一句,当使用长度为 1 的数据纹理且只有字节为 13 的代码时,我得到 100% 黑色输出。
  • 啊,是的,当然,似乎我的大脑在解析该行时有点忽略了abs 调用:D
  • 可能有问题;我一年左右没有写过任何真正的 GLSL。阅读它是为了大致的想法,而不是确切的实现。
最近更新 更多