OpenGL ES-glReadPixels
Я делаю скриншот с glReadPixels для выполнения эффекта "перекрестного" между двумя изображениями.
на симуляторе Marmalade SDK скриншот сделан просто отлично, и эффект "перекрестного" работает как удовольствие:
однако именно так он выглядит на устройствах 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 ответов
Это ошибка водителя. Просто.
водитель неправильно понял высоту поверхности в видеопамяти. Вы можете ясно видеть это в верхних строчках. Также мусор, который вы видите в нижней части изображения, - это память, где драйвер думает изображение сохраняется, но там есть разные данные. Возможно, текстуры / данные вершин.
и извините, я не знаю, как это исправить. Возможно, Вам повезет с другим форматом поверхности или с помощью включение / выключение мультисамплинга.
В конце концов, это было отсутствие памяти. "Новый uint8[dataLength];" никогда не возвращал существующий указатель, таким образом, весь процесс был поврежден.
Тома, твоя идея очистить буфер на самом деле помогла мне решить проблему. Спасибо.
Я не знаю об android или SDK, который вы используете, но на IOS, когда я делаю снимок экрана, я должен сделать буфер размером следующей текстуры пота, что-то вроде этого:
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 просто дает мне следующий размер банка, поэтому,если размер экрана был 320x480, x, y будет 512x512.
может быть, то, что вы видите, - это обертывание буфера, потому что он ожидает большего размера буфера ?
также это может быть причиной для его работа в симуляторе, а не на устройстве, моя видеокарта не имеет ограничения по размеру горшка, и я получаю аналогичный (странный) результат.
Я предполагаю, что происходит то, что вы пытаетесь использовать glReadPixels
на окне, которое закрыто. Если область просмотра покрыта, то результат glReadPixels
неопределено.
посмотреть как использовать glDrawPixels () и glReadPixels ()? и Проблема Собственности Пикселей.
как сказал здесь :
решение сделать внеэкранный буфер (ФБО) и оказывает ФБО.
другой опция - убедиться, что окно не закрыто при использовании glReadPixels
.
Я получаю скриншот моей игры для android без каких-либо проблем на устройстве android с помощью glReadPixels.
Я еще не уверен, в чем проблема в вашем случае, нужна дополнительная информация. Итак, начнем:
-
Я бы рекомендовал вам не указывать формат PixelStore. Я беспокоюсь о вашем выравнивании в 1 байт, вы действительно "используете его" / "знаете, что он делает"? Кажется, вы получаете именно то, что вы указываете - один дополнительный байт(посмотрите на свое изображение, там один дополнительный пиксель все время!) вместо полностью упакованного изображения. Поэтому попробуйте удалить это:
glPixelStorei(GL_UNPACK_ALIGNMENT, 1); glPixelStorei (GL_PACK_ALIGNMENT, 1);
-
Я не уверен в коде C, так как я работал только на java, но это выглядит как возможный пункт:
/ ширина/высота deviceWidth = IwGxGetDeviceWidth(); deviceHeight = IwGxGetDeviceHeight ();
вы получаете размер устройства? Вы должны использовать свой OpenGL размер поверхности, например:
public void onSurfaceChanged(GL10 gl, int width, int height) {
int surfaceWidth = width;
int surfaceHeight = height;
}
-
что вы делаете дальше с захваченным изображением? Вы знаете, что блок памяти, который вы получили от opengl, - это RGBA, но все операции с изображениями не opengl ожидают ARGB? Например, здесь в вашем коде вы ожидаете, что alpha будет первым битом, а не последним:
img - >SetFormat(CIwImage:: ABGR_8888);
в случае, если 1, 2 и 3 не помогли, вы можете сохранить захваченный экран на телефон sdcard для изучения позже. У меня есть программа, которая преобразует блок opengl RGBA в обычное растровое изображение для изучения на ПК. Я могу поделиться с вами.
У меня нет решения для исправления glReadPixels. Я предлагаю вам изменить свой алгоритм, чтобы избежать необходимости считывать данные с экрана.
посмотри на этой странице. Эти ребята сделали эффект переворота страницы все в Flash. Это все в 2D, иллюзия достигается только с теневыми градиентами.
Я думаю, что вы можете использовать аналогичный подход, но немного лучше в 3D. В основном вам придется разделить на три части: передний перед верхней страницей (облака), нижней страницей (девушка) и задней стороной первой страницы. Вы должны нарисовать каждую часть отдельно. Вы можете легко нарисовать переднюю верхнюю страницу и нижнюю страницу вместе на одном экране, вам просто нужно вызвать код чертежа для каждого с предустановленной областью отсечения, которая выровнена с линией разделения, где изгибается верхняя страница. После того, как вам нужно нарисовать верхние и задние разделы страницы, вы можете нарисовать серую заднюю часть сверху, также выровненную по разрезу линия.
при таком подходе единственное, что вы теряете, это немного деформации, когда изображение облаков начинает изгибаться, конечно, никакой деформации не произойдет с моим методом. Надеюсь, что это не уменьшит эффект, я думаю, что тени намного важнее, чтобы дать эффект глубины и скроет эту незначительную непоследовательность.