Ertelenmiş aydınlatma kurulumunda çift paraboloid nokta ışık gölgeleri


10

Ertelenmiş aydınlatma kurulumunun bir türü olan hafif bir ön geçişin basit bir uygulamasını gösteren bu öğretici / örnek kodla oynuyorum .

Çift paraboloid gölge haritaları kullanarak nokta ışık gölgeleri uygulama sürecindeyim. DPM'nin bu açıklamasını takip ediyorum: http://gamedevelop.eu/en/tutorials/dual-paraboloid-shadow-mapping.htm

Gölge haritaları oluşturabiliyorum ve iyi görünüyorlar.

Şu anda yaşadığım sorunun nokta ışığını oluştururken gölge haritasında derinlik değerine bakan piksel gölgelendiricimde olduğuna inanıyorum.

İşte nokta ışık gölgelendirici kodum: http://olhovsky.com/shadow_mapping/PointLight.fx

İlgilenilen piksel gölgelendirici işlevi PointLightMeshShadowPS.

Herkes bu işlevde göze batan bir hata görüyor mu?

Umarım birisi bu sorunu daha önce çözmüştür :)

resim açıklamasını buraya girin

resim açıklamasını buraya girin

Yukarıdaki resimlerde de görebileceğiniz gibi, gönderinin gölgeleri yazıların konumlarıyla uyuşmuyor, bu nedenle bir yerlerde bazı dönüşümler yanlış ...

Nokta ışığı zemine çok yakın olduğunda (neredeyse zemine temas ederken) böyle görünür.

resim açıklamasını buraya girin

Nokta ışığı yere yaklaştıkça, gölgeler bir araya gelir ve iki gölge haritasının buluştuğu çizgi boyunca (yani, ışık gölgesinin iki gölge haritasını yakalamak için çevrildiği düzlem boyunca) temas eder.


Düzenle:

Daha fazla bilgi:

resim açıklamasını buraya girin

Nokta ışığını başlangıç ​​noktasından uzaklaştırdığımda, ışık kamerasının gölgeyi kesen "sağ" vektörüne paralel bir çizgi vardır. Yukarıdaki görüntü nokta ışığını sola hareket ettirmenin sonucunu göstermektedir. Nokta ışığını sağa taşırsam, bunun yerine sağda eşdeğer bir kırpma çizgisi vardır. Sanırım bu, düşündüğüm gibi piksel gölgeleyicisinde bir şeyi yanlış dönüştürdüğümü gösteriyor.


Düzenleme: Bu soruyu daha açık hale getirmek için, birkaç kod parçası.

İşte şu anda gölgeli bir spot ışığı çizmek için kullandığım kod . Bu çalışır ve beklediğiniz gibi gölge eşleme kullanır.

VertexShaderOutputMeshBased SpotLightMeshVS(VertexShaderInput input)
{
    VertexShaderOutputMeshBased output = (VertexShaderOutputMeshBased)0;    
    output.Position = mul(input.Position, WorldViewProjection);

    //we will compute our texture coords based on pixel position further
    output.TexCoordScreenSpace = output.Position;
    return output;
}

