Java OpenGL четырехмерный экран с текстурой
У меня есть приложение 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();
Конечный результат - это квад, который не покрывает весь видовой экран (он частично включен) и не содержит пикселей из буфера. Что я здесь делаю неправильно?
спасибо Джефф
3 ответа
Во-первых, вы должны только создать текстуру в вашем коде инициализации. Вы не должны вызывать 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 был настроен правильно, это должно работать.
Это может и не быть проблемой, но это не поможет: вы нажимаете на матрицу просмотра модели дважды для одного нажатия. Вы вообще не используете матрицу проекций.
Я бы порекомендовал установить матрицу проекции один раз при запуске, без каких-либо нажатий или всплывающих окон. Вам также не нужно нажимать и вставлять матрицу просмотра модели. (Вы можете выполнить настройку текстуры один раз при запуске.)
Я бы начал с проверки 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 и связать его позже.