Hello Guest

Can't draw texture on a quad using glDrawElements

  • 12 Replies
  • 311 Views
Can't draw texture on a quad using glDrawElements
« on: October 03, 2019, 15:28:05 »
Hi!
I have a problem using glDrawElements method.
I can draw a 2d quad with a texture on it using glVertex3f:

public void renderTerrainTile(float x0, float y0, float z0, Material mat){
        //Still 2D
        GL13.glEnable(GL11.GL_TEXTURE_2D);
        GL13.glBindTexture(GL11.GL_TEXTURE_2D, mat.getTexture().getID());
       
        GL11.glBegin(GL11.GL_TRIANGLE_STRIP); {
            GL11.glTexCoord2f(1.0f, 0.0f);
            GL11.glVertex3f(x0, y0 + 1, z0);
           
            GL11.glTexCoord2f(1.0f, 1.0f);
            GL11.glVertex3f(x0, y0, z0);
           
            GL11.glTexCoord2f(0.0f, 0.0f);
            GL11.glVertex3f(x0 + 1, y0 + 1, z0);
           
            GL11.glTexCoord2f(0.0f, 1.0f);
            GL11.glVertex3f(x0 + 1, y0, z0);
        } GL11.glEnd();
       
        GL13.glBindTexture(GL11.GL_TEXTURE_2D, 0);

        GL11.glPopMatrix();
    }

And it draws a normal square with my texture attached on it.
Then I have another method that uses mesh:

    public void render(Mesh mesh, Shader shader){
        GL30.glBindVertexArray(mesh.getVAO());

        GL30.glEnableVertexAttribArray(0);
        GL30.glEnableVertexAttribArray(1);
        GL30.glEnableVertexAttribArray(2);
       
        GL13.glEnable(GL11.GL_TEXTURE_2D);
       
        GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, mesh.getIBO());

        GL13.glActiveTexture(GL13.GL_TEXTURE0);
        GL13.glBindTexture(GL11.GL_TEXTURE_2D, mesh.getMaterial().getTextureID());

        //shader.bind();

        GL11.glDrawElements(GL11.GL_TRIANGLES, mesh.getIndices().length, GL11.GL_UNSIGNED_INT, 0);

        //shader.unbind();

        GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, 0);
        GL13.glBindTexture(GL11.GL_TEXTURE_2D, 0);

        GL30.glDisableVertexAttribArray(0);
        GL30.glDisableVertexAttribArray(1);
        GL30.glDisableVertexAttribArray(2);

        GL30.glBindVertexArray(0);
    }

I get a black square without shader when it should be the same as the square produced by the other method.
Can you help me to figure out the error? Thank you in advance!

*

Offline KaiHH

  • ****
  • 207
Re: Can't draw texture on a quad using glDrawElements
« Reply #1 on: October 03, 2019, 15:38:27 »
Generic vertex attributes do not work with the fixed-function pipeline (built-in) shaders, because OpenGL does not know which attribute arrays are your texture coordinates.
You have to use e.g. glTexCoordPointer if you want to use the fixed-function pipeline without custom shaders.

EDIT: And in fact, even using the generic vertex attribute at index 0 for your vertex positions is illegal when using the fixed-function pipeline, even though drivers will usually let you get away with this by assuming generic vertex attribute index 0 to be the position.
« Last Edit: October 03, 2019, 15:42:52 by KaiHH »

Re: Can't draw texture on a quad using glDrawElements
« Reply #2 on: October 05, 2019, 17:49:35 »
Thank you for the reply. Now I totally changed approach, but now I get a white quad.

public void render(){
        glActiveTexture(GL_TEXTURE0);
       
        glBindTexture(GL_TEXTURE_2D, material.getTextureID());

        glBindVertexArray(getVAO());
       
        glEnableVertexAttribArray(0);
        glEnableVertexAttribArray(1);

        glDrawElements(GL_TRIANGLES, indices.length, GL_UNSIGNED_INT, 0);

        glDisableVertexAttribArray(0);
        glDisableVertexAttribArray(1);
       
        glBindVertexArray(0);
    }

Maybe is the problem here?

