Qual è l'utilità del raggio quadrato e del raggio quadrato inverso per i calcoli di illuminazione?


16

In una delle diapositive di "Rendering DirectX 11 in Battlefield 3" PowerPoint ho notato il seguente codice:

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

Non capisco perché dovrebbero memorizzare il raggio quadrato e persino il quadrato inverso (che credo sia semplicemente un raggio di 1 quadrato) invece di memorizzare semplicemente il raggio? Come stanno usando questi dati nei loro calcoli? Inoltre, che dire delle luci a cono e linea? Questa struttura deve essere solo per i punti luce, non riesco a vederlo funzionare per altri tipi - non ci sono abbastanza dati. Mi piacerebbe comunque sapere come usano quel quadrato e invSquare.

AGGIORNAMENTO: Ok finalmente ho capito.

Ecco la classica equazione di attenuazione della luce, facilmente reperibile in rete:

float3 lightVector = lightPosition - surfacePosition;

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

È relativamente costoso come length(lightVector)sta effettivamente facendo questo:

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

inoltre l'operazione di divisione (/lightRadius)è anche piuttosto costosa.

Invece di calcolare l'attenuazione della luce in questo modo, puoi calcolarla nel modo seguente, che sarebbe molto più veloce:

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

dove invRadiusSqr può essere pre-calcolato a livello di CPU e passato come costante shader.

Inoltre, di conseguenza si ottiene un'attenuazione della luce quadratica (anziché lineare nel primo caso), il che è ancora meglio, poiché la luce IRL ha dimostrato di avere un decadimento quadratico.

Grazie a tutti per il vostro aiuto!


13
Imbottitura. Gli shader sono allineati a 16 byte. E se dai un'occhiata a come è formato il codice, vedrai che verrà impacchettato in due float4. Perché non memorizzare qualcosa di utile quando lo otterrai gratuitamente dalla cache?
Tordin,

Risposte:


23

Questo è semplicemente un tipo di ottimizzazione dato che invSqrRadius = 1/SqrRadius, invece di calcolare il raggio quadrato inverso per ogni luce ogni volta che la memorizzano semplicemente nella cache, la ragione è che la divisione è di solito un'operazione "lenta" almeno rispetto alla moltiplicazione.

Questa ottimizzazione è rilevante soprattutto:

  • quando l'operazione viene eseguita un numero enorme di volte per ogni luce, quindi la memorizzazione nella cache del valore libererà ulteriori cicli CPU / GPU
  • E supponendo che il tempo di accesso alla memoria per la lettura del valore sia effettivamente più veloce del ricalcolo.

Per quanto riguarda il modo in cui viene utilizzato, non sono sicuro della loro specifica implementazione, ma per quanto riguarda 1/sqrRadius, questo è semplicemente usato per l'attenuazione della luce, il decadimento e l'abbattimento. È rilevante anche per i riflettori e direzionali, l'unica differenza nel caso dei riflettori è che è necessario calcolare il fattore del riflettore dopo aver applicato l'attenuazione . Per quanto riguarda le luci direzionali come il sole, di solito non ha alcuna attenuazione o caduta, quindi immagino che verrà ignorato.

[EDIT] Giusto per elaborare più, è senza dati irrilevanti. L'irradiamento della luce può essere calcolato usando la seguente equazione:

E = Phi / 4 * pi * rSqr;

Dove

E è la densità dell'area del flusso.

Phi è flusso di luminosità.

4 * pi * rSqr è la superficie di una sfera.

Questa equazione spiega perché la quantità di energia ricevuta diminuisce con la distanza al quadrato.

Un altro punto è che è necessario calcolare la distanza tra il vertice e la luce per calcolare il contributo della luce su un vertice specifico (è improbabile che questo valore sia memorizzato nella cache), il vertice può essere all'interno o all'esterno dell'intervallo di luce che ci porta al punto successivo dove Radius Squareè utile per l'abbattimento.

Se si desidera un esempio pratico per il calcolo della riduzione della luce e dell'abbattimento, questo è particolarmente utile nei renderer differiti basati su piastrelle, ecco un esempio .


Maledizione, mi hai battuto di 7 secondi! ;) (e anche con una risposta più completa!)
Trevor Powell,

Grazie per il commento dettagliato, esp per il link! Da quello che ho capito da quest'ultimo collegamento, Battlefield 3 non memorizza il raggio ma la distanza effettiva tra la sorgente luminosa e il ricevitore di luce, giusto? Questo è il valore "d" che usano nell'articolo.
Cubrman,

@cubrman è difficile speculare senza vedere il codice. La mia ipotesi è che sia il raggio inverso di SQL. E le equazioni che usano potrebbero variare notevolmente dall'articolo.
concept3d

Ma dimmi, come puoi usare un raggio di luce nudo invertito al quadrato in un calcolo dell'illuminazione? Ogni fonte che ho trovato in rete mi dice che devo trovare la DISTANZA tra la superficie di ricezione e la fonte di luce, dividere quest'ultima per il raggio di luce originale E POI quadrare il risultato. Dove useresti mai il raggio quadrato o invSqrRadius? Mi sembrano dati del tutto irrilevanti.
Cubrman,

1
@cubrman ha aggiornato la risposta.
concept3d

6

invSqrRadius non è 1 - sqrRadius; è 1 / sqrRadius.

Significa che puoi moltiplicare per invSqrRadius, invece di dividere per sqrRadius (poiché la divisione è in genere molto più costosa della moltiplicazione)


6

Le altre risposte qui riguardavano il raggio quadrato inverso, ma esaminerò invece il raggio quadrato (che concept3d ha toccato, ma credo che meriti ulteriori discussioni).

A cosa servono i quadrati sono i confronti di distanza. Sappiamo che il calcolo della distanza tra due punti comporta una radice quadrata e che le radici quadrate sono costose da calcolare, ma se tutto ciò che vogliamo fare è confrontare le distanze (al fine di trovare quale è minore o maggiore e fare qualcosa di interessante in base al risultato) possiamo buttare fuori la radice quadrata.

Se sqrt (x)> sqrt (y), allora è anche il caso che x> y.

Per una luce, il raggio quadrato è uguale alla distanza tra il centro della luce e la sua massima estensione - ovviamente al quadrato.

Per i calcoli dell'illuminazione, questo può essere usato per un caso precoce. Se la distanza tra il punto che stai illuminando e il centro della luce (quadrato) è maggiore del raggio quadrato, il punto non riceve luce e non è necessario eseguire il resto dei tuoi calcoli. Questa è quindi solo un'ottimizzazione (abbastanza comune): possiamo usare il raggio quadrato per fare il confronto della distanza senza costose radici quadrate, e al costo di solo una sottrazione e un prodotto punto.

Naturalmente, non so se questo è esattamente ciò per cui BF3 lo sta usando, ma mi aspetto che non sia troppo lontano dal segno.


Quindi, se ti ho capito correttamente, il codice sarà: if (dot ((lightPos - surfacePos), (lightPos - surfacePos))> lightRadiusSqr) non fare l'illuminazione, giusto?
Cubrman,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.