I'm working on a game in XNA 4 and I recently switched to a deferred shading implementation following this guide. A strange white outline is showing up on my models now and I'm not sure whats causing this. I thought maybe it was a lack of precision on the normal render target or the depth render target but increasing them to 64 bits (Rgba64) instead of 32 (Color) didn't help. I also thought it might be some problem with the specular calculation so I tried setting the specular to 0 but that didn't help either. Debugging the pixel in PIX shows the diffuse value is being calculated as nearly white for that pixel. Any ideas? I included a picture of the problem below, it's easier to see it at full size.
Pixel Shader:
float4 PixelShaderFunction(VertexShaderOutput input) : COLOR0
{
input.ScreenPosition.xy /= input.ScreenPosition.w;
float2 texCoord = 0.5f * (float2(input.ScreenPosition.x, -input.ScreenPosition.y) + 1) - halfPixel;
float4 normalData = tex2D(normalSampler, texCoord);
//Transform normal back into [-1, 1] range
float3 normal = normalize(2.0f * normalData.xyz - 1.0f);
float specularPower = normalData.a;
float specularHardness = tex2D(colorSampler, texCoord).a * 255;
float depthVal = tex2D(depthSampler, texCoord).r;
//Compute screen-space position
float4 position = float4(input.ScreenPosition.xy, depthVal, 1.0f);
//Transform to world space
position = mul(position, InvertViewProjection);
position /= position.w;
//Surface-to-light vector
float3 lightVector = lightPosition - position;
float3 projectedTexCoords = position - lightPosition;
projectedTexCoords = mul(projectedTexCoords, float3x3(
float3(-1, 0, 0),
float3(0, 1, 0),
float3(0, 0, 1)));
float distanceToLight = length(lightVector) / lightRadius;
float shadow = ShadowContribution(projectedTexCoords, distanceToLight);
float attenuation = saturate(1.0f - distanceToLight);
lightVector = normalize(lightVector);
//Compute diffuse light
float normalDotLight = max(0, dot(normal, lightVector));
float3 diffuseLight = normalDotLight * Color.rgb;
float3 reflectionVector = normalize(reflect(-lightVector, normal));
float3 directionToCamera = normalize(cameraPosition - position);
float specularLight = specularPower * pow(saturate(dot(reflectionVector, directionToCamera)), specularHardness);
return shadow * attenuation * lightIntensity * float4(diffuseLight.rgb, specularLight);
}
Edit: Sorry about the JPG, stackexchange's uploader did that on its own. Roy T: I did actually reference your XNA4 conversion of the tutorial for the parts that changed from XNA3. Since I didn't make any big changes to the code I thought maybe this bug existed in the original but was just impossible to see with so many lights all moving around, so I removed all but one light and the bug showed up again (look near the lizard's elbow)
Here are the GBuffer contents for my scene:
Color Buffer:
Depth Buffer:
Normal Buffer:
Final Render:
Edit2:
I'm starting to suspect the problem is CombineFinal.fx when it samples the color map. This is the computation for a properly colored pixel right next to a white pixel:
diffuseColor : (0.435, 0.447, 0.412)
diffuseLight : (1.000, 1.000, 0.902)
light : (1.000, 1.000, 0.902, 0.000)
PixelShaderFunction : (0.435, 0.447, 0.371, 1.000)
specularLight : 0.000
And this is the output from an improperly colored white pixel directly next to it:
diffuseColor : (0.824, 0.792, 0.741)
diffuseLight : (1.000, 1.000, 0.902)
light : (1.000, 1.000, 0.902, 0.000)
PixelShaderFunction : (0.824, 0.792, 0.669, 1.000)
specularLight : 0.000
The diffuseColor is the only difference, and this color is taken directly from the color map. Perhaps there is a slight error in the computation of the texture coordinate to sample from?
Lighting Pass: