Dies ist eine lange Antwort, aber tatsächlich ist die Grundvoraussetzung von Divide-by-Camera-Z sehr einfach: Je weiter etwas von Ihnen entfernt ist, desto kleiner erscheint es. Auch die kleineren Abstände zwischen zwei Dingen erscheinen.
Positionen (Nicht erforderlich, wenn Sie Unity verwenden!)
Zunächst müssen Sie Positionen / Punkte mit der richtigen Perspektive rendern.
Die Positionen liegen auf einer flachen Ebene. Sie möchten so etwas wie das Bild rechts ... betrachten Sie die Ecken der Kacheln als Beispielpunkte / -positionen.
So nähern Sie sich der Transformation von Punkten:
- Ihr Koordinatensystem ist wie folgt: Positiv
z
läuft in den Bildschirm, x
läuft von links nach rechts und y
läuft nach unten. Kamera z ist Welt z. Das ist die Verknüpfung, die dies viel einfacher macht als das Schreiben einer vollständigen 3D-Engine. Nachteil? Die Kamera kann die Ausrichtung nicht ändern (obwohl sie die Position ändern kann).
- Speichern Sie die ursprüngliche 3D-Position Ihrer Kamera. Setzen Sie es etwas zurück (minus
z
) vom Ursprung der Welt.
- Speichern Sie eine Sammlung von 3D-Punkten in der xz-Ebene (geben Sie sie an
y=0
). Versuchen Sie , sie auf der ganzen Welt Ursprung zentriert in x
, (0,0,0)
dh von negativ n
zu positiv n
. Dies dient dazu, sie im Ansichtsfenster zu zentrieren, wenn das Rendern beginnt.
- Betrachten Sie den Ursprung des Verkleinerungspunkts / Pixelplots als die Mitte des Bildschirms.
- Legen Sie einen Abstand von der Kamera fest, in dem 1 Weltraumeinheit = 1 Pixel ist. Das heißt, wenn Sie die Kamera nur um eine Weltraumeinheit bewegen, wird jedes Objekt, das 10 Einheiten entfernt ist, nur um 1 Pixel verschoben - ziemlich weit! Speichern Sie diesen Abstand als Konstante
K
.
Rendern Sie nun für jeden Punkt an einer Position mit der folgenden Formel: screenPosition(x,y) = screenOrigin + (worldPosition(x,y) - cameraPosition(x,y)) / ((worldPosition(z) - cameraPosition(z)) * K)
... Wie Sie sehen können, basiert die Renderposition auf dem z
Abstand zwischen dem aktuellen Punkt und der Kamera.
Spielen Sie mit der Z-Position der Kamera, bis Sie Punkte sehen, die gerendert werden. Sie werden jedoch sehen, dass alle Punkte auf der Mittellinie des Bildschirms angezeigt werden. Also müssen wir Abhilfe schaffen. Versuchen Sie K=1
vs. K=10
, um den Unterschied zu sehen.
Sie können die Kamera jetzt nach innen bewegen, um y
zu sehen, wie sich Ihre Kamera über und unter der Ebene der Punkte befindet (dh die Punkte werden perspektivisch korrekt unter oder über der Mittellinie des Bildschirms gerendert, wenn Sie die Kamera nach oben und unten bewegen ).
Dies sind sehr grobe Richtlinien. Es gibt verschiedene Implementierungsdetails, die Ihnen überlassen bleiben. Der erste Schritt besteht darin, etwas anzuzeigen und von dort aus zu ändern. Ein Detail, das Ihnen in den Sinn kommt, ist, dass Sie, wenn Sie möchten, dass die Kamera eher so aussieht, als würde sie auf den Boden blicken, Ihren Rendering-Ursprung nach oben und näher an den oberen Rand des Ansichtsfensters verschieben müssen. Ein weiteres Detail ist, dass Ihre Entfernung zwischen Kamera und Punkt möglicherweise ein Trigger-Verhältnis enthalten muss ... Ich denke, die Verwendung tan
bietet eine realistischere Perspektive. Erinnern Sie sich nicht genau daran, aber Sie werden schnell sehen, ob die Perspektive seltsam aussieht und sich entsprechend anpassen kann. Ich kann nicht genauer sein, ohne ein Beispiel neu zu schreiben.
Verziehen und Skalieren pro Werbetafel (erforderlich)
Jetzt, da Sie die Perspektive unter Ihren Punktpositionen sehen und Positionen (wie bei Zeichen) nach Belieben hinzufügen, entfernen oder verschieben können, müssen Sie auch die Perspektive auf die einzelnen Sprites anwenden, die an diesen Positionen verwurzelt sind.
In D2 schien es mir immer eine einfache seitliche Warp-Funktion zu sein, die mehr auf die Werbetafeln am unteren Bildschirmrand als auf die oberen angewendet wird, und auch mehr, wenn Sie sich weiter von der nach unten laufenden Mittellinie entfernen der Bildschirm.
Möglicherweise werden auch die Werbetafeln vertikal skaliert, z. Bäume werden im Vergleich zu ihrer erwarteten Größe kürzer, näher am unteren Bildschirmrand (damit es so aussieht, als ob die Kamera auf die Bäume herabblickt - ich fand, dass Tristrams Bäume der beste Weg sind, dies sicher zu erkunden, damals in der Tag ;) ).
Was ich tun würde ist:
- Bewältigen Sie die grundlegende Skalierungsfunktion basierend auf der Entfernung von Kamera zu Boden an verschiedenen Punkten. Sie hätten also eine ähnliche Skalierung für jede Scanlinie.
- Erst nachdem ich das getan hatte, würde ich mir die seitliche Verzerrung ansehen - zuerst basierend auf dem Abstand von der Mittellinie, die über den Bildschirm läuft.
- Zuletzt würde ich untersuchen, wie diese seitliche Verzerrung durch die Entfernung auf dem Bildschirm beeinflusst wird (und ich habe das Gefühl, dass ein einfaches Triggerverhältnis das Herzstück davon sein würde).
Perspektivisch korrekte Kacheln (Nicht erforderlich, wenn Sie Unity verwenden!)
Das Obige gibt Ihnen hoffentlich korrekt positionierte, verzogene "Stand-up" -Sprites (dh Objekte, die senkrecht zur Grundebene sitzen, wie Charaktere, Bäume, Häuser).
Sie müssen jedoch auch überlegen, wie sich die Bodenfliesen korrekt und nahtlos verformen lassen. Und ich denke, Sie werden feststellen, dass dies der Teil ist, für den insbesondere eine GPU auf D2 erforderlich war. Ich erinnere mich, dass auf Systemen ohne GPU die Perspektivoption deaktiviert war. Der Grund dafür wäre mit ziemlicher Sicherheit gewesen, dass die GPU eine Texturoberfläche aufnehmen und sehr schnell eine perspektivische Korrektur darauf anwenden kann, ohne Störungen zwischen den Kacheln und ohne Bedenken hinsichtlich der Durchführung nicht affiner Transformationen im Anwendungscode, die einige Matrixmathematik beinhalten und kann ein bisschen teuer sein:
Ich habe ein paar Vorschläge für Sie, um damit umzugehen:
- (Einheit) Verwenden Sie eine Einheitskamera, um das Rendering der flachen, strukturierten Grundebene bereitzustellen, und behandeln Sie die Verzerrungen der Werbetafeln separat basierend auf den Positionen des Bildschirmbereichs.
- Führen Sie diese Logik (oder sogar die gesamte Renderlogik) in GPU-Shadern aus.
- Verwenden Sie überhaupt keine Bodenfliesen. Verwenden Sie stattdessen einfach Punkt-Sprites - genau wie die Zeichen selbst - auf einer einheitlich gefärbten Ebene (z. B. Grün für Gras), um Details bereitzustellen, damit diese Ebene nicht langweilig aussieht. Dies erhöht Ihre Rendering-Kosten, ist jedoch sicherlich der einfachste Weg, um dieses Problem zu lösen.