Bầu trời tán xạ khí quyển từ các tạo tác không gian


20

Tôi đang trong quá trình thực hiện sự tán xạ khí quyển của các hành tinh từ không gian. Tôi đã sử dụng shader của Sean O'Neil từ http://http.developer.nvidia.com/GPUGems2/gpugems2_ch CHƯƠNG16.html làm điểm bắt đầu.

Tôi có khá nhiều vấn đề tương tự liên quan đến fCameraAngle ngoại trừ với trình tạo bóng SkyFromSpace trái ngược với trình tạo bóng GroundFromSpace như ở đây: http://www.gamedev.net/topic/621187-sean-oneils-at Khíheric-scattering /

Tôi nhận được các vật phẩm lạ với bầu trời từ shader không gian khi không sử dụng fCameraAngle = 1trong vòng lặp bên trong. Nguyên nhân của những cổ vật này là gì? Các vật phẩm biến mất khi fCameraAngle bị giới hạn ở 1. Tôi dường như cũng thiếu màu sắc có trong hộp cát của O'Neil ( http://sponeil.net/doads.htmlm )

Vị trí camera X = 0, Y = 0, Z = 500. GroundFromSpace ở bên trái, SkyFromSpace ở bên phải. nhập mô tả hình ảnh ở đây

Vị trí camera X = 500, Y = 500, Z = 500. GroundFromSpace ở bên trái, SkyFromSpace ở bên phải. nhập mô tả hình ảnh ở đây

Tôi thấy rằng góc máy ảnh dường như xử lý rất khác nhau tùy theo nguồn:

Trong các shader gốc, góc camera trong SkyFromSpaceShader được tính như sau:

float fCameraAngle = dot(v3Ray, v3SamplePoint) / fHeight;

Trong khi ở mặt đất từ ​​không gian đổ bóng, góc camera được tính như sau:

float fCameraAngle = dot(-v3Ray, v3Pos) / length(v3Pos);

Tuy nhiên, nhiều nguồn tin trực tuyến khác nhau với phủ định các tia. Tại sao lại thế này?

Đây là một dự án C # Windows.Forms thể hiện vấn đề và tôi đã sử dụng để tạo các hình ảnh: https://github.com/ollipekka/At KhíhericScatteringTest /

Cập nhật: Tôi đã phát hiện ra từ dự án ScatterCPU được tìm thấy trên trang web của O'Nilil rằng tia camera bị phủ định khi camera ở trên điểm bị bóng mờ để độ tán xạ được tính từ điểm đến camera.

Thay đổi hướng tia thực sự sẽ loại bỏ các vật phẩm, nhưng đưa ra các vấn đề khác như được minh họa ở đây:

Tia âm cho góc camera

Hơn nữa, trong dự án ScatterCPU, O'Neil bảo vệ chống lại các tình huống trong đó độ sâu quang học cho ánh sáng nhỏ hơn 0:

float fLightDepth = Scale(fLightAngle, fScaleDepth);

if (fLightDepth < float.Epsilon)
{
    continue;
}

Như đã chỉ ra trong các bình luận, cùng với những tạo tác mới này, điều này vẫn còn để lại câu hỏi, có gì sai với những hình ảnh mà camera được đặt ở vị trí 500, 500, 500? Cảm giác như quầng sáng tập trung vào phần hoàn toàn sai của hành tinh. Người ta kỳ vọng rằng ánh sáng sẽ ở gần vị trí mà mặt trời chiếu vào hành tinh hơn là nơi nó thay đổi từ ngày sang đêm.

Dự án github đã được cập nhật để phản ánh những thay đổi trong bản cập nhật này.


1
Tôi muốn chọc mã của bạn và cố gắng giúp đỡ, nhưng có vẻ như để cài đặt XNA cho VS 2012 Tôi yêu cầu VS 2010 ...

Tôi đã xóa tất cả các tham chiếu bên ngoài đến dự án và dự án không cần XNA nữa. Đây là một dự án Windows.Forms đơn giản và nó không cần bất cứ điều gì đặc biệt để chạy. Do đó, việc chuyển đổi sang phiên bản Visual Studio cũ là khá đơn giản.
ollipekka

Bạn đang nói về các tạo tác pixel về phía trung tâm của hình cầu trong hình ảnh đầu tiên của bạn? Những người không nên thực sự ảnh hưởng đến hình ảnh cuối cùng. Trình tạo bóng SkyFromSpace được cho là sẽ được áp dụng cho một quả cầu từ trong ra ngoài, do đó, chỉ có thể nhìn thấy một chút bầu khí quyển vượt ra ngoài hành tinh, trong khi trung tâm với các tạo tác sẽ được ẩn đằng sau hành tinh. Tuy nhiên, cả mặt đất và bầu trời đều nhìn ra máy ảnh ở mức 500.500.500 ..... hmm

Câu trả lời:


1

Tôi không có mã làm việc ngay bây giờ, vì tôi đang chuyển đổi công cụ của mình nhưng đây là các cài đặt tham số làm việc của tôi:

