Kare hesaplama yarıçapı ve ters kare yarıçapının aydınlatma hesaplamaları için faydası nedir?


16

"DirectX 11 Battlefield 3 Rendering" PowerPoint slaytlardan birinde Aşağıdaki kod fark ettim:

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

Neden sadece yarıçapı depolamak yerine kare yarıçapı ve hatta ters kare (sadece 1 kare yarıçap olduğuna inanıyorum) depolayacaklarını anlamıyorum? Bu verileri hesaplamalarında nasıl kullanıyorlar? Dahası, koni ve hat ışıkları ne olacak? Bu yapı sadece nokta ışıkları için olmalı, diğer türler için çalıştığını göremiyorum - yeterli veri yok. Yine de o kareyi ve invSquare'i nasıl kullandıklarını bilmek isterim.

GÜNCELLEME: Tamam sonunda anladım.

İşte ağda kolayca bulunan klasik ışık zayıflama denklemi:

float3 lightVector = lightPosition - surfacePosition;

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

length(lightVector)Aslında bunu yapmak nispeten maliyetlidir :

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

ayrıca bölüm operasyonu (/lightRadius)da oldukça maliyetlidir.

Işık zayıflamasını bu şekilde hesaplamak yerine, aşağıdaki şekilde hesaplayabilirsiniz; bu çok daha hızlı olacaktır:

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

burada invRadiusSqr, CPU düzeyinde önceden hesaplanabilir ve gölgelendirici sabiti olarak geçirilebilir.

Dahası, sonuç olarak ikinci dereceden bir ışık zayıflaması elde edersiniz (eski durumda doğrusal yerine), bu daha da iyidir, çünkü IRL ışığının kuadratik falloff'a sahip olduğu gösterilmiştir.

Yardımlarınız için herkese teşekkürler!


13
Dolgu malzemesi. Gölgelendiriciler 16 bayt hizalıdır. Kodun nasıl oluşturulduğuna bir göz atarsanız, kodun iki float4 içine paketleneceğini göreceksiniz. Neden önbellekten ücretsiz alacağınız zaman faydalı bir şey saklamıyorsunuz?
Tordin

Yanıtlar:


23

Bu, basitçe invSqrRadius = 1/SqrRadiusher önbelleğe aldıklarında her ışık için ters kare yarıçapını hesaplamak yerine, bölünmenin genellikle en azından çarpma ile karşılaştırıldığında "yavaş" bir işlem olması nedeniyle bir tür optimizasyondur .

Bu optimizasyon özellikle aşağıdakilerle ilgilidir:

  • işlem her ışık için büyük miktarda yapıldığında, değerin önbelleğe alınması ekstra CPU / GPU döngülerini serbest bırakır
  • Ve değeri okumak için bellek erişim süresinin varsayılması aslında değeri yeniden hesaplamaktan daha hızlıdır.

Nasıl kullanıldığına ilişkin olarak 1/sqrRadius, bunların spesifik uygulamalarından emin değilim, ancak bu sadece hafif zayıflama, falloff ve culling için kullanılır. Yönlü ve spot ışığı için de geçerlidir, spot ışığı durumunda tek fark , zayıflamayı uyguladıktan sonra spot ışığı faktörünü hesaplamanız gerektiğidir . Güneş gibi yön ışıklarına gelince, genellikle herhangi bir zayıflama veya serpinti yoktur, bu yüzden göz ardı edilecektir.

[DÜZENLE] Sadece daha fazla ayrıntıya varmak, ilgisiz veriler değildir . Işık Işınımı aşağıdaki denklem kullanılarak hesaplanabilir:

E = Phi / 4 * pi * rSqr;

Nerede

E , akının alan yoğunluğudur.

Phi ışınım akısıdır.

4 * pi * rSqr bir kürenin yüzey alanıdır.

Bu denklem, alınan enerji miktarının neden kare mesafeyle düştüğünü açıklar.

