2017-08-16 9 views
-1

Hintergrund Info:OpenGL Rendering Quads an der falschen Position

Ich bin mit OpenGL und LWJGL 3 einige Quads auf dem Bildschirm zu zeichnen. Ich muss wissen, wenn die Maus über einem Quad ist. Wenn ich die Quads auf den Bildschirm rende, verwende ich die OpenGL-Koordinaten von -1 bis 1 für X und Y und mit (0,0) in der Mitte des Bildschirms. Wenn ich die Mausposition bekommen verwende ich

glfwSetCursorPosCallback(); 

, die mir die Koordinaten im Bereich von 0 bis der Breite oder Höhe des Fensters und mit (0,0) in der oberen linken Ecke (unter der Titelleiste) gibt. Ich nehme dann die Mauskoordinate und berechne die OpenGL-Koordinaten.

Zum Beispiel, wenn meine Fenstergröße (800, 600) und meine Maus bei (200, 200) wäre würde ich (-0.5, 0.33) [da (400, 300) würde zu (0, 0) zuordnen in den OpenGL-Koordinaten].

hier ist also mein Problem:

OpenGL auf die Titelleiste in seinen Koordinaten enthalten, wobei als glfwSetCursorPosCallback(); nicht. Das bedeutet, wenn ich einen Scheitelpunkt bei (-0,5, 0,33) [wie in meinem Beispiel] rendere, rendert er bei ungefähr (200, ~ 210).

Wie Sie sehen können, ist es schwieriger, zwischen den Koordinatensystemen zu wechseln, da die beiden Koordinatensysteme unterschiedliche Bereiche abdecken.

Ich habe nach Möglichkeiten gesucht, die Titelleiste von den OpenGL-Koordinaten auszuschließen, die Titelleiste vollständig zu entfernen und die Höhe der Titelleiste zu erhalten (damit ich sie in meine Berechnungen einbeziehen und die richtigen Anpassungen vornehmen kann) . Ich war nicht in der Lage, herauszufinden, wie ich das tun könnte, also suche ich nach einer Möglichkeit, dies zu tun, oder nach einer anderen Methode, die mein Problem lösen wird.


EDIT 1: Hinzufügen von Code

@Nicol Bolas mir mitgeteilt, dass dies nicht der Fall, wie OpenGL normal funktioniert so muss es etwas in meinem Code verursacht dies sein. Ich glaube, ich habe die Teile meines Codes zur Verfügung gestellt, die für mein Problem verantwortlich sind:


Hier ist meine Renderer-Klasse [ich den drawQuad() -Methode bin mit]

Hinweis: I verwende derzeit nicht die Ansichts-, Modell- oder Projektionsmatrizen in meinen Shadern.

public class Renderer { 

    private VertexArrayObject vao; 
    private VertexBufferObject vbo; 
    private ShaderProgram shaderProgram; 

    private FloatBuffer vertices; 
    private int numVertices; 
    private boolean drawing; 

    //private Font font; 
    //private Font debugFont; 


    public void drawQuad(float x, float y, float width, float height, Color c) { 
    /* Calculate Vertex positions */ 
     float x1 = x; 
     float y1 = y; 
     float x2 = x + width; 
     float y2 = y - height; 

    /* Calculate color */ 
     float r = c.getRed(); 
     float g = c.getGreen(); 
     float b = c.getBlue(); 

    /* Put data into buffer */ 
     vertices.put(x1).put(y1).put(0.0f).put(r).put(g).put(b); 
     vertices.put(x1).put(y2).put(0.0f).put(r).put(g).put(b); 
     vertices.put(x2).put(y2).put(0.0f).put(r).put(g).put(b); 
     vertices.put(x2).put(y1).put(0.0f).put(r).put(g).put(b); 

    /* We drawed X vertices */ 
     numVertices += 4; 
    } 


    // Initialize renderer 
    public void init(){ 

     // Set up shader programs 
     setupShaderProgram(); 

     // Enable blending (?????) 
     glEnable(GL_BLEND); 
     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 

    } 

    // Clears drawing area 
    public void clear() { 
     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 
    } 

    // Begin rendering 
    public void begin() { 
     if (drawing) throw new IllegalStateException("Renderer is already drawing."); 
     drawing = true; 
     numVertices = 0; 
    } 

    // End rendering 
    public void end() { 
     if (!drawing) throw new IllegalStateException("Renderer is not drawing."); 
     drawing = false; 
     flush(); 
    } 