// Inited in code
float innerRadius = sphere.Radius;
float outerRadius = innerRadius*1.025f;
float scale = 1.0f/(outerRadius - innerRadius);
float scaleDepth = outerRadius - innerRadius;
float scaleOverScaleDepth = scale/scaleDepth;

Vector4 invWavelength = new Vector4(
    (float) (1.0/Math.Pow(wavelength.X, 4.0)),
    (float) (1.0/Math.Pow(wavelength.Y, 4.0)),
    (float) (1.0/Math.Pow(wavelength.Z, 4.0)),
    1);

float ESun = 15.0f;
float kr = 0.0025f;
float km = 0.0015f;
float g = -0.95f;
float g2 = g * g;
float krESun = kr * ESun;
float kmESun = km * ESun;
float epkr4Pi = epkr4Pi = (float)(kr * 4 * Math.PI)
float epkm4Pi = epkr4Pi = (float)(kr * 4 * Math.PI)

Đây là shader:

struct AtmosphereVSOut
{
    float4 Position : POSITION;
    float3 t0 : TEXCOORD0;
    float3 c0 : TEXCOORD1; // The Rayleigh color
    float3 c1 : TEXCOORD2; // The Mie color
    float4 LightDirection : TEXCOORD3;
};

// The scale equation calculated by Vernier's Graphical Analysis
float expScale (float fCos)
{
    //float x = 1.0 - fCos;
    float x = 1 - fCos;
    return scaleDepth * exp(-0.00287 + x*(0.459 + x*(3.83 + x*(-6.80 + x*5.25))));

}
// Calculates the Mie phase function
float getMiePhase(float fCos, float fCos2, float g, float g2)
{
    return 1.5 * ((1.0 - g2) / (2.0 + g2)) * (1.0 + fCos2) / pow(1.0 + g2 - 2.0*g*fCos, 1.5);
}

// Calculates the Rayleigh phase function
float getRayleighPhase(float fCos2)
{
    return 0.75 + (1.0 + fCos2);
}

// Returns the near intersection point of a line and a sphere
float getNearIntersection(float3 vPos, float3 vRay, float fDistance2, float fRadius2)
{
    float B = 2.0 * dot(vPos, vRay);
    float C = fDistance2 - fRadius2;
    float fDet = max(0.0, B*B - 4.0 * C);
    return 0.5 * (-B - sqrt(fDet));
}

AtmosphereVSOut
AtmosphereFromSpaceVS(float4 vPos : POSITION )
{
    // Multiply the camera position vector in world space by the 
    // World Inverse matrix so that it gets transformed to
    // object space coordinates
    float4 vEyePosInv = mul(vEyePos, mWorldInverse);

    // Compute a ray from the vertex to the camera position
    float3 vRay = vPos - vEyePosInv.xyz;

    // Transform the Light Position to object space and use
    // the result to get a ray from the position of the light
    // to the vertex. This is our light direction vector
    // which has to be normalized.
    float4 vLightDir = mul(vLightPosition,mWorldInverse) - vPos;
    vLightDir.xyz = normalize(vLightDir.xyz);
    vLightDir.w = 1.0;

    // From the vRay vector we can calculate the 
    // "far" intersection with the sphere
    float fFar = length (vRay);
    vRay /= fFar;

    // But we have to check if this point is obscured by the planet
    float B = 2.0 * dot(vEyePosInv, vRay);
    float C = cameraHeight2 - (innerRadius*innerRadius);
    float fDet = (B*B - 4.0 * C);

    if (fDet >= 0)
    {
        // compute the intersection if so
        fFar = 0.5 * (-B - sqrt(fDet));
    }

    // Compute the near intersection with the outer sphere
    float fNear = getNearIntersection (vEyePosInv, vRay, cameraHeight2, outerRadius2);

    // This is the start position from which to compute how
    // the light is scattered
    float3 vStart = vEyePosInv + vRay * fNear;
    fFar -= fNear;

    float fStartAngle = dot (vRay, vStart) / outerRadius;
    float fStartDepth = exp (scaleOverScaleDepth * (innerRadius - cameraHeight));
    float fStartOffset = fStartDepth * expScale (fStartAngle);
    float fSampleLength = fFar / samples;
    float fScaledLength = fSampleLength * scale;
    float3 vSampleRay = vRay * fSampleLength;
    float3 vSamplePoint = vStart + vSampleRay * 0.5f;

    // Now we have to compute each point in the path of the
    // ray for which scattering occurs. The higher the number
    // of samples the more accurate the result.
    float3 cFrontColor = float3 (0,0,0);
    for (int i = 0; i < samples; i++)
    {
        float fHeight = length (vSamplePoint);
        float fDepth = exp (scaleOverScaleDepth * (innerRadius - fHeight));
        float fLightAngle = dot (vLightDir, vSamplePoint) / fHeight;
        float fCameraAngle = dot(-vRay, vSamplePoint) / fHeight;
        float fScatter = (fStartOffset + fDepth * (expScale (fLightAngle) - expScale (fCameraAngle)));

        float3 cAttenuate = exp (-fScatter * (vInvWavelength.xyz * kr4PI + km4PI));

        cFrontColor += cAttenuate * (fDepth * fScaledLength);
        vSamplePoint += vSampleRay;
    }

    // Compute output values
    AtmosphereVSOut Out;

    // Compute a ray from the camera position to the vertex
    Out.t0 = vEyePos.xyz - vPos.xyz;

    // Compute the position in clip space
    Out.Position = mul(vPos, mWorldViewProj);

    // Compute final Rayleigh and Mie colors
    Out.c0.xyz = cFrontColor * (vInvWavelength.xyz * krESun);
    Out.c1.xyz = cFrontColor * kmESun;

    // Pass the light direction vector along to the pixel shader
    Out.LightDirection = vLightDir;

    return Out;
}

