Quelle est l'utilité du rayon carré et du rayon carré inverse pour les calculs d'éclairage?

16

Sur l'une des diapositives de PowerPoint "Rendu DirectX 11 dans Battlefield 3", j'ai remarqué le code suivant:

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

Je ne comprends pas pourquoi stockeraient-ils le rayon carré et même l'inverse du carré (qui, je crois, est simplement un rayon de 1 carré) au lieu de simplement stocker le rayon? Comment utilisent-ils ces données dans leurs calculs? De plus, qu'en est-il des lampes à cône et à ligne? Cette structure ne doit être que pour les lumières ponctuelles, je ne la vois pas fonctionner pour d'autres types - il n'y a pas assez de données. J'aimerais quand même savoir comment ils utilisent ce carré et invSquare.

MISE À JOUR: Ok, je l'ai enfin compris.

Voici l'équation classique d'atténuation de la lumière, facilement trouvée sur le net:

float3 lightVector = lightPosition - surfacePosition;

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

C'est relativement coûteux, comme length(lightVector)c'est le cas en réalité:

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

en outre, l'opération de division (/lightRadius)est également très coûteuse.

Au lieu de calculer l'atténuation de la lumière de cette façon, vous pouvez la calculer de la manière suivante, ce qui serait beaucoup plus rapide:

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

où invRadiusSqr peut être précalculé au niveau du processeur et passé en tant que constante de shader.

De plus, vous obtenez une atténuation de la lumière quadratique en conséquence (au lieu de linéaire dans le premier cas), ce qui est encore mieux, car la lumière IRL a montré une atténuation quadratique.

Merci à tous pour votre aide!

cubrman
la source
13
Rembourrage. Les shaders sont alignés sur 16 octets. Et si vous regardez comment le code est formaté, vous verrez qu'il sera emballé dans deux float4. Pourquoi ne pas stocker quelque chose d'utile lorsque vous l'obtiendrez gratuitement du cache?
Tordin

Réponses:

23

Il s'agit simplement d'une sorte d'optimisation étant donné qu'au invSqrRadius = 1/SqrRadiuslieu de calculer le rayon carré inverse pour chaque lumière chaque fois qu'ils la mettent simplement en cache, la raison est que la division est généralement une opération "lente" au moins par rapport à la multiplication.

Cette optimisation est pertinente notamment:

  • lorsque l'opération est effectuée un nombre énorme de fois pour chaque lumière, la mise en cache de la valeur libérera des cycles CPU / GPU supplémentaires
  • Et en supposant que le temps d'accès à la mémoire pour lire la valeur est en fait plus rapide que de le recalculer.

En ce qui concerne la façon dont il est utilisé, je ne suis pas sûr de leur mise en œuvre spécifique, mais en ce qui concerne 1/sqrRadius, cela est simplement utilisé pour l'atténuation de la lumière, l'atténuation et l'abattage. Il est également pertinent pour la direction et le projecteur, la seule différence en cas de projecteur est que vous devez calculer le facteur de projecteur après avoir appliqué l'atténuation . En ce qui concerne les lumières directionnelles comme le soleil, il n'y a généralement pas d'atténuation ni d'atténuation, donc je suppose qu'il sera ignoré.

[EDIT] Juste pour développer davantage, ce ne sont pas des données non pertinentes. L'irradiance lumineuse peut être calculée en utilisant l'équation suivante:

E = Phi / 4 * pi * rSqr;

E est la densité surfacique du flux.

Phi est le flux de rayonnement.

4 * pi * rSqr est la surface d'une sphère.

Cette équation explique pourquoi la quantité d'énergie reçue diminue avec la distance au carré.

Un autre point est que vous devez calculer la distance entre le sommet et la lumière pour calculer la contribution de la lumière sur un sommet spécifique (cette valeur est peu susceptible d'être mise en cache), le sommet peut être dans ou en dehors de la plage de lumière qui nous amène au point suivant où Radius Squareest utile pour l'abattage.

Si vous voulez un exemple pratique pour calculer l'atténuation de la lumière et l'abattage, c'est particulièrement utile dans les rendus différés en mosaïque, voici un exemple .

concept3d
la source
Maudits, tu m'as battu de 7 secondes! ;) (et avec une réponse plus complète aussi!)
Trevor Powell
Merci pour le commentaire détaillé, surtout pour le lien! D'après ce que j'ai compris de ce dernier lien, Battlefield 3 stocke non pas le rayon mais la distance réelle entre la source de lumière et le récepteur de lumière, non? C'est la valeur "d" qu'ils utilisent dans l'article.
cubrman
@cubrman, il est difficile de spéculer sans voir le code. Je suppose que c'est l'inverse radiusSqr. Et les équations qu'ils utilisent peuvent varier considérablement de l'article.
concept3d
Mais dites-moi, comment pouvez-vous utiliser un rayon de lumière inversée nue au carré dans un calcul d'éclairage? Chaque source que j'ai trouvée sur le net me dit que je dois trouver la DISTANCE entre la surface de réception et la source de lumière, diviser cette dernière par le rayon de lumière d'origine ET PUIS mettre le résultat au carré. Où utiliseriez-vous un rayon carré ou invSqrRadius? Cela me semble être des données complètement hors de propos.
cubrman
1
@cubrman a mis à jour la réponse.
concept3d
6

invSqrRadius n'est pas 1 - sqrRadius; c'est 1 / sqrRadius.

Cela signifie que vous pouvez multiplier par invSqrRadius, au lieu de diviser par sqrRadius (car la division est généralement beaucoup plus coûteuse que la multiplication)

Trevor Powell
la source
6

Les autres réponses ici concernaient le rayon carré inverse, mais je vais plutôt regarder le rayon carré (dont concept3d a parlé, mais je crois qu'il mérite une discussion plus approfondie).

Les carrés sont utiles pour les comparaisons de distance. Nous savons que le calcul de la distance entre deux points implique une racine carrée, et les racines carrées sont coûteuses à calculer, mais si tout ce que nous voulons faire est de comparer les distances (afin de trouver ce qui est inférieur ou supérieur, et faire quelque chose d'intéressant en fonction de la résultat) nous pouvons jeter la racine carrée.

Si sqrt (x)> sqrt (y) alors c'est aussi le cas que x> y.

Pour une lumière, le rayon carré est le même que la distance entre le centre de la lumière et son étendue maximale - au carré, bien sûr.

Pour les calculs d'éclairage, cela peut être utilisé pour un cas de sortie anticipée. Si la distance entre le point que vous allumez et le centre de la lumière (au carré) est supérieure au rayon carré, le point ne reçoit aucune lumière et vous n'avez pas besoin d'exécuter le reste de vos calculs. Il ne s'agit donc que d'une optimisation (assez courante) - nous pouvons utiliser le rayon carré pour faire la comparaison de distance sans racines carrées coûteuses, et au prix d'une soustraction et d'un produit scalaire.

Bien sûr, je ne sais pas si c'est exactement pour cela que BF3 l'utilise, mais je m'attends à ce que je ne sois pas trop loin de la cible.

Maximus Minimus
la source
Donc, si je vous ai bien compris, le code sera: si (point ((lightPos - surfacePos), (lightPos - surfacePos))> lightRadiusSqr) ne fait pas d'éclairage, non?
cubrman