【问题标题】:OpenGL drawing texture wrongOpenGL绘制纹理错误
【发布时间】:2018-07-23 17:26:50
【问题描述】:

我正在使用 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,但显示如下:

所以,它是颠倒的,比预期的要大得多,而且位置不对。

我做错了什么?

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

【问题讨论】:

  • 请提供MCVE。 OpenGL 是一个状态机。您的render 函数将产生什么取决于几十个不同的状态位(如视口、转换设置、顶点着色器、纹理对象的尺寸)。你的问题就像问“我得到f(g(h(i(j(k(l(m(1.0)))))))) = 42,但我期待23,怎么了?”,而没有告诉fm的功能。
  • 感谢您的回答,这样可以吗? pastebin.com/1UcrFwdn
  • 请将代码添加到问题本身。并且代码仍然缺少纹理规范部分。
  • 对不起,现在已经完成了。

标签: java opengl textures lwjgl


【解决方案1】:

一一解决你的问题

1.所以,它是颠倒的,

OpenGL 的纹理坐标(不仅是 GL,这通常适用于所有常见的渲染 API)的定义方式是,原点将位于您在上传数据时指定的第一个像素处。您的图像很可能是按照从左到右、从上到下的约定来定义和加载的 - 因此您将分配 (0,0) texcoords 的顶点将显示图像的右上角。

现在,GL 的窗口空间是用数学约定定义的(至少默认情况下),原点在底部左侧。而且您正在查看一些投影矩阵:

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

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

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

所以当你现在这样做时:

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

将应用上述变换,并且具有左上角纹素的顶点将最终位于视口的左下角。

2。比预期的要大很多

您按如下方式设置视口转换:

GL11.glViewport(0, 0, 1920, 1200);

现在,这只是定义了另一个转换,现在从 NDC 到窗口空间。只是x_ndc=-1 分别映射到x_win=0 x_ndc=1x_win=1920y

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

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

  • 您的代码并未完全重现该问题,并且

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

    可能与此无关。

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

3.并且在错误的位置

这也是你不匹配 OpenGL 坐标约定的结果。

4.我做错了什么?

您编写的代码使用了已弃用的 OpenGL。您现在依赖于十年前已弃用的固定功能管道。这些功能已从 OpenGL 的现代核心配置文件中完全删除。甚至在此之前,glBegin()/glEnd() 的即时模式渲染基本上已被 20 年前的顶点数组所取代。如果你现在正在学习 OpenGL,你真的应该尽量避免学习那些老东西,并从一个干净的核心配置文件 OpenGL 上下文开始。

【讨论】:

  • 感谢您给出这样的答案。总的来说,我们可以说我应该停止使用 glVertex2f 和 glTexCoord2f 吗?并开始使用着色器?
  • 这当然是见仁见智。但是,是的,这是我的建议。作为奖励,它会使其中一些转换更加清晰,因为它们确实发生在顶点着色器中,因此不再是黑匣子了。
  • 好的,很高兴知道。但是OpenGL的初始化部分正确吗?
  • 不确定您现在要问的是什么。 GL 初始化是用 GL 完成的
  • 顶点着色器不是 OpenGL 的一部分吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多