当前位置: 首页 > 知识库问答 >
问题:

OpenGL在错误位置渲染四边形

黄俊誉
2023-03-14

背景信息:

我正在使用OpenGL和LWJGL 3在屏幕上绘制一些四边形。我需要知道鼠标何时在四轴上。当我将四边形渲染到屏幕上时,我使用OpenGL坐标,X和Y的范围是从-1到1,而(0,0)在屏幕的中心。当我得到我使用的鼠标位置时

glfwSetCursorPosCallback();

这给了我从0到窗口宽度或高度的坐标,在左上角(标题栏下方)有(0,0)。然后取鼠标坐标并计算OpenGL坐标。

例如,如果我的窗口大小为(800,600),而我的鼠标为(200,200),我将得到(-0.5,0.33)[因为(400,300)将映射到OpenGL坐标中的(0,0)]。

所以这是我的问题:

OpenGL在其坐标中包含标题栏,其中as < code > glfwsetcursorboscallback();不会。这意味着如果我在(-0.5,0.33)渲染一个顶点,它会在(200,210)左右渲染。

如您所见,由于两个坐标系覆盖不同的区域,因此在坐标系之间切换更加困难。

我一直在寻找从OpenGL坐标中排除标题栏的方法,以完全去除标题栏并获得标题栏的高度(这样我可以将其包括在计算中并进行正确的调整)。我还不知道如何做这些,所以我正在寻找一种方法,或者一种不同的方法来解决我的问题。


编辑1:添加代码

@Nicol Bolas告诉我,OpenGL通常不是这样工作的,所以我的代码中一定有什么原因导致了这种情况。我相信我已经提供了我的代码中可能导致我的问题的部分:


这是我的渲染器类【我使用的是draquad()方法】

注意:我目前没有在我的着色器中使用视图、模型或投影矩阵。

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);

    }

}

下面是我的init()方法,它创建并设置了我的窗口:

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();

}


编辑2:临时解决方案

我能够使用glfwWindowHint(GLFW_DECORATED,GLFW_FALSE);从窗口中删除整个边框,包括标题栏,这解决了问题。但是,现在我显然没有关闭、最小化等选项。,在我的窗口上,尽管我想如果有必要,我可以自己编写这些程序。如果我找到任何其他解决方案,将更新。

共有1个答案

孟乐逸
2023-03-14

GLFW 函数通常使用窗口的工作区(内部窗口区域不包括标题栏、滚动条等),因此 glfwSetCursorPosCall 回调为您提供预期的值。如果您的 OpenGL 帧缓冲器由于某种原因在标题栏后面呈现内容(无论是设置不正确还是只是特定于平台的详细信息),您仍然应该能够使用 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);

(免责声明:我只是遵循上面代码中的语法,因为我只熟悉C API。)

标题栏的大小将存储在<code>top

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

openglY 值应为根据标题栏大小调整的 OpenGL [-1, 1] 剪辑空间坐标。

 类似资料:
  • 我已经试着让这段代码工作了一段时间,但我仍然不知道我做错了什么。(LWJGL-Java) 我曾尝试在网上查看其他人的代码,但我找不到任何重大区别。事实上,我学会了将OpenGL与C结合使用,所以我的大脑可能会被它卡住,这可能就是我找不到错误的原因。 这是init(调用一次) 这是渲染函数: 着色器: 顶点: Framgent公司:

  • 我正在尝试创建一个简单的三角形网格,在弄清楚为什么我刚刚得到了一个blanc屏幕(由于某些原因,x64配置给我带来了问题)之后,我面临一个新问题: 我得到的是: 我使用GLEW 1.10.0加载OpenGL,使用GLM 0.9.5.4加载OpenGL数学内容,使用SDL 2.0.3加载窗口内容。在Visual Studio 2013 Ultimate的Windows 8.1上运行的一切都带有最新的

  • 下面的LWJGL代码将在屏幕中心呈现一个蓝色正方形。相反,我得到了一个空白的白色屏幕。就像渲染根本不工作,或者我在屏幕外渲染。 我是OpenGL和LWJGL的新手,所以我力不从心。我浏览了所有内容,但似乎找不到任何可能与代码有关的问题。 OpenGLTest.scala VertexArray.scala

  • 如果你想渲染内置错误页面,你可以使用next/error: import React from 'react' import Error from 'next/error' import fetch from 'isomorphic-unfetch' export default class Page extends React.Component { static async getIni

  • 在过去的几天里,我一直在尝试将纹理缩放为Quad(OpenGL 3)... 但由于某些原因,我只得到渲染到四元网格上的图像左上角像素,我使用平滑的UTIL加载和绑定纹理。。。。 代码如下: 主要游戏。Java语言 着色器程序。Java语言 顶点着色器: 片段着色器: 装载机。Java语言 模型Java语言 vbo. java 这是我想要渲染的图像(它是测试图像)(PNG格式)一头奶牛: 这是我得到

  • 纹理根本不渲染,几何体都是黑色的。 截图:http://i.imgur.com/ypMdQY4.png 代码:http://pastebin.com/SvB8rxxt 我也会链接到我试图渲染的纹理和transformations.py模块,但是我没有被允许放置两个以上链接的声誉。谷歌搜索“现代opengl 02”会给你前者的教程,“转换py”会给你后者。 搜索“纹理材料开始”以查找纹理材料的设置位