Java OpenGL 屏幕大小的纹理映射四边形

发布于 2024-11-14 19:42:59 字数 1517 浏览 2 评论 0原文

我有一个 Java OpenGL (JOGL) 应用程序,我正在尝试创建一个覆盖整个屏幕的纹理映射四边形。将一些像素绘制到缓冲区,然后我想将这些像素读入纹理并在屏幕上重新绘制它们(应用片段着色器)。我将纹理映射到视口的代码是:

        gl.glMatrixMode(GL.GL_PROJECTION);                                        
        gl.glPushMatrix();                                                 
        gl.glLoadIdentity();                                               
        gl.glOrtho( 0, width, height, 0, -1, 1 );                          
        gl.glMatrixMode(GL.GL_MODELVIEW);                                  
        gl.glPushMatrix();                                                 
        gl.glLoadIdentity();
        IntBuffer ib = IntBuffer.allocate(1);
        gl.glEnable(GL.GL_TEXTURE_2D);
        gl.glGenTextures(1, ib);
        gl.glPixelStorei(GL.GL_PACK_ALIGNMENT, 1);
        //buff contains pixels read from glReadPixels
        gl.glTexImage2D(GL.GL_TEXTURE_2D, 0, GL.GL_RGBA, width, height, 0, GL.GL_RGBA, GL.GL_UNSIGNED_BYTE, buff);
        gl.glBindTexture(GL.GL_TEXTURE_2D, ib.get(0));
        gl.glBegin(GL.GL_QUADS);
        gl.glTexCoord2f(0,1);
        gl.glVertex2f(0,0); 
        gl.glTexCoord2f(0,0);
        gl.glVertex2f(0,height);
        gl.glTexCoord2f(1,0);   
        gl.glVertex2f(width,height);
        gl.glTexCoord2f(1,1);      
        gl.glVertex2f(width,0);
        gl.glEnd();
        gl.glBindTexture(GL.GL_TEXTURE_2D, 0);
        gl.glPopMatrix();
        gl.glPopMatrix();

最终结果是一个四边形,它没有覆盖整个视口(它部分打开)并且不包含缓冲区中的像素。我在这里做错了什么?

谢谢, 杰夫

I have a Java OpenGL (JOGL) app, and I'm trying to create a texture mapped quad that covers the entire screen. In draw some pixels to a buffer and then I want to read those pixels into a texture and redraw them on screen (with a fragment shader applied). My code for mapping the texture to the viewport is:

        gl.glMatrixMode(GL.GL_PROJECTION);                                        
        gl.glPushMatrix();                                                 
        gl.glLoadIdentity();                                               
        gl.glOrtho( 0, width, height, 0, -1, 1 );                          
        gl.glMatrixMode(GL.GL_MODELVIEW);                                  
        gl.glPushMatrix();                                                 
        gl.glLoadIdentity();
        IntBuffer ib = IntBuffer.allocate(1);
        gl.glEnable(GL.GL_TEXTURE_2D);
        gl.glGenTextures(1, ib);
        gl.glPixelStorei(GL.GL_PACK_ALIGNMENT, 1);
        //buff contains pixels read from glReadPixels
        gl.glTexImage2D(GL.GL_TEXTURE_2D, 0, GL.GL_RGBA, width, height, 0, GL.GL_RGBA, GL.GL_UNSIGNED_BYTE, buff);
        gl.glBindTexture(GL.GL_TEXTURE_2D, ib.get(0));
        gl.glBegin(GL.GL_QUADS);
        gl.glTexCoord2f(0,1);
        gl.glVertex2f(0,0); 
        gl.glTexCoord2f(0,0);
        gl.glVertex2f(0,height);
        gl.glTexCoord2f(1,0);   
        gl.glVertex2f(width,height);
        gl.glTexCoord2f(1,1);      
        gl.glVertex2f(width,0);
        gl.glEnd();
        gl.glBindTexture(GL.GL_TEXTURE_2D, 0);
        gl.glPopMatrix();
        gl.glPopMatrix();

