# Wo befindet sich ein Punkt?



## import java.dev.org (10. Nov 2018)

Servus, es geht zwar nicht um die Programmierung eines Spiels, aber um ein Thema, das besonders in diesem Bereich zu finden ist, daher schreib ich das mal hier rein, hoffe das passt 
Also, folgende Situation: Ich habe eine Kamera mit einer Position im 3-dimensionalen Raum, sowie einen Richtungsvector, der aufzeigt in welche Richtung die Kamera gerade schaut. Diese Kamera hat ein variables Sichtfeld, sagen wir mal 90° in die Breite, also in jede Richtung 45, und 60° in die Höhe. 
Dann hab ich noch einen Punkt mit eine Position, und jetzt will ich wissen wo auf dem Bildschirm sich dieser Punk befindet. Dafür habe ich jetzt 2 Winkel ausgerechnet, den zwischen dem Richtungsvektor der Kamera und dem Punkt mit der Kamera als Ursprung, auf der xy- Ebene um die x-Koordinate des Punktes auf dem Bildschirm zu bestimmen, und das gleiche auf der yz-Ebene um die y-Koordinate zu bestimmen. Das Verhältnis der Winkel zu den 45° bzw. 30° habe ich dann auf den Bildschirm übertragen. Ich hoffe bisher kann mir jeder folgen.

Das funktioniert jetzt allerdings nur sehr bedingt, denn nur mit den Winkeln kann der Punkt ja sowohl links, als auch rechts, bzw. ober- und unterhalb der Richtungsvektors der Kamera liegen. Wie kann ich jetzt möglichst ressourcensparend festlegen wo *genau* der Punkt jetzt am Bildschirm hin muss? 
Meine Idee war es einen weiteren Vektor festzulegen, der die obere, linke Ecke des Sichtfeldes der Kamera beschreibt und dann, je nachdem ob der Winkel des Punktes zu diesem Vektor größer oder kleiner als zum Richtungsvektor der Kamera ist, kann man erkennen in welches "Quartal" des Bildschirms der Punkt gehört. Allerdings klingt das nicht sehr effektiv und mir fehlen leider die entsprechenden Formeln um diesen zweiten Vektor zu bestimmen 

Also gibt es hier eine bessere Lösung? Oder kennt jemand sogar allgemein für die Ganze Geschichte einen schöneren Weg?

Kurz zusammengefasst: Ich will eigentlich nur Punkte in einem 3-dimensionalen Koordinatensystem auf einen 2-dimensionalen Bildschirm übertragen.


Grüße M


----------



## DrZoidberg (10. Nov 2018)

Am besten ist es du übersetzt die Koordinaten des Punktes erst einmal in das Koordinatensystem der Kamera. Im dem System liegt der Ursprung in der "Linse" der Kamera und die Z Achse zeigt von der Kamera weg. Die XY Ebene ist daher parallel zum virtuellen Bildschirm, der sich hinter der Kamera befindet.
In diesem Koordinatensystem ist die Projektion des Punktes dann trivial über den Dreisatz möglich.
Du benötigst für das ganze entweder eine Drehmatrix oder ein Quaternion, das die Rotation der Kamera relativ zum normalen Koord.System des Spiels beschreibt.
Wie führst du denn Rotationen in deinem Spiel bisher durch?


----------



## httpdigest (10. Nov 2018)

Für eine solche perspektivische Projektion kannst du reine Lineare Algebra anwenden und brauchst dich an keiner Stelle mit Trigonometrie/Winkeln herumschlagen, die alles nur unnötigen kompliziert machen.
Sowas wird ja zu Haufe in OpenGL/Direct3D gemacht. Hier mal ein paar sehr gute Lernmaterialien:
- http://www.songho.ca/opengl/gl_projectionmatrix.html
- https://www.scratchapixel.com/lesso...n-matrix/opengl-perspective-projection-matrix

Und hier ein kleines Code-Beispiel, um einen Punkt zu projizieren (mit JOML als Bibliothek für die ganzen Berechnungen):

