Comment éviter les étirements momentanés sur l'autorotation des applications iOS OpenGL ES

Cela m'a dérangé récemment. Il est assez simple de mettre en place une application OpenGL ES qui prend en charge à la fois le portrait et le paysage. Mais pendant l'autorotation, le système semble étirer de force le tampon de rendu aux nouvelles dimensions une fois, autorotate, puis appeler l'habituel -layoutSubviews -> -resizeFromLayer: etc. afin que les drawables puissent être ajustés aux nouvelles dimensions de la window.

La plupart des applications que j'ai vues qui supportent le portrait et le paysage semblent se contenter de cette approche facile. Mais je me request si je peux faire mieux …

Peut-être que je devrais intercepter l'autorotation avant qu'elle ne se produise (en utilisant les methods habituelles de UIViewController ), "étendre" une fois le tampon de rendu à un carré parfait de la taille d'écran la plus longue (par exemple, 1136px x 1136px sur un iPhone 5) saigne hors écran, effectue l'autorotation (pas de changement de taille de rendu et donc pas d'étirement, comme lorsque vous basculez entre deux orientations paysage, par exemple), et ajuste à nouveau le framebuffer pour disposer les marges invisibles "gaspillées" hors écran? (bien sûr, je pourrais avoir un framebuffer carré tout le long, mais ce serait inefficace en matière de remplissage)

Aucune suggestion? Une meilleure façon d'accomplir cela à laquelle je n'ai pas pensé?

MODIFIER

J'ai modifié mon -resizeFromLayer: code comme suit:

 CGRect bounds = [layer bounds]; // Enlarge layer to square of the longest side: if (bounds.size.width < bounds.size.height) { bounds.size.width = bounds.size.height; } else{ bounds.size.height = bounds.size.width; } [layer setBounds:bounds]; // Adjust size to match view's layer: [_mainContext renderbufferStorage:GL_RENDERBUFFER fromDrawable:(CAEAGLLayer*) [_view layer]]; // Query the new size: glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &_backingWidth); glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &_backingHeight); // (etc., you know the drill...) 

…Et il fonctionne! Dans l'état actuel des choses, j'ai un gaspillage de carburant carré sans gaspillage, hors de l'écran, mais c'est juste une preuve de concept. Sur le code de production, j'effectuerais ce redimensionnement juste avant l'autorotation, et resizeai ensuite les dimensions de l'écran.

J'ai réussi à corriger cela assez facilement dans mon application 3D en récupérant la taille de la vue depuis la couche de presentationLayer GLKView. Cela donnera la taille de la vue actuelle pendant l'animation de rotation, et la masortingce de projection correcte peut être calculée en fonction de cette taille pendant l'étape de mise à jour. Cela empêche toute distorsion de format d'image incorrecte.

Si vous voulez essayer ceci, vous pouvez append les lignes suivantes au model de jeu OpenGL dans Xcode:

 - (void)update { // get the size from the presentation layer, so that animating does not squish CALayer *presentationLayer = [self.view.layer presentationLayer]; CGSize layerSize = presentationLayer.bounds.size; float aspect = fabsf(layerSize.width / layerSize.height); GLKMasortingx4 projectionMasortingx = GLKMasortingx4MakePerspective(GLKMathDegreesToRadians(65.0f), aspect, 0.1f, 100.0f); ... }