Uzay eserlerinden atmosferik saçılma gökyüzü


20

Bir gezegenin uzaydan atmosferik saçılması uygulama sürecindeyim. Http://http.developer.nvidia.com/GPUGems2/gpugems2_chapter16.html adresinden Sean O'Neil'in gölgelendiricilerini başlangıç ​​noktası olarak kullanıyorum .

Ben burada olduğu gibi GroundFromSpace gölgelendiricinin aksine SkyFromSpace gölgelendirici dışında fCameraAngle ile ilgili hemen hemen aynı sorunu var: http://www.gamedev.net/topic/621187-sean-oneils-atmospheric-scattering/

fCameraAngle = 1İç döngüde kullanmadığınızda uzay gölgelendiricisinden gökyüzü ile garip eserler alıyorum . Bu eserlerin nedeni nedir? FCameraAngle 1 ile sınırlandığında eserler kayboluyor. O'Neil'ın sanal alanında bulunan renk tonundan da yoksun gibi görünüyorum ( http://sponeil.net/downloads.htm )

Kamera konumu X = 0, Y = 0, Z = 500. Solda GroundFromSpace, sağda SkyFromSpace. resim açıklamasını buraya girin

Kamera konumu X = 500, Y = 500, Z = 500. Solda GroundFromSpace, sağda SkyFromSpace. resim açıklamasını buraya girin

Kamera açısının kaynağa bağlı olarak çok farklı ele alındığını gördüm:

Orijinal gölgelendiricilerde SkyFromSpaceShader'daki kamera açısı şu şekilde hesaplanır:

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

Alan gölgelendiriciden zeminde kamera açısı şu şekilde hesaplanır:

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

Ancak, çeşitli kaynaklar ışını reddeden çevrimiçi tamircilik. Bu neden?

İşte sorunu gösteren ve görüntüleri oluşturmak için kullandığım bir C # Windows.Forms projesi: https://github.com/ollipekka/AtmosphericScatteringTest/

Güncelleme: O'Neil'ın sitesinde bulunan ScatterCPU projesinden, kamera gölgelendirilen noktanın üzerinde olduğunda kamera ışınının reddedildiğini öğrendim, böylece saçılma noktadan kameraya hesaplanır.

Işın yönünü değiştirmek gerçekten yapaylıkları ortadan kaldırır, ancak burada gösterildiği gibi başka problemler ortaya çıkarır:

Kamera açısı için negatif ışın

Ayrıca, ScatterCPU projesinde O'Neil, ışık için optik derinliğin sıfırdan küçük olduğu durumlara karşı koruma sağlar:

float fLightDepth = Scale(fLightAngle, fScaleDepth);

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

Yorumlarda belirtildiği gibi, bu yeni eserler ile birlikte bu hala soru bırakıyor, kameranın 500, 500, 500 olarak konumlandırıldığı görüntülerde sorun nedir? Hale, gezegenin tamamen yanlış kısmına odaklanmış gibi geliyor. Biri, ışığın günden geceye değişmek yerine güneşin gezegene çarpması gereken noktaya daha yakın olmasını beklerdi.

Github projesi bu güncellemedeki değişiklikleri yansıtacak şekilde güncellendi.


1
Kodunuzu dürtmek ve yardım etmeye çalışmak isterdim, ama VS 2012 için XNA yüklemek gibi görünüyor VS 2010 gerektirir ...

Projeye yapılan tüm dış referansları kaldırdım ve projenin artık XNA'ya ihtiyacı yok. Bu basit bir Windows.Forms projesidir ve çalıştırmak için özel bir şeye ihtiyaç duymamalıdır. Bu nedenle, eski Visual Studio sürümüne dönüştürmek oldukça önemsiz olmalıdır.
ollipekka

İlk görüntünüzde kürenin merkezine doğru piksel eserler hakkında mı konuşuyorsunuz? Bunlar son görüntüyü gerçekten etkilememelidir. SkyFromSpace gölgelendiricisinin bir iç-dış küreye uygulanması gerekiyordu, bu yüzden sadece gezegenin ötesine uzanan atmosferin biti görünür olacak, eserler içeren merkez gezegenin arkasına gizlenecek. Ancak hem yer hem de gökyüzü gölgeleme kamera için 500.500.500 ..... hmm

Yanıtlar:


1

Şu anda çalışma kodum yok, çünkü motorumu değiştiriyorum ama bunlar benim çalışma parametre ayarlarımdı:

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

Bu gölgelendiriciydi:

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;
    }

