如何 return 采样像素的掩码
how to return the mask of sampled pixels
我正在使用 GitHub (here) 上提供的程序,使用 OpenGL 将等距柱状图像(360 度图像)转换为透视图(视口)。为此,光线追踪方法用于在单位球体上找到碎片点的交点,稍后将使用此信息从等距柱状图像中采样所需的像素并将它们投影到透视图上。一切正常,但现在沿着投影结果,我需要程序 return 对我来说也是一个掩码图像(类型为无符号字节,大小与等距柱状图像相同),它表示从等距柱状图像中采样的像素.
我如何才能将片段着色器更改为 return 给我这个无符号字节掩码(0 表示非样本,255 表示采样像素),同时在帧缓冲区上渲染视图?
更具体地说,我当前的片段着色器如下所示:
const float pi = 3.141592653589793;
varying vec3 planePoints;
uniform sampler2D tex;
void main()
{
vec2 equirectangularTexturePos;
vec3 spherepos = normalize(planePoints);
equirectangularTexturePos.x = (atan(spherepos.y, -spherepos.x)+pi)/(2.0*pi);
equirectangularTexturePos.y = acos(spherepos.z)/(pi);
gl_FragColor = texture2D(tex, equirectangularTexturePos);
}
我想要的是将如下类似的东西添加到我的片段着色器中:
texture2D(mask, equirectangularTexturePos) = 255;
我写这篇文章只是为了详细说明一个可能的解决方案,我试图在上面的评论中使用 Image Load Store 来暗示这个解决方案。首先,您需要创建一个与等距柱状纹理具有相同维度的新纹理(您可以使用 GL_R8 作为内部格式)。您可以使用 glTexImage2D 或 glTexStorage2D 来完成。
然后您需要在着色器中声明一个图像绑定点,并将蒙版图像的第一级绑定到该图像绑定点。然后,在您的着色器中,当您从原始颜色纹理中采样时,您还将使用 imageStore()
函数在该纹素位置写入遮罩纹理。注意:纹素位置是在实际纹素中,而不是整个纹理尺寸的一小部分!
对于第一个近似值,我们只使用原始样本位置的截断整数坐标(用于 texture2D 调用)。实际上,由于您使用 GL_LINEAR 作为过滤函数,您应该计算最近的 4 个纹素并写入这些纹素。请参阅 https://www.khronos.org/registry/OpenGL/specs/gl/glspec13.pdf 的 PDF 第 150 页以了解 GL 使用哪种算法来确定线性过滤的四个纹素。
所以你的部分着色器看起来像这样:
#extension GL_ARB_shader_image_load_store : enable
layout(binding = 0, r8) writeonly uniform image2D maskImage;
...
ivec2 texel = ivec2(equirectangularTexturePos * textureSize(tex, 0));
imageStore(maskImage, texel, vec4(1.0, 0.0, 0.0, 0.0));
为了将图像绑定到图像绑定点,您可以在宿主程序中使用它:
glBindImageTexture(0, maskTex, 0, false, 0, GL_WRITE_ONLY, GL_R8);
另外不要忘记在 运行 着色器之前清除纹理。在着色器 运行 并填充遮罩纹理的 0 级访问纹素之后,您需要添加适当的同步屏障,以便从该纹理获取的进一步 GL 调用可以看到更新的纹理值。您可以通过:
glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
现在您可以以任何方式使用该纹理并从中获取源代码,例如使用另一个着色器。
我正在使用 GitHub (here) 上提供的程序,使用 OpenGL 将等距柱状图像(360 度图像)转换为透视图(视口)。为此,光线追踪方法用于在单位球体上找到碎片点的交点,稍后将使用此信息从等距柱状图像中采样所需的像素并将它们投影到透视图上。一切正常,但现在沿着投影结果,我需要程序 return 对我来说也是一个掩码图像(类型为无符号字节,大小与等距柱状图像相同),它表示从等距柱状图像中采样的像素.
我如何才能将片段着色器更改为 return 给我这个无符号字节掩码(0 表示非样本,255 表示采样像素),同时在帧缓冲区上渲染视图?
更具体地说,我当前的片段着色器如下所示:
const float pi = 3.141592653589793;
varying vec3 planePoints;
uniform sampler2D tex;
void main()
{
vec2 equirectangularTexturePos;
vec3 spherepos = normalize(planePoints);
equirectangularTexturePos.x = (atan(spherepos.y, -spherepos.x)+pi)/(2.0*pi);
equirectangularTexturePos.y = acos(spherepos.z)/(pi);
gl_FragColor = texture2D(tex, equirectangularTexturePos);
}
我想要的是将如下类似的东西添加到我的片段着色器中:
texture2D(mask, equirectangularTexturePos) = 255;
我写这篇文章只是为了详细说明一个可能的解决方案,我试图在上面的评论中使用 Image Load Store 来暗示这个解决方案。首先,您需要创建一个与等距柱状纹理具有相同维度的新纹理(您可以使用 GL_R8 作为内部格式)。您可以使用 glTexImage2D 或 glTexStorage2D 来完成。
然后您需要在着色器中声明一个图像绑定点,并将蒙版图像的第一级绑定到该图像绑定点。然后,在您的着色器中,当您从原始颜色纹理中采样时,您还将使用 imageStore()
函数在该纹素位置写入遮罩纹理。注意:纹素位置是在实际纹素中,而不是整个纹理尺寸的一小部分!
对于第一个近似值,我们只使用原始样本位置的截断整数坐标(用于 texture2D 调用)。实际上,由于您使用 GL_LINEAR 作为过滤函数,您应该计算最近的 4 个纹素并写入这些纹素。请参阅 https://www.khronos.org/registry/OpenGL/specs/gl/glspec13.pdf 的 PDF 第 150 页以了解 GL 使用哪种算法来确定线性过滤的四个纹素。
所以你的部分着色器看起来像这样:
#extension GL_ARB_shader_image_load_store : enable
layout(binding = 0, r8) writeonly uniform image2D maskImage;
...
ivec2 texel = ivec2(equirectangularTexturePos * textureSize(tex, 0));
imageStore(maskImage, texel, vec4(1.0, 0.0, 0.0, 0.0));
为了将图像绑定到图像绑定点,您可以在宿主程序中使用它:
glBindImageTexture(0, maskTex, 0, false, 0, GL_WRITE_ONLY, GL_R8);
另外不要忘记在 运行 着色器之前清除纹理。在着色器 运行 并填充遮罩纹理的 0 级访问纹素之后,您需要添加适当的同步屏障,以便从该纹理获取的进一步 GL 调用可以看到更新的纹理值。您可以通过:
glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
现在您可以以任何方式使用该纹理并从中获取源代码,例如使用另一个着色器。