OpenGL从当前绑定到帧缓冲区的纹理单元读取

时间:2016-07-22 20:21:01

标签: opengl textures framebuffer opengl-4 feedback-loop

我在尝试从当前连接到绘图帧缓冲区的纹理单元中读取数据时遇到了问题。只要我在绘制调用之间使用glTextureBarrier,就会删除错误。但是,我试图消除绘制调用,因此这是一个不理想的解决方案。 OpenGL 4.5规范(第9.3节纹理和帧缓冲之间的反馈循环)表明

  

将纹理附加到帧缓冲对象的机制不会阻止a   一维或二维纹理级别,立方体贴图纹理级别的面或a   当相同的纹理绑定到纹理单元时,二维数组或三维纹理的图层被附着到绘制帧缓冲区。虽然这种情况成立,但访问该图像的纹理操作将产生未定义的结果,如第8.14节末尾所述。   ...   具体来说,如果任何着色器阶段获取纹素并且通过片段着色器输出写入相同的纹素,则渲染片段的值是未定义的,即使读取和写入不在同一个绘制调用中,除非以下任何例外情况适用:

     
    

读取和写入来自/不相交的纹素集(在考虑纹理过滤规则之后)。

         

每个纹素只有一次读写,读取就在     片段着色器调用,用于写入相同的纹素(例如,使用texelFetch2D(sampler, ivec2(gl_FragCoord.xy), 0);)

         

如果已经编写了纹理元素,那么为了安全地读取结果,纹素提取必须在由命令void TextureBarrier( void );分隔的后续绘制调用中     TextureBarrier将保证写入已完成且缓存已完成     在执行后续绘制调用之前已失效。

  

我对4个其他纹理没有问题。对于这些纹理,我只对同一个纹素进行一次读取和一次写入,因此它们被第二个异常覆盖。导致问题的纹理需要一些过滤,因此在写入之前我需要多次读取和来自不同的纹素。我认为这可以通过第一个异常允许,所以我将它们放在一个数组纹理中,交替读取和写入哪一层。这个想法是,这将创建一个设置,其中读取和写入来自/不相交的纹素集。它没有帮助。

我还试图在每次其他绘制调用时都执行glTextureBarrier,看看它是否是导致该问题的第三个绘制调用。当我一直使用障碍时,当我没有使用障碍时,这给出了不同的(仍然是错误的)结果。

绘制调用正在绘制0,0,0中的一个点,该点在几何着色器中展开为全屏四边形。

更新

我正在通过体积数据进行光线追踪。

帧缓冲设置

    glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, rayPositionTexture, 0);
    glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, rayDirectionTexture, 0);
    glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, IORTexture, 0);
    glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT3, resultTexture, 0);
    glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT4, rayOffsetTexture, 0, 0);
    glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT5, rayOffsetTexture, 0, 1);

着色

...
uniform sampler2D RayPositionTexture;
uniform sampler2D RayDirectionTexture;
uniform sampler2DArray RayOffsetTexture;
uniform sampler2D IORTexture;
uniform sampler2D ColorTexture;
...
flat in uint offsetIndex;
layout(location = 0) out vec4  outRayPosition;
layout(location = 1) out vec4  outRayDirection;
layout(location = 2) out float outIOR;
layout(location = 3) out vec4  outColor;
layout(location = 4) out vec4  outRayOffsetA;
layout(location = 5) out vec4  outRayOffsetB;
...
vec3 filteredOffset(ivec2 Pixel)
{
    vec3 Offset = vec3(0.0);
    float TotalWeight = 0.0;
    for(int i = -KernelRadius; i <= KernelRadius; i++)
    {
        for (int j = -KernelRadius; j <= KernelRadius; j++)
        {
            ivec2 SampleOffset = ivec2(i,j);
            ivec3 SampleLocation = ivec3(Pixel + SampleOffset, offsetIndex);
            vec3  Sample = texelFetch(RayOffsetTexture, SampleLocation, 0).xyz;
            float Weight = KernelRadius > 0 ? gauss(SampleOffset) : 1.0f;

            Offset += Sample * Weight;
            TotalWeight += Weight;
        }
    }
    Offset = Offset / TotalWeight;
    return Offset;
}
...
        //if (offsetIndex == 1)
        outRayOffsetA = vec4(RayDirection.xyz - RayDirectionNew, 0.0);
        //else
        outRayOffsetB = vec4(RayDirection.xyz - RayDirectionNew, 0.0);
        outIOR = IOR;
    } else {
        // if (offsetIndex == 1)
        outRayOffsetA = vec4(0.0);
        // else
        outRayOffsetB = vec4(0.0);
        outIOR = PreviousIOR;
        //imageStore(VolumeBackTexture, Pixel, vec4(1.0));
    }
    outColor = Color;
...

画出电话

GLenum drawBuffers[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3, GL_COLOR_ATTACHMENT4, GL_COLOR_ATTACHMENT5 };
glDrawBuffers(6, drawBuffers);

// Run shader
glBindVertexArray(pointVAO);
float distance = 0.0f;
for (int i = 0; distance < 1.73205080757f; i++)
{
    glTextureBarrier();
    glDrawArrays(GL_POINTS, i, 1); 
    distance += fUnitStep;
}
glBindVertexArray(0);

上面没有纹理障碍会产生与

相同的结果(错误的结果)
glBindVertexArray(pointVAO);
glDrawArrays(GL_POINTS, 0, int(std::ceil(1.73205080757f / fUnitStep)));
glBindVertexArray(0); 

1 个答案:

答案 0 :(得分:0)

要回答这个问题,这里需要TextureBarrier,因为我想从刚刚绘制的纹素中读取内容。只有在先前的绘制调用已完成并且纹理缓存已失效的情况下,才能安全地完成此操作,这正是TextureBarrier保证的。