Perché il calcolo del colore del cielo in Mathematica non è corretto?


17

Sto cercando di implementare un algoritmo per calcolare il colore del cielo basato su questo documento (modello di Perez). Prima di iniziare a programmare lo shader volevo testare il concetto in Mathematica. Ci sono già alcuni problemi che non riesco a liberarmi. Forse qualcuno ha già implementato l'algoritmo.

Ho iniziato con equazioni per le luminanza zenitale assoluti Yz, xze yzcome proposto nella carta (pagina 22). I valori per Yzsembrano essere ragionevoli. Il diagramma seguente mostra Yzuna funzione della distanza zenitale del sole per una torbidità Tdi 5:

Yz (z)

La funzione gamma (zenit, azimuth, solarzenith, solarazimuth) calcola l'angolo tra un punto con la data distanza zenitale e azimut e il sole in una data posizione. Anche questa funzione sembra funzionare. Il diagramma seguente mostra questo angolo per solarzenith=0.5e solarazimuth=0. zenithcresce dall'alto verso il basso (da 0 a Pi / 2), azimuthcresce da sinistra a destra (-Pi a Pi). Puoi vedere chiaramente la posizione del sole (il punto luminoso, l'angolo diventa zero):

gamma (zenit, azimuth, 0.5,0)

La funzione Perez (F) e i coefficienti sono stati implementati come indicato nel documento. Quindi i valori di colore Yxy dovrebbero essere absolute value * F(z, gamma) / F(0, solarzenith). Mi aspetto che tali valori siano compresi nell'intervallo [0,1]. Tuttavia, questo non è il caso del componente Y (vedere l'aggiornamento di seguito per i dettagli). Ecco alcuni valori di esempio:

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

Ecco il risultato attuale:

Immagine RGB

Il Notebook Mathematica con tutti i calcoli può essere trovato qui e la versione PDF qui .

Qualcuno ha idea di cosa devo cambiare per ottenere gli stessi risultati del documento?

C come il codice

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

Soluzione

Come promesso, ho scritto un articolo di blog sul rendering del cielo. Puoi trovarlo qui .


Ho il sospetto che più persone qui sarebbero in grado di aiutarti se tu provassi a implementare l'algoritmo nel codice reale (shader o altro) invece che in Mathematica.
Tetrad

2
C'è un Mathematica SE , anche se dovresti controllare le loro FAQ per vedere se la tua domanda è sull'argomento laggiù.
MichaelHouse

Bene, la domanda non riguarda davvero Mathematica, ma l'algoritmo. Ho aggiunto la versione PDF del notebook, in modo che tutti possano leggerlo. Sono sicuro che la sintassi è comprensibile per un programmatore comune e probabilmente più comprensibile del codice shader.
Nico Schertler,

@NicoSchertler: Il problema è che non penso che molte persone qui capiscano la sintassi di Mathematica. Probabilmente avrai più fortuna se riscrivi il tuo codice in un linguaggio simile a C o Python, almeno ai fini di questa domanda.
Panda Pajama

2
La domanda è davvero troppo localizzata e potrebbe chiudersi, ma grazie per il collegamento cartaceo, è interessante.
Sam Hocevar,

Risposte:


4

Esistono due errori nella matrice utilizzata per xz: 1.00166 dovrebbe essere 0.00166 e 0.6052 dovrebbe essere 0.06052.


Grazie per la correzione. Il risultato ora sembra migliore, ma non può essere corretto. Gradirei se consideri la domanda aggiornata.
Nico Schertler,

-2

Sembra che potrebbe essere un problema di ridimensionamento del valore del colore?


2
Sebbene la tua ipotesi possa essere corretta, sarebbe più utile fornire ulteriori spiegazioni. Dal momento che non puoi rispondere all'intera domanda, quello che hai scritto dovrebbe essere un commento sotto la domanda.
danijar,

Questo non fornisce una risposta alla domanda. Per criticare o richiedere chiarimenti a un autore, lascia un commento sotto il suo post: puoi sempre commentare i tuoi post e una volta che avrai una reputazione sufficiente sarai in grado di commentare qualsiasi post .
MichaelHouse

1
Non capisco perché i suggerimenti non siano tollerati affatto qui. Se guardi la soluzione sopra, è un problema di valore. Indicare le persone nella giusta direzione è il modo migliore per imparare che dare soluzioni esatte tutto il tempo, no? E no, non posso commentare sotto la sua domanda perché non mi è permesso. Ecco perché ho commentato qui. Ma grazie per il degrado. Davvero gentile da parte tua e molto incoraggiante per le nuove persone come me. Grazie.
boobami,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.