PSOut
AtmosphereFromSpacePS(AtmosphereVSOut In)
{
    PSOut Out;

    float cos = saturate(dot (In.LightDirection, In.t0) / length (In.t0));
    float cos2 = cos*cos;

    float fMiePhase = getMiePhase(cos,cos2,g,g2);
    float fRayleighPhase = getRayleighPhase(cos2);

    float exposure = 2.0;
    Out.color.rgb = 1.0 - exp(-exposure * (fRayleighPhase * In.c0 + fMiePhase * In.c1));
    Out.color.a = Out.color.b;

    return Out;
    }

Hãy cho tôi biết nếu nó vẫn hoạt động. Nếu bạn cần bất kỳ trợ giúp nào khác, tôi sẽ cố gắng tìm hiểu mã của tôi. Tôi nghĩ rằng tôi đã sử dụng hai hình cầu để thực hiện kết xuất: một cho bề mặt và một cho bầu khí quyển.


0

một số dấu vết suy nghĩ: kiểm tra độ chính xác của phao của bạn. ở quy mô không gian, hầu hết tất cả các lần float32 là không đủ. Kiểm tra bộ đệm dpeth nếu bạn có kết xuất nguyên thủy, giống như một quả cầu dưới bóng đổ tán xạ của bạn.

Những tạo tác này, cũng có thể được tìm thấy trong quá trình raytracing, đây thường là các tia thứ cấp giao nhau với sự dao động bề mặt chính từ các vấn đề chính xác của phao.

EDIT: ở mức 1000 (tất cả các số nguyên có thể biểu thị đầy đủ cho đến 16 triệu trong đại diện float32, nhờ mantissa 24 bit), số tiếp theo cho float32 là 1000.00006103 nên độ chính xác của bạn vẫn khá tốt trong phạm vi này.

tuy nhiên nếu bạn sử dụng phạm vi mét, để nhìn thấy một hành tinh thì khoảng cách này có nghĩa là các giá trị 100.000.000 và tiếp theo là 100000008: 8 mét chính xác ở 100.000km.

điều này sẽ khiến máy ảnh nhảy nếu bạn cố gắng di chuyển xung quanh một vệ tinh, và việc kết xuất vệ tinh sẽ bị hỏng nếu số 0 của thế giới của bạn là trung tâm của hành tinh. nếu nó là trung tâm của hệ sao thì nó còn tệ hơn nữa.

tra cứu flavien brebion (Ysaneya) và trò chơi tìm kiếm trái đất vô tận. Anh ấy có tạp chí dev thú vị của gamedev và diễn đàn của anh ấy, nơi anh ấy giải thích cách khoảng cách hệ thống sao không thể quản lý bằng cách sử dụng tuyệt đối.

Ông cũng đề cập đến vấn đề đệm sâu ở các loại phạm vi đó, và là một trong những vấn đề đầu tiên, nếu không phải là đầu tiên, để giới thiệu thang đo logarit. http://www.gamedev.net/blog/73/entry-2006307-tip-of-the-day-logarithmic-zbuffer-artifacts-fix/ hoàn thiện hơn nhiều ở đây: http://outerra.blogspot.jp/ 2012/11 / maximizing-height-buffer-Range-and.html

Phần mềm kiểm tra phần mềm: ý tưởng tốt, đó là một cách tuyệt vời để soạn thảo các shader để bạn có thể gỡ lỗi những gì đang diễn ra từng bước. chỉ cần kiểm tra các giá trị của bạn theo từng dòng và nếu có gì đó lạ, bạn có thể điều tra. Tôi không thấy trong đoạn mã bạn đã đăng phần mà góc máy ảnh được sử dụng trong trình đổ bóng, vì vậy tôi hơi bối rối về phần này.


Bạn có thể giải thích những gì bạn có nghĩa là độ chính xác nổi? Các thang đo đang được sử dụng trong ví dụ là từ -1000 đến 1000. Ví dụ này hoàn toàn là một triển khai phần mềm tại thời điểm đó, kết quả của trình đổ bóng được hiển thị thành hình ảnh và sau đó được hiển thị bằng API c # System.Drawing, mà có nghĩa là ví dụ này không sử dụng nguyên thủy.
ollipekka
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.