LWJGL OpenGL glGenVertexArrays() Error: This Funct

2019-07-28 06:19发布

问题:

All, Having difficulty with glGenVertexArrays(). I get the following error:

Exception in thread "main" java.lang.IllegalStateException: This functionality is not available. at org.lwjgl.system.Checks.checkFunctionality(Checks.java:57) at org.lwjgl.opengl.GL30.getInstance(GL30.java:667) at org.lwjgl.opengl.GL30.getInstance(GL30.java:662) at org.lwjgl.opengl.GL30.nglGenVertexArrays(GL30.java:2789) at org.lwjgl.opengl.GL30.glGenVertexArrays(GL30.java:2816) at renderEngine.Loader.createVAO(Loader.java:26) at renderEngine.Loader.loadToVAO(Loader.java:19) at renderEngine.MainGameLoop.main(MainGameLoop.java:27)

Here is my Main Game Loop (I call GL.createCapabilities() from the createDisplay() method.)

package renderEngine;

import static org.lwjgl.glfw.GLFW.*;

public class MainGameLoop {

public static DisplayManager dm = new DisplayManager();

public static void main(String[] args) {

    //Create Display
    dm.createDisplay();

    Loader loader = new Loader();
    Renderer renderer = new Renderer();

    float[] vertices = {
        -0.5f,0.5f,0f,
        -0.5f,-0.5f,0f,
        0.5f,-0.5f,0f,

        0.5f,-0.5f,0f,
        0.5f,0.5f,0f,
        -0.5f,0.5f,0f
    };

    RawModel model = loader.loadToVAO(vertices);
    //Game Loop
    while (glfwWindowShouldClose(dm.getWindowID()) != GLFW_TRUE) {
        renderer.prepare();
        renderer.render(model);
        dm.updateDisplay();
    }

    //Destroy Display
    dm.destroyWindow();
    loader.cleanUp();
}
}

As referenced above, here is the Display Manager class:

package renderEngine;

import static org.lwjgl.glfw.GLFW.*;

import org.lwjgl.glfw.GLFW;
import org.lwjgl.glfw.GLFWErrorCallback;
import org.lwjgl.glfw.GLFWKeyCallback;
import org.lwjgl.opengl.GL;

public class DisplayManager {

private GLFWErrorCallback errorCallback;
private GLFWKeyCallback keyCallback;

private long windowID; 

//Constructor
public DisplayManager(){
    init();
}

private void init(){
    if(glfwInit() != GLFW_TRUE){
        throw new IllegalStateException("Unable to initiate GLFW");
    }
}

public long createDisplay(){
    windowID = glfwCreateWindow(640,480,"Hello World!", 0, 0);
    if(windowID == 0){
        glfwTerminate();
        throw new RuntimeException("Failed to create the GLFW window");
    }

    GLFW.glfwSetWindowTitle(windowID, "GLFW Window");

    setErrorCallback();
    setKeyCallback();

    glfwMakeContextCurrent(windowID);
    GL.createCapabilities();

    return windowID;
}

public long getWindowID(){
    return this.windowID;
}

private void setErrorCallback(){
    errorCallback = GLFWErrorCallback.createPrint(System.err);
    glfwSetErrorCallback(errorCallback);
}

private void setKeyCallback(){

    keyCallback = new GLFWKeyCallback(){
        @Override
        public void invoke(long window, int key, int scancode, int action, int mods) {
            if(key == GLFW_KEY_ESCAPE && action == GLFW_PRESS){
                glfwSetWindowShouldClose(window, GLFW_TRUE);
            }
        }
    };
    glfwSetKeyCallback(windowID, keyCallback);
}

public void updateDisplay(){
    GLFW.glfwSwapInterval(1);
    glfwSwapBuffers(windowID);
    glfwPollEvents();
}

public void destroyWindow(){
    glfwDestroyWindow(windowID);
    keyCallback.release();
    glfwTerminate();
    errorCallback.release();
}

}

If would seem the above mentioned error is with the loader class:

package renderEngine;

