Jeffrey Cross
Jeffrey Cross

Quakes schnelle inverse Quadratwurzel

Die inverse Quadratwurzelfunktion (1 / sqrt (x)) wird während der Draw-Schleife einer Spiel-Engine stark verwendet, um Vektoren in "Einheitsvektoren" mit einer Länge von 1 zu normalisieren. Normalisierte Vektoren sind wichtig, weil Sie das Punktprodukt von zwei Werten von (Ax * Bx + Ay * By + Az * Bz) ist das Ergebnis der Cosinus des Winkels zwischen den beiden Vektoren.

Stellen Sie sich vor, Sie haben einen Vektor, der die Richtung einer Oberfläche beschreibt (ihre Oberflächennormale) und einen zweiten Vektor, der die Richtung des Sonnenlichts beschreibt. Wenn der Sonnenlichtvektor parallel zu Ihrer Oberflächennormalen ist, dh die Oberfläche ist der Sonne zugewandt, ist das Punktprodukt der zwei normalisierten Vektoren der Cosinus von 0, der 1 ist. Wenn die Oberfläche 90 Grad von der Sonne entfernt ist, Das Punktprodukt ist der Cosinus von 90, der Wert 0 ist. Alles, was sich dazwischen befindet, und Sie erhalten einen Wert zwischen 0 und 1, mit dem Sie im Wesentlichen beschreiben können, wie hell Sie diese Oberfläche beleuchten sollen.

Jetzt führen Sie diese Berechnung für jedes Dreieck aus, das in einem 3D-Spiel sichtbar ist, und Sie tun dies alles 30 oder mehrmals pro Sekunde, und Sie haben einen grundlegenden Lichteffekt auf Punktquellen! Denken Sie jedoch daran, dass Sie diese inverse Quadratwurzelfunktion benötigen, um Einheitsvektoren für jedes dieser Dreiecke zu berechnen. Die Quadratwurzeloperation ist langsam. Mach es tausendmal pro Draw-Loop, und du hast selbst ein langsames Spiel.

Wenn es Ihnen aber nichts ausmacht, ein bisschen Genauigkeit wegzuwerfen, gibt es einen schnelleren Weg.

Es gibt eine inverse Quadratwurzel-Funktion, die von vielen Spiel-Engines verwendet wird, die angeblich in Quake III von Nvidia-Programmierer Gary Tarolli entstanden sind. Es sieht aus wie das:

float InvSqrt (float x) {float xhalf = 0.5f * x; int i = * (int *) & x; // Bits für den Gleitkommawert erhalten i = 0x5f3759df - (i >> 1); // gibt eine erste Schätzung y0 x = * (float *) & i; // Konvertiere Bits zurück in Float x = x * (1.5f-xhalf * x * x); // Newton-Schritt, Wiederholung erhöht die Genauigkeit. Rückgabe x; }

Warten Sie, was war das?!?!

Newton hatte damals eine clevere Methode gefunden, die inverse Quadratwurzel anzunähern. Zunächst teilen Sie die ursprüngliche Zahl x durch zwei. Nennen wir das "xhalf". Dann können Sie die inverse Quadratwurzel ziemlich genau schätzen. Nennen wir das g. Dann nehmen Sie diese beiden Variablen und führen diese Berechnung aus (die Sie als letzten Schritt in der InvSqrt-Funktion erkennen):

g = g * (1,5 - x halb * g * g)

Wenn Sie das immer und immer wieder tun, indem Sie bei jeder Iteration das aktualisierte g einsetzen, wird g schnell auf die inverse Quadratwurzel von x eingehen! Wenn Sie zu Beginn ein anständiges g auswählen, werden Sie mit ein oder zwei Iterationen dem korrekten Wert sehr nahe kommen.

Die Frage ist, wie finden Sie den ersten Schätzwert für das erste g? Die Game Engine-Codierer verwenden einen Trick, um Fließkommazahlen binär darzustellen, wobei Exponent und Mantisse ähnlich der wissenschaftlichen Notation aufgeschlüsselt sind. In einem 32-Bit-Float ist das am weitesten links stehende Bit ein Vorzeichenbit und ist für positive Zahlen 0. Danach folgen 8 Bits des Exponenten (um 127 voreingestellt, um negative und positive Exponenten darzustellen), und die letzten 23 Bits repräsentieren die Mantisse.

Um eine inverse Quadratwurzel zu erzeugen, müssen Sie den Exponenten grundsätzlich mit -1/2 multiplizieren. Wenn Sie diese Bits nach rechts verschieben (eine sehr schnelle Operation), besteht die Auswirkung auf den Exponenten darin, sie durch 2 zu teilen. Sie müssen den Exponenten jedoch immer noch von 0 subtrahieren, um das Vorzeichen zu ändern Mantisse, die auch in der Bit-Shift-Operation betroffen war?

Hier kommt die magische 0x5f3759df-Nummer ins Spiel. Sie ist absolut verrückt, aber durch das Subtrahieren des Bit-Shift-Ergebnisses von 0x5f3759df wird die Mantisse auf nahe ihrem ursprünglichen Zustand zurückgesetzt und der Exponent wird von 0 abgezogen (unter Berücksichtigung der Vorspannung von 127). .

Das Ergebnis liegt sehr nahe an der inversen Quadratwurzel. Nahe genug für einen einzigen Durchlauf durch die Newtonsche Gleichung, um einen Wert zu erhalten, der für praktische Zwecke genau genug ist.

Schnelles Inverses Quadratwurzel von Quake Schnelles Inverses Quadratwurzel - Details und Mathematik hinter der magischen Zahl (PDF)

Aktie

Leave A Comment