Dlaczego moje obliczenia koloru nieba w Mathematica są nieprawidłowe?

17

Próbuję zaimplementować algorytm do obliczania koloru nieba na podstawie tego papieru (model Pereza). Zanim zacząłem programować moduł cieniujący, chciałem przetestować tę koncepcję w Mathematica. Są już pewne problemy, których nie mogę się pozbyć. Może ktoś już zaimplementował algorytm.

Zacząłem z równań dla bezwzględnych zenital luminancji Yz, xza yzjak zaproponowano w dokumencie (strona 22). Wartości dla Yzwydają się rozsądne. Poniższy schemat pokazuje Yzjako funkcję zenitalnej odległości Słońca dla zmętnienia T5:

Yz (z)

Funkcja gamma (zenit, azymut, solarzenit, solarazimuth) oblicza kąt między punktem o danej odległości zenitalnej i azymutu a słońcem w danej pozycji. Wydaje się, że ta funkcja również działa. Poniższy schemat pokazuje ten kąt dla solarzenith=0.5i solarazimuth=0. zenithrośnie od góry do dołu (0 do Pi / 2), azimuthrośnie od lewej do prawej (-Pi do Pi). Możesz wyraźnie zobaczyć pozycję słońca (jasny punkt, kąt staje się zerowy):

gamma (zenit, azymut, 0,5,0)

Zaimplementowano funkcję Pereza (F) i współczynniki podane w artykule. Zatem wartości koloru Yxy powinny być absolute value * F(z, gamma) / F(0, solarzenith). Oczekuję, że wartości te będą się mieścić w przedziale [0,1]. Nie dotyczy to jednak komponentu Y (szczegółowe informacje znajdują się w aktualizacji poniżej). Oto kilka przykładowych wartości:

{Y, x, y}
{19.1548, 0.25984, 0.270379}
{10.1932, 0.248629, 0.267739]
{20.0393, 0.268119, 0.280024}

Oto aktualny wynik:

Obraz RGB

Notatnik Mathematica ze wszystkimi obliczeniami można znaleźć tutaj, a wersję PDF tutaj .

Czy ktoś ma pomysł, co muszę zmienić, aby uzyskać takie same wyniki jak w pracy?

C jak kod

// 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();
    }
}

Rozwiązanie

Zgodnie z obietnicą napisałem artykuł na blogu o renderowaniu nieba. Możesz go znaleźć tutaj .

Nico Schertler
źródło
Podejrzewam, że więcej osób byłoby w stanie Ci pomóc, gdybyś próbował zaimplementować algorytm w rzeczywistym kodzie (moduł cieniujący lub inny) zamiast w Mathematica.
Tetrad
2
Istnieje Mathematica SE , ale musisz sprawdzić ich FAQ, aby sprawdzić, czy twoje pytanie dotyczy danego tematu.
MichaelHouse
Cóż, pytanie tak naprawdę nie dotyczy Matematyki, ale algorytmu. Dodałem wersję PDF notatnika, aby każdy mógł go przeczytać. Jestem pewien, że składnia jest zrozumiała dla zwykłego programisty i prawdopodobnie bardziej zrozumiała niż kod modułu cieniującego.
Nico Schertler
@NicoSchertler: Problem polega na tym, że nie sądzę, aby wiele osób tutaj rozumiało składnię Mathematica. Prawdopodobnie będziesz mieć więcej szczęścia, jeśli przepiszesz kod w języku podobnym do C lub Python, przynajmniej na potrzeby tego pytania.
Panda Pajama
2
Pytanie jest zbyt zlokalizowane i może zostać zamknięte, ale dzięki papierowemu linkowi jest to interesujące.
sam hocevar

Odpowiedzi:

4

W macierzy używanej są dwa błędy xz: 1.00166 powinien wynosić 0,00166, a 0,6052 powinien wynosić 0,06052.

sam hocevar
źródło
Dziękuję za poprawienie mnie. Wynik wygląda teraz lepiej, ale nie może być poprawny. Byłbym wdzięczny, jeśli weźmiesz pod uwagę zaktualizowane pytanie.
Nico Schertler
-2

Wygląda na to, że może to być problem ze skalowaniem wartości kolorów?

boobami
źródło
2
Chociaż twoje założenie może być prawidłowe, bardziej pomocne byłoby podanie dodatkowych wyjaśnień. Ponieważ nie możesz odpowiedzieć na całe pytanie, to, co napisałeś, powinno być komentarzem do pytania.
danijar
To nie daje odpowiedzi na pytanie. Aby skrytykować lub poprosić autora o wyjaśnienie, zostaw komentarz pod jego postem - zawsze możesz komentować własne posty, a gdy będziesz mieć odpowiednią reputację , będziesz mógł komentować każdy post .
MichaelHouse
1
Nie rozumiem, dlaczego w ogóle sugestie nie są tutaj tolerowane. Jeśli spojrzysz na powyższe rozwiązanie, jest to problem z wartością. Wskazanie ludziom we właściwym kierunku jest lepszym sposobem na naukę niż ciągłe podawanie dokładnych rozwiązań, prawda? I nie, nie mogę skomentować poniżej jego pytania, ponieważ nie wolno mi. Dlatego skomentowałem tutaj. Ale dzięki za degradację. Naprawdę miło z twojej strony i bardzo zachęcająca dla nowych ludzi takich jak ja. Dziękuję Ci.
boobami,