#java #android #opengl #opengles
Всем привет! Возникла проблема с glViewport в OpenGL ES 2.0 под Android. Я реализовал следующий алгоритм. Изображение генерируется в текстуру с использованием FBO. Шейдер, который генерирует изображение, также принимает на вход предыдущую отрисованную текстуру того же размера. Шейдер использует ее для более быстрой генерации следующей текстуры. Для всего этого у меня есть 2 фреймбуфера (+ экранный фреймбуфер), к каждому из которых приаттачена 1 текстура. После каждого цикла отрисовки ссылки на фреймбуферы меняются местами, чтобы каждый раз не копировать предыдущее изображение. Размер текстуры степени 2, т.е. размеры текстуры и экрана не совпадают. Итак, проблема в том, что на экран рендерится не вся текстура, а лишь ее часть. Код отрисовки: //Меняем местами ссылки на буферы evenRender = !evenRender; int srcFB = evenRender? 0:1; int dstFB = evenRender? 1:0; //Привязываем буфер, куда будет генерироваться изображение GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, frameBufferID[dstFB]); //Выбираем размеры окна вывода как размеры экрана устройства **GLES20.glViewport(0, 0, mScreenWidth, mScreenHeight);** GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f); //Выбираем предыдущую отрисованную текстуру GLES20.glActiveTexture(GLES20.GL_TEXTURE0 + srcFB); GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, frameTextureID[srcFB]); //Устанавливаем шейдер для генерации изображения GLES20.glUseProgram(sp_ImageGeneration); int mPositionHandle = GLES20.glGetAttribLocation(sp_ImageGeneration, "vPosition"); GLES20.glVertexAttribPointer(mPositionHandle, 3, GLES20.GL_FLOAT, false, 0, offscreen_vertexBuffer); GLES20.glEnableVertexAttribArray(mPositionHandle); int mTexCoordLoc = GLES20.glGetAttribLocation(sp_ImageGeneration, "a_texCoord"); GLES20.glVertexAttribPointer ( mTexCoordLoc, 2, GLES20.GL_FLOAT, false, 0, offscreen_uvBuffer); GLES20.glEnableVertexAttribArray(mTexCoordLoc); ... //Отправляем шейдеру предыдущую отрисованную текстуру int mSamplerLoc = GLES20.glGetUniformLocation (sp_ImageGeneration, "prev_frame" ); GLES20.glUniform1i(mSamplerLoc, srcFB); GLES20.glDrawElements(GLES20.GL_TRIANGLES, indices.length, GLES20.GL_UNSIGNED_SHORT, drawListBuffer); GLES20.glDisableVertexAttribArray(mPositionHandle); GLES20.glDisableVertexAttribArray(mTexCoordLoc); //Привязываем экранный буфер GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0); GLES20.glViewport(0, 0, mScreenWidth, mScreenHeight); GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f); //Выбираем текстуру в том буфере, куда генерировалось изображение GLES20.glActiveTexture(GLES20.GL_TEXTURE0 + dstFB); GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, frameTextureID[dstFB]); // Устанавливаем простой шейдер GLES20.glUseProgram(sp_Image); mPositionHandle = GLES20.glGetAttribLocation(sp_Image, "vPosition"); GLES20.glVertexAttribPointer(mPositionHandle, 3, GLES20.GL_FLOAT, false, 0, vertexBuffer); GLES20.glEnableVertexAttribArray(mPositionHandle); mTexCoordLoc = GLES20.glGetAttribLocation(sp_Image, "a_texCoord" ); GLES20.glVertexAttribPointer ( mTexCoordLoc, 2, GLES20.GL_FLOAT, false, 0, uvBuffer); GLES20.glEnableVertexAttribArray(mTexCoordLoc); ... //Отправляем шейдеру текстуру, куда генерировалось изображение mSamplerLoc = GLES20.glGetUniformLocation (sp_Image, "s_texture" ); GLES20.glUniform1i(mSamplerLoc, dstFB); GLES20.glDrawElements(GLES20.GL_TRIANGLES, indices.length, GLES20.GL_UNSIGNED_SHORT, drawListBuffer); GLES20.glDisableVertexAttribArray(mPositionHandle); GLES20.glDisableVertexAttribArray(mTexCoordLoc); GLES20.glUseProgram(0); GLES20.glActiveTexture(0); GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0); Координаты треугольников, на которые происходит отрисовка: float koefWidth = (float)texSize / mScreenWidth; float koefHeight = (float)texSize / mScreenHeight; vertices = new float[] { 0, 0, 0f, 0, mScreenHeight * koefHeight, 0f, mScreenWidth * koefWidth, mScreenHeight * koefHeight, 0f, mScreenWidth * koefWidth, 0, 0f }; offscreen_vertices = new float[] { 0, 0, 0f, 0, mScreenHeight * koefHeight* koefHeight, 0f, mScreenWidth * koefWidth * koefWidth , mScreenHeight * koefHeight* koefHeight, 0f, mScreenWidth * koefWidth * koefWidth, 0, 0f }; texSize - размер текстуры. Например, mScreenWidth = 800, mScreenHeight = 600, texSize = 1024. Координаты текстур uvs и offscreen_uvs одинаковы: uvs = new float[] { 0, 0, 0, 1, 1, 1, 1, 0, }; Фреймбуферы и текстуры для них были созданы так: frameBufferID = new int[2]; frameTextureID = new int[2]; GLES20.glGenFramebuffers(2, frameBufferID, 0); GLES20.glGenTextures(2, frameTextureID, 0); GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, frameBufferID[0]); GLES20.glActiveTexture(GLES20.GL_TEXTURE0); GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, frameTextureID[0]); GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGB, texSize, texSize, 0, GLES20.GL_RGB, GLES20.GL_UNSIGNED_BYTE, null); GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE); GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE); GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR); GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR); GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0, GLES20.GL_TEXTURE_2D, frameTextureID[0], 0); //Next framebuffer GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, frameBufferID[1]); GLES20.glActiveTexture(GLES20.GL_TEXTURE0 + 1); GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, frameTextureID[1]); GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGB, texSize, texSize, 0, GLES20.GL_RGB, GLES20.GL_UNSIGNED_BYTE, null); GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE); GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE); GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR); GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR); GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0, GLES20.GL_TEXTURE_2D, frameTextureID[1], 0); Я очень долго пробовал менять значения в glViewport, выделенном звездочками, а также координаты треугольников. Но тогда либо возникали графические артефакты, либо сильно падала производительность. Заранее спасибо!
Ответы
Ответ 1
Вопрос решен. Оказалось, "графические артефакты" были связаны со спецификой работы моего шейдера. Он берет текстуры из фреймбуфера, но я не учитывал то, что эти текстуры были уменьшены glViewport'ом. Из-за этого данные текстур обрабатывались неправильно, что и выливалось в артефакты результирующего изображения. Решилось добавлением в шейдер соответствующих коэффициентов при обработке текстур. Эта проблема мучила меня на протяжении недели, и теперь я очень рад! :)
Комментариев нет:
Отправить комментарий