XNA Creators Club Online
Page 1 of 1 (5 items)
Sort Posts: Previous Next

Normal Mapping Lighting Front and Back Surfaces

Last post 2/10/2010 1:54 AM by PumpkinPieman. 4 replies.
  • 2/9/2010 5:17 PM

    Normal Mapping Lighting Front and Back Surfaces

    Hey,

    I'm having an issue with a normal mapping test of mine. It actually does work, however there is a little side effect that I've been trying to figure out. I understand why it happens, but I am still lost trying to figure out a logical method to stop it outside of multiplying the end result colour by the light.z (normalized distance from the lit surface).

    Here is a picture I whipped up to show you the problem I am having with the code.



    The cube on the left has the light source lighting surface A and B, but surface C should not be lit because the light source is behind the surface. But because the light vector doesn't scale the x and y components based on the distance to the surface (light.z) the surface will still light the x and y directions. I'm new to normal mapping and so far I understand the general concepts. It's just the subtleties that I'm trying to get accustomed to.

    Here is the source code for my shader (at least the relevant parts)

    1 //----------------------------------------------------------------------------- 
    2 // Vertex Shaders. 
    3 //----------------------------------------------------------------------------- 
    4 VertexShaderOutput VertexShaderFunction(VertexShaderInput input) 
    5
    6     VertexShaderOutput output; 
    7  
    8     float4 worldPosition    = mul(input.Position, World); 
    9     float3 lightDir         = LightPosition - worldPosition; 
    10     float3 eyeDir           = EyePosition - worldPosition; 
    11  
    12     float3x3 worldToTangent; 
    13     worldToTangent[0] = mul(input.Tangent,      World); 
    14     worldToTangent[1] = mul(input.Binormal,     World); 
    15     worldToTangent[2] = mul(input.Normal,       World); 
    16  
    17     output.Position     = mul(worldPosition, ViewProjection); 
    18     output.TexCoord     = input.TexCoord; 
    19     output.LightDir     = mul(worldToTangent, lightDir); 
    20     output.EyeDir       = eyeDir; 
    21      
    22     return output; 
    23
    24  
    25 //----------------------------------------------------------------------------- 
    26 // Pixel Shaders. 
    27 //----------------------------------------------------------------------------- 
    28 PixelShaderOutput PixelShaderFunction(VertexShaderOutput input) : COLOR0 
    29
    30     PixelShaderOutput output; 
    31  
    32     // TODO: add your pixel shader code here. 
    33     float3 light    = normalize(input.LightDir);                                // light direction vector 
    34     float3 eye      = normalize(input.EyeDir);                                  // eye direction vector 
    35     float3 normal   = normalize(tex2D(NormalSampler, input.TexCoord).xyz-0.5);  // surface normal 
    36     float4 colour   = tex2D(TextureSampler, input.TexCoord);                    // surface colour 
    37     float3 refVec   = reflect(light, normal);                                   // light reflection vector 
    38      
    39  
    40     float diffuseIntensity  = saturate(dot(light, normal)); 
    41     float specularIntensity = max(dot(refVec, eye), 0); 
    42      
    43     float4 diffuse = (/* AmbientLightColor + */ colour * diffuseIntensity); 
    44     float4 specular = (Shininess * LightColour * pow(specularIntensity, SpecularPower)); 
    45      
    46     output.Colour = diffuse + specular; 
    47     output.Colour.w = 1; 
    48     return output; 
    49


    Maybe someone on the XNA forums can pick up something I didn't see.

    Thanks for your help.
  • 2/9/2010 6:32 PM In reply to

    Re: Normal Mapping Lighting Front and Back Surfaces

    Not sure if it is your complete issue, but I believe when you get the reflection vector, you want to use the negative of your lightdir.  That is, you want to know where something coming from your light would reflect.   See rizman's clarification in this post http://forums.xna.com/forums/p/26722/146635.aspx#146635

    Best,
    Byron
    ..shaders make you feel... powerful, or very very stupid.
    http://drjbn.spaces.live.com/
  • 2/9/2010 7:19 PM In reply to

    Re: Normal Mapping Lighting Front and Back Surfaces

    Your normal map directions sampled from the texture are probably in local coordinates for the surface, while your light direction is in world space coordinates.  You need to transform the local normal map coordinates into world space before you use them for lighting calculations.

    Edit: never mind, I missed the light direction transformation in your vertex shader.

    Attempt #2:

    Try doing this:

    if ( light.Z > 0.0 )
       output.Colour = diffuse + specular;
    else
       output.Colour = diffuse;

    That will cut out the specular reflection for surfaces that should be self-shadowed by the light.
  • 2/9/2010 7:59 PM In reply to

    Re: Normal Mapping Lighting Front and Back Surfaces

    Sigil has a point i hadn't considered.

    Try changing these these lines

    float3 refVec   = reflect(light, normal);                                   // light reflection vector 
    38 float3 refVec = reflect( -light,normal);
     float diffuseIntensity  = saturate(dot(light, normal)); 
         

     
    40 float specularIntensity = max(dot(refVec, eye), 0);
    41Float specularIntensity = max(dot(refVec,eye),0) * saturate(20*diffuseIntensity);
      

    There are cases where the normal points away from the light, but the reflection vector points to the eye, but you shouldn't see anything because the face is away from the light.  Putting the saturate(20*diffuseIntensity) will make sure that you don't get reflections to the eye when the object is facing away.

    Best,
    Byron
    ..shaders make you feel... powerful, or very very stupid.
    http://drjbn.spaces.live.com/
  • 2/10/2010 1:54 AM In reply to

    Re: Normal Mapping Lighting Front and Back Surfaces

    I was aware about the need to change the light vector when reflecting. At first glance, it looked better without the negation but looking at the specular intensity on the cube it appears negating it was correct .. just not as appealing. hehe :P

    As for the specular intensity problem, it isn't a specular intensity problem. The problem effects both diffuseintensity and specularintensity. And the main reason why it occurs is this.

    set l light(lx, ly, -0.5); // a light behind the surface
    set n normal(nx, ny, 0.5); // a normal coming off the surface

    now, take in to account that a light source with a l.z value < 0 is behind the surface it should not be lit. However.
    l dot n
    lx*nx + ly*ny + (-0.5*0.5)
    = lx*nx + ly*ny - 0.25

    now unless that side of the equation adds up to 0 for all l.z < 0 then you're going to see something through both the diffuse and specular components on the lit face or not.

    lets assume that the light vector for l.y and the normal vector for n.y are 0 to eliminate it from the dot product.

    l.x*n.x - 0.25

    now since the light are shifted in to tangent space as it approaches l.x = 0 it's decreasing and then becomes negative the second half of the rotation around the surface.

    Which wound mean that any normal vectors in the negative x direction wouldn't be eliminated but they would if n.x > 0 through (max(0, (negative * positive = negative))).

    The problem I'm having is that the examples I see for normal mapping don't seem to correct this, but work correctly. Making a quick fix is easy, understanding why and solving it isn't. If I can't figure that out, then I haven't fully understood the concept. :P
Page 1 of 1 (5 items) Previous Next
var gDomain='m.webtrends.com'; var gDcsId='dcschd84w10000w4lw9hcqmsz_8n3x'; var gTrackEvents=1; var gFpc='WT_FPC'; /*<\/scr"+"ipt>");} /*]]>*/
DCSIMG