Bu kağıda (Perez 'modeli) dayalı gökyüzü rengini hesaplamak için bir algoritma uygulamaya çalışıyorum . Gölgelendiriciyi programlamaya başlamadan önce, Mathematica'daki konsepti test etmek istedim. Zaten kurtulamadığım bazı sorunlar var. Belki birisi zaten algoritmayı uygulamıştır.
Ben mutlak zenital parlaklıklarına için denklemler ile başladı Yz
, xz
ve yz
kağıt (sayfa 22) önerdiği gibi. Değerleri Yz
makul görünmektedir. Aşağıdaki şema, 5 Yz
bulanıklık T
ile güneşin zenital mesafesinin bir fonksiyonu olarak göstermektedir :
Gama fonksiyonu (zenith, azimuth, solarzenith, solarazimuth) verilen zenital mesafe ile azimut ve verilen pozisyondaki güneş arasındaki bir nokta arasındaki açıyı hesaplar. Bu işlev de işe yarıyor gibi görünüyor. Aşağıdaki şema solarzenith=0.5
ve için bu açıyı göstermektedir solarazimuth=0
. zenith
yukarıdan aşağıya doğru büyür (0'dan Pi / 2'ye), azimuth
soldan sağa doğru büyür (-Pi'den Pi'ye). Güneşin pozisyonunu açıkça görebilirsiniz (parlak nokta, açı sıfır olur):
Perez fonksiyonu (F) ve katsayıları makalede verildiği gibi uygulanmıştır. Sonra Yxy renk değerleri olmalıdır absolute value * F(z, gamma) / F(0, solarzenith)
. Bu değerlerin [0,1] aralığında olmasını bekliyorum. Ancak, Y bileşeni için durum böyle değildir (ayrıntılar için aşağıdaki güncellemeye bakın). Aşağıda bazı örnek değerler verilmiştir:
{Y, x, y}
{19.1548, 0.25984, 0.270379}
{10.1932, 0.248629, 0.267739]
{20.0393, 0.268119, 0.280024}
Mevcut sonuç:
Tüm hesaplamaları içeren Mathematica Not Defteri'ni burada ve PDF sürümünü burada bulabilirsiniz .
Gazetede olduğu gibi aynı sonuçları almak için neyi değiştirmem gerektiğine dair bir fikri olan var mı?
C kodu gibi
// this function returns the zenital Y component for
// a given solar zenital distance z and turbidity T
float Yz(float z, float T)
{
return (4.0453 * T - 4.9710)*tan( (4.0f/9-T/120)*(Pi-2*z) ) - 0.2155 * T + 2.4192
}
// returns zenital x component
float xz(float z, float T)
{
return //matrix calculation, see paper
}
// returns zenital y component
float yz(float z, float T)
{
return //matrix calculation, see paper
}
// returns the rgb color of a Yxy color
Color RGB(float Y, float x, float y)
{
Matrix m; //this is a CIE XYZ -> RGB conversion matrix
Vector v;
v.x = x/y*Y;
v.y = Y;
v.z = (1-x-y)/y*Y;
v = M * v; //matrix-vector multiplication;
return Color ( v.x, v.y, v.z );
}
// returns the 5 coefficients (A-E) for the given turbidity T
float[5] CoeffY(float T)
{
float[5] result;
result[0] = 0.1787 * T - 1.4630;
result[1] = -0.3554 * T + 0.4275;
...
return result;
}
//same for Coeffx and Coeffy
// returns the angle between an observed point and the sun
float PerezGamma(float zenith, float azimuth, float solarzenith, float solarazimuth)
{
return acos(sin(solarzenith)*sin(zenith)*cos(azimuth-solarazimuth)+cos(solarzenith)*cos(zenith));
}
// evalutes Perez' function F
// the last parameter is a function
float Perez(float zenith, float gamma, float T, t->float[5] coeffs)
{
return (1+coeffs(T)[0] * exp(coeffs(T)[1]/cos(zenith)) *
(1+coeffs(T)[2] * exp(coeffs(T)[3]*gamma) +
coeffs(T)[4]*pow(cos(gamma),2))
}
// calculates the color for a given point
YxyColor calculateColor(float zenith, float azimuth, float solarzenith, float solarazimuth, float T)
{
YxyColor c;
float gamma = PerezGamma(zenith, azimuth, solarzenith, solarazimuth);
c.Y = Yz(solarzenith, T) * Perez(zenith, gamma, T, CoeffY) / Perez(0, solarzenith, T, CoeffY);
c.x = xz(solarzenith, T) * Perez(zenith, gamma, T, Coeffx) / Perez(0, solarzenith, T, Coeffx);
c.y = yz(solarzenith, T) * Perez(zenith, gamma, T, Coeffy) / Perez(0, solarzenith, T, Coeffy);
return c;
}
// draws an image of the sky
void DrawImage()
{
for(float z from 0 to Pi/2) //zenithal distance
{
for(float a from -Pi to Pi) //azimuth
{
YxyColor c = calculateColor(zenith, azimuth, 1, 0, 5);
Color rgb = RGB(c.Y, c.x, c.y);
setNextColor(rgb);
}
newline();
}
}
Çözüm
Söz verdiğim gibi gökyüzünü oluşturmakla ilgili bir blog yazısı yazdım. Burada bulabilirsiniz .