Saya telah bermain-main dengan kode contoh / tutorial ini yang menunjukkan implementasi sederhana pra-lulus cahaya, yang merupakan jenis pengaturan pencahayaan yang ditangguhkan.
Saya sedang dalam proses menerapkan titik cahaya bayangan, menggunakan peta bayangan parabola ganda. Saya mengikuti deskripsi DPM ini: http://gamedevelop.eu/en/tutorials/dual-paraboloid-shadow-mapping.htm
Saya dapat membuat peta bayangan, dan mereka tampak bagus.
Saya percaya bahwa masalah saat ini yang saya alami adalah di pixel shader saya yang mencari nilai kedalaman di peta bayangan saat merender titik lampu.
Berikut ini adalah kode shader light point saya: http://olhovsky.com/shadow_mapping/PointLight.fx
Fungsi pixel shader yang menarik adalah PointLightMeshShadowPS
.
Adakah yang melihat kesalahan mencolok dalam fungsi itu?
Semoga seseorang telah mengatasi masalah ini sebelumnya :)
Seperti yang Anda lihat pada gambar di atas, bayangan posting tidak cocok dengan posisi tulisan, sehingga beberapa transformasi salah di suatu tempat ...
Ini terlihat seperti ketika titik cahaya sangat dekat dengan tanah (hampir menyentuh tanah).
Saat titik cahaya bergerak lebih dekat ke tanah, bayangan bergabung dan menyentuh sepanjang garis tempat dua peta bayangan bertemu (yaitu, di sepanjang pesawat tempat kamera cahaya dibalik untuk menangkap dua peta bayangan).
Edit:
Informasi lebih lanjut:
Ketika saya memindahkan titik cahaya dari asal, ada garis sejajar dengan vektor "kanan" kamera cahaya yang klip bayangan. Gambar di atas menunjukkan hasil dari memindahkan titik cahaya ke kiri. Jika saya memindahkan titik cahaya ke kanan, ada garis kliping yang setara di sebelah kanan. Jadi saya pikir ini menunjukkan bahwa saya mengubah sesuatu yang tidak benar dalam pixel shader, seperti yang saya kira.
Sunting: Untuk membuat pertanyaan ini lebih jelas, berikut adalah beberapa kode.
Berikut adalah kode yang saat ini saya gunakan untuk menggambar titik cahaya yang gelap . Ini berfungsi, dan menggunakan pemetaan bayangan seperti yang Anda harapkan.
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;
}
Sekarang di sini adalah kode titik cahaya yang saya gunakan, yang memiliki semacam bug dalam transformasi menjadi ruang cahaya saat menggunakan peta bayangan:
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;
}
sumber
Jawaban:
Dengan PIX Anda dapat men-debug piksel yang terisolasi, mungkin Anda menemukan kesalahan dengan cara ini. FOV atau kesalahan proyeksi adalah isyarat panas. Atau apakah Anda lupa transformasi dunia ?!
sumber
Hai Olhovsky, pertanyaan menantang yang bagus. Saya tahu rasa sakit Anda, saya menerapkan Deferred Shading, Inferred Lighting, dan bayangan dalam pekerjaan terakhir saya. Itu benar-benar menyenangkan, tetapi banyak rasa sakit juga ketika itu tidak bekerja seperti yang diharapkan.
Saya pikir saran dengan PIX sebenarnya bagus. Anda tidak perlu dipusingkan dengan instruksi assembler dari shader, tetapi Anda dapat melihat peta bayangan dan target render lainnya, pilih piksel dan panggil pixel shader-nya dan melangkahinya dan juga vertex-shader-nya.
Trik debug umum untuk situasi semacam ini termasuk penyederhanaan adegan.
Salah satu yang terlintas di pikiran saya adalah: letakkan kamera pada posisi yang sama dengan sumber cahaya dengan sifat yang sama dan atribut lainnya seperti pada pass pencahayaan. Sekarang Anda dapat dengan mudah membandingkan nilai dalam pixel-shader. Pixel-xy pada render-pass normal untuk objek Anda saat ini harus sama dengan pixel-xy yang dihitung untuk pencarian dalam shadowmap, selama ia memiliki resolusi yang sama.
Yang lain adalah beralih ke proyeksi ortografis, membuat sesuatu mudah, dapat diprediksi, dan dapat diperiksa. Semakin sederhana semakin baik Anda dapat memeriksa setiap langkah perhitungan.
Selain itu, dapatkah Anda menunjukkan bagaimana Anda membuat matriks yang menghitung posisi dalam bayangan-peta untuk piksel saat ini, yaitu transformasi dari layar-ruang ke ruang-cahaya?
sumber
CameraTransform
Matriks ini sebenarnya adalah matriks dunia dari kamera yang saat ini melihat pemandangan. TheLightViewProj
matrix sebenarnya hanya matriks dunia cahaya, sebagai pandangan matriks cahaya hanya matriks identitas.