LWJGL 3鼠标移动

问题描述 投票:3回答:3

我想在我的lwjgl3 Java应用程序中实现FPS样式的鼠标外观,但是由于没有Mouse.getDX()Mouse.getDY(),因此我正在寻找使用glfw绑定的其他方法。我编写了在update()方法中调用的方法:

public double[] pollMouseDelta() {
    DoubleBuffer x = BufferUtils.createDoubleBuffer(1);
    DoubleBuffer y = BufferUtils.createDoubleBuffer(1);

    glfwGetCursorPos(WINDOW, x, y);
    x.rewind();
    y.rewind();

    double tempX = mouseX;
    double tempY = mouseY;

    mouseX = x.get();
    mouseY = y.get();

    return new double[] {
           mouseX - tempX,
           mouseY - tempY
    };
}

其中mouseXmouseY是全局变量。在我的更新方法中,我执行以下操作:

double[] mouseDelta = pollMouseDelta();

camera.rotate(Camera.Direction.LEFT_RIGHT, (float) (0.2f * -mouseDelta[0]));
camera.rotate(Camera.Direction.UP_DOWN, (float) (0.2f * mouseDelta[1]));

camera.update();

我还将GLFW_CURSOR模式设置为GLFW_CURSOR_DISABLED。但是相机断断续续,跳跃很大。另外,有时鼠标似乎被倒转了。

有什么建议吗?

java opengl lwjgl glfw
3个回答
4
投票

这里是我的FPS风格相机的基础代码片段。如您所见,我正在沿着屏幕中心沿X和Y轴计算鼠标位置的增量。

您可以在我的System.out.println中看到我为增量计算的值,以及它应按此量旋转的事实。然后,我将这些值乘以我的灵敏度,然后将相机旋转这个量。

import org.lwjgl.BufferUtils;
import org.lwjgl.Sys;
import org.lwjgl.glfw.*;
import org.lwjgl.opengl.*;

import java.nio.ByteBuffer;
import java.nio.DoubleBuffer;
import java.nio.FloatBuffer;

import static org.lwjgl.glfw.Callbacks.*;
import static org.lwjgl.glfw.GLFW.*;
import static org.lwjgl.glfw.GLFW.glfwGetCursorPos;
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GL15.*;
import static org.lwjgl.opengl.GL20.*;
import static org.lwjgl.opengl.GL30.*;
import static org.lwjgl.system.MemoryUtil.*;

public class Main {

    // We need to strongly reference callback instances.
    private GLFWErrorCallback errorCallback;
    private GLFWKeyCallback   keyCallback;

    // The window handle
    private long window;

    public void run() {
        System.out.println("Hello LWJGL " + Sys.getVersion() + "!");

        try {
            init();
            loop();

            // Release window and window callbacks
            glfwDestroyWindow(window);
            keyCallback.release();
        } finally {
            // Terminate GLFW and release the GLFWerrorfun
            glfwTerminate();
            errorCallback.release();
        }
    }

    private void init() {
        // Setup an error callback. The default implementation
        // will print the error message in System.err.
        glfwSetErrorCallback(errorCallback = errorCallbackPrint(System.err));

        // Initialize GLFW. Most GLFW functions will not work before doing this.
        if ( glfwInit() != GL11.GL_TRUE )
            throw new IllegalStateException("Unable to initialize GLFW");

        // Configure our window
        glfwDefaultWindowHints(); // optional, the current window hints are already the default
        glfwWindowHint(GLFW_VISIBLE, GL_FALSE); // the window will stay hidden after creation
        glfwWindowHint(GLFW_RESIZABLE, GL_TRUE); // the window will be resizable
        glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
        glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
        glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
        glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);


        int WIDTH = 800;
        int HEIGHT = 600;

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

        // Setup a key callback. It will be called every time a key is pressed, repeated or released.
        glfwSetKeyCallback(window, keyCallback = new GLFWKeyCallback() {
            @Override
            public void invoke(long window, int key, int scancode, int action, int mods) {
                if ( key == GLFW_KEY_ESCAPE && action == GLFW_RELEASE )
                    glfwSetWindowShouldClose(window, GL_TRUE); // We will detect this in our rendering loop
            }
        });

        // Get the resolution of the primary monitor
        ByteBuffer vidmode = glfwGetVideoMode(glfwGetPrimaryMonitor());
        // Center our window
        glfwSetWindowPos(
                window,
                (GLFWvidmode.width(vidmode) - WIDTH) / 2,
                (GLFWvidmode.height(vidmode) - HEIGHT) / 2
        );

        // Make the OpenGL context current
        glfwMakeContextCurrent(window);
        // Enable v-sync
        glfwSwapInterval(1);

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

