ท้องฟ้าที่กระเจิงจากชั้นบรรยากาศจากสิ่งประดิษฐ์ในอวกาศ


20

ฉันกำลังอยู่ในขั้นตอนการดำเนินการกระจายดาวเคราะห์ในอวกาศจากอวกาศ ฉันใช้เฉดสีของ Sean O'Neil จากhttp://http.developer.nvidia.com/GPUGems2/gpugems2_chapter16.htmlเป็นจุดเริ่มต้น

ฉันมีปัญหาเดียวกันที่เกี่ยวข้องกับ fCameraAngle ยกเว้นกับ SkyFromSpace shader ซึ่งตรงข้ามกับ GroundFromSpace shader ที่นี่: http://www.gamedev.net/topic/621187-sean-oneils-atmospheric-scattering/

ฉันได้รับวัตถุแปลกประหลาดที่มีท้องฟ้าจากอวกาศ shader เมื่อไม่ได้ใช้fCameraAngle = 1ในวงใน สาเหตุของสิ่งประดิษฐ์เหล่านี้คืออะไร? สิ่งประดิษฐ์นั้นหายไปเมื่อ fCameraAngle ถูก จำกัด ไว้ที่ 1 ฉันก็ดูเหมือนจะไม่มีสีสันที่ปรากฏในกล่องทรายของ O'Neil ( http://sponeil.net/downloads.htm )

ตำแหน่งกล้อง X = 0, Y = 0, Z = 500 GroundFromSpace ทางซ้าย, SkyFromSpace ทางด้านขวา ป้อนคำอธิบายรูปภาพที่นี่

ตำแหน่งกล้อง X = 500, Y = 500, Z = 500 GroundFromSpace ทางซ้าย, SkyFromSpace ทางด้านขวา ป้อนคำอธิบายรูปภาพที่นี่

ฉันพบว่ามุมกล้องดูเหมือนจะจัดการแตกต่างกันมากขึ้นอยู่กับแหล่งที่มา:

ในเฉดสีดั้งเดิมมุมกล้องใน SkyFromSpaceShader ถูกคำนวณดังนี้:

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

มุมกล้องถูกคำนวณดังนี้:

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

อย่างไรก็ตามแหล่งต่าง ๆ ออนไลน์ทิงเกอร์กับ negating รังสี ทำไมนี้

นี่คือโครงการ C # Windows รูปแบบที่แสดงให้เห็นถึงปัญหาและฉันเคยใช้ในการสร้างภาพ: https://github.com/ollipekka/AtmosphericScatteringTest/

อัปเดต:ฉันพบจากโครงการ ScatterCPU ที่พบในไซต์ของ O'Neil ว่ารังสีของกล้องถูกลบล้างเมื่อกล้องอยู่เหนือจุดที่มีการแรเงาเพื่อให้การคำนวณการกระเจิงจากจุดหนึ่งไปยังอีกกล้องหนึ่ง

การเปลี่ยนทิศทางของรังสีเป็นการลบสิ่งประดิษฐ์ แต่แนะนำปัญหาอื่น ๆ ดังที่แสดงไว้ที่นี่:

Negating ray สำหรับมุมกล้อง

นอกจากนี้ในโครงการ ScatterCPU โอนีลจะป้องกันสถานการณ์ที่ความลึกเชิงแสงสำหรับแสงน้อยกว่าศูนย์:

float fLightDepth = Scale(fLightAngle, fScaleDepth);

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

ตามที่ระบุไว้ในความคิดเห็นพร้อมกับสิ่งประดิษฐ์ใหม่ ๆ เหล่านี้ยังคงทิ้งคำถามเกิดอะไรขึ้นกับภาพที่วางตำแหน่งกล้องที่ 500, 500, 500? รู้สึกเหมือนว่ารัศมีนั้นมุ่งเน้นไปที่ส่วนที่ผิดอย่างสมบูรณ์ของโลก ใครจะคาดหวังว่าแสงจะเข้าใกล้จุดที่ดวงอาทิตย์น่าจะกระทบกับโลกมากกว่าที่จะเปลี่ยนจากกลางวันและกลางคืน

โครงการ GitHub ได้รับการปรับปรุงเพื่อสะท้อนถึงการเปลี่ยนแปลงในการปรับปรุงนี้


1
ฉันชอบที่จะกระตุ้นรหัสของคุณและพยายามช่วย แต่ดูเหมือนว่าจะติดตั้ง XNA สำหรับ VS 2012 ฉันต้องการ VS 2010 ...

ฉันลบการอ้างอิงภายนอกทั้งหมดไปยังโครงการและโครงการไม่ต้องการ XNA อีกต่อไป มันเป็นโครงการ Windows.Forms ที่เรียบง่ายและไม่จำเป็นต้องมีอะไรพิเศษในการทำงาน ดังนั้นจึงควรแปลงให้เป็น Visual Studio เวอร์ชันที่เก่ากว่าเล็กน้อย
ollipekka

