无法在 openGL 片段着色器中正确检索 16 位整数
Cannot correctly retrieve 16-bit integers inside openGL fragment shader
我想做的事:在 iOS.
上使用 openGL ES 2.0,在片段着色器中使用带符号的 16 位整数进行 GPGPU 计算
我已经验证我已经正确设置了我的(输入)纹理缓冲区和(输出)帧缓冲区,并且可以传递 16 位整数(通过使用无符号的 8 位指针别名到缓冲区),将各个字节渲染到帧缓冲区,检索字节并在 CPU 端重建正确的 16 位值。
如果我调用 glClearColor,我可以传入
这样的值
glClearColor(0.5, 0.5, 0.5, 0.5); // endian-agnostic way to initialize buffer with "no data" values (-32640)
glClear(GL_COLOR_BUFFER_BIT);
我正在使用 glClearColor 的测试值 (0.5, 0.5, 0.5, 0.5)。这些应该等同于传入 -32640(有符号)或 32896(无符号)。
我可以正确地检索片段着色器中的值(作为无符号等效值)
#extension GL_EXT_shader_framebuffer_fetch : require
varying highp vec2 vTexCoord;
uniform sampler2D myTexture;
void main()
{
lowp vec4 myIntArray = texture2D( myTexture, vTexCoord);
// Retrieve value from frame buffer
lowp vec4 lastFragColor = gl_LastFragData[0];
// Recover the value (stored in alpha (high byte) and red (low byte)
highp float signed_value = lastFragColor.a;
signed_value = signed_value*255.0*256.0 + lastFragColor.r*255.0;
// ... Do stuff with the recovered value.
// Here, I simply verify value is recovered correctly (as an unsigned int equivalent):
// This draws the pixel green, indicating success
if (signed_value >= 32896.0) {
gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
}
else {
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}
// But changing the threshold value very slightly (replacing the lines
// above with those below) draws the pixel red, correctly
// indicating the condition is not met, because the value is
// 32896
if (signed_value >= 32896.01) {
gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
}
else {
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}
}
但是,我想传递一个不同值的数组,所以我没有使用 glClearColor,而是设置了一个缓冲区,并将一个指向我的有符号 16 位整数数组的指针传递给它(基本上是别名到我的有符号 int16_t 字节就好像它们只是无符号字节一样。)
然后我可以将它们渲染到帧缓冲区,并使用 glReadPixels 并将指向该数组的 int16_t 指针重新设置为 CPU 上的别名以返回正确的值。然而,使用与上面相同的逻辑,但访问我的纹理而不是帧缓冲区:
highp float signed_value = myIntArray.a;
signed_value = value*255.0*256.0 + myIntArray.r*255.0;
使用纹理中的值,我只能在片段着色器中正确重建从 0 到 32767 的值,但不能重建 > 32767 的值。我需要能够重建 2^16 个可能值中的任何一个,或者作为签名或未签名。为什么我可以从帧缓冲区而不是我的纹理缓冲区重建大于 32767 的值?
(编辑添加:更正 - 似乎我无法通过我的纹理传入、渲染和检索 所有 16 位整数......之前出现的是负面的值是使用 glClear() 进行初始化的产物。我通过纹理渲染为黑色传递的负值,并在 CPU 上重建为零。正确处理 0 到 32767 之间的值。所以...是可以传入带符号的 int16 值(或无符号的 int16 值 > 32767)并在片段着色器中正确重建它们?)
原来片段着色器代码没问题;我找错地方了。我不知道的是,"client" 将输入限制为非负值。谜团解开了,尽管额头上有一个大耳光。
我想做的事:在 iOS.
上使用 openGL ES 2.0,在片段着色器中使用带符号的 16 位整数进行 GPGPU 计算我已经验证我已经正确设置了我的(输入)纹理缓冲区和(输出)帧缓冲区,并且可以传递 16 位整数(通过使用无符号的 8 位指针别名到缓冲区),将各个字节渲染到帧缓冲区,检索字节并在 CPU 端重建正确的 16 位值。
如果我调用 glClearColor,我可以传入
这样的值glClearColor(0.5, 0.5, 0.5, 0.5); // endian-agnostic way to initialize buffer with "no data" values (-32640)
glClear(GL_COLOR_BUFFER_BIT);
我正在使用 glClearColor 的测试值 (0.5, 0.5, 0.5, 0.5)。这些应该等同于传入 -32640(有符号)或 32896(无符号)。
我可以正确地检索片段着色器中的值(作为无符号等效值)
#extension GL_EXT_shader_framebuffer_fetch : require
varying highp vec2 vTexCoord;
uniform sampler2D myTexture;
void main()
{
lowp vec4 myIntArray = texture2D( myTexture, vTexCoord);
// Retrieve value from frame buffer
lowp vec4 lastFragColor = gl_LastFragData[0];
// Recover the value (stored in alpha (high byte) and red (low byte)
highp float signed_value = lastFragColor.a;
signed_value = signed_value*255.0*256.0 + lastFragColor.r*255.0;
// ... Do stuff with the recovered value.
// Here, I simply verify value is recovered correctly (as an unsigned int equivalent):
// This draws the pixel green, indicating success
if (signed_value >= 32896.0) {
gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
}
else {
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}
// But changing the threshold value very slightly (replacing the lines
// above with those below) draws the pixel red, correctly
// indicating the condition is not met, because the value is
// 32896
if (signed_value >= 32896.01) {
gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
}
else {
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}
}
但是,我想传递一个不同值的数组,所以我没有使用 glClearColor,而是设置了一个缓冲区,并将一个指向我的有符号 16 位整数数组的指针传递给它(基本上是别名到我的有符号 int16_t 字节就好像它们只是无符号字节一样。)
然后我可以将它们渲染到帧缓冲区,并使用 glReadPixels 并将指向该数组的 int16_t 指针重新设置为 CPU 上的别名以返回正确的值。然而,使用与上面相同的逻辑,但访问我的纹理而不是帧缓冲区:
highp float signed_value = myIntArray.a;
signed_value = value*255.0*256.0 + myIntArray.r*255.0;
使用纹理中的值,我只能在片段着色器中正确重建从 0 到 32767 的值,但不能重建 > 32767 的值。我需要能够重建 2^16 个可能值中的任何一个,或者作为签名或未签名。为什么我可以从帧缓冲区而不是我的纹理缓冲区重建大于 32767 的值?
(编辑添加:更正 - 似乎我无法通过我的纹理传入、渲染和检索 所有 16 位整数......之前出现的是负面的值是使用 glClear() 进行初始化的产物。我通过纹理渲染为黑色传递的负值,并在 CPU 上重建为零。正确处理 0 到 32767 之间的值。所以...是可以传入带符号的 int16 值(或无符号的 int16 值 > 32767)并在片段着色器中正确重建它们?)
原来片段着色器代码没问题;我找错地方了。我不知道的是,"client" 将输入限制为非负值。谜团解开了,尽管额头上有一个大耳光。