Verwirrung über GLViewport

9

Ich hoffe, jemand kann mir helfen, das GLViewport zu verstehen und was passiert, wenn wir die Größe ändern

Dies wird meine Verwirrung veranschaulichen ....

Geben Sie hier die Bildbeschreibung ein

Also, hier habe ich ein Quad in der Mitte des Bildschirms. Wenn mein GLViewport mit der Breite und Höhe des Geräts übereinstimmt, erhalte ich das Bild auf dem ersten Bild (links). Genau das, was ich erwarten würde.

  • Geräteauflösung 2560 x 1600
  • Auflösung des Ansichtsfensters 2560 x 1600
  • Quad Größe 200 x 200 (Hinweis, das Bild oben ist nicht maßstabsgetreu !!! :-))
  • Quad-Form, erscheint als Quadrat

Nun zum 2. Bild (rechts) ...

  • Geräteauflösung 2560 x 1600
  • Auflösung des Ansichtsfensters 2560 x 1200 (und vertikal zentriert)
  • Quad-Größe (200, 200)
  • Quad-Form, erscheint als Rechteck

Meine Frage ist, warum das Quad jetzt als Rechteck und nicht als Quadrat angezeigt wird. Ich habe durch Protokollierung bestätigt, dass mein Quad 200 x 200 Pixel groß ist - bleibt die Größe der physischen Pixel doch gleich? Sie können sich nicht ändern. Also, was ist hier los?

Ich dachte (eindeutig falsch), dass beim Skalieren des Ansichtsfensters nur Pixel abgeschnitten wurden.

Würde mich freuen, wenn jemand erklären könnte, wie das funktioniert.

Bearbeiten

Derzeit stelle ich mein Ansichtsfenster folgendermaßen ein:

width = (int) Math.min(deviceWidth, deviceHeight * 1.702127659574468);    
height = (int) Math.min(deviceHeight, deviceWidth / 1.702127659574468);

ratio = width / height;
GLES20.glViewport(offsetX, offsetY, width, height);

Matrix.orthoM(mProjMatrix, 0, -ratio, ratio, -1, 1, 3, 7);

offsetX und offsetY sind nur so, dass das Ansichtsfenster zentriert ist, wenn Briefkästen vorhanden sind.

BungleBonce
quelle
Haben Sie Ihre Projektionsmatrix sowie das Ansichtsfenster beim Wechsel von 1600 auf 1200 vertikale Pixel geändert? (Sie müssen)
bcrist
Hallo @bcrist, siehe meine Bearbeitung, um zu zeigen, wie ich mein Ansichtsfenster einstelle. Alles, was ich zeichne, das die gleiche Anzahl von Pixeln hat (z. B. 50 x 50 oder 100 x 100), wird "gestreckt" gezeichnet - Irgendwelche Ideen?!
BungleBonce
Übrigens, wenn Sie glScissoranstelle von verwenden glViewport, werden einfach Pixel abgeschnitten, ohne zu ändern, wo etwas gerendert wird. glViewportverhält sich eher so, als würde man die Größe des Originalbilds ändern, anstatt es zu beschneiden; Deshalb zerquetscht es Ihre Box.
Nathan Reed
Danke @NathanReed, ich bin immer noch sehr verwirrt. Was ich habe, ist Folgendes: Ein Ansichtsfenster, das den gesamten Bildschirm einnimmt. Bei einer Scherenbox, die so skaliert ist, dass das Verhältnis des Originalgeräts erhalten bleibt (damit ich das Spiel in der Scherenbox anzeigen und außerhalb davon als Füllmaterial zeichnen kann), erscheint alles gestreckt (vertikal), also länger als breit. Was mache ich falsch?
BungleBonce
Hmm. Das Scissor Rect sollte nichts am Seitenverhältnis oder der Skalierung des Bildes ändern. Wenn es ohne Schere korrekt aussieht, sollte das Bild einfach zugeschnitten werden, indem nur die Schere aktiviert wird - das gleiche Ansichtsfenster, die gleiche Projektionsmatrix usw. beibehalten.
Nathan Reed

Antworten:

11

Um zu verstehen, was los ist, müssen Sie die Rendering-Pipeline verstehen:

Ihre Geometrie (das Quad) wird anfänglich im Weltraum definiert. Stellen Sie sich dies als ein globales Koordinatensystem vor. Innerhalb des Vertex-Shaders werden diese in normalisierte Gerätekoordinaten (NDC) umgewandelt, ein virtuelles Koordinatensystem, das so definiert ist, dass alles von -1 bis 1 auf den Bildschirm gezeichnet wird. Beachten Sie, dass der NDC in X und Y zwischen -1 und 1 liegt und völlig unabhängig vom Seitenverhältnis und der Auflösung des Geräts ist. Diese Transformation vom Weltraum zum NDC erfolgt durch die Modell-, Ansichts- und Projektionsmatrix (in einer einfachen Form wurde zunächst nur eine Matrix für alles oder die Geometrie in NDC definiert!).

Die Rasterisierungseinheit muss wissen, wo und wie groß das Raster sein soll. Dies definieren Sie mit dem glViewport-Aufruf: Wo sollen die ersten beiden Parameter beginnen, die Größe sind die zweiten beiden. Die Hardware konvertiert dann durch einfaches Skalieren und Verschieben von NDC in Pixelkoordinaten - und das sehen Sie in Ihrem Beispiel: eine Skalierung auf der Y-Achse.

Um sicherzustellen, dass Ihr Quad im richtigen Seitenverhältnis gerendert wird, müssen Sie auch die Projektionsmatrix so anpassen, dass sie das erwartete Seitenverhältnis des glViewport-Aufrufs enthält.

