Tại sao tính toán màu trời của tôi trong Mathicala không chính xác?


17

Tôi đang cố gắng thực hiện một thuật toán để tính toán màu trời dựa trên bài báo này (mô hình của Perez). Trước khi tôi bắt đầu lập trình trình đổ bóng, tôi muốn kiểm tra khái niệm trong Mathicala. Đã có một số vấn đề tôi không thể thoát khỏi. Có lẽ ai đó đã thực hiện thuật toán.

Tôi bắt đầu với các phương trình cho độ chói zenital tuyệt đối Yz, xzyznhư đề xuất trong bài báo (trang 22). Các giá trị Yzdường như là hợp lý. Sơ đồ sau đây cho thấy Yzlà một hàm của khoảng cách zenital của mặt trời cho độ đục T5:

Yz (z)

Hàm gamma (zenith, azimuth, solarzenith, solarazimuth) tính toán góc giữa một điểm với khoảng cách zenital đã cho và góc phương vị và mặt trời tại vị trí đã cho. Chức năng này dường như cũng hoạt động. Sơ đồ sau cho thấy góc này cho solarzenith=0.5solarazimuth=0. zenithphát triển từ trên xuống (0 đến Pi / 2), azimuthphát triển từ trái sang phải (-Pi đến Pi). Bạn có thể thấy rõ vị trí của mặt trời (điểm sáng, góc trở thành số không):

gamma (thiên đỉnh, góc phương vị, 0,5,0)

Hàm Perez (F) và các hệ số đã được thực hiện như được nêu trong bài báo. Thì các giá trị màu Yxy phải là absolute value * F(z, gamma) / F(0, solarzenith). Tôi hy vọng những giá trị đó sẽ nằm trong phạm vi [0,1]. Tuy nhiên, đây không phải là trường hợp của thành phần Y (xem cập nhật bên dưới để biết chi tiết). Dưới đây là một số giá trị mẫu:

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

Đây là kết quả hiện tại:

Hình ảnh RGB

Sổ tay Mathicala với tất cả các tính toán có thể được tìm thấy ở đây và phiên bản PDF ở đây .

Có ai có ý tưởng gì về những gì tôi phải thay đổi để có được kết quả tương tự như trong bài báo không?

C như mã

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

Giải pháp

Như đã hứa, tôi đã viết một bài viết trên blog về việc vẽ lại bầu trời. Bạn có thể tìm thấy nó ở đây .


Tôi nghi ngờ rằng nhiều người ở đây sẽ có thể giúp bạn nếu bạn cố gắng thực hiện thuật toán theo mã thực tế (shader hoặc cách khác) thay vì trong Mathicala.
Tetrad

2
Có một Mathicala SE , mặc dù bạn sẽ phải kiểm tra Câu hỏi thường gặp của họ để xem câu hỏi của bạn có thuộc chủ đề ở đó không.
MichaelHouse

Chà, câu hỏi không thực sự là về Mathematica, mà là về thuật toán. Tôi đã thêm phiên bản PDF của máy tính xách tay, để mọi người có thể đọc nó. Tôi chắc chắn rằng cú pháp dễ hiểu đối với một lập trình viên thông thường và có lẽ dễ hiểu hơn mã shader.
Nico Schertler

@NicoSchertler: Vấn đề là tôi không nghĩ nhiều người ở đây hiểu cú pháp Mathicala. Bạn có thể sẽ gặp nhiều may mắn hơn nếu bạn viết lại mã của mình bằng ngôn ngữ giống như C hoặc Python, ít nhất là cho mục đích của câu hỏi này.
Panda Pyjama

2
Câu hỏi thực sự quá cục bộ và có thể bị đóng lại, nhưng cảm ơn vì liên kết giấy, thật thú vị.
sam hocevar

Câu trả lời:


4

Có hai lỗi trong ma trận được sử dụng cho xz: 1.00166 là 0,00166 và 0,6052 phải là 0,06052.


Cảm ơn vì sự đúng đắn của bạn. Kết quả bây giờ có vẻ tốt hơn, nhưng không thể chính xác. Tôi sẽ đánh giá cao nếu bạn xem xét các câu hỏi cập nhật.
Nico Schertler

-2

Có vẻ như đó có thể là vấn đề mở rộng giá trị màu?


2
Mặc dù giả định của bạn có thể đúng nhưng sẽ hữu ích hơn khi cung cấp các giải thích bổ sung. Vì bạn không thể trả lời toàn bộ câu hỏi những gì bạn đã viết nên là một nhận xét dưới câu hỏi.
danijar

Điều này không cung cấp một câu trả lời cho câu hỏi. Để phê bình hoặc yêu cầu làm rõ từ một tác giả, hãy để lại nhận xét bên dưới bài đăng của họ - bạn luôn có thể nhận xét về bài đăng của riêng bạn và khi bạn có đủ danh tiếng, bạn sẽ có thể nhận xét về bất kỳ bài đăng nào .
MichaelHouse

1
Tôi không hiểu tại sao các đề xuất không được chấp nhận ở đây. Nếu bạn nhìn vào giải pháp ở trên, đó là một vấn đề giá trị. Chỉ cho mọi người đi đúng hướng là cách học tốt hơn là đưa ra giải pháp chính xác mọi lúc phải không? Và không, tôi không thể bình luận bên dưới câu hỏi của anh ấy vì tôi không được phép. Đó là lý do tại sao tôi bình luận ở đây. Nhưng cảm ơn vì sự hạ bệ. Thực sự tốt đẹp của bạn và rất khích lệ những người mới như tôi. Cảm ơn bạn.
boobami
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.