Mehrere Ansichtsfenster mit modernem OpenGL?

9

Ich benutze SDL2 .

Derzeit hat mein einziger Shader eine MVP-Matrix und transformiert die Punkte damit.

Ich berechne meine Ansichts- und Projektionsmatrix für eine Kamera mit GLM:

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

Ich habe danach gesucht, kann jedoch nur die Legacy-Implementierung mehrerer Ansichtsfenster finden.

Wenn ich zum Beispiel 4 Kameras erstelle und sagen wir, dass sie alle gleich sind , außer dass jede Kamera ein anderes Viertel des Bildschirms zum Rendern hat. (Also ich möchte 4 Ansichtsfenster mit dem gleichen Inhalt)

Wie kann ich das machen? Tut mir leid, wenn ich nicht genug Informationen gegeben habe, zögern Sie nicht zu fragen.

Tudvari
quelle
Möchten Sie das Rendern speziell viermal durchführen oder nur einmal rendern und das Ergebnis an vier verschiedenen Stellen anzeigen?
Trichoplax
Führen Sie das Rendern viermal durch. Was ich geschrieben habe, ist nur ein vereinfachtes Beispiel. Ich möchte zum Beispiel, dass die Hauptkamera ein Auto am vollen Fenster rendert und eine andere Kamera das Auto von der Seite in einem kleinen Quadrat in einer der Ecken rendert.
Tudvari
Wenn ich das richtig verstanden , so dass Sie 4 Teile zum Beispiel teilen Sie Ihre Fenster müssen und in jedem Teil machen andere Teile der Szene wie das ?
Narthex
Ja, aber nicht unbedingt 4 Teile. Ich möchte, dass es flexibel ist. Flexible Größe und Position des Ansichtsfenster-Rechtecks.
Tudvari
Siehe auch
Ciro Santilli 法轮功 病毒 审查 六四 事件 21

Antworten:

8

Das Rendern in verschiedene Ansichtsfenster (Teile) desselben Bildschirms kann wie folgt erfolgen:

Teilen Sie beispielsweise den Bildschirm in vier Teile und rendern Sie dieselbe Szene viermal in jeder Ecke mit unterschiedlichen Uniformen und unterschiedlichen Ansichtsfenstern:

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
Narthex
quelle
Mit glViewPort () kann ich also definieren, wo ich als nächstes zeichnen möchte, und mit glBlendFunc kann ich definieren, wie die GPU die überlappenden Bereiche (Framebuffer) miteinander mischen soll. Hab ich recht?
Tudvari
1
Ja, Sie können das frei parametrisieren. Als Parameter von viewportsind x, y der linken unteren Ecke des Blocks und Breite, Höhe des Blocks. Mit dem Mischen können Sie experimentieren.
Narthex
1
warum mischen? Wie hängt es mit der Frage zusammen?
Raxvan
3
Sie benötigen keine Mischung oder mehrere Framebuffer. Beim Rendern werden keine Pixel außerhalb des aktuellen glViewport-Rechtecks ​​geschrieben. Sie können also jedes Ansichtsfenster nacheinander einrichten und zeichnen. BTW können Sie auch die Verwendung Scheren Test klärt auf ein bestimmtes Rechteck zu beschränken, falls Sie überlappende Ansichtsfenstern wollen.
Nathan Reed
2
Das Mischen hat nichts damit zu tun und macht die Antwort verwirrender. Das Einrichten der Ansichtsfenster ist alles, was benötigt wird
Standard
10

Wenn Sie Ihren eigenen Vertex / Fragment Shader schreiben, gibt es eine weitere zusätzliche Möglichkeit, dies zu tun. Es ist viel komplizierter, kann aber für Sie und / oder andere nützlich sein. Außerdem wird der gesamte Zeichenvorgang beschleunigt, da nur ein Aufruf eines Zeichenbefehls verwendet wird. Die maximale Anzahl von Ansichtsfenstern wird von GL_MAX_VIEWPORTS definiert und beträgt normalerweise 16.

Seit OpenGL 4.1 existiert die Methode glViewportArrayv . Es kann ein Array von Ansichtsfenstern definieren. Den mit dieser Methode erstellten Ansichtsfenstern ist ein Index zugewiesen.

Dieser Index kann im Vertex Shader verwendet werden, um das Ansichtsfenster festzulegen, in dem die Szene gerendert wird. (Sie müssen die Erweiterung " ARB_shader_viewport_layer_array " in den Shader-Code aufnehmen.)

In Ihrem Fall würde ich Folgendes vorschlagen:

  • Speichern Sie die 4 Kameramatrizen in einem Shader-Speicherpuffer (Array von mat4), um sie im Vertex-Shader zu haben
  • Verwenden Sie eine indizierte Zeichnung , zum Beispiel: glDrawElementsInstanced
  • Verwenden Sie die integrierte gl_InstanceID des Vertex Shader, um auf das Kameramatrix-Array zuzugreifen
  • Setzen Sie die Build-In-Variable-Ausgabevariable gl_ViewportIndex im Fragment Shader auf die gl_InstanceID. (Details siehe ARB_fragment_layer_viewport )
Christian_B
quelle
" Dieser Index kann im Vertex Shader verwendet werden, um das Ansichtsfenster festzulegen, in dem die Szene gerendert wird. " Nein, das kann nicht. Nicht ohne die Erweiterung ARB_shader_viewport_layer_array oder die AMD-Entsprechungen. Keines davon ist Standard in GL 4.5. Sie denken vielleicht an Geometry Shader.
Nicol Bolas
@Nicol, Danke für diesen Hinweis! Ich habe vergessen zu erwähnen, dass Sie die Erweiterung einschließen müssen. Ich werde meine Antwort bearbeiten.
Christian_B
5

Dies ist eine Kopie der Antwort von @ narthex, außer nur mit den Ansichtsfenstern, da dies alles ist, was Sie benötigen. Ich bin mir nicht sicher, warum der Frame Buffer / Blend in seiner Antwort enthalten ist.

//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
Standard
quelle
0

Dies sind alles gute Antworten, und doch gibt es einen anderen Weg: (Gibt es nicht immer?)

Aufgrund der wachsenden Beliebtheit der virtuellen Realität haben die Mitarbeiter von OculusVR ein Trio von "Multiview" -Erweiterungen entwickelt, die heißen:

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

Mit diesen Erweiterungen können mehrere Ansichten derselben Szene in einem einzigen Zeichenaufruf gerendert werden, wodurch die Redundanz beim Rendern derselben Szene im selben Zustand aus Sicht jedes Auges beseitigt wird. Obwohl für VR-Zwecke erstellt, ist der Entwickler nicht unbedingt auf nur zwei Ansichten beschränkt. Diese Erweiterung ermöglicht vielmehr so ​​viele Ansichten, wie MAX_VIEWS_OVR angibt.

Bevor Sie diese Erweiterungen verwenden, sollte der Entwickler den Grafiktreiber des Benutzers auf Unterstützung prüfen, indem er den folgenden Code hinzufügt:

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 );
}

Von dort aus müssen Sie Ihren Framebuffer einrichten, um diese Funktion nutzen zu können:

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

und ebenfalls im Shader:

#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);
}

In einer CPU-gebundenen Anwendung kann diese Erweiterung die Renderzeit erheblich verkürzen, insbesondere bei komplexeren Szenen :

Relative CPU-Zeit zwischen Multiview und normalem Stereo.  Je kleiner desto besser, mit der Anzahl der Würfel auf der x-Achse und der relativen Zeit auf der y-Achse.

Jackalope
quelle