【发布时间】:2016-07-22 20:21:01
【问题描述】:
我在尝试从当前附加到绘图帧缓冲区的纹理单元中读取数据时遇到了问题。只要我在绘图调用之间使用 glTextureBarrier,错误就会被删除。但是我试图消除绘图调用,所以这是一个不理想的解决方案。 OpenGL 4.5 规范(第 9.3 节纹理和帧缓冲区之间的反馈循环)指出
将纹理附加到帧缓冲区对象的机制不会阻止 一维或二维纹理级别,立方体贴图纹理级别的面,或 将二维数组或三维纹理的图层附加到绘制帧缓冲区,同时将相同的纹理绑定到纹理单元。虽然这种情况成立,但访问该图像的纹理操作将产生未定义的结果,如第 8.14 节末尾所述。 ... 具体来说,如果任何着色器阶段获取纹素并且通过片段着色器输出写入相同的纹素,则渲染片段的值是未定义的,即使读取和写入不在同一个绘制调用中,除非适用以下任何例外:
读取和写入来自/到不相交的纹素集(在考虑了纹理过滤规则之后)。
每个texel只有一次读取和写入,读取在 写入相同纹素的片段着色器调用(例如,使用
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);
【问题讨论】:
-
除非您提供一些代码,否则很难说这里可能出了什么问题...
-
@peppe 嘿嘿,这里有很多代码,看看哪些部分会有所帮助?我在帖子中没有提到的一个注意事项是阵列纹理的图层附加到不同的颜色附件。但据我所知,这是唯一的方法。
-
好吧,至少你的 FBO 设置的设置草图,着色器的相关部分,你正在渲染什么样的数据......
-
@peppe 我已经用代码更新了问题
标签: opengl textures framebuffer opengl-4 feedback-loop