Robert
quelle
Hallo @Robert, vielen Dank dafür. Ich habe einige Schwierigkeiten, dies umzusetzen. Könnten Sie bitte ein Beispiel für die Einrichtung der Projektionsmatrix in Ihrer Antwort geben? Vielen Dank!
BungleBonce
4
Hallo Benutzer22241, es gibt keine OpenGL-Befehle, um dies für Sie zu tun. Sie müssen die Matrix selbst definieren (ein 4 x 4-Array von Floats) und sie Ihrem Vertex-Shader als Uniform zur Verfügung stellen. Welche Projektion Sie benötigen (Perspektive, orthogonal), hängt davon ab, was Sie tun möchten. Wenn Ihnen die mathematischen Konzepte von 3D-Projektionen neu sind, sollten Sie OpenGL-Tutorials nachschlagen, in denen das Kernprofil vermittelt wird, das in dieser Hinsicht genauso funktioniert wie OpenGL ES.
Robert
@BungleBonce Obwohl es im Kernprofil keine OpenGL-Befehle dafür gibt, können Sie sich immer die Dokumentation veralteter Befehle wie ansehen, in der glFrustumdie genaue Matrix aufgeführt ist, die von diesen Funktionen erstellt wird. Eine andere häufig verwendete Projektionsmatrix wurde von erstellt glOrtho. Obwohl all diese Befehle veraltet sind, sind die darin enthaltenen Dokumente eine hervorragende Quelle für einige vorab abgeleitete Mathematik.
Ruslan
0

In Ihrem Aufruf von glViewport geben Sie weniger Pixel in Breite und Höhe an. Ihre Projektionsmatrix wird in Pixel definiert. Deshalb müssen Sie nach einem glViewport-Aufruf eine neue Projektionsmatrix berechnen.

bogglez
quelle
Hallo @bogglez, danke für deine Antwort. Ich habe meine Frage bearbeitet, um (am Ende) anzuzeigen, welchen Code ich für mein Ansichtsfenster verwende. Ich benutze nur glViewPort - ist das falsch? Könnten Sie bitte ein Beispiel dafür zeigen, was Sie in Ihrer Antwort meinen? Vielen Dank.
BungleBonce
Lesen Sie dies: songho.ca/opengl/gl_projectionmatrix.html Für 2D möchten Sie eine orthogonale Projektionsmatrix, für 3D möchten Sie wahrscheinlich eine perspektivische Matrix. Wenn Sie modernes OpenGL verwenden, stellen Sie einem Shader eine Matrix zur Verfügung. Wenn Sie veraltetes OpenGL mit der festen Grafikpipeline verwenden, verwenden Sie Funktionen wie glLoadMatrix, glFrustum usw., um die Projektionsmatrix zu berechnen. Die Utility-Bibliothek GLU verfügt über die Funktionen gluPerspective ( opengl.org/sdk/docs/man2/xhtml/gluPerspective.xml ) und gluOrtho2D ( opengl.org/sdk/docs/man2/xhtml/gluOrtho2D.xml ), um Ihnen dabei zu helfen.
Bogglez
0

Zum ersten Bild:

  1. Wir erstellen eine Projektionsmatrix. Beispielsweise werden folgende Parameter verwendet: Left1, Right1, Bottom1, Top1, Near1, Far1. Hier ist Aspect_Ratio_1A = (Rechts1 - Links1) / (Oben1 - Unten1);

  2. Dann führen wir eine Ansichtsport-Transformation durch. Die verwendeten Parameter sind beispielsweise: Breite1, Höhe1. (Der Einfachheit halber erwähne ich keine Verschiebungsparameter). Hier ist Aspect_Ratio_1B = Width1 / Height1;

Für das zweite Bild:

  1. Wir erstellen dieselbe Projektionsmatrix mit denselben Parametern wie zuvor. Also: Aspect_Ratio_2A = Aspect_Ratio_1A;

  2. Diesmal hat die Ansichtsport-Transformation verschiedene Parameter: Breite2 und Höhe2. Hier ist Aspect_Ratio_2B = Breite2 / Höhe2.

Wir stellen fest, dass Aspect_Ratio_1B und Aspect_Ratio_2B unterschiedlich sind. Insbesondere sind sie:

Aspect_Ratio_1B = 2560/1600 = 1,6 Aspect_Ratio_2B = 2560/1200 = 2,13

Wenn wir also zusammenfassen, was wir für den zweiten Fall tun, ist:

Wir projizieren das Bild mit Aspect_Ratio_2A auf eine Ebene und skalieren es auf Aspect_Ratio_2B, bevor wir es dem Benutzer zeigen. Andere Benutzer bitten uns, unsere Projektionsmatrix so zu korrigieren, dass Aspect_Ratio_2A = Aspect_Ratio_2B.

Wir können auch Roberts Kommentare ein paar Mal lesen, um ein besseres Verständnis zu haben.

Ich kann auch nicht zustimmen, dass das rote Quad im zweiten Bild eine Größe von 200 x 200 Pixel hat, wenn es auf dem Bildschirm gezeichnet wird. Da wir wissen, dass ein Pixel ein Quadrat ist, benötigt die längere Seite mehr Pixel, um sicher gezeichnet zu werden, wenn das Quad eine der Seiten länger als die andere hat. Ich persönlich weiß nicht, was Protokollierung ist, aber möglicherweise gibt sie keine Bildschirmpixelgröße zurück.

Jamil
quelle