OpenGL绘制纹理错误

时间:2018-07-23 17:26:50

标签: java opengl textures lwjgl

我正在使用LWJGL并尝试绘制纹理,其渲染代码如下:

public static void main(String[] args) {
    GLFWErrorCallback.createPrint(System.err).set();
    if (!GLFW.glfwInit()) {
        throw new IllegalStateException("Unable to initialize GLFW");
    }
    GLFW.glfwWindowHint(GLFW.GLFW_VISIBLE, GLFW.GLFW_FALSE);
    GLFW.glfwWindowHint(GLFW.GLFW_RESIZABLE, GLFW.GLFW_TRUE);
    window = GLFW.glfwCreateWindow(1280, 720, "Test", 0, 0);
    GLFW.glfwMakeContextCurrent(window);
    GL.createCapabilities();
    GL11.glMatrixMode(GL11.GL_PROJECTION);
    GL11.glLoadIdentity();
    GL11.glOrtho(0, 1280, 0, 720, 1, -1);
    GL11.glMatrixMode(GL11.GL_MODELVIEW);
    GL11.glViewport(0, 0, 1920, 1200);
    GL11.glClearColor(1.0F, 1.0F, 1.0F, 1.0F);
    int x = 0, y = 0;
    ByteBuffer imageBuffer = readFile(filename);
    IntBuffer w = BufferUtils.createIntBuffer(1);
    IntBuffer h = BufferUtils.createIntBuffer(1);
    IntBuffer comp = BufferUtils.createIntBuffer(1);
    ByteBuffer image = STBImage.stbi_load_from_memory(imageBuffer, w, h, comp, 0);  
    int textureId = GL11.glGenTextures();
    int glTarget = GL11.GL_TEXTURE_2D;
    GL11.glBindTexture(glTarget, textureId);
    glTexParameteri(glTarget, GL11.GL_TEXTURE_WRAP_S, GL12.GL_CLAMP_TO_EDGE);
    glTexParameteri(glTarget, GL11.GL_TEXTURE_WRAP_T, GL12.GL_CLAMP_TO_EDGE);
    glTexParameteri(glTarget, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_NEAREST);
    glTexParameteri(glTarget, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST);
    int width = w.get(0);
    int height = h.get(0);
    /** Send texel data to OpenGL if texture is 2d texture */
    if (glTarget == GL11.GL_TEXTURE_2D) {
        if(comp.get(0) == 3){
            GL11.glTexImage2D(glTarget, 0, GL11.GL_RGB, width, height, 0, GL11.GL_RGB, GL11.GL_UNSIGNED_BYTE, image);
        }
        else{
            GL11.glTexImage2D(glTarget, 0, GL11.GL_RGBA, width, height, 0, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, image);
            GL11.glEnable(GL11.GL_BLEND);
            GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
        }
    }
    while (Sgl.window.isAlive()) {
        GLFW.glfwPollEvents();
        GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT);
        /* Texture display part */
        bind();
        GL11.glEnable(glTarget);
        GL11.glBegin(GL11.GL_QUADS);
        GL11.glTexCoord2f(0,0);
        GL11.glVertex2f(x,y);
        GL11.glTexCoord2f(1,0);
        GL11.glVertex2f(x+width,y);
        GL11.glTexCoord2f(1,1);
        GL11.glVertex2f(x+width,y+height);
        GL11.glTexCoord2f(0,1);
        GL11.glVertex2f(x,y+height);
        GL11.glEnd();
        GL11.glDisable(glTarget);
        /*End texture display part*/
        GLFW.glfwSwapBuffers(window);
    }
}

问题是窗口大1280x720,图像只有392x69,但显示方式如下:

enter image description here

所以,它倒过来了,比预期的要大得多,并且位置错误。

我在做什么错了?

编辑:由于代码的大小,我删除了一些if子句。

1 个答案:

答案 0 :(得分:3)

一个接一个地解决您的问题

  

1。因此,它是颠倒的,

OpenGL的纹理坐标(不仅是GL,对于所有常见的渲染API都是如此)的定义方式是,原点将在上载数据时指定的第一个像素处为b。定义和加载图像时最先考虑的是从左到右,从上到下的约定-因此,要分配(0,0)texcoords的顶点将显示图像的右上角。 / p>

现在,GL的窗口空间(至少默认情况下)使用数学约定定义,原点位于底部的左侧。您会发现一些投影矩阵:

  

GL11.glOrtho(0,1280,0,720,1,-1);

这会将x=0映射到x_ndc=-1,将x=1280映射到x_ndc=1,将y=0映射到y_ndc=-1,将y=720映射到{ {1}}。 (它将映射相对于您指定的范围y_ndc=1刚刚翻转的z坐标,因此[1,-1]z=-1z_ndc=-1z=1,但这无关紧要。)

NDC是z_ndc=1,其中normalized device coordinates是视口的左下角,而(-1,-1)是视口的右上角。

因此,当您现在这样做时:

(1,1)

将应用上述变换,带有左上角纹理元素的顶点将最终在视口的左下角。

  

2。比预期的要大得多

您可以按照以下步骤设置视口转换:

  GL11.glVertex2f(x,y); // NOTE: x and y are just 0 here
  GL11.glTexCoord2f(1,0);

现在,这只是定义了另一个转换,现在是从NDC到窗口空间。只是将GL11.glViewport(0, 0, 1920, 1200); 映射到x_ndc=-1 x_win=0x_ndc=1并分别映射到x_win=1920

因此,输入坐标y映射到NDC中的(0,0),并进一步映射到仍然位于左下角的窗口空间中的(-1,1)(0,0)将被映射到NDC中的(392,93),并被映射到窗口空间中的~(0.3,0.129),这比您的图像实际要大得多。

它仍然应该适合您的窗口,但是从屏幕截图看来,它似乎不合适。可能有几种解释:

  • 您的代码无法完全再现问题,并且

      

    由于代码的大小,我删除了一些if子句。

    可能或可能与此无关。

  • 您正在使用某些“高DPI缩放比例”(如Microsoft所说)或操作系统的类似功能。您在GLFW中指定的窗口的大小不是 (以像素为单位),而是以某些特定于系统和平台的单位。 GLFW提供了means to query the actual pixel sizes,您应该在设置窗口的适当视口时使用它。
  • ...
  

3。并且位置错误

那也是您不匹配OpenGL坐标约定的结果。

  

4。我在做什么错了?

您编写的代码使用不推荐使用的OpenGL 。您所依赖的是固定功能管道,而该功能管道在十年前之前已被弃用。这些功能已从现代OpenGL核心配置文件中完全删除。甚至在此之前,(588,115)进行的即时模式渲染基本上早于20年前被顶点数组所取代。如果您现在正在学习OpenGL,则应该真正避免学习那些旧知识,而应从干净的核心配置文件OpenGL上下文开始。