//////////////////////////////////////////////////////
// Pixel shader to compute spot lights with shadows
//////////////////////////////////////////////////////
float4 SpotLightMeshShadowPS(VertexShaderOutputMeshBased input) : COLOR0
{
    //as we are using a sphere mesh, we need to recompute each pixel position into texture space coords
    float2 screenPos = PostProjectionSpaceToScreenSpace(input.TexCoordScreenSpace) + GBufferPixelSize;
    //read the depth value
    float depthValue = tex2D(depthSampler, screenPos).r;

    //if depth value == 1, we can assume its a background value, so skip it
    //we need this only if we are using back-face culling on our light volumes. Otherwise, our z-buffer
    //will reject this pixel anyway

    //if depth value == 1, we can assume its a background value, so skip it
    clip(-depthValue + 0.9999f);

    // Reconstruct position from the depth value, the FOV, aspect and pixel position
    depthValue*=FarClip;

    //convert screenPos to [-1..1] range
    float3 pos = float3(TanAspect*(screenPos*2 - 1)*depthValue, -depthValue);

    //light direction from current pixel to current light
    float3 lDir = LightPosition - pos;

    //compute attenuation, 1 - saturate(d2/r2)
    float atten = ComputeAttenuation(lDir);

    // Convert normal back with the decoding function
    float4 normalMap = tex2D(normalSampler, screenPos);
    float3 normal = DecodeNormal(normalMap);

    lDir = normalize(lDir);

    // N dot L lighting term, attenuated
    float nl = saturate(dot(normal, lDir))*atten;

    //spot light cone
    half spotAtten = min(1,max(0,dot(lDir,LightDir) - SpotAngle)*SpotExponent);
    nl *= spotAtten;

    //reject pixels outside our radius or that are not facing the light
    clip(nl -0.00001f);

    //compute shadow attenuation

    float4 lightPosition = mul(mul(float4(pos,1),CameraTransform), MatLightViewProjSpot);

    // Find the position in the shadow map for this pixel
    float2 shadowTexCoord = 0.5 * lightPosition.xy / 
                            lightPosition.w + float2( 0.5, 0.5 );
    shadowTexCoord.y = 1.0f - shadowTexCoord.y;
    //offset by the texel size
    shadowTexCoord += ShadowMapPixelSize;

    // Calculate the current pixel depth
    // The bias is used to prevent floating point errors 
    float ourdepth = (lightPosition.z / lightPosition.w) - DepthBias;

    nl = ComputeShadowPCF7Linear(nl, shadowTexCoord, ourdepth);

    float4 finalColor;

    //As our position is relative to camera position, we dont need to use (ViewPosition - pos) here
    float3 camDir = normalize(pos);

    // Calculate specular term
    float3 h = normalize(reflect(lDir, normal));
    float spec = nl*pow(saturate(dot(camDir, h)), normalMap.b*50);
    finalColor = float4(LightColor * nl, spec); 

    //output light
    return finalColor * LightBufferScale;
}

Şimdi gölge haritaları kullanırken ışık boşluğuna dönüşümde bir çeşit hataya sahip olduğum nokta ışık kodu:

VertexShaderOutputMeshBased PointLightMeshVS(VertexShaderInput input)
{
    VertexShaderOutputMeshBased output = (VertexShaderOutputMeshBased)0;    
    output.Position = mul(input.Position, WorldViewProjection);

    //we will compute our texture coords based on pixel position further
    output.TexCoordScreenSpace = output.Position;
    return output;
}