public Mesh mesh = new Mesh(new float[]{
        -0.5f,  0.5f,  0.0f,
        -0.5f, -0.5f,  0.0f,
         0.5f, -0.5f,  0.0f,
         0.5f,  0.5f,  0.0f,
    }, new float[]{
        0.5f, 0.0f, 0.0f,
        0.5f, 0.5f, 0.0f,
        0.0f, 0.0f, 0.0f,
        0.0f, 0.5f, 0.0f
    }, new int[] {
        0, 1, 2,
        2, 3, 0
    }, mat);

Where "mat" is the material object which contains the texture.
I really don't get the problem.

Thank you.

*

Offline KaiHH

  • ****
  • 207
Re: Can't draw texture on a quad using glDrawElements
« Reply #3 on: October 05, 2019, 17:55:21 »
I obviously have no idea what you are doing with this "Mesh mesh" object and with the "mat" variable in it and what exactly you mean by "totally changed approach". Are you now using shaders or not? If not, then what did you do differently? You are still using generic vertex attributes like before. That's all I can see. You have to show a lot more of your code in order for anyone to help you.

Re: Can't draw texture on a quad using glDrawElements
« Reply #4 on: October 05, 2019, 18:01:44 »
Sorry. Here it is the Mesh class:

public class Mesh {
    private float[] positions;
    private float[] texcoords;
    private int[] indices;
    private Material material;
   
    private int vao;

    private List<Integer> vboIdList;

    private int vertexCount;
   
    public Mesh(float[] positions, float[] texcoords, int[] indices, Material material) {
        this.positions = positions;
        this.texcoords = texcoords;
        this.indices   = indices;
        this.material  = material;
    }
   
    public void create(){
        material.create();
       
        FloatBuffer posBuffer        = null;
        FloatBuffer textCoordsBuffer = null;
        IntBuffer indicesBuffer      = null;
       
        try {
            vertexCount = indices.length;
            vboIdList = new ArrayList<>();

            vao = glGenVertexArrays();
            glBindVertexArray(vao);

            int vboId = glGenBuffers();
            vboIdList.add(vboId);
           
            posBuffer = MemoryUtil.memAllocFloat(positions.length);
            posBuffer.put(positions).flip();
           
            glBindBuffer(GL_ARRAY_BUFFER, vboId);
            glBufferData(GL_ARRAY_BUFFER, posBuffer, GL_STATIC_DRAW);
            glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, 0);

            vboId = glGenBuffers();
            vboIdList.add(vboId);
           
            textCoordsBuffer = MemoryUtil.memAllocFloat(texcoords.length);
            textCoordsBuffer.put(texcoords).flip();
           
            glBindBuffer(GL_ARRAY_BUFFER, vboId);
            glBufferData(GL_ARRAY_BUFFER, textCoordsBuffer, GL_STATIC_DRAW);
            glVertexAttribPointer(1, 2, GL_FLOAT, false, 0, 0);

            vboId = glGenBuffers();
            vboIdList.add(vboId);
           
            indicesBuffer = MemoryUtil.memAllocInt(indices.length);
            indicesBuffer.put(indices).flip();
           
            glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vboId);
            glBufferData(GL_ELEMENT_ARRAY_BUFFER, indicesBuffer, GL_STATIC_DRAW);
           
            glBindBuffer(GL_ARRAY_BUFFER, 0);
            glBindVertexArray(0);
        } finally {
            if (posBuffer != null) {
                MemoryUtil.memFree(posBuffer);
            }
            if (textCoordsBuffer != null) {
                MemoryUtil.memFree(textCoordsBuffer);
            }
            if (indicesBuffer != null) {
                MemoryUtil.memFree(indicesBuffer);
            }
        }
    }

    public float[] getVertexPositions() {
        return positions;
    }
   
    public float[] getTextureCoords() {
        return texcoords;
    }

    public int[] getIndices() {
        return indices;
    }

    public int getVAO() {
        return vao;
    }
   
    public Material getMaterial() {
        return material;
    }
   
    public int getVertexCount(){
        return vertexCount;
    }
   
    public void render(){
        glActiveTexture(GL_TEXTURE0);
       
        glBindTexture(GL_TEXTURE_2D, material.getTextureID());

        glBindVertexArray(getVAO());
       
        glEnableVertexAttribArray(0);
        glEnableVertexAttribArray(1);

        glDrawElements(GL_TRIANGLES, indices.length, GL_UNSIGNED_INT, 0);

        glDisableVertexAttribArray(0);
        glDisableVertexAttribArray(1);
       
        glBindVertexArray(0);
    }
   
    public void destroy() {
        glBindBuffer(GL_ARRAY_BUFFER, 0);
       
        vboIdList.forEach((vboId) -> {
            glDeleteBuffers(vboId);
        });
       
        material.destroy();
       
        glBindVertexArray(0);
        glDeleteVertexArrays(vao);
    }
}

