Tôi đã chơi xung quanh với mã hướng dẫn / mẫu này cho thấy việc triển khai ánh sáng trước đơn giản, đây là một loại thiết lập ánh sáng bị trì hoãn.
Tôi đang trong quá trình thực hiện các bóng sáng điểm, sử dụng các bản đồ bóng hai mặt. Tôi đang theo mô tả này của DPM: http://gamedevelop.eu/en/tutorials/dual-paraboloid-shadow-mapping.htmlm
Tôi có thể tạo ra các bản đồ bóng, và chúng có vẻ ổn.
Tôi tin rằng vấn đề hiện tại tôi gặp phải là trong trình đổ bóng pixel của tôi, tìm kiếm một giá trị độ sâu trong bản đồ bóng khi kết xuất đèn điểm.
Đây là mã shader ánh sáng điểm của tôi: http://olhovsky.com/shadow_mapping/PointLight.fx
Các chức năng pixel shader quan tâm là PointLightMeshShadowPS
.
Có ai nhìn thấy một lỗi rõ ràng trong chức năng đó?
Hy vọng rằng ai đó đã giải quyết vấn đề này trước đây :)
Như bạn có thể thấy trong các hình ảnh ở trên, bóng của bài đăng không khớp với vị trí của bài đăng, vì vậy một số biến đổi bị sai ở đâu đó ...
Đây là những gì nó trông giống như khi ánh sáng điểm rất gần mặt đất (gần như chạm đất).
Khi ánh sáng điểm di chuyển gần mặt đất hơn, các bóng kết hợp với nhau và chạm dọc theo đường mà hai bản đồ bóng gặp nhau (nghĩa là dọc theo mặt phẳng nơi camera ánh sáng được lật để chụp hai bản đồ bóng).
Biên tập:
Thêm thông tin:
Khi tôi di chuyển ánh sáng điểm ra khỏi điểm gốc, có một đường thẳng song song với vectơ "bên phải" của camera ánh sáng cắt bóng. Hình trên cho thấy kết quả của việc di chuyển ánh sáng điểm sang trái. Nếu tôi di chuyển ánh sáng điểm sang phải, thay vào đó sẽ có một đường cắt tương đương ở bên phải. Vì vậy, tôi nghĩ rằng điều này chỉ ra rằng tôi đang chuyển đổi một cái gì đó không chính xác trong trình đổ bóng pixel, như tôi nghĩ.
Chỉnh sửa: Để làm cho câu hỏi này rõ ràng hơn, đây là một vài đoạn mã.
Đây là đoạn mã mà tôi hiện đang sử dụng để vẽ một đốm sáng bị che khuất . Điều này hoạt động và sử dụng ánh xạ bóng như bạn mong đợi.
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;
}
Bây giờ đây là mã ánh sáng điểm mà tôi đang sử dụng, có một số lỗi trong quá trình chuyển đổi thành không gian ánh sáng khi sử dụng bản đồ bóng:
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;
}