    private void loop() {
        // This line is critical for LWJGL's interoperation with GLFW's
        // This line is critical for LWJGL's interoperation with GLFW's
        // OpenGL context, or any context that is managed externally.
        // LWJGL detects the context that is current in the current thread,
        // creates the ContextCapabilities instance and makes the OpenGL
        // bindings available for use.
        GLContext.createFromCurrent();


        // Create a FloatBuffer to hold our vertex data
        FloatBuffer vertices = BufferUtils.createFloatBuffer(9);
        // Add vertices of the triangle
        vertices.put(new float[]
                {
                        0.0f,  0.5f,  0.0f,
                        0.5f, -0.5f,  0.0f,
                        -0.5f, -0.5f,  0.0f
                });
        // Rewind the vertices
        vertices.rewind();


        int vbo = glGenBuffers();
        int vao = glGenVertexArrays();

        glBindBuffer (GL_ARRAY_BUFFER, vbo);
        glBufferData (GL_ARRAY_BUFFER, vertices, GL_STATIC_DRAW);
        glBindVertexArray(vao);

        glEnableVertexAttribArray (0);
        glBindBuffer (GL_ARRAY_BUFFER, vbo);
        glVertexAttribPointer (0, 3, GL_FLOAT, false, 0, 0);

        final String vertex_shader =
                "#version 410\n" +
                        "in vec3 vp;\n" +
                        "void main () {\n" +
                        "  gl_Position = vec4 (vp, 1.0);\n" +
                        "}";

        final String frag_shader =
                "#version 400\n"    +
                        "out vec4 frag_colour;" +
                        "void main () {"         +
                        "  frag_colour = vec4 (0.5, 0.0, 0.5, 1.0);" +
                        "}";

        int shader_programme = glCreateProgram();


        int vertexShaderID = glCreateShader(GL_VERTEX_SHADER);
        glShaderSource(vertexShaderID, vertex_shader);
        glCompileShader (vertexShaderID);

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

        glAttachShader (shader_programme, vertexShaderID);

        int fragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER);
        glShaderSource(fragmentShaderID, frag_shader);
        glCompileShader (fragmentShaderID);

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

        glAttachShader (shader_programme, fragmentShaderID);

        glLinkProgram (shader_programme);

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

        glValidateProgram(shader_programme);

        if(glGetProgrami(shader_programme, GL_VALIDATE_STATUS) == 0){
            System.err.println(glGetProgramInfoLog(shader_programme, 1024));
            System.exit(1);
        }

        boolean mouseLocked = false;
        double newX = 400;
        double newY = 300;

        double prevX = 0;
        double prevY = 0;

        boolean rotX = false;
        boolean rotY = false;

        glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);


        while ( glfwWindowShouldClose(window) == GL_FALSE ) {

            if (glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_1) == GLFW_PRESS) {
                glfwSetCursorPos(window, 800/2, 600/2);

                mouseLocked = true;
            }

            if (mouseLocked){
                DoubleBuffer x = BufferUtils.createDoubleBuffer(1);
                DoubleBuffer y = BufferUtils.createDoubleBuffer(1);

                glfwGetCursorPos(window, x, y);
                x.rewind();
                y.rewind();

                newX = x.get();
                newY = y.get();

                double deltaX = newX - 400;
                double deltaY = newY - 300;

                rotX = newX != prevX;
                rotY = newY != prevY;

                if(rotY) {
                    System.out.println("ROTATE Y AXIS: " + deltaY);

                }
                if(rotX) {
                    System.out.println("ROTATE X AXIS: " + deltaX);
                }

                prevX = newX;
                prevY = newY;


                System.out.println("Delta X = " + deltaX + " Delta Y = " + deltaY);

                glfwSetCursorPos(window, 800/2, 600/2);
            }

            // wipe the drawing surface clear
            glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
            glUseProgram (shader_programme);
            glBindVertexArray (vao);
            // draw points 0-3 from the currently bound VAO with current in-use shader
            glDrawArrays (GL_TRIANGLES, 0, 3);
            // update other events like input handling
            glfwPollEvents ();
            // put the stuff we've been drawing onto the display
            glfwSwapBuffers (window);

        }
    }

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

}

1
投票

获得鼠标位置的另一种方法是扩展GLFWCursorPosCallback类,然后仅使用它在invoke方法中提供的x和y值。

有关此操作的很好的教程可以在这里找到:

LWJGL 3 Mouse Position


1
投票

我现在正在做类似这样的事情。

想法是每次循环时都将相机位置重置到中心,如下所示:

glfwSetCursorPos(YOUR WINDOW HANDLE, YOUR_WINDOW_WIDTH / 2, YOU_WINDOW_HEIGHT / 2);

这样,您的增量总是与距屏幕中心的距离相比。这样就可以解决您的跳转问题。

编辑(我的答案留在后头):

确定,所以我也遇到了与您相同的问题。无视我上面所说的不太正确。

我最终实现了与您正在执行的操作类似的操作,但是在增量太大而相机移动得太快的情况下却收到了相同的结果。

我为解决这个问题所做的实际上是通过以下操作使鼠标轮询每一帧并计算“增量”:

deltaX = currentMousePos.x - lastFrameMousePos.x
deltaY = currentMousePos.y - lastFrameMousePos.y

现在,增量应足够小,并且还应每帧计算一次。

然后使用这个来计算我的旋转角度:

deltaPos.getY() * sensitivity * Time.getDelta()

其中Time.getDelta()是每个帧循环之间的时间差。我最终得到的是一台相当流畅的相机,尽管还不够完美。

让我知道是否需要更多信息。

编辑2:

请在LWJGL论坛上查看与我有类似问题的链接Link。我现在确实确实可以很好地工作了。我将用代码发布一个单独的答案。

© www.soinside.com 2019 - 2024. All rights reserved.