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 .


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.


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?


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,
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.