LWJGL 3正交相机的实现会导致玩家实体闪烁

时间:2018-12-05 17:37:41

标签: java opengl camera lwjgl opengl-4

说明

我对OpenGL很陌生,并开始使用OpenGL 4.5在摄影机系统上工作。我有一个正交摄影机,该摄影机应通过由其他实体组成的2D级别跟随玩家实体(鸟瞰)。 我知道在OpenGL中没有真正的摄像头,相反,您以相反的方向移动其他所有内容,以为我在代码中实现正交摄像头很费劲。 下面的代码将播放器绘制为2D三角形,而关卡本身则由具有或不具有纹理的其他2D实体组成。

用于创建以下代码的库和语言:

  • Java 9
  • GLSL 4.5
  • 仅OpenGL 4.5核心配置文件
  • LWJGL 3
  • GLFW(LWJGL 3的一部分)
  • JOML数学库

问题

我的相机不跟随播放器,并且每当我按下一个按钮(例如D)时,OpenGL就会在屏幕上渲染两个闪烁的播放器实体,而不是将带有其相机的播放器向右移动。

我当前的代码

下面是测试播放器和相机的最小实现。可以将所有其他实体描述为没有相机实例的玩家。 因为这是我的播放器和相机的最小工作示例(没有用于初始化LWJGL 3的主类),所以我将自定义方法替换为直接OpenGL调用。

玩家:

public class TestPlayer {

    private int x = 0, y = 0;
    private float size = 1.f;
    private OrthoCamera camera;

    private int matLocation = 0;
    private FloatBuffer matBuffer = BufferUtils.createFloatBuffer(16);

    private int shaderProgram = 0;
    private IntBuffer vertexArray = BufferUtils.createIntBuffer(1);
    private IntBuffer vertexBuffer = BufferUtils.createIntBuffer(1);
    private IntBuffer indexBuffer = BufferUtils.createIntBuffer(1);

    Matrix4f projection = new Matrix4f().ortho(-16.f, 16.f, -9f, 9f, -1.f, 1.f);
    Matrix4f model = new Matrix4f().identity().translate(new Vector3f(0, 0, 0));

    private String[] vertexShaderSource = {
        "#version 450 core\n",
        "\n",
        "layout (location = 0) in vec4 position;\n",
        "\n",
        "uniform mat4 u_MVP;\n",
        "\n",
        "void main() {\n",
        "   gl_Position = u_MVP * position;\n",
        "}\n"
    };

    private String[] fragmentShaderSource = {
        "#version 450 core\n",
        "\n",
        "layout (location = 0) out vec4 colour;\n",
        "layout (location = 1) uniform vec4 u_Colour;\n",
        "\n",
        "void main() {\n",
        "   colour = u_Colour;\n",
        "}"
    };

    public TestPlayer(Vector3f position, Vector3f lookat) {
        this.camera = new OrthoCamera(position, lookat);

        this.updatePositions();

        this.shaderProgram = this.createShader();
        glUseProgram(this.shaderProgram);
        matBuffer.clear();
        matLocation = glGetUniformLocation(this.shaderProgram, "u_MVP");
        glUniformMatrix4fv(matLocation, false, projection.get(matBuffer));
        glUseProgram(0);
        glBindVertexArray(0);
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
        glBindBuffer(GL_ARRAY_BUFFER, 0);
    }