    // Flushes data to GPU to get rendered 
    public void flush() { 
     if (numVertices > 0) { 
      vertices.flip(); 

      if (vao != null) vao.bind(); 
      else vbo.bind(GL_ARRAY_BUFFER); 
      specifyVertexAttributes(); 
     } 
     shaderProgram.use(); 

     // Upload the new vertex data 
     vbo.bind(GL_ARRAY_BUFFER); 
     vbo.uploadSubData(GL_ARRAY_BUFFER, 0, vertices); 

     // Draw batch 
     glDrawArrays(GL_QUADS, 0, numVertices); 

     // Clear vertex data for next batch 
     vertices.clear(); 
     numVertices = 0; 
    } 

    private void setupShaderProgram() { 

     // Generate VertexArrayObject 
     if (Game.is32Supported()) { 
      vao = new VertexArrayObject(); 
      vao.bind(); 
     } else { 
      throw new RuntimeException("OpenGL 3.2 not supported."); 
     } 

     // Generate VertexBufferObject 
     vbo = new VertexBufferObject(); 
     vbo.bind(GL_ARRAY_BUFFER); 

     // Create FloatBuffer 
     vertices = MemoryUtil.memAllocFloat(4096); 

     // Upload null data to allocate storage for the VBO 
     long size = vertices.capacity() * Float.BYTES; 
     vbo.uploadData(GL_ARRAY_BUFFER, size, GL_DYNAMIC_DRAW); 

     // Initialize variables 
     numVertices = 0; 
     drawing = false; 

     // Load Shaders: 
     Shader vertexShader, fragmentShader; 
     if (Game.is32Supported()) { 
      vertexShader = Shader.loadShader(GL_VERTEX_SHADER, "res/shaders/vshader.vert"); 
      fragmentShader = Shader.loadShader(GL_FRAGMENT_SHADER, "res/shaders/fshader.frag"); 
     } else { 
      throw new RuntimeException("OpenGL 3.2 not supported."); 
     } 

     // Create ShaderProgram 
     shaderProgram = new ShaderProgram(); 
     shaderProgram.attachShader(vertexShader); 
     shaderProgram.attachShader(fragmentShader); 
     if (Game.is32Supported()) { 
      shaderProgram.bindFragmentDataLocation(0, "fragColor"); 
     } 
     shaderProgram.link(); 
     shaderProgram.use(); 

     // Delete linked shaders 
     vertexShader.delete(); 
     fragmentShader.delete(); 

     // Get width & height of framebuffer 
     long window = GLFW.glfwGetCurrentContext(); 
     int width, height; 
     try (MemoryStack stack = MemoryStack.stackPush()) { 
      IntBuffer widthBuffer = stack.mallocInt(1); 
      IntBuffer heightBuffer = stack.mallocInt(1); 
      GLFW.glfwGetFramebufferSize(window, widthBuffer, heightBuffer); 
      width = widthBuffer.get(); 
      height = heightBuffer.get(); 
     } 

     // Specify vertex pointers 
     specifyVertexAttributes(); 

     // Set Model Matrix to identity matrix 
     Matrix4f model = new Matrix4f(); 
     int uniModel = shaderProgram.getUniformLocation("model"); 
     shaderProgram.setUniform(uniModel, model); 

     // Set View Matrix to identity matrix 
     Matrix4f view = new Matrix4f(); 
     int uniView = shaderProgram.getUniformLocation("view"); 
     shaderProgram.setUniform(uniView, view); 

     // Set Projection Matrix to an orthographic projection 
     Matrix4f projection = Matrix4f.orthographic(0f, width, 0f, height, -1f, 1f); 
     int uniProjection = shaderProgram.getUniformLocation("projection"); 
     shaderProgram.setUniform(uniProjection, projection); 

    } 

    // Specifies the vertex shader pointers (attributes) 
    private void specifyVertexAttributes() { 

     int posAttrib = shaderProgram.getAttributeLocation("position"); 
     shaderProgram.enableVertexAttribute(posAttrib); 
     shaderProgram.pointVertexAttribute(posAttrib, 3, 6 * Float.BYTES, 0); 

     int colAttrib = shaderProgram.getAttributeLocation("color"); 
     shaderProgram.enableVertexAttribute(colAttrib); 
     shaderProgram.pointVertexAttribute(colAttrib, 3, 6 * Float.BYTES, 3 * Float.BYTES); 

    } 

} 

