Hinweis: Um die Frage so einfach wie möglich zu halten, ändere ich aktiv den Hauptteil der Frage, um den aktuellen Stand der Dinge widerzuspiegeln, anstatt unten etwas hinzuzufügen.
Ich implementiere die Schnittstellenrotation für mein GLES-basiertes Spiel für iOS, das in Xamarin.iOS mit OpenTK geschrieben wurde.
Ich erkenne die Drehung durch Überschreiben WillRotate
in meinem UIViewController
und richte alle meine Projektionsmatrizen korrekt neu ein.
Die Ergebnisse beim Zeichnen eines Sprites im Quer- und Hochformat unterscheiden sich jedoch geringfügig - die Landschaft ist etwas verschwommen -.
Dies ist das von mir verwendete Test-Sprite (128 x 128), um Rundungsfehler zu vermeiden:
Meine Testprojektionsmatrix basiert auf einem 1024x768-Display für ein iPad. Obwohl ich das Bild nicht skalieren werde, verwende ich die Punktfilterung, daher erwarte ich, dass das Rendering pixelgenau ist. Die Renderposition ist erneut (0, 0), um Rundungsfehler zu vermeiden. Das Sprite sollte sowohl im Hoch- als auch im Querformat genau in die Pixelgrenzen fallen.
Außerdem verwende ich in beiden Fällen dieselbe Textur mit demselben Sampler, demselben Shader und demselben GL-Status.
Dies passiert, wenn ich das Sprite im Hochformat rendere. So erwarte ich, dass es gerendert wird (5-fach vergrößert):
Und genau das passiert, wenn ich dasselbe Sprite im Querformat rendere.
Ich glaube, dass der Framebuffer als 768x1024 erstellt wurde, aber wenn er gedreht wird, passt er auf den 1024x768-Bildschirm, ist horizontal gequetscht und vertikal gestreckt, und dies ist der Grund für das Problem.
Wenn ich OpenTK so einstelle, dass ein 1024x1024-Framebuffer erstellt wird, wird das Ergebnis im Hoch- und Querformat konsistent. Das ist Porträt:
Beachten Sie, dass es in der Vertikalen keine Verzerrung gibt, die ebenfalls 1024 Pixel beträgt. Die Verzerrung ist auf die Horizontale beschränkt, wo die Auflösung nicht übereinstimmt. Das ist Landschaft:
Diesmal bewegte sich die Verzerrung in die Vertikale, was meine Hypothese stützte.
Wenn Sie es bei 3072 x 3072 erstellen, wobei 3072 das am wenigsten verbreitete Vielfache von 1024 und 768 ist, sind die Ergebnisse sowohl im Hoch- als auch im Querformat korrekt:
Beachten Sie, dass dies keine Lösung ist, da ich nicht nur viel Speicher verschwenden, sondern auch inkonsistente Multisampling-Artefakte mit 3D erzeugen werde, da sich die vertikale Skalierung von der horizontalen Skalierung unterscheidet. Darüber hinaus ist dies keine Option für das iPhone 5, für dessen Auflösung von 1136 x 640 ich einen Framebuffer von 45440 x 45440 erstellen müsste.
Da eine Gerätedrehung als Fenstergrößenänderung angesehen werden kann, muss der Framebuffer meiner Meinung nach neu erstellt werden, um der neuen Größe zu entsprechen. Dies ist für Windows unter Direct3D erforderlich. Ich müsste anrufen swapChain.ResizeBuffers()
, um dies in SharpDX zu tun.
Ich habe versucht, AutoResize = true
meine Einstellungen vorzunehmen iPhoneOSGameView
, aber dann wird der Framebuffer beim Drehen der Benutzeroberfläche abgeschnitten, und beim erneuten Drehen der Benutzeroberfläche verschwindet alles.
Ich mache nichts Seltsames, meine Framebuffer-Initialisierung ist ziemlich vanille:
int scaling = (int)UIScreen.MainScreen.Scale;
DeviceWidth = (int)UIScreen.MainScreen.Bounds.Width * scaling;
DeviceHeight = (int)UIScreen.MainScreen.Bounds.Height * scaling;
Size = new System.Drawing.Size((int)(DeviceWidth), (int)(DeviceHeight));
Bounds = new System.Drawing.RectangleF(0, 0, DeviceWidth, DeviceHeight);
Frame = new System.Drawing.RectangleF(0, 0, DeviceWidth, DeviceHeight);
ContextRenderingApi = EAGLRenderingAPI.OpenGLES2;
AutoResize = true;
LayerRetainsBacking = true;
LayerColorFormat = EAGLColorFormat.RGBA8;
Ich erhalte inkonsistente Ergebnisse bei einem Wechsel Size
, Bounds
und Frame
auf meiner CreateFrameBuffer
außer Kraft setzen. Leider ist die Dokumentation sehr unvollständig, so dass ich hier und da auf zufällige Änderungen zurückgegriffen habe, ohne wirklich zu wissen, was los ist.
Es gibt eine ähnliche Frage, die keine Antworten hat. Ich weiß jedoch nicht, ob sie das gleiche Problem haben wie ich.
In den Xamarin-Foren gibt es ähnliche Bedenken, insbesondere in Bezug auf das Rotationsproblem. Es scheint keine Lösung zu geben, außer GameView
vollständig fallen zu lassen.
Ist meine Vermutung, dass die Neuerstellung des Framebuffers notwendig ist, richtig? Wenn ja, weiß jemand, wie man es in OpenTK für Xamarin.iOS richtig macht?
quelle
Antworten:
Ja, der Renderpuffer muss beim Drehen der Benutzeroberfläche neu erstellt und auf die neue Größe eingestellt werden.
Es ist nicht schwierig, es neu zu erschaffen. Die Renderbuffer-ID ist jedoch privat
iPhoneOSGameView
und nur über dieRenderbuffer
Eigenschaft zugänglich , die keinen öffentlichen Setter hat.Reflexion zur Rettung! Bei der Inspektion
iPhoneOSGameView
stellte ich fest, dass es ein Feld enthältrenderbuffer
, das als Hintergrundfeld dahinter vielversprechend erscheintRenderbuffer
.Wenn ich also eine Drehung erkenne, erstelle ich meinen Renderpuffer neu und setze ihn dann über Reflektion.
Solche Dinge zu tun ist ein bisschen riskant, da ich nicht wirklich weiß, was ich sonst (wenn überhaupt) ändern muss, aber bisher sieht es gut aus.
iPhoneOSGameView
habe es nie kommen sehen ...quelle
Dies ist jetzt Teil von OpenTK.
iPhoneOSGameView
hat jetzt eineResizeFrameBuffer
Methode, die auf der Antwort von @Panda Pyjama basiert und bei der Bildschirmrotation aufgerufen werden sollte.https://github.com/opentk/opentk/pull/521
quelle