我有一个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();
最终结果是一个未覆盖整个视口的四边形(它部分打开)并且不包含缓冲区中的像素。我在这里做错了什么?
感谢, 杰夫
答案 0 :(得分:2)
首先,您应该只在初始化代码中创建纹理。你不应该每帧都调用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设置正确,这应该可行。
答案 1 :(得分:1)
这可能不是问题,但它没有帮助:您只需弹出两次模型视图矩阵一次。你根本没有弹出投影矩阵。
我建议在启动时设置一次投影矩阵,而不进行任何推动或弹出。您也不需要推送和弹出模型视图矩阵。 (您也可以在启动时进行一次纹理设置。)
答案 2 :(得分:0)
我将从使用如下代码检查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并稍后将其绑定。