Was ist der Nutzen von quadratischem Radius und inversem quadratischem Radius für Beleuchtungsberechnungen?


16

Auf einer der Folien aus PowerPoint "DirectX 11-Rendering in Battlefield 3" ist mir der folgende Code aufgefallen:

struct Light {
    float3 pos; float sqrRadius;
    float3 color; float invSqrRadius;
}

Ich verstehe nicht, warum sie den quadratischen Radius und sogar das inverse Quadrat (von dem ich glaube, dass es einfach ein Quadrat ist) speichern, anstatt einfach den Radius zu speichern? Wie verwenden sie diese Daten in ihren Berechnungen? Und was ist mit Kegel- und Linienlichtern? Diese Struktur muss nur für die Punktlichter sein, ich kann nicht sehen, dass sie für andere Typen funktioniert - es sind nicht genügend Daten vorhanden. Trotzdem würde ich gerne wissen, wie sie dieses Quadrat und invSquare verwenden.

UPDATE: Ok, ich habe es endlich verstanden.

Hier ist die klassische Lichtdämpfungsgleichung, die im Netz leicht zu finden ist:

float3 lightVector = lightPosition - surfacePosition;

float attenuation = saturate(1 - length(lightVector)/lightRadius);

Es ist relativ kostspielig, wie dies length(lightVector)tatsächlich tut:

length(lightVector) = sqrt(dot(lightVector, lightVector);

Darüber hinaus ist die Aufteilung (/lightRadius)auch recht kostspielig.

Anstatt die Lichtabschwächung auf diese Weise zu berechnen, können Sie sie folgendermaßen berechnen, was viel schneller wäre:

attenuation = saturate(1 - dot(lightVector, lightVector)*invRadiusSqr);

Dabei kann invRadiusSqr auf CPU-Ebene vorberechnet und als Shader-Konstante übergeben werden.

Darüber hinaus erhalten Sie als Ergebnis eine quadratische Lichtabschwächung (im ersten Fall nicht linear), was sogar noch besser ist, da IRL-Licht eine quadratische Abschwächung aufweist.

Vielen Dank für Ihre Hilfe!


13
Polsterung. Shader sind mit 16 Byte ausgerichtet. Und wenn Sie sich ansehen, wie der Code formatiert ist, werden Sie feststellen, dass er in zwei float4-Dateien gepackt wird. Warum nicht etwas Nützliches aufbewahren, wenn es aus dem Cache kommt?
Tordin

Antworten:


23

Dies ist einfach eine Art Optimierung, da invSqrRadius = 1/SqrRadiusanstelle der Berechnung des inversen quadratischen Radius für jedes Licht jedes Mal, wenn es einfach zwischengespeichert wird, der Grund dafür liegt, dass die Division normalerweise eine "langsame" Operation ist, zumindest im Vergleich zur Multiplikation.

Diese Optimierung ist insbesondere relevant:

  • Wenn der Vorgang für jede LED sehr oft ausgeführt wird, werden durch Zwischenspeichern des Werts zusätzliche CPU- / GPU-Zyklen freigegeben
  • Und vorausgesetzt, die Speicherzugriffszeit zum Lesen des Werts ist tatsächlich schneller als das Neuberechnen.

Was die Verwendung betrifft, bin ich mir nicht sicher, ob sie konkret implementiert wurden, aber 1/sqrRadiusdies wird lediglich für die Dämpfung, das Abfallen und das Keulen von Licht verwendet. Dies ist auch für die Ausrichtung und das Spotlight relevant. Der einzige Unterschied beim Spotlight besteht darin, dass Sie den Spotlight-Faktor nach dem Anwenden der Dämpfung berechnen müssen . In Bezug auf direktionales Licht wie Sonne hat es normalerweise keine Dämpfung oder Abnahme, daher würde ich davon ausgehen, dass es ignoriert wird.

[EDIT] Nur um mehr auszuarbeiten, es sind keine irrelevanten Daten. Die Lichtbestrahlungsstärke kann mit der folgenden Gleichung berechnet werden:

E = Phi / 4 * pi * rSqr;

Wo

E ist die Flächendichte des Flusses.

Phi ist Strahlungsfluss.

4 * pi * rSqr ist die Oberfläche einer Kugel.

Diese Gleichung erklärt, warum die empfangene Energiemenge mit der Quadratdistanz abnimmt.

Ein weiterer Punkt ist, dass Sie den Abstand zwischen dem Scheitelpunkt und dem Licht berechnen müssen, um den Lichtbeitrag für einen bestimmten Scheitelpunkt zu berechnen (es ist unwahrscheinlich, dass dieser Wert zwischengespeichert wird). Der Scheitelpunkt kann sich innerhalb oder außerhalb des Lichtbereichs befinden, der uns zum nächsten Punkt bringt wo Radius Squareist nützlich für das Keulen.

Wenn Sie ein praktisches Beispiel für die Berechnung von Lichtabfall und -ausscheidung wünschen, ist dies besonders bei gekachelten Renderern hilfreich. Hier ein Beispiel .


Flüche, du hast mich um 7 Sekunden geschlagen! ;) (und mit einer umfassenderen Antwort auch!)
Trevor Powell

