Arhn - архитектура программирования

OpenGL ES — glReadPixels

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

В симуляторе Marmalade SDK скриншот сделан просто отлично, а эффект «перехода» работает отлично: enter image  описание здесь

Однако вот как это выглядит на устройствах iOS и Android — повреждено: введите здесь описание изображения
(источник: eikona.info)

Я всегда читаю экран как 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);
}

  • Если вы удалите свой блок up-down, исчезнет ли повреждение? Просто вверх ногами? Или он поврежден и вверх ногами? 21.11.2011
  • Дело в том, что у меня нет устройства, поэтому мне нужно отправить своему клиенту, затем ждать, пока он установит и протестирует... все это может занять до пары дней :-( 21.11.2011
  • Комментарии выше теперь неуместны после повторного редактирования моего сообщения, чтобы отразить мои новые выводы. 27.11.2011
  • Попробуйте memset обнулить буфер после выделения. Таким образом, вы можете сказать, действительно ли что-либо было записано с помощью вызова glReadPixels. 27.11.2011
  • В конце концов, это была нехватка памяти. Новый uint8[dataLength]; никогда не возвращал существующий указатель, поэтому весь процесс был поврежден. TomA, твоя идея по очистке буфера действительно помогла мне решить проблему. Но как я могу дать вам +100 баллов? Пожалуйста, пришлите ответ, чтобы я мог наградить вас. Спасибо. 28.11.2011
  • @TomA: Обратите внимание, что ваш комментарий направил Билла на правильный путь, и он хотел бы дать вам награду в 100 баллов за подсказку - поспешите вернуться и изменить свой ответ в течение следующих 18 часов. :) 04.12.2011
  • Нет, на самом деле это был не ответ, а просто намек. Я рад, что смог помочь. Ваше здоровье! 04.12.2011

Ответы:


1

Это баг драйвера. Просто как тот.

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

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

27.11.2011
  • Хотелось бы, чтобы это было правдой, повреждение очевидно как в iOS, так и в Android, так что что-то еще должно быть не так на моей стороне... 28.11.2011
  • Билл, скорее всего это один и тот же 3D-чип SGX с одним и тем же ARM-драйвером на Android и iOS. 28.11.2011

  • 2

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

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

    30.11.2011

    3

    Я не знаю об 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, и я получаю аналогичный (странно выглядящий) результат.

    28.11.2011

    4

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

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

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

    Решение состоит в том, чтобы сделать внеэкранный буфер (FBO) и выполнить рендеринг в FBO.

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

    30.11.2011

    5

    Я без проблем получаю скриншот своей игры для 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 не помогли, вы можете сохранить захваченный экран на SD-карту телефона, чтобы изучить позже. У меня есть программа, которая преобразует блок opengl RGBA в обычное растровое изображение для проверки на ПК. Я могу поделиться им с вами.

    30.11.2011

    6

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

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

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

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

    30.11.2011
    Новые материалы

    Коллекции публикаций по глубокому обучению
    Последние пару месяцев я создавал коллекции последних академических публикаций по различным подполям глубокого обучения в моем блоге https://amundtveit.com - эта публикация дает обзор 25..

    Представляем: Pepita
    Фреймворк JavaScript с открытым исходным кодом Я знаю, что недостатка в фреймворках JavaScript нет. Но я просто не мог остановиться. Я хотел написать что-то сам, со своими собственными..

    Советы по коду Laravel #2
    1-) Найти // You can specify the columns you need // in when you use the find method on a model User::find(‘id’, [‘email’,’name’]); // You can increment or decrement // a field in..

    Работа с временными рядами спутниковых изображений, часть 3 (аналитика данных)
    Анализ временных рядов спутниковых изображений для данных наблюдений за большой Землей (arXiv) Автор: Рольф Симоэс , Жильберто Камара , Жильберто Кейрос , Фелипе Соуза , Педро Р. Андраде ,..

    3 способа решить квадратное уравнение (3-й мой любимый) -
    1. Методом факторизации — 2. Используя квадратичную формулу — 3. Заполнив квадрат — Давайте поймем это, решив это простое уравнение: Мы пытаемся сделать LHS,..

    Создание VR-миров с A-Frame
    Виртуальная реальность (и дополненная реальность) стали главными модными терминами в образовательных технологиях. С недорогими VR-гарнитурами, такими как Google Cardboard , и использованием..

    Демистификация рекурсии
    КОДЕКС Демистификация рекурсии Упрощенная концепция ошеломляющей О чем весь этот шум? Рекурсия, кажется, единственная тема, от которой у каждого начинающего студента-информатика..