Search code examples
c++openglgraphicsglslswizzling

OpenGL grayscale texture as float wrong format


I got an array with floating point values in 0.0 - 1.0 range (a height-map) but the texture comes back either black or just red I've tried multiple combinations of internal and source formats but nothing seems to work. My current code that just gives me a red texture is:

glGenTextures(1, &texure);
glBindTexture(GL_TEXTURE_2D, texure);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

glTexImage2D(GL_TEXTURE_2D, 0, GL_R32F, w, h, 0, GL_RED, GL_FLOAT, data);

[Edit] Image output: enter image description here Any ideas what is wrong?


Solution

  • You have to set the texture swizzling parameters, to treat OpenGL to read the green and blue color channel from the red color channel, when the texture is looked up - see glTexParameteri:

    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, GL_RED );
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED );
    

    See OpenGL 4.6 API Compatibility Profile Specification; 16.1 Texture Environments and Texture Functions; page 595:

    They are derived by computing the base color Cb and Ab from the filtered texture values Rt, Gt, Bt, At, Lt, and It as shown in table 16.1, ...

    Texture Base Texture base color Internal Format    Cb              Ab
    ...
    RED                                                (Rt, 0, 0)      1
    RG                                                 (Rt, Gt, 0)     1
    RGB                                                (Rt, Gt, Bt)    1
    RGBA                                               (Rt, Gt, Bt)    At
    

    Table 16.1: Correspondence of filtered texture components to texture base components.

    ...followed by swizzling the components of Cb, controlled by the values of the texture parameters TEXTURE_SWIZZLE_R, TEXTURE_SWIZZLE_G, TEXTURE_SWIZZLE_B, and TEXTURE_SWIZZLE_A. If the value of TEXTURE_SWIZZLE_R is denoted by swizzler, swizzling computes the first component of Cs according to

    if (swizzler == RED)
        Cs[0] = Cb[0];
    else if (swizzler == GREEN)
        Cs[0] = Cb[1];
    else if (swizzler == BLUE)
        Cs[0] = Cb[2];
    else if (swizzler == ALPHA)
        Cs[0] = Ab;
    else if (swizzler == ZERO)
        Cs[0] = 0;
    else if (swizzler == ONE)
        Cs[0] = 1; // float or int depending on texture component type
    

    If you would use a shader program, it would be possible to do something similar in the fragment shader, by Swizzling:

    in vec3 uv;
    
    out vec4 frag_color;
    
    uniform sampler2D u_texture;
    
    void main()
    {
       frag_color = texture(u_texture, uv).rrra;
    }