I'm calling the render() method from the main game loop:

@Override
    public void run(){
        initialization();
       
        while(running){
            update();
            render();
        }
    }

Re: Can't draw texture on a quad using glDrawElements
« Reply #5 on: October 05, 2019, 18:03:58 »
I'm not using shaders now though.

*

Offline KaiHH

  • ****
  • 207
Re: Can't draw texture on a quad using glDrawElements
« Reply #6 on: October 05, 2019, 18:05:58 »
The answer in my first post still applies: Generic vertex attributes do not work without shaders!
You need to use the fixed-function pipeline function calls, such as glVertexPointer and glTexCoordPointer then.

Re: Can't draw texture on a quad using glDrawElements
« Reply #7 on: October 07, 2019, 15:35:20 »
I'm now using shaders but I still get the black square:

This is the shader code. Fragment:

#version 330 core

in vec3 passColor;
in vec2 passTextureCoord;

out vec4 outColor;

uniform sampler2D tex;

void main() {
    outColor = texture(tex, passTextureCoord);
}

vertex:

#version 460 core

in vec3 position;
in vec3 color;
in vec2 textureCoord;

out vec3 passColor;
out vec2 passTextureCoord;

void main() {
    gl_Position = vec4(position, 1.0);
    passColor = color;
    passTextureCoord = textureCoord;
}

*

Offline KaiHH

  • ****
  • 207
Re: Can't draw texture on a quad using glDrawElements
« Reply #8 on: October 07, 2019, 16:22:28 »
You likely forgot to tell OpenGL how your generic vertex array indices map to the shader vertex inputs.
Read this: https://www.khronos.org/opengl/wiki/Vertex_Shader#Inputs

Re: Can't draw texture on a quad using glDrawElements
« Reply #9 on: October 07, 2019, 17:43:52 »
Still can't solve the problem.

I opened a pastebin with most of the code:
https://pastebin.com/9b0hDJSg

*

Offline KaiHH

  • ****
  • 207
Re: Can't draw texture on a quad using glDrawElements
« Reply #10 on: October 07, 2019, 17:55:33 »
Please look more thoroughly at your own code. Your shader defines 3 vertex inputs: position at location/index 0, some unused color at location/index 1 and texture coordinates at location/index 2, but you only provide two generic vertex attributes: position at index 0 and texture coordinates at index 1. Those do not match! The shader is reading texture coordinates from an undefined input and the shader will likely read all zeroes.

Re: Can't draw texture on a quad using glDrawElements
« Reply #11 on: October 07, 2019, 18:02:23 »
Thank you for all the help. I'll try this soon. Sorry but i'm still learning :)

Re: Can't draw texture on a quad using glDrawElements
« Reply #12 on: October 08, 2019, 15:03:30 »
All right, solved!

The problem was in the shaders. That's the correct code:

//VERTEX
#version 330 core

layout (location = 0) in vec3 aPos;
layout (location = 1) in vec2 aTexCoord;

out vec2 TexCoord;

void main()
{
    gl_Position = vec4(aPos, 1.0);
    TexCoord = aTexCoord;
}

//SHADER
#version 330 core
out vec4 FragColor;

in vec2 TexCoord;

uniform sampler2D ourTexture;

void main()
{
    FragColor = texture(ourTexture, TexCoord);
}

Thank you for the help!!!