Danke für den ausführlichen Kommentar, besonders für den Link! Nach dem, was ich aus letzterem Link verstanden habe, speichert Battlefield 3 nicht den Radius, sondern den tatsächlichen Abstand zwischen der Lichtquelle und dem Lichtempfänger, oder? Das ist der "d" -Wert, den sie im Artikel verwenden.
CUBRMAN

@cubrman Es ist schwer zu spekulieren, ohne Code zu sehen. Ich vermute, dass es der inverse RadiusSqr ist. Und die Gleichungen, die sie verwenden, können stark vom Artikel abweichen.
concept3d

Aber sagen Sie mir, wie können Sie einen quadratischen, invertierten Lichtradius für eine Beleuchtungsberechnung verwenden? Jede Quelle, die ich im Netz gefunden habe, sagt mir, dass ich den Abstand zwischen der Empfangsfläche und der Lichtquelle finden muss. Teilen Sie die Lichtquelle durch den ursprünglichen Lichtradius und quadrieren Sie dann das Ergebnis. Wo würden Sie jemals quadrierten Radius oder invSqrRadius verwenden? Das scheint mir völlig irrelevante Daten zu sein.
Cubrman

1
@cubrman hat die Antwort aktualisiert.
concept3d

6

invSqrRadius ist nicht 1 - sqrRadius; es ist 1 / sqrRadius.

Dies bedeutet, dass Sie mit invSqrRadius multiplizieren können, anstatt durch sqrRadius zu dividieren (da die Division in der Regel viel teurer ist als die Multiplikation).


6

Die anderen Antworten befassten sich mit dem umgekehrten quadratischen Radius, aber ich werde stattdessen den quadratischen Radius betrachten (welches Konzept3d angesprochen hat, aber ich glaube, es verdient eine weitere Diskussion).

Was für Quadrate nützlich sind, sind Entfernungsvergleiche. Wir wissen, dass die Berechnung des Abstands zwischen zwei Punkten eine Quadratwurzel erfordert und die Berechnung von Quadratwurzeln teuer ist. Wenn wir jedoch nur die Entfernungen vergleichen möchten (um herauszufinden, welche kleiner oder größer ist, und etwas Interessantes basierend auf der Ergebnis) können wir die Quadratwurzel werfen.

Wenn sqrt (x)> sqrt (y) ist, dann ist es auch so, dass x> y ist.

Für eine Leuchte entspricht der quadratische Radius dem Abstand zwischen dem Lichtmittelpunkt und der maximalen Ausdehnung - natürlich im Quadrat.

Für Beleuchtungsberechnungen kann dies für einen Early-Out-Fall verwendet werden. Wenn der Abstand zwischen dem Punkt, den Sie beleuchten, und dem Lichtmittelpunkt (Quadrat) größer als der Quadratradius ist, empfängt der Punkt kein Licht und Sie müssen den Rest Ihrer Berechnungen nicht ausführen. Dies ist daher nur eine Optimierung (eine ziemlich häufige) - wir können den Abstandsvergleich mit einem quadratischen Radius ohne teure Quadratwurzeln durchführen, und das zu einem Preis von nur einem Subtraktions- und Punktprodukt.

Ich weiß natürlich nicht, ob dies genau das ist , wofür BF3 es verwendet, aber ich würde erwarten, dass ich nicht zu weit von der Marke entfernt bin.


Wenn ich Sie also richtig verstanden habe, lautet der Code: Wenn (dot ((lightPos - surfacePos), (lightPos - surfacePos))> lightRadiusSqr) nicht leuchten, richtig?
CUBRMAN
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.