import java.util.List;
import java.nio.FloatBuffer;
import java.util.ArrayList;

import org.lwjgl.BufferUtils;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL15;
import org.lwjgl.opengl.GL20;
import org.lwjgl.opengl.GL30;

public class Loader {

private List<Integer> vaos = new ArrayList<Integer>();
private List<Integer> vbos = new ArrayList<Integer>();

public RawModel loadToVAO(float[] positions){
    int vaoID = createVAO();
    storeDataInAttributeList(0,positions);
    unbindVAO();
    return new RawModel(vaoID,positions.length/3);
}

private int createVAO() {
    int vaoID = GL30.glGenVertexArrays();
    vaos.add(vaoID);
    GL30.glBindVertexArray(vaoID);
    return vaoID;

}

private void storeDataInAttributeList(int attributeNumber, float[] data) {
    int vboID = GL15.glGenBuffers();
    vbos.add(vboID);
    GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, vboID);
    FloatBuffer buffer = storeDataInFloatBuffer(data);
    GL15.glBufferData(GL15.GL_ARRAY_BUFFER, buffer, GL15.GL_STATIC_DRAW);
    GL20.glVertexAttribPointer(attributeNumber, 3, GL11.GL_FLOAT, false, 0, 0);
    GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
}

private void unbindVAO() {
    GL30.glBindVertexArray(0); //0 un-binds currently bound VAO
}

public void cleanUp(){
    for(int vao:vaos){
        GL30.glDeleteVertexArrays(vao);
    }

    for(int vbo:vbos){
        GL15.glDeleteBuffers(vbo);
    }
}

private FloatBuffer storeDataInFloatBuffer(float[] data){
    FloatBuffer buffer = BufferUtils.createFloatBuffer(data.length);
    buffer.put(data);
    buffer.flip();
    return buffer;
}

}

In Particular this line of code:

GL30.glBindVertexArray(vaoID);

As far as I can see this is the correct method to do it, and the GL capabilities/context have been set/called from the main thread (main game loops main method, utilising the display manager)

For completeness, here are the RawModel and Renderer Classes, do not suspect an issue these these:

package renderEngine;

public class RawModel {

private int vaoID;
private int vertexCount;

public RawModel(int vaoID, int vertexCount){
    this.vaoID = vaoID;
    this.vertexCount = vertexCount;
}

public int getVaoID() {
    return vaoID;
}

public int getVertexCount() {
    return vertexCount;
}

}

And here is the Renderer Class:

package renderEngine;

import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL20;
import org.lwjgl.opengl.GL30;

public class Renderer {

public void prepare(){
    GL11.glClearColor(1, 0, 0, 1);
    GL11.glClear(GL11.GL_COLOR_BUFFER_BIT);
}

public void render(RawModel model){
    GL30.glBindVertexArray(model.getVaoID());
    GL20.glEnableVertexAttribArray(0);
    GL11.glDrawArrays(GL11.GL_TRIANGLES, 0, model.getVertexCount());
    GL20.glDisableVertexAttribArray(0);
    GL30.glBindVertexArray(0);
}

}

Any assistance you can give me regarding my implementation of 'glGenVertexArrays' would be much appreciated.

I have now added the following

    GLFW.glfwDefaultWindowHints();
    GLFW.glfwWindowHint(GLFW.GLFW_CONTEXT_VERSION_MAJOR, 3);
    GLFW.glfwWindowHint(GLFW.GLFW_CONTEXT_VERSION_MINOR, 2);

However, am now getting the following error:

Exception in thread "main" java.lang.RuntimeException: Failed to create the GLFW window at renderEngine.DisplayManager.createDisplay(DisplayManager.java:37) at renderEngine.MainGameLoop.main(MainGameLoop.java:12)

