2016-03-10 2 views
3

Я некоторое время работаю над этой проблемой, и пришло время обратиться к большему сообществу за помощью. Я прочитал много других вопросов StackOverflow по этой теме и еще не нашел подходящего решения.OpenGL: Render-to-texture больше размера экрана и glViewport

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

Теперь я хочу сгенерировать изображения, размер которых больше размера экрана, так что создаваемые скриншоты отражают больший размер изображения, но также масштабируются до размера экрана при отображении на экране. Это должно быть простым и легким процессом, однако я получаю неожиданные результаты. Результирующий снимок экрана имеет правильный размер, но пуст, за исключением области размера экрана. Например, если обработанная текстура и результирующий скриншот должны быть в 4 раза больше размера экрана (в два раза больше размера экрана для каждого измерения X и Y), файл изображения экрана будет иметь размер, но только верхний левый квадрант изображения будет нарисован. В этом примере приведено значение resulting generated screenshot. Мое окно просмотра - 768x887, и полученный скриншот правильно 1536x1774, и в пределах снимка экрана единственная цветная область - 768x887. Для наших целей здесь, мой пиксельный шейдер для рендеринга в текстуру тест отображения координат на экране ...

gl_FragColor = vec4(uv.x, 0.0, uv.y, 1.0); // during render to texture 

Обратите внимание, что, когда мы рисуем эту же текстуру на экране во время выполнения, полная экран окрашен в соответствии с этим шейдером. Почему только один квадрант скриншота заполнен, а не все? И почему, когда эта текстура рисуется на экране, отображает ли она только ту часть, которая является размером экрана, а не все с тремя пустыми квадрантами?

Получаю первоначальный размер области просмотра от GLSurfaceView.Renderer.onSurfaceChanged() и храните его в _viewportWidth и _viewportHeight. Когда я создаю текстуру буфера кадров, я традиционно создавал ее непосредственно из _viewportWidth и _viewportHeight. Теперь у меня есть, как пример ...

float quality = 2f; 
_frameBufferWidth = (int)((float)_viewportWidth * quality); 
_frameBufferHeight = (int)((float)_viewportHeight * quality); 

... и генерировать буфер кадров размером _frameBufferWidth_frameBufferHeight путем.

Я также звоню glViewport() дважды. После моего первого звонка на glBindframebuffer(), чтобы отобразить текстуру, а не экран, и после выполнения соответствующей обработки ошибок я вызываю glViewport(0, 0, _frameBufferWidth, _frameBufferHeight), который проходит без ошибок. Когда я позже захочу нарисовать эту текстуру на экране, я сделаю свой второй звонок glBindframebuffer(), и сразу после этого позвоните glViewport(0, 0, _viewportWidth, _viewportHeight). Идея заключается в том, что оригинальная визуализация текстуры идет в _frameBufferWidth размером _frameBufferHeight, и когда мы представляем ее на экране, мы хотим получить _viewportWidth размером _viewportHeight.

Любые идеи, что мне может не хватать? Заранее спасибо.

EDIT (10 марта 2016): Я просто попытался quality=0.5f и я получаю необычные результаты. Я бы предпочел поделиться больше изображений, чтобы прояснить этот сценарий, но я новый участник, и мне разрешено только два.Когда мы рисуем на экране с quality=0.5f, экран правильно окрашивается в соответствии с кодом GLSL выше: дисплей идентичен верхнему левому квадранту 768x887 скриншота, связанного выше (соответствует quality=2f). Однако цвет quality=0.5fscreenshot that is generated отличается от экрана. Этот скриншот правильно имеет размер 384x443, но он все еще отображается как 768x887 и просто вырезает часть 384x443.

Даже если код предполагает, в противном случае, кажется, что мы всегда рендеринга в _viewportWidth по _viewportHeight области, а не предполагаемой _frameBufferWidth_frameBufferHeight по площади.

У меня в основном полноэкранный квадрат для обоих проходов рендеринга, и я привык к тому, что работает нормально. Когда я вынести на экран, я образец текстуры я просто оказанной:

gl_FragColor = texture2D(u_sampler, uv); // during render to screen 

u_sampler обращается текстуру, оказанной и uv находится в [0,1] для обоих размеров. Поэтому, чтобы экран отображал что-либо, он должен выполнять поиск текстуры, чтобы получить информацию о цвете. Таким образом, ярко-красный и синий, отображаемые на экране, должны существовать в фреймбуфере изначально, даже если он отсутствует на скриншоте с правильным размером.

+0

Все это звучит вполне разумно. У вас есть другие устройства, на которых вы можете проверить его? В идеале от разных поставщиков, с разными графическими процессорами? –

+0

Hi Reto. Я просто проверил это на другом устройстве и получил тот же результат. Я начал с Samsung Galaxy Tab A и просто попробовал LG G2. Согласно моим запросам OpenGL, оба используют средство рендеринга Qualcomm Adreno и позволяют размер макс. Текстуры и размер видовых экранов 4096. Я считаю, что я получил представление о нескольких вызовах glViewport от одного из ваших других [ответов] (http://stackoverflow.com/вопросы/25937282/OpenGL-эс-рисунок в текстуру). Любая дополнительная перспектива, которую вы могли бы предоставить, была бы очень полезной! – patriot4code

+0

Из-за этого вы делаете операцию blit (glBlitFramebuffer). Они всегда работали на меня. Не могли бы вы разместить точные вызовы GL, которые вы используете? – Swifter

ответ

1

Я встретил ту же проблему с ранее, как и на iOS, также с openGL ES. Я попытался отобразить фреймбуфер 4096 * 4096 и он находится в верхнем левом углу.

Решение, которое я нашел, чтобы добавить

glViewport(0, 0, 4096, 4096) 

перед любой другой функции, такие как

glClearColor(0, 0, 0, 1); 
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 

в основной функции визуализации.

Я был в состоянии сделать его позже с

glViewport(0, 0, view.bounds.width*3, view.bounds.height*3); 

в glViewport переведет нормированные координаты пикселя координат.

Еще одна вещь, которая стоит упомянуть, что размер iOS-вида не в пикселях, а в том числе, поэтому мне нужно умножить его на 3. Вы можете проверить, действительно ли вы получили фактическую координату пикселей на Android.