คุณกำลังพูดถึงสิ่งประดิษฐ์พิกเซลที่มีต่อศูนย์กลางของทรงกลมในภาพแรกของคุณ? สิ่งเหล่านั้นไม่ควรส่งผลกระทบต่อภาพสุดท้าย SkyFromSpace shader ควรจะถูกนำไปใช้กับทรงกลมที่อยู่ด้านในดังนั้นจะเห็นเพียงเล็กน้อยของชั้นบรรยากาศที่ขยายออกไปนอกโลกในขณะที่ศูนย์กลางของสิ่งประดิษฐ์จะถูกซ่อนอยู่หลังดาวเคราะห์ อย่างไรก็ตามทั้งพื้นดินและแสงเงามองหากล้องที่ 500,500,500 ..... hmm

คำตอบ:


1

ฉันไม่มีรหัสการทำงานในขณะนี้เนื่องจากฉันกำลังเปลี่ยนเครื่องยนต์ แต่สิ่งเหล่านี้เป็นการตั้งค่าพารามิเตอร์การทำงานของฉัน:

// 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)

นี่คือ 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;
    }

แจ้งให้เราทราบหากยังใช้งานได้อยู่ หากคุณต้องการความช่วยเหลืออื่น ๆ ฉันจะพยายามขุดรหัสของฉัน ฉันคิดว่าฉันใช้สองทรงกลมเพื่อทำการเรนเดอร์: อันสำหรับพื้นผิวและอีกอันสำหรับบรรยากาศ


0

บางแทร็กความคิด: ตรวจสอบความแม่นยำของการลอยของคุณ ที่สเกลพื้นที่ส่วนใหญ่ตลอดเวลา float32 ไม่เพียงพอ ตรวจสอบบัฟเฟอร์ dpeth หากคุณมีการเรนเดอร์ดั้งเดิมเหมือนทรงกลมใต้ shader ที่กระเจิงของคุณ

สิ่งประดิษฐ์เหล่านี้สามารถพบได้ใน raytracing เช่นกันโดยปกติจะเป็นรังสีรองที่แยกออกมาพร้อมกับพื้นผิวหลักที่สั่นสะเทือนจากปัญหาความแม่นยำลอย

แก้ไข: ที่ 1,000 (จำนวนเต็มทั้งหมดสามารถแสดงได้เต็มที่จนถึง 16 ล้านในการแสดง float32 ขอบคุณ 24 mantissa 24 บิต) หมายเลขถัดไปสำหรับ float32 คือ 1,000.00006103 ดังนั้นความแม่นยำของคุณยังค่อนข้างดีในช่วงนี้

อย่างไรก็ตามหากคุณต้องใช้ช่วงมิเตอร์เพื่อดูดาวเคราะห์ระยะทางนี้จะหมายถึงค่า 100,000,000 และค่าถัดไปคือ 10,000,0008: ความแม่นยำ 8 เมตรที่ 100,000 กม.

สิ่งนี้จะทำให้กล้องกระโดดหากคุณพยายามเคลื่อนที่ไปรอบ ๆ ดาวเทียมและการสร้างภาพดาวเทียมเองก็จะแตกสลายหากศูนย์ของโลกของคุณเป็นศูนย์กลางของโลก ถ้ามันเป็นจุดศูนย์กลางของระบบดาวมันก็ยิ่งแย่

เงยหน้าขึ้นมอง Flavien brebion (Ysaneya) และการแสวงหาความไม่มีขอบเขตของเกมเพื่อโลก เขามีบันทึกการพัฒนาที่น่าสนใจของ gamedev และฟอรัมของเขาซึ่งเขาอธิบายว่าระบบดาวระยะทางเป็นไปไม่ได้ที่จะจัดการโดยใช้สมบูรณาญาสิทธิราชย์

นอกจากนี้เขายังกล่าวถึงปัญหาบัฟเฟอร์ความลึกที่ช่วงนั้นและเป็นหนึ่งในคนแรกถ้าไม่ใช่คนแรกที่จะแนะนำตาชั่งลอการิทึมซี http://www.gamedev.net/blog/73/entry-2006307-tip-of-the-day-logarithmic-zbuffer-artifacts-fix/ สมบูรณ์มากขึ้นที่นี่: http://outerra.blogspot.jp/ 2012/11 / การเพิ่มเชิงลึก-buffer-ช่วง and.html

ซอฟต์แวร์ทดสอบเตียง: ความคิดที่ดีมันเป็นวิธีที่ยอดเยี่ยมในการเขียน shaders เพื่อให้คุณสามารถดีบักสิ่งที่เกิดขึ้นทีละขั้นตอน เพียงแค่ตรวจสอบค่าของคุณทีละบรรทัดและหากมีสิ่งที่ดูแปลก ๆ คุณสามารถตรวจสอบได้ ฉันไม่เห็นรหัสที่คุณโพสต์ในส่วนที่ใช้มุมกล้องในส่วนถ่ายดังนั้นฉันรู้สึกสับสนเล็กน้อยเกี่ยวกับส่วนนี้


คุณช่วยอธิบายความแม่นยำของโฟลตได้อย่างละเอียดหรือไม่? เครื่องชั่งที่ใช้ในตัวอย่างนั้นมีค่าตั้งแต่ -1000 ถึง 1,000 ตัวอย่างคือการใช้งานซอฟต์แวร์อย่างหมดจดในขณะนี้โดยที่ผลลัพธ์ของ shader ถูกเรนเดอร์ไปยังรูปภาพแล้วแสดงโดยใช้ c # System.Drawing API ซึ่ง หมายความว่าตัวอย่างไม่ได้ใช้ประโยชน์จากดั้งเดิม
ollipekka
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.