The end result is a quad that is not covering the whole viewport (it's partially on) and that does not contain the pixels from the buffer. What am I doing incorrectly here?

thanks,
Jeff

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

迷你仙 2024-11-21 19:43:00

首先,您应该只在初始化代码中创建纹理。您不应该每帧都调用 glTexImage2D。仅当纹理大小发生变化时才再次调用glTexImage2D; glTexSubImage2D 可用于将数据上传到纹理。将 glTexImage2D 视为“新的”,而将 glTexSubImage2D 视为内存副本。

初始化 OpenGL 后执行此操作一次。

IntBuffer ib = IntBuffer.allocate(1);  //Store this in your object
gl.glGenTextures(1, ib);
gl.glPixelStorei(GL.GL_PACK_ALIGNMENT, 1);
//buff contains pixels read from glReadPixels
gl.glBindTexture(GL.GL_TEXTURE_2D, ib.get(0));
gl.glTexImage2D(GL.GL_TEXTURE_2D, 0, GL.GL_RGBA, width, height, 0, GL.GL_RGBA, GL.GL_UNSIGNED_BYTE, 0);
gl.glBindTexture(GL.GL_TEXTURE_2D, 0);

然后,在每个帧中执行以下操作:

gl.glMatrixMode(GL.GL_PROJECTION);                                        
gl.glPushMatrix();                                                 
gl.glLoadIdentity();                                               
gl.glMatrixMode(GL.GL_MODELVIEW);                                  
gl.glPushMatrix();                                                 
gl.glLoadIdentity();

gl.glBindTexture(GL.GL_TEXTURE_2D, ib.get(0));  //Retrieved from your object
gl.glEnable(GL.GL_TEXTURE_2D);
gl.glTexSubImage2D(GL.GL_TEXTURE_2D, 0, 0, 0, width, height, 0, GL.GL_RGBA, GL.GL_UNSIGNED_BYTE, buff);

gl.glBegin(GL.GL_QUADS);
    gl.glTexCoord2f(0,1);
    gl.glVertex2f(-1, -1); 
    gl.glTexCoord2f(0, 0);
    gl.glVertex2f(-1, 1);
    gl.glTexCoord2f(1, 0);   
    gl.glVertex2f(1, 1);
    gl.glTexCoord2f(1, 1);      
    gl.glVertex2f(1, -1);
gl.glEnd();

gl.glMatrixMode(GL.GL_MODELVIEW);                                  
gl.glPopMatrix();   
gl.glMatrixMode(GL.GL_PROJECTION);                                        
gl.glPopMatrix();   
gl.glMatrixMode(GL.GL_MODELVIEW);                                  

通过使用投影和模型视图的恒等性,我们能够直接在剪辑空间中提供顶点坐标。剪辑空间中的 [-1, 1] 范围映射到窗口空间中的 [0, 宽度/高度]。所以我们不必知道或关心窗口有多大;只要 glViewport 设置正确,这应该可以工作。

First, you should only create the texture in your initialization code. You should not be calling glTexImage2D every frame. Only call glTexImage2D again if the size of the texture changes; glTexSubImage2D can be used to upload data to the texture. Think of glTexImage2D as "new", while glTexSubImage2D as a memory copy.

Do this once, after initializing OpenGL.

IntBuffer ib = IntBuffer.allocate(1);  //Store this in your object
gl.glGenTextures(1, ib);
gl.glPixelStorei(GL.GL_PACK_ALIGNMENT, 1);
//buff contains pixels read from glReadPixels
gl.glBindTexture(GL.GL_TEXTURE_2D, ib.get(0));
gl.glTexImage2D(GL.GL_TEXTURE_2D, 0, GL.GL_RGBA, width, height, 0, GL.GL_RGBA, GL.GL_UNSIGNED_BYTE, 0);
gl.glBindTexture(GL.GL_TEXTURE_2D, 0);

Then, each frame, do this:

gl.glMatrixMode(GL.GL_PROJECTION);                                        
gl.glPushMatrix();                                                 
gl.glLoadIdentity();                                               
gl.glMatrixMode(GL.GL_MODELVIEW);                                  
gl.glPushMatrix();                                                 
gl.glLoadIdentity();

gl.glBindTexture(GL.GL_TEXTURE_2D, ib.get(0));  //Retrieved from your object
gl.glEnable(GL.GL_TEXTURE_2D);
gl.glTexSubImage2D(GL.GL_TEXTURE_2D, 0, 0, 0, width, height, 0, GL.GL_RGBA, GL.GL_UNSIGNED_BYTE, buff);

gl.glBegin(GL.GL_QUADS);
    gl.glTexCoord2f(0,1);
    gl.glVertex2f(-1, -1); 
    gl.glTexCoord2f(0, 0);
    gl.glVertex2f(-1, 1);
    gl.glTexCoord2f(1, 0);   
    gl.glVertex2f(1, 1);
    gl.glTexCoord2f(1, 1);      
    gl.glVertex2f(1, -1);
gl.glEnd();

gl.glMatrixMode(GL.GL_MODELVIEW);                                  
gl.glPopMatrix();   
gl.glMatrixMode(GL.GL_PROJECTION);                                        
gl.glPopMatrix();   
gl.glMatrixMode(GL.GL_MODELVIEW);                                  

By using identity for projection and modelview, we are able to supply vertex coordinates directly in clip-space. The [-1, 1] range in clip-space maps to [0, width/height] in window space. So we don't have to know or care about how big the window is; as long as the glViewport was set up correctly, this should work.

心在旅行 2024-11-21 19:43:00

这可能不是问题,但它不会有帮助:您将在一次推送中弹出模型视图矩阵两次。您根本没有弹出投影矩阵。

我建议在启动时设置一次投影矩阵,而不进行任何推送或弹出操作。您实际上也不需要推送和弹出模型视图矩阵。 (您也可以在启动时进行一次纹理设置。)

It may not be the problem, but it won't be helping: You are popping the modelview matrix twice for a single push. You are not popping the projection matrix at all.

I would recommend setting the projection matrix once at startup, without doing any pushes or pops. You don't really need to push and pop the modelview matrix either. (You could do your texture setup once at startup, too.)

独木成林 2024-11-21 19:43:00

我将首先使用如下代码检查 glError 。请注意,我使用 GL2 对象是因为旧版本的 JOGL 和 GL 对象存在一些问题,比如 GL_QUADS 不存在等愚蠢的事情。

如果您使用上述代码启用了着色器,则需要通过读取采样器来进行纹理化。如果是这样,请附上您与此渲染代码一起使用的着色器代码。

private static void checkForGLErrors(GL2 gl) {
    int errno = gl.glGetError();
    switch (errno) {
        case GL2.GL_INVALID_ENUM:
            System.err.println("OpenGL Error: Invalid ENUM");
            break;
        case GL2.GL_INVALID_VALUE:
            System.err.println("OpenGL Error: Invalid Value");
            break;
        case GL2.GL_INVALID_OPERATION:
            System.err.println("OpenGL Error: Invalid Operation");
            break;
        case GL2.GL_STACK_OVERFLOW:
            System.err.println("OpenGL Error: Stack Overflow");
            break;
        case GL2.GL_STACK_UNDERFLOW:
            System.err.println("OpenGL Error: Stack Underflow");
            break;
        case GL2.GL_OUT_OF_MEMORY:
            System.err.println("OpenGL Error: Out of Memory");
            break;
        default:
            return;
    }
}

如果纹理不会改变,我也会尝试避免在每一帧生成纹理。您可以保存textureId并稍后绑定它。

I would start with checking glError with code like the below. Note I used the GL2 object because there were some issues with older versions of JOGL and the GL object, silly things like GL_QUADS not being there.

If you have a shader enabled with the above code, you need to do the texturing by reading the sampler. If so, please attach the shader code you are using with this rendering code.

private static void checkForGLErrors(GL2 gl) {
    int errno = gl.glGetError();
    switch (errno) {
        case GL2.GL_INVALID_ENUM:
            System.err.println("OpenGL Error: Invalid ENUM");
            break;
        case GL2.GL_INVALID_VALUE:
            System.err.println("OpenGL Error: Invalid Value");
            break;
        case GL2.GL_INVALID_OPERATION:
            System.err.println("OpenGL Error: Invalid Operation");
            break;
        case GL2.GL_STACK_OVERFLOW:
            System.err.println("OpenGL Error: Stack Overflow");
            break;
        case GL2.GL_STACK_UNDERFLOW:
            System.err.println("OpenGL Error: Stack Underflow");
            break;
        case GL2.GL_OUT_OF_MEMORY:
            System.err.println("OpenGL Error: Out of Memory");
            break;
        default:
            return;
    }
}

I would also try to avoid generating the texture every frame if it is something that doesn't change. You can save the textureId and bind it later.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文