The specific implementation of my createDisplay() is as follows:

    public long createDisplay(){
    GLFW.glfwDefaultWindowHints();
    GLFW.glfwWindowHint(GLFW.GLFW_CONTEXT_VERSION_MAJOR, 3);
    GLFW.glfwWindowHint(GLFW.GLFW_CONTEXT_VERSION_MINOR, 2);


    windowID = glfwCreateWindow(640,480,"Hello World!", 0, 0);
    if(windowID == 0){
        glfwTerminate();
        throw new RuntimeException("Failed to create the GLFW window");
    }



    GLFW.glfwSetWindowTitle(windowID, "GLFW Window");

    setErrorCallback();
    setKeyCallback();

    glfwMakeContextCurrent(windowID);
    GL.createCapabilities();

    return windowID;
}

UPDATE

If have removed the error callbacks, as thought they might be causing an issue. The resulting error is:

Exception in thread "main" java.lang.RuntimeException: Failed to create the GLFW window at renderEngine.DisplayManager.createDisplay(DisplayManager.java:40) at renderEngine.MainGameLoop.main(MainGameLoop.java:12)

It seems the RuntimeException is being thrown, and is displaying my custom error message if the glfw window cannot be created. Could this be todo with the order in which I run this? I have played around with the placement of the 'init' method with noluck. There has got to be something I am overlooking?... Thanks.

Updated code for the Display Manager:

package renderEngine;

import static org.lwjgl.glfw.GLFW.*;

import org.lwjgl.glfw.GLFW;
import org.lwjgl.glfw.GLFWErrorCallback;
import org.lwjgl.glfw.GLFWKeyCallback;
import org.lwjgl.opengl.GL;

public class DisplayManager {

private GLFWErrorCallback errorCallback;
private GLFWKeyCallback keyCallback;

private long windowID; 

//Constructor
public DisplayManager(){

    init();
}

private void init(){

    if(glfwInit() != GLFW_TRUE){
        throw new IllegalStateException("Unable to initiate GLFW");
    }
}

public long createDisplay(){
    GLFW.glfwDefaultWindowHints();
    GLFW.glfwWindowHint(GLFW.GLFW_CONTEXT_VERSION_MAJOR, 3);
    GLFW.glfwWindowHint(GLFW.GLFW_CONTEXT_VERSION_MINOR, 2);


    windowID = glfwCreateWindow(640,480,"Hello World!", 0, 0);
    System.out.println(windowID);
    if(windowID == 0){
        glfwTerminate();
        throw new RuntimeException("Failed to create the GLFW window");
    }

    glfwMakeContextCurrent(windowID);
    GL.createCapabilities();


    GLFW.glfwSetWindowTitle(windowID, "GLFW Window");

    //setErrorCallback();
    //setKeyCallback();


    return windowID;
}

public long getWindowID(){
    return this.windowID;
}

private void setErrorCallback(){
    errorCallback = GLFWErrorCallback.createPrint(System.err);
    glfwSetErrorCallback(errorCallback);
}

private void setKeyCallback(){

    keyCallback = new GLFWKeyCallback(){
        @Override
        public void invoke(long window, int key, int scancode, int action, int mods) {
            if(key == GLFW_KEY_ESCAPE && action == GLFW_PRESS){
                glfwSetWindowShouldClose(window, GLFW_TRUE);
            }
        }
    };
    glfwSetKeyCallback(windowID, keyCallback);
}

public void updateDisplay(){
    GLFW.glfwSwapInterval(1);
    glfwSwapBuffers(windowID);
    glfwPollEvents();
}

public void destroyWindow(){
    glfwDestroyWindow(windowID);
    keyCallback.release();
    glfwTerminate();
    errorCallback.release();
}

}

Many Thanks and Kind Regards, Jake

回答1:

The glGenVertexArrays function requires OpenGL 3.0 or higher. You have to explicitly tell GLFW this. Before calling glfwCreateWindow:

GLFW.glfwDefaultWindowHints();
GLFW.glfwWindowHint(GLFW.CONTEXT_VERSION_MAJOR, 3);
GLFW.glfwWindowHint(GLFW.CONTEXT_VERSION_MINOR, 0);

You can check that you have OpenGL 3.0 or higher by calling GL11.glGetString(GL11.GL_VERSION) or by looking at the GL.getCapabilities().OpenGL30 flag.