Und hier ist meine Methode init(), dass mein Fenster erstellt und einrichtet:

private void init() { 


    // Setup an error callback. The default implementation 
    // will print the error message in System.err. 
    GLFWErrorCallback.createPrint(System.err).set(); 

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

    // Configure GLFW 
    glfwDefaultWindowHints(); // optional, the current window hints are already the default 
    glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE); // the window will stay hidden after creation 
    glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); // the window will be resizable 

    // ONLY ON MAC OSX (?) 
    //glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); // Tell GLFW to use OpenGL verison 3.x 
    //glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2); // Tell GLFW to use OpenGL version x.2 (combined -> 3.2) 
    //glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); 
    //glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE); // Should be forward compatible 

    // Create the window 
    window = glfwCreateWindow(WIDTH, HEIGHT, "Game_19_v0.0.1", 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, (window, key, scancode, action, mods) -> { 
     if (key == GLFW_KEY_ESCAPE && action == GLFW_RELEASE) 
      glfwSetWindowShouldClose(window, true); // We will detect this in the rendering loop 
    }); 

    // 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 

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

    // Make the window visible 
    glfwShowWindow(window); 

    // 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 GLCapabilities instance and makes the OpenGL 
    // bindings available for use. 
    GL.createCapabilities(); 

    // Input 
    glfwSetCursorPosCallback(window, cursorPosCallback = new MouseInput()); 

    // Create renderer 
    renderer = new Renderer(); 
    renderer.init(); 

    // To Render: 
    buttonManager = new ButtonManager(); 

} 


EDIT 2: Temporäre Lösung

konnte ich Verwenden Sie glfwWindowHint(GLFW_DECORATED, GLFW_FALSE);, um den gesamten Rahmen aus dem Fenster zu entfernen, einschließlich Titelleiste, wodurch das Problem behoben wurde. Nun, ich habe natürlich nicht die Möglichkeiten zu schließen, minimieren, etc., auf meinem Fenster, obwohl ich denke, dass ich diese in mir programmieren kann, wenn nötig.Wird aktualisiert, wenn ich andere Lösungen finde.

+6

"* OpenGL enthält die Titelleiste in ihren Koordinaten *" OpenGL hat keine Kenntnis der Titelleiste. Das klingt, als würdest du GLFW irgendwie missbrauchen. Aber wir wissen nicht, was das ist, weil Sie kein [mcve] zur Verfügung gestellt haben. –

+0

Ah, mein Schlechter. Ich dachte, es wäre etwas mit OpenGL, nicht mit meinem Code. Wird bearbeiten. – drewpel

Antwort

0

GLFW-Funktionen arbeiten normalerweise mit dem Clientbereich eines Fensters (der innere Fensterbereich enthält keine Titelleisten, Bildlaufleisten usw.), sodass glfwSetCursorPosCallback Ihnen die erwarteten Werte liefert. Wenn Ihr OpenGL Framebuffer ist für einige Grund-Rendering Dinge hinter der Titelleiste (ob es sich um eine falsche Installation oder nur eine Plattform-spezifische Detail) sollten Sie noch in der Lage sein, um die Titelleiste Größe zu erhalten mit glfwGetWindowFrameSize:

IntBuffer pLeft = stack.mallocInt(1); // int* 
IntBuffer pTop = stack.mallocInt(1); // int* 
IntBuffer pRight = stack.mallocInt(1); // int* 
IntBuffer pBottom = stack.mallocInt(1); // int* 

// Get the window border sizes 
glfwGetWindowFrameSize(window, pLeft, pTop, pRight, pBottom); 

(Haftungsausschluss : Ich folge nur der Syntax aus Ihrem Code oben, da ich nur mit der C++ API vertraut bin.)

Die Größe der Titelleiste wird in der top Variable gespeichert und kann dann zu dem Wert hinzugefügt werden, den Sie haben Erhalten Sie von glfwSetCursorPosCallback und glfwGetWindowSize.

float adjustedYpos = ypos + top; 
float adjustedHeight = height + top; 
float normalizedY = adjustedYpos/adjustedHeight; 
float openglY = normalizedY * -2.0f - 1.0f 

Dieser openglY Wert der OpenGL sein sollte [-1, 1] Clip-Raum basierend auf der Titelleiste Größe angepasst Koordinate.