Saya sudah menerapkan VSM (dan juga ESM) di mesin saya, tetapi hasilnya bagi saya tidak seperti yang saya harapkan dan lihat dalam banyak contoh yang dipublikasikan di jaringan.
Saya mengatur pemfilteran peta bayangan ke GL_LINEAR tetapi ketika saya membandingkan hasil dengan peta bayangan normal itu tampak lebih buruk.
Saya mencoba menghitung momen secara langsung di light point shader atau mendapatkannya dari tekstur seperti pada kebanyakan tutorial tetapi hasilnya sama.
Kode:
uniform samplerCubeShadow shadowMap;
...
vec4 worldSpace=inverse(ViewMatrix)*vec4(pos,1);
vec4 coord=LightViewMatrix*worldSpace;
vec4 abs_coord=abs(coord);
float fs_z=-max(abs_coord.x, max(abs_coord.y, abs_coord.z));
vec4 clip=LightProjectionMatrix*vec4(0.0,0.0,fs_z,1.0);
float d2=(clip.z / clip.w)*0.5+0.5; // clamp to [0..1]
...
float shadowTexel=texture(shadowMap,vec4(coord.xyz,d2));
// VSM (Variance Shadow Map)
// get partial derivatives
float dx = dFdx(d2);
float dy = dFdy(d2);
vec2 moments = vec2(d2, d2*d2+0.25*(dx*dx+dy*dy));
return chebychevInequality(moments, shadowTexel);
Dengan menggunakan kode ini saya mendapatkan hasil seperti pada gambar di atas. Saya mencoba juga untuk tidak menggunakan samplerCubeShadow tetapi samplerCube tetapi hasilnya lebih buruk. Pertama, saya mendapat bayangan keras. Kedua, bayangan tidak memenuhi area sebagaimana seharusnya ketika mendapatkan momen dari tekstur lain. Lihatlah layar kedua. Di sini juga terlihat peta kubus yang dihasilkan. Ini tidak mirip dengan apa yang ada di peta mendalam bahkan jika saya meletakkan depth / moment1 di ketiga saluran.
Shader untuk mendapatkan momen:
// Vartex shader
gl_Position=ModelViewProjectionMatrix*Vertex;
v_position=gl_Position;
// Fragment shader
float depth = v_position.z / v_position.w ;
depth = depth * 0.5 + 0.5; //Don't forget to move away from unit cube ([-1,1]) to [0,1] coordinate system
float moment1 = depth;
float moment2 = depth * depth;
// Adjusting moments (this is sort of bias per pixel) using derivative
float dx = dFdx(depth);
float dy = dFdy(depth);
moment2 += 0.25*(dx*dx+dy*dy) ;
FragColor = vec4( moment1,moment2, 0.0, 0.0 );
Saya sangat macet. Saya harap Anda akan membantu mi untuk menyelesaikan masalah saya.
EDIT:
Saya telah menemukan solusi untuk masalah kedua. Saya telah mengaktifkan blending dan itu memberi saya peta kedalaman yang salah.
Saya juga mendapatkan hasil yang lebih baik untuk masalah pertama tapi sekarang saya berjuang dengan kedalaman yang tepat untuk membandingkannya dengan kedalaman dari peta bayangan.
Dalam SM sederhana saya menggunakan kode ini:
vec4 worldSpace=inverse(ViewMatrix)*vec4(pos,1);
vec4 coord=LightViewMatrix*worldSpace;
vec4 abs_coord=abs(coord);
float fs_z=-max(abs_coord.x, max(abs_coord.y, abs_coord.z));
vec4 clip=LightProjectionMatrix*vec4(0.0,0.0,fs_z,1.0);
float d=(clip.z / clip.w)*0.5+0.5; // clamp to [0..1]
di mana pos berada di View Space. Lalu saya membaca nilai dari peta bayangan menggunakan:
texture(shadowMap,vec4(coord.xyz,d))
Dalam VSM saya menyimpan kedalaman di saluran R dalam tekstur RG32F. Nilai kedalaman dihitung dengan cara ini:
// VS
gl_Position=ModelViewProjectionMatrix*Vertex;
v_position=gl_Position;
// FS
float depth = v_position.z/v_position.w;
depth = depth * 0.5 + 0.5;
Kemudian dalam shader untuk titik cahaya saya menggunakan vektor coord (seperti pada SM standar) untuk membaca nilai dari peta bayangan dan ini berfungsi ok. Tetapi masalahnya ada di bagian ini:
// No shadow if depth of fragment is in front
if ( moments.x <= distance)
return 1.0;
Dalam koordinat berapa jarak yang harus ditempuh? Dalam koordinat apa saya memiliki kedalaman dari peta bayangan? Itu harus linier? Bisakah seseorang menjelaskan hal itu kepada saya? Saya sedikit bingung sekarang, saya mencoba banyak cara untuk mendapatkan ini dan semua hasilnya tidak seperti yang saya harapkan.
EDIT2: Mengikuti tip JarkkoL dan tutorial ini saya mengubah kode saya. Sekarang saya menyimpan kedalaman menggunakan kode ini:
// VS
v_position=ModelViewMatrix*Vertex;
gl_Position=ProjectionMatrix*v_position;
// FS
const float Near = 0.1;
const float Far = 90.0; // camera far plane
const float LinearDepthConstant = 1.0 / (Far - Near);
float depth = length(v_position)*LinearDepthConstant;
Dan saya membandingkannya dengan nilai yang saya dapatkan dengan cara ini:
float dist=length( vec3(inverse(ViewMatrix)*vec4(pos,1.0)) - PointLight.position )*LinearDepthConstant; // pos is read from depth buffer and is in view space so I want invert it to world space as it was in tutorial
Dan inilah hasilnya:
Di lingkaran merah saya menandai batas yang terlihat antara wajah peta kubus. Masih ada yang salah. Saya pikir itu bisa menjadi sesuatu dengan inversing dari View Matrix tapi saya tidak yakin.