Ich entwickle ein Spiel mit einem Minecraft-ähnlichen Gelände aus Blöcken. Da das grundlegende Rendern und Laden von Chunks jetzt erfolgt, möchte ich die Blockauswahl implementieren.
Deshalb muss ich herausfinden, welchem Block die Kamera der ersten Person gegenübersteht. Ich habe schon davon gehört, dass ich die ganze Szene nicht projiziert habe, aber ich habe mich dagegen entschieden, weil es hackig klingt und nicht genau ist. Vielleicht könnte ich einen Strahl in Blickrichtung werfen, aber ich weiß nicht, wie ich die Kollision mit einem Block in meinen Voxeldaten überprüfen soll. Natürlich müssen diese Berechnungen auf der CPU durchgeführt werden, da ich die Ergebnisse benötige, um Spiellogikoperationen durchzuführen.
Wie kann ich also herausfinden, welcher Block sich vor der Kamera befindet? Wie könnte ich einen Strahl werfen und Kollisionen überprüfen, wenn es vorzuziehen ist?
quelle
Antworten:
Als ich dieses Problem bei der Arbeit an meinen Cubes hatte , fand ich die Arbeit "Ein schneller Voxel-Traversal-Algorithmus für die Raytracing" von John Amanatides und Andrew Woo, 1987, die einen Algorithmus beschreibt, der auf diese Aufgabe angewendet werden kann. es ist genau und benötigt nur eine Schleifeniteration pro durchschnittenem Voxel.
Ich habe eine Implementierung der relevanten Teile des Algorithmus des Papiers in JavaScript geschrieben. Meine Implementierung fügt zwei Funktionen hinzu: Sie ermöglicht das Festlegen einer Grenze für die Entfernung des Raycasts (nützlich zum Vermeiden von Leistungsproblemen sowie zum Definieren einer begrenzten Reichweite) und das Berechnen der Fläche jedes Voxels, in das der Ray eingegeben wurde.
Der Eingabevektor
origin
muss so skaliert werden, dass die Seitenlänge eines Voxels 1 beträgt. Die Länge desdirection
Vektors ist nicht signifikant, kann jedoch die numerische Genauigkeit des Algorithmus beeinflussen.Der Algorithmus arbeitet unter Verwendung einer parametrisierten Darstellung des Strahls
origin + t * direction
. Für jede Koordinatenachse, verfolgen wir dent
Wert, den wir haben würde , wenn wir ein Voxel Grenze entlang dieser Achse (dh Änderung der ganzzahlige Teil der Koordinate) in den Variablen einen Schritt ausreichend zu durchqueren hattMaxX
,tMaxY
undtMaxZ
. Dann machen wir einen Schritt (unter Verwendung der Variablenstep
undtDelta
) entlang derjenigen Achse, die die geringste hattMax
- dh derjenigen, die der Voxelgrenze am nächsten liegt.Permanenter Link zu dieser Version der Quelle auf GitHub .
quelle
function intbounds(s,ds) { return (ds > 0? Math.ceil(s)-s: s-Math.floor(s)) / Math.abs(ds); }
. DaInfinity
es größer als alle Zahlen ist, glaube ich nicht, dass Sie ds davor schützen müssen, dort 0 zu sein.1/ds
eine der anderen Achsen inkrementiert. Der Fix besteht darin, zu schreibenintfloor
, um zu prüfen, ob beideds
negativ unds
ein ganzzahliger Wert sind (mod gibt 0 zurück), und in diesem Fall 0.0 zurückzugeben.Schauen Sie sich vielleicht Bresenhams Linienalgorithmus an , besonders wenn Sie mit Unit-Blocks arbeiten (wie es die meisten minecraftischen Spiele tun).
Im Grunde genommen nimmt dies zwei beliebige Punkte und zeichnet eine ungebrochene Linie zwischen ihnen. Wenn Sie einen Vektor vom Spieler auf die maximale Reichweite werfen, können Sie diese verwenden und die Positionen der Spieler als Punkte.
Ich habe hier eine 3D-Implementierung in Python: bresenham3d.py .
quelle
Um den ersten Block vor der Kamera zu finden, erstellen Sie eine for-Schleife, die von 0 bis zu einem gewissen maximalen Abstand eine Schleife bildet. Multiplizieren Sie dann den Vorwärtsvektor der Kamera mit dem Zähler und prüfen Sie, ob der Block an dieser Position fest ist. Wenn dies der Fall ist, speichern Sie die Position des Blocks für die spätere Verwendung und beenden Sie die Schleife.
Wenn Sie auch Blöcke platzieren möchten, ist das Face-Picking nicht schwieriger. Gehen Sie einfach vom Block zurück und suchen Sie den ersten leeren Block.
quelle
Ich habe mit meiner Implementierung , die den Bresenhamschen Linienalgorithmus verwendet, einen Beitrag zu Reddit verfasst . Hier ist ein Beispiel, wie Sie es verwenden würden:
Hier ist die Implementierung selbst:
quelle