```
// Vertikaler Öffnungswinkel der Kamera
float fovY = (float) Math.toRadians(60.0);
// width/height des Viewports der Kamera
float aspectRatio = (float) 800 / 600;
// 4x4-Matrix für Transformation von Weltkoordinaten -> Kamerakoordinaten -> Einheitswürfel/NDC
Matrix4f m = new Matrix4f()
  // Erzeuge perspektivische Projektion mit 0.1 als Entfernung zur "near plane" und unendlich weiter "far plane"
  .perspective(fovY, aspectRatio, 0.1f, Float.POSITIVE_INFINITY)
  // Erzeuge Transformation von Weltkoordinaten in Kamerakoordinaten (Drehung und Translation)
  .lookAt(camX, camY, camZ, // <- Position der Kamera
          lookAtX, lookAtY, lookAtZ, // <- Punkt, auf den die Kamera schaut
          upX, upY, upZ); // <- welche Richtung ist "oben" für die Kamera
// Vektor für den zu projizierenden Punkt
Vector3f point = new Vector3f(point, pointY, pointZ);
// Transformiere den Punkt in "Normalized Device Coordinates" (NDC)
m.transformProject(point);
// point.xyz ist in ([-1..1], [-1..1], [-1..1]), wenn er von der Kamera "gesehen" wird
```


----------



## import java.dev.org (11. Nov 2018)

DrZoidberg hat gesagt.:


> Am besten ist es du übersetzt die Koordinaten des Punktes erst einmal in das Koordinatensystem der Kamera. Im dem System liegt der Ursprung in der "Linse" der Kamera und die Z Achse zeigt von der Kamera weg. Die XY Ebene ist daher parallel zum virtuellen Bildschirm, der sich hinter der Kamera befindet.
> In diesem Koordinatensystem ist die Projektion des Punktes dann trivial über den Dreisatz möglich.
> Du benötigst für das ganze entweder eine Drehmatrix oder ein Quaternion, das die Rotation der Kamera relativ zum normalen Koord.System des Spiels beschreibt.
> Wie führst du denn Rotationen in deinem Spiel bisher durch?



Wie kann ich denn meinen Punkt in das Koordinatensystem der Kamera übersetzen? Ganz praktisch jetzt? Ich kann mir darunter nicht so viel vorstellen wie das gehen soll :/
Rotationen führe ich bisher über die beschriebene Methode durch, mit Kommandozeilen-eingaben, das soll wie gesagt kein Spiel werden,


----------



## DrZoidberg (11. Nov 2018)

Das einfachste währe es du übernimmst httpdigests Beispiel. Dann führt die JOML Bibliothek all diese Berechnungen für dich durch.


----------



## httpdigest (11. Nov 2018)

Wenn du das alternativ _wirklich_ verstehen willst, benötigst du Wissen über Vektorräume, Linear Algebra im Allgemeinen, Koordinatensysteme und Matrix/Vektor-Transformationen (und, falls doch mit Quaternionen, dann eben die auch noch  ).
Ich hatte dir ja bereits ein paar Quellen genannt, die ausführlichst beschreiben, wie man mit Hilfe von homogenen Koordinaten perspektivische Projektion hinbekommt. Im Grunde steckt da nicht viel mehr dahinter, als der von @DrZoidberg angesprochene berühmte Dreisatz.
Für affine Koordinatensystemtransformationen kannst du dir mal die folgenden Quellen anschauen:
- https://www.uio.no/studier/emner/ma...F3320/h03/undervisningsmateriale/lecture3.pdf
- https://www.khanacademy.org/math/precalculus/precalc-matrices#matrices-as-transformations
- https://www.khanacademy.org/math/linear-algebra/matrix-transformations
Hierbei ist absolut nichts nur speziell für Spiele. Das sind ganz allgemeine 3D-Transformationen und Projektion, die in jeder 3D-Anwendung (wie auch immer geartet - egal ob mit Kommandozeile oder GUI) benutzt werden.


----------



## Hutzli (14. Nov 2018)

Für die Quaternioneninteressierten: Ich habe letztes Semester mit einem Studienkollegen nebenbei was darüber zusammengetragen. Enthält auch die komplette Herleitung der Rotationsmatrix mit Beispielen. Das Deutsch ist schrecklich, ich hatte aber keine Zeit mehr, Korrektur zu lesen. Falls jemand einen Fehler finden sollte, bitte ich um Rückmeldung. Sollte jedoch, soweit ich's beurteilen kann, alles korrekt sein. Vielen Dank


----------

