OpenGL、GLSL 片段着色器无法读取 Sampler2D 纹理

Posted

技术标签:

【中文标题】OpenGL、GLSL 片段着色器无法读取 Sampler2D 纹理【英文标题】:OpenGL, GLSL fragment shader can't read Sampler2D texture 【发布时间】:2019-02-20 07:53:31 【问题描述】:

我目前正在为我的项目使用 OpenGL,并且正在努力将纹理数据发送到 sampler2D。

我想在片段着色器中读取纹理作为蒙版,但是当我使用texelFetch 获取像素值时,我只能获取vec4(0, 0, 0, 1)

这是我的代码。

在我的初始化中:

#pragma region mask_creation

glActiveTexture(GL_TEXTURE0);
GLuint mask_texture;
glGenTextures(1, &mask_texture);
glBindTexture(GL_TEXTURE_2D, mask_texture);

constexpr auto channel = 4;
constexpr size_t size = width * height * channel;
auto texture_data =  new float[size];

for (auto i = 0; i < size; ++i) 
    texture_data[i] = 0.7f;


glTexSubImage2D(GL_TEXTURE_2D,
    0, 
    0, 0, 
    width, height,
    GL_RGBA, 
    GL_FLOAT, 
    texture_data);

delete[] texture_data;

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

GLuint mask_ID = glGetUniformLocation(programID, "mask");

在渲染中(在while(true)循环中):

glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, mask_texture);
glUniform1i(mask_ID, 0);

在我的片段着色器中

bool is_masked = (mask_val.x > 0.5) && (mask_val.y > 0.5) && (mask_val.z > 0.5);
if (original_depth < depth_threshold) 
    vec3 N = normalize(fs_in.N);
    vec3 L = normalize(fs_in.L);
    vec3 V = normalize(fs_in.V);

    vec3 R = reflect(-L, N);

    vec3 diffuse = max(dot(N, L), 0.0) * diffuse_albedo;
    vec3 specular = pow(max(dot(R, V), 0.0), specular_power) * specular_albedo;

    color = vec4(diffuse + specular, 1.0);

else 
    if (is_masked) 
        color = vec4(0, 0, 0, 1);
    
    else 
        vec3 N = normalize(fs_in.N);
        vec3 L = normalize(fs_in.L);
        vec3 V = normalize(fs_in.V);

        vec3 R = reflect(-L, N);

        vec3 diffuse = max(dot(N, L), 0.0) * diffuse_albedo;
        vec3 specular = pow(max(dot(R, V), 0.0), specular_power) * specular_albedo;

        color = vec4(diffuse + specular, 1.0);
    

我猜纹理还没有被发送到片段着色器,当我测试时..

vec4 mask_val = texelFetch(mask, ivec2(gl_FragCoord.xy), 0);

if (mask_val.x == 0 && mask_val.y == 0 && mask_val.z == 0 && mask_val.w == 1) 
    color = vec4(1, 1, 1, 1);

我得到一个白色圆圈(我的模型是一个球体)。

【问题讨论】:

您没有为此纹理加载 mipmap,但您选择了线性过滤 - 因此纹理不完整。我不确定 OpenGL 是否允许您从这样的纹理中执行 texelFetch,即使您只触摸 LOD 0。是否存在任何错误/调试输出? @BartekBanachewicz no.. 没有错误,当我使用纹理或纹理 2D 而不是 texelFetch 时,我可以看到同样的问题...... 【参考方案1】:

纹理图像的数据存储未定义。要定义二维纹理图像,您必须调用glTexImage2DglTexSubImage2D 仅初始化纹理图像区域中的数据。

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_FLOAT, texture_data);

注意,glTexImage2D 还指定了纹理数据的内部格式。例如,可以使用调整大小的内部格式(第三个参数),例如 GL_RGBA8GL_RGBA32F

【讨论】:

glTexSubImage2D之前使用glTexStorage2D 我尝试将glTexSubImage2D替换为glTexImage2D,结果相同...我也尝试了GL_RGB32F...OTL @신준섭 问题的代码工作正常(glTexSubImage2D 除外)

以上是关于OpenGL、GLSL 片段着色器无法读取 Sampler2D 纹理的主要内容,如果未能解决你的问题,请参考以下文章

用于片段着色器的 OpenGL GLSL 绑定采样器

片段着色器不会在 OpenGL GLSL 中创建像光一样的渐变

片段着色器中设置的颜色未显示 GLSL 1.30

✠OpenGL-2-图像管线

✠OpenGL-2-图像管线

带有片段着色器的 GLSL 仅渲染黑色 GL_POINTS