Hala işe yarayıp yaramadığını bana bildirin. Başka bir yardıma ihtiyacınız olursa, kodumu araştırmaya çalışacağım. Ben render için iki küre kullandım: biri yüzey diğeri atmosfer için.


0

bazı düşünce parçaları: şamandıralarınızın hassasiyetini kontrol edin. uzay ölçeklerinde float32 çoğu zaman yeterli değildir. Saçılma gölgelendiricinizin altındaki bir küre gibi ilkel işlemeniz varsa dpeth arabelleğini kontrol edin.

Bu artefaktlar, ışın izlemede de bulunabilir, bunlar genellikle şamandıra hassaslık sorunlarından birincil yüzey titremesi ile ikincil ışınların kesişmesidir.

DÜZENLEME: 1000'de (24 bit mantis sayesinde float32 temsilinde 16 milyona kadar tüm tamsayılar tam olarak temsil edilebilir), bir float32 için bir sonraki sayı 1000.00006103'tür, bu nedenle hassasiyetiniz hala oldukça iyidir.

ancak sayaç aralıklarını kullanacak olsaydınız, bir gezegeni görmek için bu mesafe 100.000.000 ve sonraki değer 100000008: 100.000km'de 8 metre hassasiyet anlamına gelir.

bu, örneğin bir uydu etrafında hareket etmeye çalışırsanız kamera sıçramalarına neden olur ve eğer dünyanızın sıfırı gezegenin merkezi ise, uydunun görüntülenmesi tamamen bozulur. eğer yıldız sisteminin merkezi ise, o zaman daha da kötüdür.

flavien brebion (Ysaneya) ve oyun dünya için sonsuz arayışı arayın. Gamedev'in ilginç bir dev dergisine ve forumunda yıldız sistemi mesafelerinin mutlak kullanarak nasıl yönetilmesinin imkansız olduğunu açıklıyor.

Ayrıca, bu tür aralıklarda derinlik tamponu sorunundan bahseder ve logaritmik z ölçeklerini ilk sunan olmasa da ilklerden biridir. http://www.gamedev.net/blog/73/entry-2006307-tip-of-the-day-logarithmic-zbuffer-artifacts-fix/ burada çok daha eksiksiz: http://outerra.blogspot.jp/ 2012/11 / maksimize-derinlik tampon menzil and.html

Yazılım test yatağı: iyi fikir, gölgelendiricileri yazmak için mükemmel bir yoldur, böylece adım adım neler olduğunu ayıklayabilirsiniz. değerlerinizi satır satır kontrol edin ve bir şey tuhaf görünüyorsa araştırabilirsiniz. Kodlayıcıda kamera açısının gölgelendiricide kullanıldığı kısmı yayınladığınızı görmedim, bu yüzden bu kısım hakkında biraz şaşkınım.


Şamandıra hassasiyeti ile ne demek istediğinizi açıklayabilir misiniz? Örnekte kullanılan ölçekler -1000 ile 1000 arasındadır. Örnek şu anda yalnızca gölgelendiricinin bir görüntüye dönüştürüldüğü ve daha sonra c # System.Drawing API kullanılarak görüntülenen bir yazılım uygulamasıdır. bu örnek ilkelleri kullanmadığı anlamına gelir.
ollipekka
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.