GLSL Işık (Zayıflama, Renk ve yoğunluk) formülü


17

Voxel motoruma nokta ışıkları uyguluyorum ve ışık kaynağının% 100'ünden ışık yarıçapında% 0'a kadar iyi bir ışık akışı elde etmek için gerçekten zorlanıyorum.

Ben işlevi için 5 argüman var:

  1. Açık renk (Vec3)
  2. Işık yoğunluğu (ışıktan serpinti% 100 olan mesafeye kadar olan mesafe)
  3. Işıktan parçaya uzaklık
  4. Normal parçadan ışığa açı
  5. Işığın konumu

Parça renginin hesaplanması için bir işlev oluşturmak üzere beni doğru yönde iten biri olabilir mi?

Deneylerimden birinin resmi:

Voxel Motor Parça Başı Aydınlatma Testi

Düzenle (Bayt tarafından istenen geçerli kod) Bunun benim tarafımdan yalnızca bir deneme kodu olduğunu unutmayın. Bir web sitesinden float att aldım ve çeşit çalışıyor, ama mükemmel olmaktan uzak. :

void main()
{
// Light color
vec3 torchColor = vec3(1.0f, 1.0f, 1.0f);

float lightAdd = 0.0f;
for (int i=0; i<5; i++) {
    vec3 pos = lights[i];
    if (pos.x == 0.0f) continue;

    float dist = distance(vertex_pos, pos);
    if (dist < 9) {
        float att=1.0/(1.0+0.1*dist+0.01*dist*dist);
        vec3 surf2light = normalize(pos - vertex_pos);
        vec3 norm = normalize(normal);
        float dcont=max(0.0,dot(norm,surf2light));
        lightAdd += att*(dcont+0.4);
    }
}

vec3 textureColor = texture2D(texture, texture_coordinate).rgb;
vec3 torch_output = lightAdd * torchColor;

vec3 final_color = ((0.1+torch_output) * textureColor);

gl_FragColor = vec4(final_color, 1.0f); 
}

6
Hala " iyi görünümlü , doğal ışıklar elde etmek için mücadele etmek " ve "çalışıyor, ama mükemmel olmaktan uzak " gibi şeyler söylüyorsunuz . Belirli, kesin bir dil eklemeniz gerekir. Size neyin iyi baktığını, doğal ışıkların size neye benzediğini veya neyin mükemmel olduğunu bilmiyoruz.
MichaelHouse

2
Kaldırmayı denedin if (dist < 9)mi? Alternatif olarak hesaplayabileceğini attmesafe 9. Örn olduğunda mesafe 0, 0 olduğu zaman döner 1 bir fonksiyonu ilemix(1.0, 0.0, dist / 9.0)
msell

Yanıtlar:


39

Sahip olduğunuz zayıflama fonksiyonu,

att = 1.0 / (1.0 + 0.1*dist + 0.01*dist*dist)

bilgisayar grafiklerinde oldukça yaygın olanıdır - veya daha genel olarak 1.0 / (1.0 + a*dist + b*dist*dist))bazı değiştirilebilir parametreler için ave b. Bu eğrinin nasıl çalıştığını anlamak için parametrelerle etkileşimli olarak oynamak yararlıdır . Bu eğri güzeldir, çünkü büyük mesafelerde fiziksel olarak doğru ters kare yasasına yaklaşır, ancak kısa mesafelerde sonsuza kadar ateş etmez. Aslında, a = 0küresel alan ışığının oldukça iyi bir modeli.

Bununla birlikte, bunun bir dezavantajı, ışığın herhangi bir sonlu mesafede asla tamamen sıfıra gitmemesidir. Gerçek zamanlı CG'de pratik amaçlar için, if (dist < 9)maddede yaptığınız gibi, ışıkları genellikle sonlu bir mesafeden kesmemiz gerekir . Bununla birlikte, 9 yarıçapı çok kısadır - zayıflama işlevindeki ayarlarınızla, dağıtım 100 civarında oluncaya kadar ışık sıfıra yaklaşmaz.

bZayıflatma işlevindeki parametreden ışığın yarıçapını hesaplayabilirsiniz (kuadratik terim büyük mesafelerde hakim olduğu için). Zayıflama minLight0.01 gibi bir değere ulaştığında ışığı kesmek istediğinizi varsayalım . Sonra ayarlayın

radius = sqrt(1.0 / (b * minLight))

Bu, b = 0.01ve için 100 bir yarıçap verir minLight = 0.01. Alternatif olarak, yarıçapı ayarlayabilir ve beşleşecek şekilde hesaplayabilirsiniz :

b = 1.0 / (radius*radius * minLight)

İçin radius = 9ve minLight = 0.01o verir b = 1.23. Her iki şekilde de ayarlayabilirsiniz, ancak anahtar, yarıçap ve zayıflama işlevinin eşleşmesini sağlamaktır, böylece zayıflama işlevi zaten çok düşük olana kadar ışığı kesmezsiniz, böylece keskin bir kenar görmezsiniz.


Bütün bunlar, kullanabileceğiniz alternatif zayıflama fonksiyonları vardır. Oldukça yaygın olan bir diğeri:

att = clamp(1.0 - dist/radius, 0.0, 1.0); att *= att

veya biraz meraklısı:

att = clamp(1.0 - dist*dist/(radius*radius), 0.0, 1.0); att *= att

Bu parametreler için de parametrelerle oynayın . Bu eğriler , verilen yarıçapta tam sıfıra gitme avantajına sahipken, yine de doğal ters kare yasasına benziyor.


Harika! Gerçi, ben kullanırım maxüzerinde clampperformans nedenleriyle yalnızca.
Mike Weir

4
@MikeWeir Aslında [0, 1] 'e bağlanmak birçok GPU'da ücretsizdir. Bir talimat değiştirici olarak sahip oldukları yaygın bir işlemdir.
Nathan Reed
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.