Кілька вікон перегляду із сучасним OpenGL?


9

Я використовую SDL2 .

Наразі мій єдиний шейдер має матрицю MVP і перетворює точки з ним.

Я обчислюю матрицю перегляду та проекції для камери з GLM:

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

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

Якщо я створимо, наприклад, 4 камери і скажемо, що вони всі однакові , за винятком того, що кожна камера має різну чверть екрану для відображення. (Тому я хочу 4 оглядових області з однаковим вмістом)

Як я можу це зробити? Вибачте, якщо я не дав достатньо інформації, не соромтеся запитати.


Ви спеціально хочете виконати візуалізацію 4 рази або просто зробити один раз і відобразити результат у 4 різних місцях?
трихоплакс

Виконайте візуалізацію 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 я можу визначити, як GPU повинен поєднувати ділянки, що перекриваються (framebuffers), один з одним. Я прав?
Тудварі

1
Так, ви можете це параметризувати. В якості параметрів viewportє х, у лівого нижнього кута шматка і ширина, висота шматка. За допомогою суміші можна експериментувати.
нартекс

1
чому змішування? як це пов’язано з питанням?
Раксван

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

2
Змішування не має нічого спільного з цим і робить відповідь більш заплутаною. Налаштування вікон перегляду - це все, що потрібно
за замовчуванням

11

Якщо ви пишете власний штрих вершин / фрагментів, є ще одна додаткова можливість зробити це. Це набагато складніше, але може бути корисним для вас та / або інших. Крім того, це прискорює весь процес малювання, оскільки він використовує лише один виклик команди малювання. Максимальна кількість вікон перегляду визначається GL_MAX_VIEWPORTS і зазвичай становить 16.

Оскільки OpenGL 4.1 існує метод glViewportArrayv . Він може визначити масив Viewports. У вікнах перегляду, створених цим методом, призначений індекс.

Цей індекс може бути використаний у вершинній шейдері для встановлення вікна перегляду, на який відображається сцена. (Ви повинні включити розширення " ARB_shader_viewport_layer_array " у код шейдера)

У вашому випадку я б запропонував зробити наступне:

  • Зберігайте 4 матриці камер у буфері для зберігання шейдерів (масив mat4), щоб мати їх у вершинній шейдері
  • Використовуйте індексований малюнок , наприклад: glDrawElementsInstanced
  • використовувати вбудований gl_InstanceID Vertex Shader для доступу до матричного масиву камери
  • встановити збірку змінної вихідної змінної 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.