float4 PointLightMeshShadowPS(VertexShaderOutputMeshBased input) : COLOR0
{
    // as we are using a sphere mesh, we need to recompute each pixel position 
    // into texture space coords
    float2 screenPos = 
        PostProjectionSpaceToScreenSpace(input.TexCoordScreenSpace) + GBufferPixelSize;

    // read the depth value
    float depthValue = tex2D(depthSampler, screenPos).r;

    // if depth value == 1, we can assume its a background value, so skip it
    // we need this only if we are using back-face culling on our light volumes. 
    // Otherwise, our z-buffer will reject this pixel anyway
    clip(-depthValue + 0.9999f);

    // Reconstruct position from the depth value, the FOV, aspect and pixel position
    depthValue *= FarClip;

    // convert screenPos to [-1..1] range
    float3 pos = float3(TanAspect*(screenPos*2 - 1)*depthValue, -depthValue);

    // light direction from current pixel to current light
    float3 lDir = LightPosition - pos;

    // compute attenuation, 1 - saturate(d2/r2)
    float atten = ComputeAttenuation(lDir);

    // Convert normal back with the decoding function
    float4 normalMap = tex2D(normalSampler, screenPos);
    float3 normal = DecodeNormal(normalMap);

    lDir = normalize(lDir);

    // N dot L lighting term, attenuated
    float nl = saturate(dot(normal, lDir))*atten;

    /* shadow stuff */

    float4 lightPosition = mul(mul(float4(pos,1),CameraTransform), LightViewProj);

    //float4 lightPosition = mul(float4(pos,1), LightViewProj);
    float posLength = length(lightPosition);
    lightPosition /= posLength;

    float ourdepth = (posLength - NearClip) / (FarClip - NearClip) - DepthBias;
    //float ourdepth = (lightPosition.z / lightPosition.w) - DepthBias;

    if(lightPosition.z > 0.0f)
    {
        float2 vTexFront;
        vTexFront.x =  (lightPosition.x /  (1.0f + lightPosition.z)) * 0.5f + 0.5f; 
        vTexFront.y =  1.0f - ((lightPosition.y /  (1.0f + lightPosition.z)) * 0.5f + 0.5f);    

        nl = ComputeShadow(FrontShadowMapSampler, nl, vTexFront, ourdepth);
    }
    else
    {
        // for the back the z has to be inverted        
        float2 vTexBack;
        vTexBack.x =  (lightPosition.x /  (1.0f - lightPosition.z)) * 0.5f + 0.5f; 
        vTexBack.y =  1.0f - ((lightPosition.y /  (1.0f - lightPosition.z)) * 0.5f + 0.5f); 

        nl = ComputeShadow(BackShadowMapSampler, nl, vTexBack, ourdepth);
    }

    /* shadow stuff */

    // reject pixels outside our radius or that are not facing the light
    clip(nl - 0.00001f);

    float4 finalColor;
    //As our position is relative to camera position, we dont need to use (ViewPosition - pos) here
    float3 camDir = normalize(pos);

    // Calculate specular term
    float3 h = normalize(reflect(lDir, normal));
    float spec = nl*pow(saturate(dot(camDir, h)), normalMap.b*100);
    finalColor = float4(LightColor * nl, spec);

    return finalColor * LightBufferScale;
}

ve gölge haritaların kendilerinde sorun olmadığını söylüyorsunuz / (yani gölge haritalarını doku haritasına yakarsanız, doğru noktaları koyulaştırırlar mı?)
Ali1S232

Işık kaynağının konumundan kameranın görüntüsünün FOV'sinin doğru olduğundan% 100 emin misiniz?
Roy T.

Işığın kaynak konumundan kameranın oluşturulması projeksiyon matrisine sahip değildir, çünkü paraboloid çözgüsü elde etmek için projeksiyon manuel olarak yapılır. Yine de bu kodu kontrol edeceğim, iyi fikir Roy T.
Olhovsky

Gajet: "Yani gölge haritalarını doku haritasına yakarsanız, doğru noktaları koyulaştırırlar?" Gölge haritaları gölgeleri hafif alanda saklar, eğer haritaya bakarsam, doğru olduklarından emin olmanın kolay bir yolu yoktur çünkü onları ekran alanında görüyorum. "Tekstüre haritası" nedir - doku mı demek istediniz? Gölge haritalar vardır dokular.
Olhovsky

Roy T .: Işığı hareket ettirmek, gölge haritasının kırpıldığını gösterir, bu yüzden sadece gölgeyi kullanırken değil, gölgeyi kullanırken dönüşümde bir sorun vardır.
Olhovsky

Yanıtlar:


2

PIX ile izole piksellerde hata ayıklayabilirsiniz, belki de hatayı bu şekilde bulabilirsiniz. FOV veya projeksiyon hatası önemli bir ipucudur. Yoksa dünya dönüşümünü unuttun mu ?!


NVidia-fxComposer ile hata ayıklamayı da deneyebilirsiniz
Ali1S232

