Plusieurs fenêtres avec OpenGL moderne?

9

J'utilise SDL2 .

Actuellement, mon seul shader a une matrice MVP et transforme les points avec.

Je calcule ma matrice de vue et de projection pour une caméra avec GLM:

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

Je l'ai recherché, mais je ne peux trouver que l'implémentation héritée de plusieurs fenêtres.

Si je crée par exemple 4 caméras et disons qu'elles sont toutes pareilles , sauf que chaque caméra a un quart d'écran différent à restituer. (Je veux donc 4 fenêtres avec le même contenu)

Comment puis-je faire ceci? Désolé si je n'ai pas donné suffisamment d'informations, n'hésitez pas à demander.

Tudvari
la source
Cherchez-vous spécifiquement à effectuer le rendu 4 fois ou simplement à effectuer un rendu une fois et à afficher le résultat à 4 endroits différents?
trichoplax
Effectuez le rendu 4 fois. Ce que j'ai écrit n'est qu'un exemple simplifié, par exemple, je veux que la caméra principale restitue une voiture à pleine fenêtre, et une autre caméra rend la voiture de côté dans un petit carré dans l'un des coins.
Tudvari
Si j'ai bien compris cela, vous devez donc diviser votre fenêtre en 4 parties par exemple et dans chaque partie rendre d'autres parties de la scène comme ça ?
narthex
Oui, mais pas strictement en 4 parties. Je veux que ce soit flexible. Taille et position flexibles du rectangle de la fenêtre d'affichage.
Tudvari
Connexe: stackoverflow.com/questions/726379/multiple-viewports-in-opengl/…
Ciro Santilli 冠状 病毒 审查 六四 事件 法轮功

Réponses:

8

Le rendu dans différentes fenêtres (parties) du même écran peut être effectué comme suit:

Par exemple, diviser l'écran en quatre parties et rendre la même scène quatre fois à chaque coin avec différents uniformes et différentes fenêtres:

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
la source
Donc avec glViewPort () je peux définir où je veux dessiner ensuite, et avec glBlendFunc je peux définir comment le GPU doit mélanger les zones qui se chevauchent (framebuffers) entre elles. Ai-je raison?
Tudvari
1
Oui, vous êtes libre de paramétrer cela. Comme les paramètres de viewportsont x, y du coin inférieur gauche du morceau et de la largeur, la hauteur du morceau. Avec le mélange, vous pouvez expérimenter.
narthex
1
pourquoi mélanger? comment est-il lié à la question?
Raxvan
3
Vous n'avez pas besoin de mélange ou de plusieurs tampons d'image. Le rendu n'écrira pas sur des pixels en dehors du rectangle glViewport actuel, vous pouvez donc simplement configurer et dessiner chaque fenêtre tour à tour. BTW vous pouvez également utiliser le test de ciseaux pour restreindre les espaces libres à un certain rectangle, au cas où vous souhaiteriez des fenêtres qui se chevauchent.
Nathan Reed
2
Le mélange n'a rien à voir avec cela et rend la réponse plus confuse. La configuration des fenêtres est tout ce qui est nécessaire
par défaut
10

Si vous écrivez votre propre Vertex / Fragment Shader, il existe une autre possibilité supplémentaire de le faire. C'est beaucoup plus compliqué mais peut être utile pour vous et / ou pour d'autres. De plus, il accélère l'ensemble du processus de dessin car il n'utilise qu'un seul appel à une commande de dessin. Le nombre maximal de fenêtres est défini par GL_MAX_VIEWPORTS et est généralement de 16.

Depuis OpenGL 4.1, la méthode glViewportArrayv existe. Il peut définir un tableau de fenêtres. Les fenêtres créées par cette méthode ont un index affecté.

Cet index peut être utilisé dans le Vertex Shader pour définir la fenêtre dans laquelle la scène est rendue. (Vous devez inclure l' extension " ARB_shader_viewport_layer_array " dans le code du shader)

Dans votre cas, je suggère de faire ce qui suit:

  • Stockez les 4 matrices de caméra dans un tampon de stockage Shader (Array of mat4) pour les avoir dans le Vertex Shader
  • Utilisez un dessin indexé , par exemple: glDrawElementsInstanced
  • utiliser la construction dans gl_InstanceID du Vertex Shader pour accéder au tableau de la matrice de la caméra
  • définissez la variable de sortie variable gl_ViewportIndex dans le Fragment Shader sur gl_InstanceID. (pour plus de détails, voir ARB_fragment_layer_viewport )
Christian_B
la source
" Cet index peut être utilisé dans le Vertex Shader pour définir la fenêtre dans laquelle la scène est rendue. " Non, il ne peut pas. Eh bien, pas sans l'extension ARB_shader_viewport_layer_array ou les équivalents AMD. Aucun de ceux-ci n'est standard dans GL 4.5. Vous pensez peut-être aux Geometry Shaders.
Nicol Bolas
@Nicol, merci pour cet indice! J'ai oublié de mentionner que vous devez inclure l'extension. Je vais modifier ma réponse.
Christian_B
5

Ceci est une copie de la réponse de @ narthex, sauf avec seulement les fenêtres puisque c'est tout ce dont vous avez besoin. Je ne sais pas pourquoi le tampon de trame / trucs de mélange est inclus dans sa réponse.

//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
défaut
la source
0

Ce sont toutes de bonnes réponses, et pourtant il existe une autre manière: (N'est-ce pas toujours le cas?)

En raison de la popularité croissante de la réalité virtuelle, les gens d'OculusVR ont développé un trio d'extensions "Multiview" appelées:

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

Ces extensions permettent de rendre plusieurs vues de la même scène en un seul appel, ce qui élimine la redondance du rendu de la même scène dans le même état du point de vue de chaque œil. Bien que créé dans le but de VR, le développeur n'est pas nécessairement limité à seulement deux vues. Cette extension permet plutôt autant de vues que MAX_VIEWS_OVR le spécifie.

Avant d'utiliser ces extensions, le développeur doit vérifier leur prise en charge dans le pilote graphique de l'utilisateur en ajoutant le code suivant:

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

À partir de là, il s'agit de configurer votre framebuffer pour utiliser cette fonctionnalité:

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

et de même dans le 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);
}

Dans une application liée au processeur, cette extension peut réduire considérablement le temps de rendu, en particulier avec les scènes plus complexes :

Temps CPU relatif entre la multivue et la stéréo standard.  Plus c'est petit, mieux c'est, avec le nombre de cubes sur l'axe des x et le temps relatif sur l'axe des y.

Jackalope
la source