Mathematica'daki gökyüzü rengi hesaplamam neden yanlış?


17

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, xzve yzkağıt (sayfa 22) önerdiği gibi. Değerleri Yzmakul görünmektedir. Aşağıdaki şema, 5 Yzbulanıklık Tile güneşin zenital mesafesinin bir fonksiyonu olarak göstermektedir :

Yz (Z)

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.5ve için bu açıyı göstermektedir solarazimuth=0. zenithyukarıdan aşağıya doğru büyür (0'dan Pi / 2'ye), azimuthsoldan 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):

y (başucu, azimut, 0.5,0)

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ç:

RGB görüntü

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 .


Mathematica yerine gerçek kodda (gölgelendirici veya başka bir şekilde) algoritmayı uygulamaya çalışsaydınız, burada daha fazla kişinin size yardımcı olabileceğinden şüpheleniyorum.
Tetrad

2
Bir Mathematica SE var , ancak sorunuzun konuyla ilgili olup olmadığını görmek için SSS'lerini kontrol etmeniz gerekir.
MichaelHouse

Soru aslında Mathematica ile ilgili değil, algoritma ile ilgili. Not defterinin PDF sürümünü ekledim, böylece herkes okuyabilir. Sözdiziminin ortak bir programcı için anlaşılır ve muhtemelen gölgelendirici kodundan daha anlaşılır olduğundan eminim.
Nico Schertler

@NicoSchertler: Sorun şu ki, buradaki birçok insanın Mathematica sözdizimini anladığını sanmıyorum. En azından bu sorunun amaçları için kodunuzu C benzeri veya Python benzeri bir dilde yeniden yazarsanız muhtemelen daha fazla şansınız olacaktır.
Panda Pijama

2
Soru gerçekten çok yerelleştirilmiş ve kapanabilir, ancak kağıt bağlantısı için teşekkürler, ilginç.
sam hocevar

Yanıtlar:


4

Kullanılan matriste iki hata vardır xz: 1.00166 0.00166 ve 0.6052 0.06052 olmalıdır.


Düzeltme için teşekkürler. Sonuç şimdi daha iyi görünüyor, ancak doğru olamaz. Güncellenmiş soruyu düşünürseniz sevinirim.
Nico Schertler

-2

Renk değeri ölçeklendirme sorunu olabilir gibi görünüyor?


2
Varsayımınız doğru olsa da, ek açıklamalar yapmak daha yararlı olacaktır. Tüm soruyu cevaplayamadığınız için, yazdıklarınız sorunun altında bir yorum olmalıdır.
danijar

Bu soruya bir cevap vermez. Bir yazardan eleştiri almak veya açıklama istemek için yazılarının altına bir yorum bırakın - her zaman kendi yayınlarınıza yorum yapabilirsiniz ve yeterli bir üne sahip olduğunuzda herhangi bir yazı hakkında yorum yapabilirsiniz .
MichaelHouse

1
Buradaki önerilerin neden hiç hoş görmediğini anlamıyorum. Yukarıdaki çözüme bakarsanız, bu bir değer sorunudur. İnsanları doğru yöne yönlendirmek, öğrenmenin her zaman kesin çözümler vermekten daha iyi bir yol değil mi? Ve hayır, sorunun altında yorum yapamam çünkü buna izin verilmiyor. Bu yüzden buraya yorum yaptım. Ama adanmışlık için teşekkürler. Gerçekten çok hoş ve benim gibi yeni insanlara çok cesaret verici. Teşekkür ederim.
boobami
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.