Search code examples
javaopengljava-8lwjgl

Texture renders incorrectly (OpenGL)


I've been trying to render an 8x8 texture. I've used code from 2 tutorials, but the texture doesn't render correctly. For now I have this initialization code:

int shaderProgram,fragmentShader,vertexShader,texture,elementBuffer,vertexBuffer, vertexArray;

public Texture2D(String texturePath_, String vertexShader_,String fragmentShader_)
{
    vertexArray=GL30.glGenVertexArrays();
    GL30.glBindVertexArray(vertexArray);
    String[] vertexshader=Utilities.loadShaderFile(vertexShader_,getClass());
    String[] fragmentshader=Utilities.loadShaderFile(fragmentShader_,getClass());
    if(vertexshader==null)
        throw new NullPointerException("The vertex shader is null");
    if(fragmentshader==null)
        throw new NullPointerException("The fragment shader is null");
    vertexShader=GL20.glCreateShader(GL20.GL_VERTEX_SHADER);
    GL20.glShaderSource(vertexShader,vertexshader);
    GL20.glCompileShader(vertexShader);
    Utilities.showShaderCompileLog(vertexShader);

    fragmentShader=GL20.glCreateShader(GL20.GL_FRAGMENT_SHADER);
    GL20.glShaderSource(fragmentShader,fragmentshader);
    GL20.glCompileShader(fragmentShader);
    Utilities.showShaderCompileLog(fragmentShader);

    shaderProgram= GL20.glCreateProgram();
    GL20.glAttachShader(shaderProgram,fragmentShader);
    GL20.glAttachShader(shaderProgram,vertexShader);

    GL30.glBindFragDataLocation(shaderProgram,0,"fragcolor");
    GL20.glLinkProgram(shaderProgram);
    GL20.glUseProgram(shaderProgram);
    texture= GL11.glGenTextures();
    GL11.glBindTexture(GL11.GL_TEXTURE_2D,texture);
    GL11.glTexParameteri(GL11.GL_TEXTURE_2D,GL11.GL_TEXTURE_WRAP_S, GL13.GL_CLAMP_TO_BORDER);
    GL11.glTexParameteri(GL11.GL_TEXTURE_2D,GL11.GL_TEXTURE_WRAP_T,GL13.GL_CLAMP_TO_BORDER);
    GL11.glTexParameteri(GL11.GL_TEXTURE_2D,GL11.GL_TEXTURE_MIN_FILTER,GL11.GL_LINEAR);
    GL11.glTexParameteri(GL11.GL_TEXTURE_2D,GL11.GL_TEXTURE_MAG_FILTER,GL11.GL_LINEAR);

    ByteBuffer image;
    FloatBuffer verteces;
    IntBuffer imagewidth,imageheight, positions,imagechannels;
    try(MemoryStack memoryStack=MemoryStack.stackPush())
    {
        imageheight=memoryStack.mallocInt(1);
        imagewidth=memoryStack.mallocInt(1);
        positions=memoryStack.mallocInt(6);
        imagechannels=memoryStack.mallocInt(1);
        image= STBImage.stbi_load(texturePath_,imagewidth,imageheight,imagechannels,0);
        if(image==null) throw new NullPointerException("Failed to load image");
        verteces=memoryStack.mallocFloat(28);
    }
    positions.put(0).put(1).put(2).put(2).put(3).put(0).flip();
    int width=imagewidth.get();
    int height=imageheight.get();
    GL11.glTexImage2D(GL11.GL_TEXTURE_2D,0,GL11.GL_RGBA,width,height,0,GL11.GL_RGBA,GL11.GL_UNSIGNED_BYTE,image);


    elementBuffer=GL15.glGenBuffers();
    GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER,elementBuffer);
    GL15.glBufferData(GL15.GL_ELEMENT_ARRAY_BUFFER,positions,GL15.GL_STATIC_DRAW);
    float x1=0f, x2=1f;
    float y1=1f,y2=-1f;

    verteces.put(x1).put(y1).put(1).put(1).put(1).put(0).put(0);
    verteces.put(x1).put(y2).put(1).put(1).put(1).put(1).put(0);
    verteces.put(x2).put(y2).put(1).put(1).put(1).put(1).put(1);
    verteces.put(x2).put(y1).put(1).put(1).put(1).put(0).put(1).flip();

    vertexBuffer=GL15.glGenBuffers();
    GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER,vertexBuffer);
    GL15.glBufferData(GL15.GL_ARRAY_BUFFER,verteces,GL15.GL_STATIC_DRAW);
    int uniform=GL20.glGetUniformLocation(shaderProgram,"texture_image");
    GL20.glUniform1i(uniform,0);
    int position=GL20.glGetAttribLocation(shaderProgram,"position");
    GL20.glEnableVertexAttribArray(position);
    GL20.glVertexAttribPointer(position,2,GL11.GL_FLOAT,false,0,0);
    int color=GL20.glGetAttribLocation(shaderProgram,"color");
    GL20.glEnableVertexAttribArray(color);
    GL20.glVertexAttribPointer(color,3,GL11.GL_FLOAT,false,7*Float.BYTES, 2 * Float.BYTES);
    int textureST=GL20.glGetAttribLocation(shaderProgram,"textureCoord");
    GL20.glEnableVertexAttribArray(textureST);
    GL20.glVertexAttribPointer(textureST,3,GL11.GL_FLOAT,false,7*Float.BYTES,  5 * Float.BYTES);
    Utilities.showErrors(1);
}

The result is: enter image description here

But I'd like the texture to occupy all area. The shaders compile fine, and there are no GL errors. If I change values to the ones from the tutorial:

verteces.put(-1f).put(1f).put(1).put(1).put(1).put(0).put(0);
verteces.put(1f).put(1f).put(1).put(1).put(1).put(1).put(0);
verteces.put(1f).put(-1f).put(1).put(1).put(1).put(1).put(1);
verteces.put(-1f).put(-1f).put(1).put(1).put(1).put(0).put(1).flip();

I get: enter image description here

The tutorials: https://open.gl/textures and https://github.com/SilverTiger/lwjgl3-tutorial/wiki/Textures

I'm using profile 3.0 with shaders version 300 ES. The texture's format is PNG.


Solution

  • The vertex attribute layout:

    GL20.glVertexAttribPointer(position,2,GL11.GL_FLOAT,false,0,0);
    GL20.glVertexAttribPointer(color,3,GL11.GL_FLOAT,false,7*Float.BYTES, 2 * Float.BYTES);
    GL20.glVertexAttribPointer(textureST,3,GL11.GL_FLOAT,false,7*Float.BYTES,  5 * Float.BYTES);
    

    doesn't look correct. There are multiple problems with it:

    • The texture coordinates try to read 3 floats from the array. In combination with the stride, your last vertex will read outside the VBO. Most probably texture coordinates should only read 2 floats.
    • The total number of floats used (2+3+3=8) does not fit to the data where only 7 floats per vertex are given. This is solved when texture coordinates read only two floats.
    • The stride of the positions look wrong. 0 means that all positions are tightly packed. Basically, the positions use the first 8 floats in the VBO. If you look at them: {-1, 1, 1, 1, 1, 0, 0, 1}, then this is exactly the geometry you see. It was just luck that it worked in first place. Solution: Change position layout to: GL20.glVertexAttribPointer(position,2,GL11.GL_FLOAT,false,7*Float.BYTES,0);