【问题标题】:Access to 3D array in fragment shader在片段着色器中访问 3D 数组
【发布时间】:2019-09-27 21:52:43
【问题描述】:

我正在尝试通过使用 PyOpenGL 的 Python 程序向片段着色器提供对标量数据的 3 维数组的访问。

在片段着色器中,我声明了一个 3d 采样器制服

uniform sampler3D vol;

在 Python 程序中,我有以下代码来设置标量 3d 纹理

vol = numpy.random.rand(3, 3, 3).astype(np.float32)
texture = glGenTextures(1)
glUniform1i(glGetUniformLocation(program, "vol"), 0)
glActiveTexture(GL_TEXTURE0 + 0)
glBindTexture(GL_TEXTURE_3D, texture)
glTexImage3D(GL_TEXTURE_3D, 0, GL_RED, 3, 3, 3, 0, GL_RED, GL_FLOAT, vol)
glEnable(GL_TEXTURE_3D)

但是,无论我从采样器的哪个位置获取值,例如

color = texture(vol, vec3(0, 0, 0));

看来我总是得到黑色 (0, 0, 0)。

我做错了什么?

我知道我的片段着色器的基本设置是有效的,即如果我写 color = vec3(1, 0, 0) 我会得到红色像素。

我也知道没有 OpenGL 错误,因为我在运行程序时使用了 glutInit() 处理的选项 -glerror,这导致 OpenGL 错误被转换为 Python 异常。

【问题讨论】:

    标签: python opengl glsl fragment-shader


    【解决方案1】:

    那是因为您的GL_RED 纹理格式被钳制<0,1> 范围内!!!

    要进行补救,您需要使用非钳位纹理格式或禁用钳位...这里的示例适用于我的 GL 实现:

    从这两种格式中提取的格式:

    glTexImage3D(GL_TEXTURE_3D, 0, GL_R16F, xs,ys,zs, 0, GL_RED, GL_FLOAT, dat);
    
    glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA8, size, size, size, 0, GL_RGBA, GL_UNSIGNED_BYTE, pdata);
    

    对于标量数据,我会使用第一个选项。还有更多格式没有被限制,你试试看吧……

    从未使用过禁用钳位功能,但在研究类似问题时在某处看到此代码(不确定是否有效):

    glClampColorARB(GL_CLAMP_VERTEX_COLOR_ARB, GL_FALSE);
    glClampColorARB(GL_CLAMP_READ_COLOR_ARB, GL_FALSE);
    glClampColorARB(GL_CLAMP_FRAGMENT_COLOR_ARB, GL_FALSE);
    

    理论上你可以使用任何纹理格式...

    为了验证你可以使用这个:

    我也没有看到纹理集的任何参数。我希望是这样的:

    glBindTexture(GL_TEXTURE_3D,txrvol);
    glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
    glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R,GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER,GL_NEAREST);
    glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER,GL_NEAREST);
    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE,GL_MODULATE);
    

    为了避免插值弄乱您的非精确纹理坐标的数据...

    【讨论】:

    • 禁用钳位的可能性当然很有趣,但我不明白这可能是什么问题:我传递的数据是区间 [0, 1] 中的随机值,以及颜色分量在同一范围内指定...
    • @A.Donda 你确认生成的纹理不只是零吗?您是否还检查了 GLSL 编译和链接日志是否有错误?您是否尝试过在所有 3 个轴上进行 GL_NEAREST 过滤?所有这些都可能导致错误的输出...
    • 我想通了,看看我自己的答案。该解决方案向我表明,纹理不是将非图像数据放入片段着色器的最佳方式。你能推荐一个更好的方法吗?我已经看到从 4.3 开始,支持多维数组制服......
    【解决方案2】:

    我发现了问题:显然 GL_TEXTURE_3D 默认为 mipmapped,我只提供了级别 0,并且(我不清楚)另一个级别被选中。问题由glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAX_LEVEL, 0)解决。

    【讨论】:

    • 这很奇怪,因为我也以这种方式传递非纹理数据并且没有glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAX_LEVEL, 0) 没有问题。可能是特定于驱动程序的我正在使用 nVidia gfx 卡,或者甚至可能是特定于环境的,因为您使用不同的语言并且还使用库(不仅仅是 GL/GLSL),因此它们可能会自行更改一些设置也。顺便说一句,-glerror 选项仅处理 GL 错误还是 GLSL 错误?我只是好奇我不使用 GLUT
    • @Spektre,我有一个带有官方驱动程序的 GeForce GTX 1060。 – 是的,它还报告 GLSL 编译错误。感谢您的帮助!
    猜你喜欢
    • 2021-04-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-12
    • 2023-03-27
    • 1970-01-01
    • 2014-11-08
    相关资源
    最近更新 更多