Search code examples
javaopenglopencllwjgl

Java lwjgl GLSL shader issue with mac osx Validation Failed: No vertex array object bound


I am building OPENGL application in Java using lwjgl and following part of tutorial on YouTube by thebennybox

I am able to create rectangle using Mesh class i build.

import engine.core.Util;

import static org.lwjgl.opengl.GL15.*;
import static org.lwjgl.opengl.GL20.*;

public class Mesh {

    private int vbo;
    private int size;

    public Mesh() {
       this.vbo = glGenBuffers();
       this.size = 0;
    }

    public void addVertices(Vertex[] vertices){
        this.size = vertices.length * Vertex.SIZE;
        glBindBuffer(GL_ARRAY_BUFFER, vbo);
        glBufferData(GL_ARRAY_BUFFER, Util.createFlippedBuffer(vertices), GL_STATIC_DRAW);
    }

    public void draw(){
        glEnableVertexAttribArray(0);
        glBindBuffer(GL_ARRAY_BUFFER, vbo);
        glVertexAttribPointer(0, 3, GL_FLOAT, false, Vertex.SIZE * 4, 0);
        glDrawArrays(GL_TRIANGLES, 0, this.size);
        glDisableVertexAttribArray(0);
    }
}

And util helper

import engine.render.Vertex;
import org.lwjgl.BufferUtils;

import java.nio.FloatBuffer;

public class Util {

    public static FloatBuffer createFloatBuffer(int size){
        return BufferUtils.createFloatBuffer(size);
    }

    public static FloatBuffer createFlippedBuffer(Vertex[] vertices){

        FloatBuffer buffer = createFloatBuffer(vertices.length * Vertex.SIZE);

        for(int i = 0; i < vertices.length; i++) {
            buffer.put(vertices[i].getPos().getX());
            buffer.put(vertices[i].getPos().getY());
            buffer.put(vertices[i].getPos().getZ());
        }

        buffer.flip();
        return buffer;
    }
}

Here is how i am rendering

  this.mesh = new Mesh();

   Vertex[] data = new Vertex[]{
           //1st triangle
           new Vertex(new Vector3(0.5f,-0.5f,0)), //RB
           new Vertex(new Vector3(-0.5f,-0.5f,0)), //LB
           new Vertex(new Vector3(0.5f,0.5f,0)), //RT
           //2nd triangle
           new Vertex(new Vector3(-0.5f,0.5f,0)), //RB
           new Vertex(new Vector3(0.5f,0.5f,0)), //RT
           new Vertex(new Vector3(-0.5f,-0.5f,0)), //LB
   };

   mesh.addVertices(data);

   public void render(){ //update per frame
     mesh.draw();
   } 

So far it worked. Then I followed tutorial for shader and got error

Validation Failed: No vertex array object bound.

Here is shader class

import static org.lwjgl.opengl.GL32C.*;

public class Shader {

    private int program;

    public Shader() {
        program = glCreateProgram();

        if(program == 0){
            System.out.println("Shader creation failed!");
            System.exit(1);
        }
    }


    public void addVertexShader(String text){

        //System.out.println(text);
        addProgram(text, GL_VERTEX_SHADER);
    }

    public void addGeometryShader(String text){
        addProgram(text, GL_GEOMETRY_SHADER);
    }

    public void addFragmentShader(String text){
        addProgram(text, GL_FRAGMENT_SHADER);
    }

    public void bind(){
        glUseProgram(program);
    }

    public void compileShader(){

        glLinkProgram(program);

        if(glGetProgrami(program, GL_LINK_STATUS) == 0){
            System.out.println(glGetProgramInfoLog(program, 1024));
            System.exit(1);
        }

        glValidateProgram(program);

        if(glGetProgrami(program, GL_VALIDATE_STATUS) == 0){

           // System.out.println("ffff");
            System.out.println( glGetProgramInfoLog(program, 1024));
            System.exit(1);
        }

    }

    public void addProgram(String text, int type){

        int shader = glCreateShader(type);

        if(shader == 0){
            System.out.println("Shader creation failed!");
            System.exit(1);
        }

        glShaderSource(shader, text);
        glCompileShader(shader);

        if(glGetShaderi(shader, GL_COMPILE_STATUS) == 0){
            System.out.println(glGetShaderInfoLog(shader, 1024));
            System.exit(1);
        }

        glAttachShader(program, shader);

    }
}

And here is ResourceLoader

  import java.io.BufferedReader;
  import java.io.FileReader;

  public class ResourceLoader {

      public static String loadShader(String fileName){

          StringBuilder shaderSource = new StringBuilder();
          BufferedReader shaderReader = null;

          try {
              shaderReader = new BufferedReader(new FileReader(fileName));
              String line;
              while ((line = shaderReader.readLine()) != null){
                  shaderSource.append(line).append("\n");
              }
          } catch (Exception e){
              System.out.println(e.getMessage());
          }

          return shaderSource.toString();
      }
  }

GLSL CODE FOR BOTH FILE

  ==== basicVertex.glsl
  #version 410 core

  out vec4 outColor;

  void main(){
  outColor = vec4(0.0, 1.0, 1.0, 1.0);
  }

  =========  basicFragment.glsl
  #version 410 core

  layout (location = 0) in vec3 position;


  void main(){
      gl_Position = vec4(position, 1.0);
  }

Solution

  • You've to create and use a Vertex Array Object.

    The Vertex Array Object stores the specification of the arrays of generic vertex attribute data.

    Create and bind the VAO when you specify the vertex arrays.e.g:

    public class Mesh {
    
        private int vao;
        private int vbo;
        private int size;
    
        public Mesh() {
           this.size = 0;
    
           this.vao = glGenVertexArrays();
           this.vbo = glGenBuffers();
    
           glBindVertexArray(this.vao);
    
           glBindBuffer(GL_ARRAY_BUFFER, vbo);
           glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, 0);
           glEnableVertexAttribArray(0);
        }
    
        // [...]
    }
    

    And use it when you draw the geometry:

    public class Mesh {
    
        // [...]
    
        public void draw(){
    
            glBindVertexArray(this.vao);
            glDrawArrays(GL_TRIANGLES, 0, this.size);
            glBindVertexArray(0); // <--- Note, this is not needed
        }
    }