    private void updatePositions() {
        if(vertexArray.hasRemaining()) {
            glDeleteVertexArrays(this.vertexArray);
            vertexArray.clear();
        }
        if(indexBuffer.hasRemaining()) {
            glDeleteBuffers(this.indexBuffer);
            indexBuffer.clear();
        }
        if(vertexBuffer.hasRemaining()) {
            glDeleteBuffers(this.vertexBuffer);
            vertexBuffer.clear();
        }

        float[] positions = {
            x-size, y-size,
            x     , y+size,
            x+size, y-size
        };

        int[] indices = {
            0, 1, 2
        };

        glGenVertexArrays(this.vertexArray);
        FloatBuffer vertexData = BufferUtils.createFloatBuffer(3 * 2);
        vertexData.put(positions);
        vertexData.flip();
        glGenBuffers(this.vertexBuffer);
        glBindBuffer(GL_ARRAY_BUFFER, this.vertexBuffer.get(0));
        glBufferData(GL_ARRAY_BUFFER, vertexData, GL_STATIC_DRAW);

        glBindVertexArray(this.vertexArray.get(0));
        glBindBuffer(GL_ARRAY_BUFFER, this.vertexBuffer.get(0));
        glEnableVertexAttribArray(0);
        glVertexAttribPointer(0, 2, GL_FLOAT, false, Float.BYTES * 2, 0);

        IntBuffer indexData = BufferUtils.createIntBuffer(3);
        indexData.put(indices);
        indexData.flip();

        glGenBuffers(this.indexBuffer);
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this.indexBuffer.get(0));
        glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexData, GL_STATIC_DRAW);
    }

    public void update() {
        this.camera.update(new Vector3f(x, y, 1));
    }

    public void keyUpdate(int key) {
        if(key == GLFW.GLFW_KEY_W)
            y++;
        if(key == GLFW.GLFW_KEY_S)
            y--;
        if(key == GLFW.GLFW_KEY_A)
            x--;
        if(key == GLFW.GLFW_KEY_D)
            x++;
    }

    public void render(double currentTime) {
        matBuffer.clear();
        this.updatePositions();
        glUseProgram(this.shaderProgram);
        glBindVertexArray(this.vertexArray.get(0));
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this.indexBuffer.get(0));

        // colour
        glUniform4f(1, 0.f, .8f, 1.f, 1.f);

        Matrix4f matrix = projection.mul(camera.getView().mul(model));
        glUniformMatrix4fv(matLocation, false, matrix.get(matBuffer));
        glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, 0);
    }

    public void dispose() {
        glBindVertexArray(0);
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
        glBindBuffer(GL_ARRAY_BUFFER, 0);

        glDeleteVertexArrays(this.vertexArray);
        glDeleteBuffers(this.indexBuffer);
        glDeleteBuffers(this.vertexBuffer);

        glUseProgram(0);
        glDeleteProgram(this.shaderProgram);
    }

    private int createShader() {
        int program = glCreateProgram();
        int vertexShader = glCreateShader(GL_VERTEX_SHADER);
        glShaderSource(vertexShader, vertexShaderSource);
        glCompileShader(vertexShader);

        if(glGetShaderi(vertexShader, GL_COMPILE_STATUS) == GL_FALSE) {
            System.err.println("ERROR: Compiling vertex shader");
            System.err.println(glGetShaderInfoLog(vertexShader));
            glDeleteShader(vertexShader);
            return -1;
        }

        int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
        glShaderSource(fragmentShader, fragmentShaderSource);
        glCompileShader(fragmentShader);

        if(glGetShaderi(fragmentShader, GL_COMPILE_STATUS) == GL_FALSE) {
            System.err.println("ERROR: Compiling fragment shader");
            System.err.println(glGetShaderInfoLog(fragmentShader));
            glDeleteShader(fragmentShader);
            return -1;
        }

        glAttachShader(program, vertexShader);
        glAttachShader(program, fragmentShader);
        glLinkProgram(program);

        glValidateProgram(program);

        glDeleteShader(vertexShader);
        glDeleteShader(fragmentShader);

        return program;
    }
}

相机: 请注意,这是准系统相机类。目的是在添加更多功能之前,使这个非常简单的相机版本正常工作。

public class OrthoCamera {

    private Vector3f position;
    private Matrix4f view = new Matrix4f().identity();

    public OrthoCamera(Vector3f position, Vector3f lookAt) {
        this.position = position;
        this.view.lookAt(position, lookAt, new Vector3f(0, 1, 0));
    }

    public void update(Vector3f lookAt) {
        this.view.identity().lookAt(position, lookAt, new Vector3f(0, 1, 0));
    }

    public Matrix4f getView() {
        return this.view;
    }
}

编辑: 我刚刚创建了问题的GIF。蓝色三角形是TestPlayer,另一个三角形是不可移动的实体。 D键是下面的gif中唯一(被)按下过的键。

visualisation of the problem, blue triangle is TestPlayer

编辑2: 最小示例的主类:

public class HelloWorld {

    // The window handle
    private long window;

    private TestPlayer player;
    private TestPlayer2 player2;

    private Callback glErrorCallback;

