Несколько окон просмотра с современным OpenGL?


9

Я использую SDL2 .

В настоящее время мой единственный шейдер имеет матрицу MVP и преобразует точки с ее помощью.

Я рассчитываю свою матрицу просмотра и проекции для камеры с GLM:

glm::lookAt(pos, pos + forward, up);
glm::perspective(fov, aspectRatio, zNear, zFar);

Я искал его, но я могу найти только устаревшую реализацию нескольких окон просмотра.

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

Как я могу это сделать? Извините, если я не дал достаточно информации, не стесняйтесь спрашивать.


Вы специально хотите выполнить рендеринг 4 раза или просто сделать рендеринг один раз и отобразить результат в 4 разных местах?
Trichoplax

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

Если я правильно понял, так что вам нужно разделить окно, например, на 4 части и в каждой части визуализировать другие части сцены, как это ?
притвор

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

Ответы:


8

Рендеринг в разные видовые окна (части) одного экрана может быть выполнен следующим образом:

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

bindFramebuffer();
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
scene->setConstPerFrameUniforms();

//left bottom
glViewport(0, 0, WindowWidth*0.5, WindowHeight*0.5);
scene->setVarPerFrameUniforms(1);
scene->draw();

//right bottom
glViewport(WindowWidth*0.5, 0, WindowWidth*0.5, WindowHeight*0.5);
scene->setVarPerFrameUniforms(2);
scene->draw();

//left top
glViewport(0, WindowHeight*0.5, WindowWidth*0.5, WindowHeight*0.5);
scene->setVarPerFrameUniforms(3);
scene->draw();

//right top
glViewport(WindowWidth*0.5, WindowHeight*0.5, WindowWidth*0.5, WindowHeight*0.5);
scene->setVarPerFrameUniforms(4);
scene->draw();

glViewport(0, 0, WindowWidth, WindowHeight); //restore default

Таким образом, с помощью glViewPort () я могу определить, где я хочу рисовать дальше, а с помощью glBlendFunc я могу определить, как графический процессор должен смешивать перекрывающиеся области (кадровые буферы) друг с другом. Я прав?
Тудвари

1
Да, вы можете параметризировать это. В качестве параметров viewportиспользуются x, y левого нижнего угла фрагмента и ширина, высота фрагмента. С смешением вы можете экспериментировать.
притвор

1
зачем смешивать? как это связано с вопросом?
Раксван

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

2
Смешивание не имеет к этому никакого отношения и делает ответ более запутанным. Настройка окна просмотра - это все, что нужно
умолчанию

11

Если вы пишете свой собственный Vertex / Fragment Shader, есть еще одна дополнительная возможность сделать это. Это намного сложнее, но может быть полезно для вас и / или других. Кроме того, он ускоряет весь процесс рисования, поскольку использует только один вызов команды рисования. Максимальное количество Viewports определяется GL_MAX_VIEWPORTS и обычно составляет 16.

Начиная с OpenGL 4.1, метод glViewportArrayv существует. Он может определять массив Viewports. Видовые окна, созданные этим методом, имеют присвоенный индекс.

Этот индекс может быть использован в вершинном шейдере для установки области просмотра, в которой отображается сцена. (Вы должны включить расширение « ARB_shader_viewport_layer_array » в код шейдера)

В вашем случае я бы предложил сделать следующее:

  • Сохраните 4 матрицы камер в буфере хранения шейдеров (массив mat4), чтобы поместить их в вершинный шейдер
  • Используйте индексированный рисунок , например: glDrawElementsInstanced
  • используйте сборку gl_InstanceID вершинного шейдера для доступа к матричному массиву камеры
  • установите выходную переменную построения в переменной gl_ViewportIndex в шейдере фрагмента как gl_InstanceID. (подробнее см. ARB_fragment_layer_viewport )

« Этот индекс можно использовать в вершинном шейдере для установки области просмотра, в которой отображается сцена. » Нет, это невозможно. Ну, не без расширения ARB_shader_viewport_layer_array или эквивалентов AMD. Ни один из них не является стандартным в GL 4.5. Возможно, вы думаете о геометрических шейдерах.
Никол Болас

@Nicol, спасибо за подсказку! Я забыл упомянуть, что вы должны включить расширение. Я отредактирую свой ответ.
Christian_B

5

Это копия ответа @ narthex, за исключением только областей просмотра, поскольку это все, что вам нужно. Я не уверен, почему кадровый буфер / смесь смешивания включены в его ответ.

//left bottom
glViewport(0, 0, WindowWidth*0.5, WindowHeight*0.5);
scene->draw();

//right bottom
glViewport(WindowWidth*0.5, 0, WindowWidth*0.5, WindowHeight*0.5);
scene->draw();

//left top
glViewport(0, WindowHeight*0.5, WindowWidth*0.5, WindowHeight*0.5);
scene->draw();

//right top
glViewport(WindowWidth*0.5, WindowHeight*0.5, WindowWidth*0.5, WindowHeight*0.5);
scene->draw();

glViewport(0, 0, WindowWidth, WindowHeight); //restore default

1

Все это хорошие ответы, но есть и другой способ: (не всегда ли?)

В связи с растущей популярностью виртуальной реальности, сотрудники OculusVR разработали трио расширений «Multiview», которые называются:

  1. OVR_multiview ,
  2. OVR_multiview2 , &
  3. OVR_multiview_multisampled_render_to_texture

Эти расширения позволяют визуализировать несколько видов одной и той же сцены в одном вызове отрисовки, устраняя избыточность рендеринга одной и той же сцены в одном и том же состоянии с точки зрения каждого глаза. Хотя созданный для целей VR, разработчик не обязательно ограничен просто двумя представлениями. Скорее, это расширение позволяет использовать столько представлений, сколько указано в MAX_VIEWS_OVR .

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

const GLubyte* extensions = GL_CHECK( glGetString( GL_EXTENSIONS ) );
char * found_extension = strstr( (const char*)extensions, "GL_OVR_multiview" );
if (NULL == found_extension)
{
     exit( EXIT_FAILURE );
}

Оттуда, это вопрос настройки вашего кадрового буфера для использования этой функции:

glFramebufferTextureMultisampledMultiviewOVR = PFNGLFRAMEBUFFERTEXTUREMULTISAMPLEDMULTIVIEWOVR(eglGetProcAddress("glFramebufferTextureMultisampleMultiviewOVR"));
glFramebufferTextureMultisampledMultiviewOVR (GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, textureID, 0, 0, 2);

и аналогично в шейдере:

#version 300 es
#extension GL_OVR_multiview : enable

layout(num_views = 2) in;
in vec3 vertexPosition;
uniform mat4 MVP[2];

void main(){
    gl_Position = MVP[gl_ViewID_OVR] * vec4(vertexPosition, 1.0f);
}

В приложении с привязкой к ЦП это расширение может значительно сократить время рендеринга, особенно в более сложных сценах :

Относительное время процессора между многовидовым и обычным стерео.  Чем меньше, тем лучше, с количеством кубиков на оси X и относительным временем на оси Y.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.