访问GL_DEPTH_COMPONENT纹理
Accessing a GL_DEPTH_COMPONENT texture
>我目前正在尝试实现屏幕空间环境光遮蔽。我的想法是按照标准方式使用多通道渲染,其中我使用前一个通道的深度信息来计算遮挡因子。因此,在我的"设置"代码中,我创建了一个帧缓冲和纹理对象并将它们绑定在一起。纹理是使用 GL_DEPTH_COMPONENT24 作为内部格式创建的,我正在发出 glDrawBuffer(GL_NONE) 调用,因为我不想要任何颜色输出。
此外,我有 3 个名为 AnimatedObject 的类实例,它们有自己的绘制方法,还有一个渲染器类在绘制时包装所有这些方法。目前,我的渲染器做了一些类似于
drawIntoDepthBuffer();
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
drawOntoScreen();
在上面的代码片段中,drawIntoDepthBuffer()
使用我的深度缓冲区程序,drawOntoScreen()
使用主顶点和片段着色器。我现在面临的问题如下:我根本无法访问在第二次绘制调用中渲染到的纹理。着色器都可以很好地编译和链接。使用深度缓冲区程序绘制到屏幕上会产生完美的输出,也不在主着色器中使用渲染的纹理会产生预期的结果。
我得到的错误是通用的OpenGL错误
错误: OpenGL 错误: 无效操作 (1282)
我也尝试在主着色器中使用sampler2Dshadow
制服,但在这种情况下,我真的不知道如何访问它,因为您需要一个vec3
来采样它,这在我的情况下根本没有意义。
以下是不同的代码片段:
"主"片段着色器:
#version 430 core
layout (binding = 0) uniform sampler2D texture_main;
layout (binding = 1) uniform sampler2D depth_map;
in vec3 normal;
in vec2 uv;
out vec4 outColor;
void main()
{
float test = texture(depth_map, gl_FragCoord.xy / textureSize(depth_map, 0)).r; //<---- this fails
float lambert = clamp(dot(normalize(normal), normalize(vec3(-0.5,1,1))), 0.2f, 1);
outColor = test * lambert * texture(texture_main, uv);
}
深度片段着色器:
#version 430 core
layout(location = 0) out float fragment_depth;
void main() {
fragment_depth = gl_FragCoord.z;
}
两个阶段的顶点着色器相同,如下所示:
#version 430 core
layout (location = 0) in vec3 inPos;
layout (location = 1) in vec3 inNormal;
layout (location = 2) in vec2 inUv;
uniform mat4 mvp;
out vec3 normal;
out vec2 uv;
void main()
{
gl_Position = mvp * inPos;
normal = inverse(transpose(mvp)) * inNormal;
uv = inUv;
}
相应的绘制调用看起来像这些行:
void draw_screen(GLuint depth_texture)
{
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glUseProgram(main_program);
glActiveTexture(GL_TEXTURE0 + 1);
glBindTexture(GL_TEXTURE_2D, depth_texture);
for (const auto& surface : surfaces)
{
glActiveTexture(GL_TEXTURE0));
glBindTexture(GL_TEXTURE_2D, surface);
glDrawArrays(GL_TRIANGLES, pos, count);
pos += pos_increment;
}
}
void draw_depth(GLuint framebuffer_id)
{
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer_id);
glUseProgram(depth_program);
for (const auto& surface : surfaces)
{
glBindTexture(GL_TEXTURE_2D, surface);
glDrawArrays(GL_TRIANGLES, pos, count);
pos += pos_increment;
}
}
下面是帧缓冲对象的设置:
glGenFramebuffers(1, &depth_framebuffer_id);
glBindFramebuffer(GL_FRAMEBUFFER, depth_framebuffer_id);
glGenTextures(1, &depth_texture_id);
glBindTexture(GL_TEXTURE_2D, depth_texture_id);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, viewport_width, viewport_height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, depth_texture_id, 0);
glDrawBuffer(GL_NONE);
我很抱歉有这么多代码,但这就是将所有这些联系在一起所需要的。任何帮助将不胜感激。
编辑:在摆弄了几个小时后,我发现错误是由调用glUniformMatrix4fv(location_mvp, 1, GL_TRUE, mvp._m)
引发的,顾名思义,它将MVP矩阵设置为统一。当我注释掉这一行时,depth_map采样器可以从纹理中读取(但它显然只包含垃圾值)。另一方面,如果我把这一行放进去,代码只有在我不访问depth_map采样器时才有效。这可能是什么原因?
好吧,似乎在第一次运行着色程序后,mvp 矩阵的位置会发生变化。它可以很好地渲染第一个对象,但是当第二个对象要渲染时,会弹出错误。我只是通过查找glGetUniformLocation
的位置来修复它,但是我仍然不明白为什么这个问题以如此奇怪的方式表现出来。首先,完全相同的代码适用于主着色程序(顶点着色器和调用代码完全相同),其次,当我不使用深度纹理时,我不明白程序是如何运行的。当后续传递中未使用整个渲染通道时,驱动程序是否能够优化它们?
基本上,您可以像访问任何其他纹理一样访问深度图。 但是,虽然gl_FragCoord.xy
提供窗口坐标,但texture
需要范围 [0.0, 1.0] 的浮点坐标。
如果深度贴图的大小和视口的大小相等(在您的情况下应该是这种情况),则使用texelFetch
:
float test = texelFetch(depth_map, ivec2(gl_FragCoord.xy), 0).r;
或者你必须除以纹理的大小(textureSize
):
float test = texture(depth_map, gl_FragCoord.xy / textureSize(depth_map, 0)).r;
注意,如果深度图的大小不等于视口大小,则必须提供视口大小作为统一变量:
uniform vec2 vp_size;
float test = texture(depth_map, gl_FragCoord.xy / vp_size).r;
参见 GLSL - OpenGL 着色语言 - 4.4.1.3 片段着色器输入,第 65 页
4.4.1.3 片段着色器输入
默认情况下,gl_FragCoord假定窗口坐标的原点左下角,并假定像素中心位于半像素坐标处。
答案的扩展:
第一遍是"仅深度"刀路。您不会将任何颜色平面附加到帧缓冲区,因此也不应写入片段着色器中的任何颜色平面。您必须使用空main
:
void main( void )
{
}
注意,如果要显式设置片段深度,则必须写入gl_FragDepth
。默认情况下,gl_FragCoord
的z
组件分配给gl_FragDepth
:
void main( void )
{
gl_FragDepth = gl_FragCoord.z;
}
此外,如果设置了统一变量的值,则必须在设置统一变量(glUniformMatrix4fv
)之前安装当前程序(glUseProgram
),因为glUniform*
为当前程序对象指定统一变量的值。
- OpenInventor从9.8升级到10.4.2后,GLSL纹理返回零
- SFML纹理像播放器
- OpenGL大的3D纹理(>2GB)非常慢
- UE4-如何在给定4个屏幕坐标的情况下缩放纹理或材质
- 着色器纹理值与创建纹理时写入的值不同
- OpenGL将纹理四边形渲染为(0,0)
- 宽度为奇数的16位纹理为片状
- 使用 CUDA 和纹理进行图像减法
- 在不使用统一的情况下将纹理传递给 GLSL 着色器?
- 将使用太多的纹理插值器 - 带旋转的着色器
- dx11 渲染到纹理仅显示透明颜色
- OpenGL 4.3 错误地将第 4 个纹理坐标映射到与第 3 个纹理坐标相同的位置
- 如何使用 DXGI 格式DXGI_FORMAT_R1_UNORM创建 2D 纹理?
- 纹理单位重叠?渲染了错误的纹理
- SFML 纹理变换(放大)
- SDL2 二维纹理分配/池化
- Qt OpenGL 渲染到纹理性能问题
- 为什么我会得到黑色纹理?
- glBindTexture 是否覆盖活动纹理单元的内容
- 无法将图像加载到纹理矢量 (SFML)