在片段着色器中使用 textureCube 访问环境贴图失败

Posted

技术标签:

【中文标题】在片段着色器中使用 textureCube 访问环境贴图失败【英文标题】:Accessing environment map with textureCube fails in fragment shader 【发布时间】:2013-04-02 22:59:26 【问题描述】:

我正在编写一个考虑两个表面的折射着色器。 因此,我使用 FBO 将深度和法线渲染到纹理,并使用立方体贴图来表示环境。 我需要使用存储在纹理中的法线值从立方体贴图中获取值,以获得背面的折射法线。

只要我不尝试从其值已从纹理中检索到的向量访问它,立方体贴图就可以完美地工作。

这是一个失败的最小片段着色器。颜色保持绝望的黑色。 我确信对纹理 2D 的调用返回非零值:如果我尝试显示方向中包含的纹理颜色(表示法线),我会得到一个完美着色的模型。无论我对“方向”向量进行何种操作,它都会一直失败。

uniform samplerCube cubemap;
uniform sampler2D normalTexture;
uniform vec2 viewportSize;

void main()

   vec3 direction = texture2D(normalTexture, gl_FragCoord.xy/viewportSize).xyz;
   // direction = vec3(1., 0., 0) + direction; // fails as well!!
   vec4 color = textureCube(cubemap, direction);
   gl_FragColor = color;

这里是显示为颜色的向量“方向”的值,只是证明它们不为空! 这是上述着色器的结果(只是茶壶)。

虽然这段代码运行良好:

uniform samplerCube cubemap;
uniform vec2 viewportSize;
varying vec3 T1;

void main()

   vec4 color = textureCube(cubemap, T1);
   gl_FragColor = color;

我想不出任何原因为什么我的颜色会在我访问采样器立方体值时保持黑色!

为了完整起见,即使我的立方体贴图有效,以下是用于设置它的参数: glGenTextures(1, &mTextureId);

glEnable(GL_TEXTURE_CUBE_MAP);
glBindTexture(GL_TEXTURE_CUBE_MAP, mTextureId);
// Set parameters
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);

除非我在某个地方遗漏了重要的东西,否则我认为这可能是驱动程序错误。 我没有任何显卡,我使用的是 Intel Core i5 处理器芯片组。

00:02.0 VGA compatible controller: Intel Corporation 2nd Generation Core Processor Family Integrated Graphics Controller (rev 09)

知道为什么会发生这种情况,或者您有解决方法吗?

编辑:这是我的着色器类绑定纹理的方式

4 textures to bind
Bind texture 3 on texture unit unit 0
Bind to shader uniform: 327680
Bind texture 4 on texture unit unit 1
Bind to shader uniform: 262144
Bind texture 5 on texture unit unit 2
Bind to shader uniform: 393216
Bind texture 9 on texture unit unit 3
Bind to shader uniform: 196608

纹理 3 和 4 是深度,5 是法线贴图,9 是立方体贴图。

以及进行绑定的代码:

void Shader::bindTextures() 
    dinf << m_textures.size() << " textures to bind" << endl;
    int texture_slot_index = 0;
    for (auto it = m_textures.begin(); it != m_textures.end(); it++) 
        dinf << "Bind texture " << it->first<< " on texture unit unit "
                << texture_slot_index << std::endl;
        glActiveTexture(GL_TEXTURE0 + texture_slot_index);
        glBindTexture(GL_TEXTURE_2D, it->first);
        // Binds to the shader
        dinf << "Bind to shader uniform: " << it->second << endl;
        glUniform1i(it->second, texture_slot_index);
        texture_slot_index++;
    
    // Make sure that the texture unit which is left active is the number 0
    glActiveTexture(GL_TEXTURE0);


m_textures 是纹理 ID 到统一 ID 的映射。

【问题讨论】:

【参考方案1】:

您似乎没有为法线贴图和立方体贴图使用单独的纹理单元。一切都默认为纹理单元 0。你需要这样的东西:

uniform sampler2D norm_tex;

uniform samplerCube cube_tex;

在着色器中。使用 (3.2+) 核心配置文件时,纹理查找应该只使用“重载”texture 函数。对于 (3.3+),您还可以使用 sampler objects。

生成纹理并将其绑定到单独的纹理单元:

... generate 'norm_tex' and 'cube_tex' ...

glActiveTexture(GL_TEXTURE0);
... bind 'norm_tex' and set parameters ...

glActiveTexture(GL_TEXTURE1);
... bind 'cube_tex' and set parameters ...

... glUseProgram(prog); ...

glUniform1i(glGetUniformLocation(prog, "norm_map"), 0);
glUniform1i(glGetUniformLocation(prog, "cube_map"), 1);

【讨论】:

感谢您的回答!我也想到了这个问题,但我很确定纹理绑定正确。我的 Shader 类正在绑定所有纹理,然后将它们分配给着色器的统一值。如果您想查看绑定的痕迹,请参阅我的问题。 @geenux - 片段着色器只列出一个采样器。 是的,我忘记将它添加到最小着色器中,但这不是问题 ;) 现在一切都已修复!【参考方案2】:

我想通了,真的是一件很愚蠢的事情。 我忘记更改我的着色器函数以将立方体贴图绑定为 GL_TEXTURE_CUBE_MAP,所有内容都绑定为 GL_TEXTURE_2D!

还是谢谢!

【讨论】:

以上是关于在片段着色器中使用 textureCube 访问环境贴图失败的主要内容,如果未能解决你的问题,请参考以下文章

有没有办法在片段着色器中使用先前渲染的结果?

在片段着色器中绘制别名像素完美线?

在片段着色器中丢失纹理定义

在着色器中访问时,OpenGL如何决定使用MAG_FILTER和MIN_Filter?

如何在片段着色器中进行自定义模板测试

如何在片段着色器中找到 4 个顶点之间的插值位置?