OpenGL ES - glReadPixels - PullRequest
       17

OpenGL ES - glReadPixels

9 голосов
/ 21 ноября 2011

Я делаю снимок экрана с glReadPixels, чтобы выполнить "перекрестный" эффект между двумя изображениями.

На симуляторе Marmalade SDK снимок экрана сделан очень хорошо, и эффект "перекрёстного перехода" приносит удовольствие: enter image description here

Тем не менее, вот как это выглядит на устройствах iOS и Android - повреждено: http://www.eikona.info/images/81269689420703803966.png

Я всегда читаю экран как RGBA 1 байт / канал, поскольку в документации написано , это ВСЕГДА принято.

Вот код, используемый для снимка экрана:

uint8* Gfx::ScreenshotBuffer(int& deviceWidth, int& deviceHeight, int& dataLength) {

    /// width/height
    deviceWidth = IwGxGetDeviceWidth();
    deviceHeight = IwGxGetDeviceHeight();
    int rowLength = deviceWidth * 4; /// data always returned by GL as RGBA, 1 byte/each

    dataLength = rowLength * deviceHeight;

    // set the target framebuffer to read
    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
    glPixelStorei(GL_PACK_ALIGNMENT, 1);
    uint8* buffer = new uint8[dataLength];
    glReadPixels(0, 0, deviceWidth, deviceHeight, GL_RGBA, GL_UNSIGNED_BYTE, buffer);

    return buffer;
}

void Gfx::ScreenshotImage(CIwImage* img, uint8*& pbuffer) {

    int deviceWidth, deviceHeight, dataLength;

    pbuffer = ScreenshotBuffer(deviceWidth, deviceHeight, dataLength);
    img->SetFormat(CIwImage::ABGR_8888);
    img->SetWidth(deviceWidth);
    img->SetHeight(deviceHeight);
    img->SetBuffers(pbuffer, dataLength, 0, 0);
}

Ответы [ 6 ]

5 голосов
/ 30 ноября 2011

В конце концов, это был недостаток памяти.«Новый uint8 [dataLength];»никогда не возвращал существующий указатель, поэтому весь процесс был поврежден.

TomA, ваша идея очистки буфера фактически помогла мне решить проблему.Спасибо.

5 голосов
/ 27 ноября 2011

Это ошибка драйвера. Все просто.

Драйвер неверно определил высоту поверхности видеопамяти. Вы можете ясно видеть это в верхних строках. Также мусор, который вы видите в нижней части изображения, - это память, в которой драйвер считает изображение сохраненным, но там есть другие данные. Возможно, текстуры / данные вершин.

И извините, я не знаю, как это исправить. Возможно, вам повезет больше с другим форматом поверхности или включением / отключением мультисэмплинга.

3 голосов
/ 30 ноября 2011

Я предполагаю, что происходит то, что вы пытаетесь использовать glReadPixels в закрытом окне.Если область просмотра покрыта, то результат glReadPixels не определен.

См. Как использовать glDrawPixels () и glReadPixels ()? и Проблема владения пикселями.

Как сказано здесь :

Решение состоит в создании закадрового буфера (FBO) и визуализации в FBO.

Другой вариант - убедиться, что окно не закрыто при использовании glReadPixels.

3 голосов
/ 28 ноября 2011

Я не знаю, какой Android или SDK вы используете, но в IOS, когда я делаю снимок экрана, мне нужно сделать буфер размером следующей текстуры POT, что-то вроде этого:

int x = NextPot((int)screenSize.x*retina);
int y = NextPot((int)screenSize.y*retina);

void *buffer = malloc( x * y * 4 );

glReadPixels(0,0,x,y,GL_RGBA,GL_UNSIGNED_BYTE,buffer);

Функция NextPot просто дает мне следующий размер POT, поэтому, если бы размер экрана был 320x480, x, y был бы 512x512.

Может быть, то, что вы видите - это обтекание буфера, потому что оно ожидаетбольший размер буфера?

Также это может быть причиной того, что он работает в симуляторе, а не на устройстве, у моей видеокарты нет ограничения размера POT, и я получаю похожий (странный вид) результат.

1 голос
/ 30 ноября 2011

Я получаю скриншот моей игры для Android без проблем на устройстве Android с использованием glReadPixels.

Я пока не уверен, в чем проблема в вашем случае, нужно больше информации.Итак, начнем:

  1. Я бы порекомендовал вам не указывать формат PixelStore.Я беспокоюсь о вашем выравнивании в 1 байт, вы действительно «используете это» / «знаете, что он делает»?Кажется, вы получаете именно то, что вы указываете - один дополнительный байт (посмотрите на ваше изображение, там один дополнительный пиксель все время!) Вместо полностью упакованного изображения.Поэтому попробуйте удалить это:

    glPixelStorei (GL_UNPACK_ALIGNMENT, 1);glPixelStorei (GL_PACK_ALIGNMENT, 1);

  2. Я не уверен в коде C, так как работал только в Java, но это выглядит как возможная точка:

    //ширина / высота deviceWidth = IwGxGetDeviceWidth ();deviceHeight = IwGxGetDeviceHeight ();

Получаете ли вы размер устройства?Вы должны использовать свой размер поверхности OpenGL, например:

public void onSurfaceChanged(GL10 gl, int width, int height) {
int surfaceWidth = width;
int surfaceHeight = height;
}
  1. Что вы будете делать с захваченным изображением?Знаете ли вы, что блок памяти, который вы получили от opengl, является RGBA, но все операции с изображениями не-opengl ожидают ARGB?Например, здесь, в вашем коде, вы ожидаете, что альфа будет первым битом, а не последним:

    img-> SetFormat (CIwImage :: ABGR_8888);

  2. В случае, если 1, 2 и 3 не помогли, возможно, вы захотите сохранить захваченный экран на телефон SDCard, чтобы проверить позже.У меня есть программа, которая преобразует блок opengl RGBA в обычное растровое изображение для проверки на ПК.Я могу поделиться с вами.

1 голос
/ 30 ноября 2011

У меня нет решения для исправления glReadPixels.Я предлагаю изменить свой алгоритм, чтобы избежать необходимости считывания данных с экрана.

Взгляните на эту страницу .Эти ребята сделали эффект перелистывания страниц во Flash.Это все в 2D, иллюзия достигается только с теневыми градиентами.

Я думаю, что вы можете использовать аналогичный подход, но немного лучше в 3D.По сути, вам нужно разделить эффект на три части: верхняя страница (облака), нижняя страница (девушка) и обратная сторона первой страницы.Вы должны нарисовать каждую часть отдельно.Вы можете легко нарисовать лицевую верхнюю и нижнюю страницы вместе на одном экране, вам просто нужно вызвать код рисования для каждого с предустановленной областью отсечения, которая выровнена по линии разделения, где изгибается верхняя страница.После того, как вы нарисовали верхнюю и заднюю части страницы, вы можете нарисовать серую обратную обращенную часть сверху, также выровненную по линии разделения.изображение облаков начинает изгибаться, конечно, при моем методе деформации не произойдет.Надеюсь, что это не уменьшит эффект, я думаю, что тени гораздо важнее, чтобы придать эффект глубины, и скрывают это незначительное несоответствие.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...