2016-03-10 1 views
3

J'ai travaillé sur ce problème pendant un certain temps et il est temps de demander l'aide de la communauté. J'ai lu beaucoup d'autres questions de StackOverflow sur ce sujet et n'ai pas encore trouvé une solution pertinente.OpenGL: Rendu de texture plus grand que la taille de l'écran et glViewport

J'ai un projet Android OpenGL bien établi qui restitue une texture, avant de restituer cette texture à l'écran. Ce mécanisme est fondamental pour mon application et j'ai beaucoup d'histoire et de confiance en elle. J'ai récemment ajouté de nouvelles fonctionnalités pour prendre en interne une capture d'écran du rendu; c'est-à-dire que mon application est capable de sauvegarder la texture rendue dans un fichier. Ces images ont traditionnellement été exactement la taille de l'affichage.

Maintenant, je veux générer des images plus grandes que la taille de l'écran, de sorte que les captures d'écran générées reflètent la taille d'image plus grande, mais sont également proportionnées à la taille de l'écran. Cela devrait être un processus simple et direct, cependant, je reçois des résultats inattendus. La capture d'écran qui en résulte est la taille correcte, mais est vide, sauf pour une zone de la taille de l'écran. Par exemple, si la texture restituée et la capture d'écran résultante sont censées être 4 fois la taille d'affichage de l'écran (deux fois la taille de l'écran pour chaque dimension X et Y), le fichier d'image sera la taille prévue, mais seulement le quadrant de l'image aura été dessiné. Dans cet exemple, voici le resulting generated screenshot. Ma fenêtre d'affichage est 768x887 et la capture d'écran qui en résulte est correctement 1536x1774 et dans la capture d'écran, la seule zone colorée est 768x887. Pour nos besoins ici, mon shader fragment pour le rendu de la texture est un test de coordonnées cartographie à l'écran ...

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

Notez que lorsque nous tirons cette même texture à l'écran lors de l'exécution, la pleine l'écran est coloré en accord avec ce shader. Pourquoi un seul quadrant de la capture d'écran est-il rempli, au lieu du tout? Et pourquoi, lorsque cette texture est dessinée à l'écran, n'affiche-t-elle que la partie qui correspond à la taille de l'écran, plutôt que le tout avec les trois quadrants vides?

Je reçois la taille d'origine de la fenêtre de GLSurfaceView.Renderer.onSurfaceChanged() et la stocke dans _viewportWidth et _viewportHeight. Lorsque je crée la texture de tampon de trame, je l'ai créé traditionnellement directement à partir de _viewportWidth et _viewportHeight. Maintenant, je l'ai, à titre d'exemple ...

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

... et générer la mémoire tampon de trame de taille _frameBufferWidth par _frameBufferHeight. J'appelle également glViewport() deux fois. Après mon premier appel à glBindframebuffer() pour rendre à la texture et non à l'écran, et après avoir effectué la gestion des erreurs pertinentes, j'appelle glViewport(0, 0, _frameBufferWidth, _frameBufferHeight), qui passe sans erreur. Quand je veux plus tard dessiner cette texture à l'écran, je fais mon deuxième appel glBindframebuffer(), et immédiatement après, appelez glViewport(0, 0, _viewportWidth, _viewportHeight). L'idée est, le rendu original à la texture se passe dans une image de taille _frameBufferWidth par _frameBufferHeight et quand nous présentons à l'écran, nous voulons une taille _viewportWidth par.

Des idées que je pourrais manquer? Merci d'avance.

EDIT (10 Mars, 2016): Je viens d'essayer quality=0.5f et je reçois des résultats inhabituels. Je préférerais partager plus d'images pour clarifier ce scénario, mais je suis un nouveau membre et j'en ai seulement deux.Lorsque nous dessinons à l'écran avec quality=0.5f, l'écran est correctement coloré selon le code GLSL ci-dessus: l'affichage est identique au quadrant supérieur gauche 768x887 de la capture d'écran ci-dessus (correspondant à quality=2f). Le quality=0.5fscreenshot that is generated, cependant, est coloré différemment de l'écran. Cette capture d'écran a correctement la taille 384x443 prévue, mais est toujours rendue comme si elle est 768x887 et juste en rognant une partie 384x443.

Même si le code suggère le contraire, il semble que nous rendre toujours à un _viewportWidth par zone _viewportHeight, plutôt que l'intention _frameBufferWidth par zone _frameBufferHeight.

J'ai fondamentalement un quad plein écran pour les deux passes de rendu et je suis habitué à ce qui fonctionne bien. Quand je rends à l'écran, j'échantillon, la texture que je viens de rendu à:

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

Le u_sampler accède à la texture nous rendu et uv est dans [0,1] pour les deux dimensions. Donc, pour que l'écran affiche quelque chose, il doit faire une recherche de texture pour obtenir ses informations de couleur. Ainsi, le rouge et le bleu vif montrés sur l'écran doivent exister dans le framebuffer à l'origine, même s'il manque dans la capture d'écran de taille correcte.

+0

Tout cela semble assez raisonnable. Avez-vous d'autres appareils sur lesquels vous pouvez le tester? Idéalement de différents fournisseurs, avec différents GPU? –

+0

Salut Reto. Je viens de tester cela sur un autre appareil et j'ai eu le même résultat. J'ai commencé avec un Samsung Galaxy Tab A et j'ai juste essayé un LG G2. Selon mes requêtes OpenGL, les deux utilisent le moteur de rendu Qualcomm Adreno et permettent une taille maximale de la texture et des dimensions de viewport de 4096. Je crois avoir eu l'idée de plusieurs appels glViewport de l'un de vos autres [http://stackoverflow.com/questions/25937282/opengl-es-dessin-à-texture). Toute perspective supplémentaire que vous pourriez fournir serait extrêmement bénéfique! – patriot4code

+0

Du son de cela, vous faites une opération blit (glBlitFramebuffer). Ceux-ci ont toujours travaillé pour moi. Pourriez-vous poster les appels GL précis que vous utilisez? – Swifter

Répondre

1

J'ai rencontré le même problème avec avant, comme sur iOS, également avec OpenGL ES. J'ai essayé de rendre le framebuffer d'un 4096 * 4096 et c'est dans le coin supérieur gauche.

La solution que je trouve est d'ajouter

glViewport(0, 0, 4096, 4096) 

avant toute autre fonction telle que

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

dans la fonction principale rendu.

j'ai pu le rendre plus tard avec

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

comme glViewport se traduira par la normalisation de coordonnées à la coordonnée pixel. Une autre chose à mentionner est que, sur iOS, la taille de la vue n'est pas en pixel mais au point, je dois donc la multiplier par 3. Vous pouvez vérifier si vous obtenez la coordonnée pixel réelle sur Android.