    private static final IntBuffer SCREEN_WIDTH = BufferUtils.createIntBuffer(1);
    private static final IntBuffer SCREEN_HEIGHT = BufferUtils.createIntBuffer(1);

    public void run() {
        // Output in my case: Hello LWJGL 3.2.0 build 12!
        System.out.println("Hello LWJGL " + Version.getVersion() + "!");

        init();
        loop();

        if(glErrorCallback != null)
            this.glErrorCallback.free();

        // Free the window callbacks and destroy the window
        glfwFreeCallbacks(window);
        glfwDestroyWindow(window);

        GL.setCapabilities(null);

        // Terminate GLFW and free the error callback
        glfwTerminate();
        glfwSetErrorCallback(null).free();
    }

    private void init() {
        GLFWErrorCallback.createPrint(System.err).set();
        if ( !glfwInit() )
            throw new IllegalStateException("Unable to initialize GLFW");

        // Configure GLFW
        glfwDefaultWindowHints();
        glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);
        glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE);
        glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
        glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 5);
        glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

        glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GLFW_TRUE);

        // Create the window
        window = glfwCreateWindow(1280, 720, "Hello World!", NULL, NULL);
        if ( window == NULL )
            throw new RuntimeException("Failed to create the GLFW window");

        glfwSetKeyCallback(window, (window, key, scancode, action, mods) -> {
            if ( key == GLFW_KEY_ESCAPE && action == GLFW_RELEASE )
                glfwSetWindowShouldClose(window, true);

            if ( action == GLFW.GLFW_PRESS)
                if(player != null)
                    player.keyUpdate(key);
        });

        // Get the thread stack and push a new frame
        try ( MemoryStack stack = stackPush() ) {
            IntBuffer pWidth = stack.mallocInt(1); // int*
            IntBuffer pHeight = stack.mallocInt(1); // int*

            // Get the window size passed to glfwCreateWindow
            glfwGetWindowSize(window, pWidth, pHeight);

            // Get the resolution of the primary monitor
            GLFWVidMode vidmode = glfwGetVideoMode(glfwGetPrimaryMonitor());

            // Center the window
            glfwSetWindowPos(
                window,
                (vidmode.width() - pWidth.get(0)) / 2,
                (vidmode.height() - pHeight.get(0)) / 2
            );
        } // the stack frame is popped automatically

        glfwMakeContextCurrent(window);
        // Enable v-sync
        glfwSwapInterval(1);

        // Make the window visible
        glfwShowWindow(window);
    }

    private void loop() {
        GL.createCapabilities();

        glfwGetFramebufferSize(this.window, SCREEN_WIDTH, SCREEN_HEIGHT);
        glViewport(0, 0, SCREEN_WIDTH.get(), SCREEN_HEIGHT.get());

        this.glErrorCallback = GLUtil.setupDebugMessageCallback();
        // Set the clear color
        glClearColor(0.0f, 0.0f, 0.0f, 0.0f);


        player = new TestPlayer(new Vector3f(0, 0, 0), new Vector3f(0, 0, 0));
        player2 = new TestPlayer2();

        // Run the rendering loop until the user has attempted to close
        // the window or has pressed the ESCAPE key.
        while ( !glfwWindowShouldClose(window) ) {
            glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // clear the framebuffer

            // normally, update would not be called as often as render
            player.update();
            player2.update();
            player2.render(glfwGetTime());

            // the player with the camera
            player.render(glfwGetTime());

            glfwSwapBuffers(window); // swap the color buffers

            // Poll for window events. The key callback above will only be
            // invoked during this call.
            glfwPollEvents();
        }
        player.dispose();
        player2.dispose();
    }

    public static void main(String[] args) {
        new HelloWorld().run();
    }
}

第二个静态实体:

public class TestPlayer2 {

    private int x = 3, y = 3;
    private float size = 1.f;

    private int shaderProgram = 0;
    private IntBuffer vertexArray = BufferUtils.createIntBuffer(1);
    private IntBuffer vertexBuffer = BufferUtils.createIntBuffer(1);
    private IntBuffer indexBuffer = BufferUtils.createIntBuffer(1);

