Tôi đã triển khai VSM (và cả ESM) trong công cụ của mình nhưng kết quả đối với tôi không như tôi mong đợi và thấy trong nhiều ví dụ được công bố trên mạng.
Tôi đặt tính năng lọc bản đồ bóng thành GL_LINEAR nhưng khi tôi so sánh kết quả với bản đồ bóng bình thường thì nó rõ ràng tệ hơn.
Tôi đã thử tính toán các khoảnh khắc trực tiếp trong shader ánh sáng điểm hoặc lấy nó từ kết cấu như trong hầu hết các hướng dẫn nhưng kết quả là như nhau.
Mã số:
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);
Sử dụng mã này tôi nhận được kết quả như trên hình ảnh. Tôi cũng đã cố gắng không sử dụng samplerCubeShadow nhưng samplerCube nhưng kết quả thậm chí còn tồi tệ hơn. Đầu tiên, tôi có bóng cứng. Thứ hai, bóng đổ không lấp đầy diện tích như bình thường khi có được khoảnh khắc từ kết cấu khác. Nhìn vào màn hình thứ hai. Đây cũng là nhìn vào bản đồ khối tạo ra. Nó không giống với những gì trong bản đồ độ sâu ngay cả khi tôi đặt độ sâu / khoảnh khắc1 ở cả 3 kênh.
Shader để có được khoảnh khắc:
// 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 );
Tôi thực sự bế tắc. Tôi hy vọng bạn sẽ giúp mi giải quyết vấn đề của tôi.
BIÊN TẬP:
Tôi đã tìm thấy giải pháp cho vấn đề thứ hai. Tôi đã kích hoạt pha trộn và nó cho tôi bản đồ độ sâu sai.
Tôi cũng nhận được kết quả tốt hơn cho vấn đề đầu tiên nhưng bây giờ tôi đang chiến đấu với độ sâu phù hợp để so sánh nó với độ sâu từ bản đồ bóng tối.
Trong SM đơn giản tôi sử dụng mã này:
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]
trong đó pos là vị trí trong View Space. Sau đó, tôi đọc các giá trị từ bản đồ bóng bằng cách sử dụng:
texture(shadowMap,vec4(coord.xyz,d))
Trong VSM, tôi lưu trữ độ sâu trong kênh R trong kết cấu RG32F. Giá trị độ sâu được tính theo cách này:
// VS
gl_Position=ModelViewProjectionMatrix*Vertex;
v_position=gl_Position;
// FS
float depth = v_position.z/v_position.w;
depth = depth * 0.5 + 0.5;
Sau đó, trong shader cho ánh sáng điểm, tôi sử dụng vectơ tọa độ (như trong SM tiêu chuẩn) để đọc các giá trị từ bản đồ bóng và điều này hoạt động tốt. Nhưng vấn đề là ở phần này:
// No shadow if depth of fragment is in front
if ( moments.x <= distance)
return 1.0;
Trong khoảng cách tọa độ nên được nhận? Trong tọa độ nào tôi có chiều sâu từ bản đồ bóng tối? Nó nên tuyến tính? Ai đó có thể giải thích cho tôi điều đó? Bây giờ tôi hơi bối rối, tôi đã thử nhiều cách để có được điều này và tất cả các kết quả không như tôi mong đợi.
EDIT2: Theo mẹo của JarkkoL và hướng dẫn này tôi đã thay đổi mã của mình. Bây giờ tôi đang lưu trữ độ sâu bằng cách sử dụng mã này:
// 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;
Và tôi so sánh nó với giá trị mà tôi có được theo cách này:
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
Và đây là kết quả:
Trong vòng tròn màu đỏ, tôi đánh dấu đường viền có thể nhìn thấy giữa các mặt bản đồ khối. Vẫn còn một cái gì đó sai. Tôi nghĩ rằng điều đó có thể xảy ra khi đảo ngược View Matrix nhưng tôi không chắc chắn.