#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'ом. Из-за этого данные текстур обрабатывались неправильно, что и выливалось в артефакты результирующего изображения. Решилось добавлением в шейдер соответствующих коэффициентов при обработке текстур. Эта проблема мучила меня на протяжении недели, и теперь я очень рад! :)
Комментариев нет:
Отправить комментарий