    private String[] vertexShaderSource = {
        "#version 450 core\n",
        "\n",
        "layout (location = 0) in vec4 position;\n",
        "\n",
        "uniform mat4 u_MVP;\n",
        "\n",
        "void main() {\n",
        "   gl_Position = u_MVP * position;\n",
        "}\n"
    };

    private String[] fragmentShaderSource = {
        "#version 450 core\n",
        "\n",
        "layout (location = 0) out vec4 colour;\n",
        "layout (location = 1) uniform vec4 u_Colour;\n",
        "\n",
        "void main() {\n",
        "   colour = u_Colour;\n",
        "}"
    };

    public TestPlayer2() {
        float[] positions = {
            x-size, y-size,
            x     , y+size,
            x+size, y-size
        };

        int[] indices = {
            0, 1, 2
        };

        glGenVertexArrays(this.vertexArray);
        FloatBuffer vertexData = BufferUtils.createFloatBuffer(3 * 2);
        vertexData.put(positions);
        vertexData.flip();
        glGenBuffers(this.vertexBuffer);
        glBindBuffer(GL_ARRAY_BUFFER, this.vertexBuffer.get(0));
        glBufferData(GL_ARRAY_BUFFER, vertexData, GL_STATIC_DRAW);

        glBindVertexArray(this.vertexArray.get(0));
        glBindBuffer(GL_ARRAY_BUFFER, this.vertexBuffer.get(0));
        glEnableVertexAttribArray(0);
        glVertexAttribPointer(0, 2, GL_FLOAT, false, Float.BYTES * 2, 0);

        IntBuffer indexData = BufferUtils.createIntBuffer(3);
        indexData.put(indices);
        indexData.flip();

        glGenBuffers(this.indexBuffer);
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this.indexBuffer.get(0));
        glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexData, GL_STATIC_DRAW);

        Matrix4f projection = new Matrix4f().ortho(-16.f, 16.f, -9f, 9f, -1.f, 1.f);

        this.shaderProgram = this.createShader();
        glUseProgram(this.shaderProgram);
        int location = glGetUniformLocation(this.shaderProgram, "u_MVP");
        FloatBuffer buffer = BufferUtils.createFloatBuffer(16);
        glUniformMatrix4fv(location, false, projection.get(buffer));
        glUseProgram(0);
        glBindVertexArray(0);
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
        glBindBuffer(GL_ARRAY_BUFFER, 0);
    }

    private int createShader() {
        int program = glCreateProgram();
        int vertexShader = glCreateShader(GL_VERTEX_SHADER);
        glShaderSource(vertexShader, vertexShaderSource);
        glCompileShader(vertexShader);

        if(glGetShaderi(vertexShader, GL_COMPILE_STATUS) == GL_FALSE) {
            System.err.println("ERROR: Compiling vertex shader");
            System.err.println(glGetShaderInfoLog(vertexShader));
            glDeleteShader(vertexShader);
            return -1;
        }

        int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
        glShaderSource(fragmentShader, fragmentShaderSource);
        glCompileShader(fragmentShader);

        if(glGetShaderi(fragmentShader, GL_COMPILE_STATUS) == GL_FALSE) {
            System.err.println("ERROR: Compiling fragment shader");
            System.err.println(glGetShaderInfoLog(fragmentShader));
            glDeleteShader(fragmentShader);
            return -1;
        }

        glAttachShader(program, vertexShader);
        glAttachShader(program, fragmentShader);
        glLinkProgram(program);

        glValidateProgram(program);

        glDeleteShader(vertexShader);
        glDeleteShader(fragmentShader);

        return program;
    }

    public void update() {
        // Nothing in here, static entity
    }

    public void render(double currentTime) {
        glUseProgram(this.shaderProgram);
        glBindVertexArray(this.vertexArray.get(0));
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this.indexBuffer.get(0));

        glUniform4f(1, 8.f, .8f, 1.f, 1.f);
        glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, 0);
    }

    public void dispose() {
        glBindVertexArray(0);
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
        glBindBuffer(GL_ARRAY_BUFFER, 0);

        glDeleteVertexArrays(this.vertexArray);
        glDeleteBuffers(this.indexBuffer);
        glDeleteBuffers(this.vertexBuffer);

        glUseProgram(0);
        glDeleteProgram(this.shaderProgram);
    }
}

0 个答案:

没有答案