Derleme kodu değerlerine bakmanın bu noktada bana çok yardımcı olacağını sanmıyorum, çünkü dönüşümün ilk etapta nasıl yapılması gerektiğini anlamakta zorlanıyorum. Dolayısıyla, kayıt 10'da veya nerede olursa olsun hangi değerin olduğunu görmek gerçekten yardımcı olmayacaktır.
Olhovsky

“Yoksa dünya dönüşümünü unuttun mu ?!” Aslında gölge haritaları oluştururken dünya dönüşümünü uygulamayı unuttum - doh! Bu şimdi çalışıyor, tüm gölgelendiricileri sahip olduğum gibi bırakıyor.
Olhovsky

1

Hey Olhovsky, güzel zorlu bir soru. Acını biliyorum, son işime Ertelenmiş Gölgeleme, Çıkarılan Aydınlatma ve gölgeler uyguladım. Gerçekten çok eğlenceliydi, ama beklendiği gibi çalışmadığında çok fazla acı.

Bence PIX'in tavsiyesi aslında iyi. Gölgelendiricinin montajcı yönergeleriyle uğraşmak zorunda kalmazsınız, ancak gölge haritalarına ve diğer oluşturma hedeflerine bakabilir, bir piksel seçebilir ve piksel gölgelendiricisini çağırabilir ve içinden ve tepe gölgelendiricisinden geçebilirsiniz.

Bu tür durumlar için genel hata ayıklama püf noktaları sahnenin basitleştirilmesini içerir.

Aklıma gelen kamera: ışık geçişiyle aynı fovy ve diğer özelliklere sahip ışık kaynağı ile aynı konuma getirin. Artık piksel gölgelendiricideki değerleri kolayca karşılaştırabilirsiniz. Geçerli nesneniz için normal oluşturma geçişindeki piksel-xy, aynı çözünürlüğe sahip olduğu sürece, gölge haritasındaki arama için hesaplanan piksel-xy ile aynı olmalıdır.

Bir diğeri de ortografik projeksiyona geçmek, bir şeyi kolay, öngörülebilir ve kontrol edilebilir hale getirmek. Ne kadar basitse, her hesaplama adımını o kadar iyi kontrol edebilirsiniz.

Bunun dışında, geçerli pikselin gölge haritasında konumunu hesaplayan matrisi nasıl oluşturduğunuzu, yani ekran uzayından ışık uzayına dönüşümünü gösterebilir misiniz?


Sadece gölge haritasını görmek Parabloid'tir, bu hata ayıklamayı daha da zorlaştırır ve mevcut piksel konumunu ve gölge haritasındaki konumu karşılaştırmak için kamerayı ışık konumuna koyma fikri işe yaramaz, nevermind :)
Maik Semder

İlgileniyorsanız bana kris@olhovsky.com adresinden bir e-posta gönderin. Projemin bir kopyasını yanıtlayacağım. Aksi takdirde: CameraTransformMatris aslında sahneyi görüntüleyen kameranın dünya matrisidir. LightViewProjIşığın görünümü matrisi sadece kimlik matrisidir olarak matris, aslında ışığın sadece dünyanın matristir.
Olhovsky

Onunla basit bir C ++ projesi yapabilir misiniz? Parabloid dönüşüm de olmalı doğru mu?
Maik Semder

Paraboloid dönüşümü, soruya bağladığım piksel gölgelendiricisinde. Benim C ++ becerileri sanırım tüm ertelenmiş render boru hattı kapsüllü hızlı bir C ++ proje kadar sınırlı :) Ancak, C ++ ile yetkin, o zaman benim C # kodunu okumak çok zor olmamalı düşünüyorum. Özellikle endişelerin çoğu gerçekten piksel gölgelendiricisinde ve belki de ona geçirilen matrikslerde olduğu için.
Olhovsky

G_mDPView ve g_mDPWorldView'dan bahsediyordum. Nasıl hesaplandığını gösterebilir misiniz?
Maik Semder
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.