Search code examples
openglrustglsl

How can i fix this texture rendering issue in this basic OpenGL demo?


I tried making a basic square + texture demo in Rust OpenGL and the texture i rendered looks like this:

Bad render

...while it's supposed to look like this:

Texture

Below is my texture creation and upload code, which is a rust-ized version of learnopengl.com's version of creating, binding and uploading a basic texture:

pub fn from_image(file: String) -> Result<Texture, String> {
            let mut texture: GLuint = 0;
            match image::open(file.clone()) {
                Err(err) => panic!("Could not load image {:?}: {}", file, err),
                Ok(img) => {
                    let (width, height) = img.dimensions();
                    let img = match img {
                        DynamicImage::ImageRgb8(img) => img,
                        img => img.to_rgb8(),
                    };

                    unsafe {
                        glGenTextures(1, &mut texture);
                        if texture == 0 {
                            return Err(String::from("Error creating texture"));
                        }

                        glBindTexture(GL_TEXTURE_2D, texture);

                        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT as GLint);  // set texture wrapping to GL_REPEAT (default wrapping method)
                        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT as GLint);
                        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
                                        GL_LINEAR_MIPMAP_LINEAR as GLint);
                        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
                                        GL_LINEAR as GLint);

                        glTexImage2D(GL_TEXTURE_2D,
                                     0,
                                     GL_RGB8 as GLint,
                                     width as GLsizei,
                                     height as GLsizei,
                                     0,
                                     GL_RGB,
                                     GL_UNSIGNED_BYTE,
                                     img.as_raw().as_ptr().cast());

                        glGenerateMipmap(GL_TEXTURE_2D);
                    }
                    Ok(Texture(texture))
                }
            }
        }

Here are my shaders:

const VERT_SHADER: &str = r#"#version 330 core
         layout (location = 0) in vec3 pos;
         layout (location = 1) in vec2 aTexCoords;

         out vec2 texCoords;

         void main() {
            gl_Position = vec4(pos.x, pos.y, pos.z, 1.0);
            texCoords = aTexCoords;
         }"#;

const FRAG_SHADER: &str = r#"#version 330 core
        out vec4 final_color;

        in vec2 texCoords;

        uniform sampler2D Texture;

        void main() {
            final_color = texture(Texture, texCoords);
        }
        "#;

Here are my VAOs, VBO and EBO, which i took from learnopengl.com

const VAO: [Vertex; 4] =
        [[0.5, 0.5, 0.0, 1.0, 1.0], [0.5, -0.5, 0.0, 1.0, 0.0], [-0.5, -0.5, 0.0, 0.0, 0.0], [-0.5, 0.5, 0.0, 0.0, 1.0]];

const EBO: [TriIndexes; 2] = [[0, 1, 3], [1, 2, 3]];

    unsafe {
        glVertexAttribPointer(
            0,
            3,
            GL_FLOAT,
            GL_FALSE,
            (5 * size_of::<f32>()) as GLsizei,
            0 as *const _,
        );

        glEnableVertexAttribArray(0);

        glVertexAttribPointer(
            1,
            2,
            GL_FLOAT,
            GL_FALSE,
            (5 * size_of::<f32>()) as GLsizei,
            (2 * size_of::<f32>()) as *const _,
        );

        glEnableVertexAttribArray(1);
    }

Solution

  • The issue is the offset is incorrect for the second parameter in the VAO. It is currently an offset of 2 when it should really be an offset of 3. This causes the texture coordinates to be interpreted as [0.0, 1.0], [0.0, 1.0], [0.0, 0.0], [0.0, 0.0]. This effectively causes the y-axis of a sample to be ignored as the texture is only sampled along its diagonal.

    This is the corrected version of the call:

    glVertexAttribPointer(
        1,
        2,
        GL_FLOAT,
        GL_FALSE,
        (5 * size_of::<f32>()) as GLsizei,
        (3 * size_of::<f32>()) as *const _,  // <- This was the line with the issue
    );