LWJGL 3 Реализация ортогональной камеры вызывает мерцание объекта игрока - PullRequest
0 голосов
/ 05 декабря 2018

Описание

Я новичок в 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);
    }
}
...