Başka bir nokta, belirli bir tepe noktasındaki ışık katkısını hesaplamak için tepe noktası ve ışık arasındaki mesafeyi hesaplamanız gerekir (bu değerin önbelleğe alınması olası değildir), tepe noktası bizi bir sonraki noktaya getiren ışık aralığının içinde veya dışında olabilir burada Radius Squareitlaf için yararlıdır.

Hafif serpinti ve itlağın hesaplanması için pratik bir örnek istiyorsanız, bu özellikle kiremit bazlı ertelenmiş renderörlerde yararlıdır, burada bir örnek .


Lanet olsun, beni 7 saniye geçtin! ;) (ve daha kapsamlı bir cevapla!)
Trevor Powell

Ayrıntılı yorum için teşekkürler, bağlantı için esp! İkinci bağlantıdan anladığım kadarıyla, Battlefield 3 yarıçapı değil, ışık kaynağı ve ışık alıcısı arasındaki gerçek mesafeyi saklıyor, değil mi? Makalede kullandıkları "d" değeri budur.
cubrman

@cubrman kod görmeden tahmin etmek zor. Benim tahminim bunun ters yarıçap olması. Ve kullandıkları denklemler makaleden çok farklı olabilir.
concept3d

Ama söyle bana, bir aydınlatma hesaplamasında kare şeklinde çıplak ters ışık yarıçapını nasıl kullanabilirsin? Ağda bulduğum her kaynak bana alıcı yüzey ile ışık kaynağı arasındaki MESAFEDİ bulmam gerektiğini söyler, ikincisini orijinal ışık yarıçapına böler ve SONRA kareyi sonuçlandırır. Kare yarıçapı veya invSqrRadius'u nerelerde kullanırsınız? Bu benim için tamamen alakasız veri gibi görünüyor.
cubrman

1
@cubrman cevabı güncelledi.
concept3d

6

invSqrRadius 1 - sqrRadius değil; 1 / sqrRadius.

Bu, sqrRadius'a bölmek yerine invSqrRadius ile çarpabileceğiniz anlamına gelir (bölme genellikle çarpma işleminden çok daha pahalıdır)


6

Buradaki diğer cevaplar ters kare yarıçapıyla ilgiliydi, ancak bunun yerine kare yarıçapa bakacağım (hangi concept3d'ye değindi, ancak daha fazla tartışmayı hak ettiğine inanıyorum).

Kareler için kullanışlı olan mesafe karşılaştırmalarıdır. İki nokta arasındaki mesafeyi hesaplamanın bir kare kök içerdiğini ve kare köklerin hesaplanmasının pahalı olduğunu biliyoruz, ancak yapmak istediğimiz tek şey mesafeleri karşılaştırmaksa (hangisinin daha az veya daha büyük olduğunu bulmak ve sonuç) kare kökü atabiliriz.

Sqrt (x)> sqrt (y) ise x> y için de geçerlidir.

Bir ışık için, kare yarıçapı ışığın merkezi ile maksimum kare arasındaki mesafeyle aynıdır - elbette kare.

Aydınlatma hesaplamaları için bu erken bir durum için kullanılabilir. Aydınlattığınız nokta ile ışığın merkezi (kare) arasındaki mesafe, kare yarıçapından daha büyükse, nokta ışığı almaz ve geri kalan hesaplamalarınızı çalıştırmanıza gerek yoktur. Bu nedenle bu sadece bir optimizasyondur (oldukça yaygın olanı) - pahalı kare kökler olmadan ve sadece bir çıkarma ve nokta ürünü pahasına mesafe karşılaştırması yapmak için kare yarıçapı kullanabiliriz.

Tabii ki, bunun tam olarak BF3'ün ne için kullanılıp kullanılmadığını bilmiyorum, ama çok uzakta olmamam bekleniyor.


Seni doğru anladıysam, kod şöyle olacak: if (dot ((lightPos - surfacePos), (lightPos - surfacePos))> lightRadiusSqr) aydınlatma yapmıyor, değil mi?
cubrman
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.