locked
Pixel shader question on BumpMapping code sample

    Question

  • In BumpPixelShader.hlsl line 55, the conditional statement reads

    if ( (costh<0) && ( sin+height*0.02 < 1 ) )
        intensity = 0;
    

    Could someone kindly explain what is  sin+height*0.02?
    Tuesday, August 13, 2013 4:04 AM

Answers

  • That whole block serves to control how much lighting, if any, is applied to bump mapped areas that are beyond the terminator (the line between lighted areas and dark areas on the sphere). If, for example, it was just

    if ( costh < 0 )
        intensity = 0;

    then no light would be applied beyond the terminator (try it) and the bump mapping effect would lose some of its believability since you would expect something like the peaks of the Himalayas to still be lit for a little while after the location of their base passed into darkness.

    By contrast, if changed to something like this

    if ( (costh < 0) && (sin + height*1.0 < 1) )
        intensity = 0;

    then the result would be that parts of the sphere (like the peaks of the Himalayas) would remain lit for far longer than they should (such that sun light would need to be passing through the globe somehow and magically only lighting those peak height surfaces). Again, try it and you should see the result.

    So to take the case of the existing code

    if ( (costh < 0) && (sin + height*0.02 < 1)
        intensity = 0;

    what's going on is essentially the following:

    if ( (the surface is not lit because it's beyond the terminator) && (the sine of the surface normal to light + (the height from the bump map * 2%) < 1)

        set intensity to 0.

    Based on how costh (cosine of theta) is calculated, the angle (theta) between the vector going towards the light source and the vector representing the surface normal (i.e. the vector which is pointing away from the sphere and which also is perpendicular to the tangent plane formed at that point on the sphere) is 90 degrees. Past the terminator (into darkness) that angle increases steadily up to 180 degrees at the point on the opposite side of the sphere that is as far from the light source as possible.

    At 90 degrees, cosine is 0 and sine is 1. At 91 degrees, cosine is negative and sine is 0.9998... . Height is a value between 0 and 1. For dramatic purposes, it's assumed that a height with a value of 1 is equal to 2% of the radius of the sphere (hence the 0.02). (In reality, the Earth's mean radius is 6371 km while the highest point above sea level, the peak of Mt. Everest, is 8.848 km, giving a real value of ~0.139% rather than the 2% in the sample.)

    Given the assumption of 2%, the height from the bump map is multiplied by 0.02 and then added to the sine value. So at 91 degrees, a bump height of 1 gives us (sin(91) + (1 * 0.02)) = (0.9998477 + 0.02) = 1.0198477. This value, being greater than 1.0, the intensity of light at that point is kept at its originally calculated value (rather than being set to 0).

    The net effect is that parts of the globe remain lit despite being in the dark side of the earth because, based on their height, their distance from the terminator, and their surface normal (if the normal isn't pointing towards the light direction then nothing would be lit since the surface at that point would be facing away from the light source), they still have light hitting them. The farther a point gets from the terminator, the less likely it is to still be lit since the sine value decreases the farther into the dark side we get from the terminator. Somewhere between 101.4 degrees and 101.5 degrees all possible lighting from this effect ceases since the sine value crosses from above 0.98 to below it (i.e. 0.97...) such that height * 0.02 can't get the value to 1 in order to pass the ( sin + height*0.02 < 1 ) test.


    Visual C++ MVP | Website | Blog | @mikebmcl | Windows Store DirectX Game Template

    • Proposed as answer by MikeBMcLMVP Tuesday, August 13, 2013 5:42 PM
    • Marked as answer by Leonard Tuesday, August 13, 2013 11:37 PM
    Tuesday, August 13, 2013 5:42 PM

All replies

  • That whole block serves to control how much lighting, if any, is applied to bump mapped areas that are beyond the terminator (the line between lighted areas and dark areas on the sphere). If, for example, it was just

    if ( costh < 0 )
        intensity = 0;

    then no light would be applied beyond the terminator (try it) and the bump mapping effect would lose some of its believability since you would expect something like the peaks of the Himalayas to still be lit for a little while after the location of their base passed into darkness.

    By contrast, if changed to something like this

    if ( (costh < 0) && (sin + height*1.0 < 1) )
        intensity = 0;

    then the result would be that parts of the sphere (like the peaks of the Himalayas) would remain lit for far longer than they should (such that sun light would need to be passing through the globe somehow and magically only lighting those peak height surfaces). Again, try it and you should see the result.

    So to take the case of the existing code

    if ( (costh < 0) && (sin + height*0.02 < 1)
        intensity = 0;

    what's going on is essentially the following:

    if ( (the surface is not lit because it's beyond the terminator) && (the sine of the surface normal to light + (the height from the bump map * 2%) < 1)

        set intensity to 0.

    Based on how costh (cosine of theta) is calculated, the angle (theta) between the vector going towards the light source and the vector representing the surface normal (i.e. the vector which is pointing away from the sphere and which also is perpendicular to the tangent plane formed at that point on the sphere) is 90 degrees. Past the terminator (into darkness) that angle increases steadily up to 180 degrees at the point on the opposite side of the sphere that is as far from the light source as possible.

    At 90 degrees, cosine is 0 and sine is 1. At 91 degrees, cosine is negative and sine is 0.9998... . Height is a value between 0 and 1. For dramatic purposes, it's assumed that a height with a value of 1 is equal to 2% of the radius of the sphere (hence the 0.02). (In reality, the Earth's mean radius is 6371 km while the highest point above sea level, the peak of Mt. Everest, is 8.848 km, giving a real value of ~0.139% rather than the 2% in the sample.)

    Given the assumption of 2%, the height from the bump map is multiplied by 0.02 and then added to the sine value. So at 91 degrees, a bump height of 1 gives us (sin(91) + (1 * 0.02)) = (0.9998477 + 0.02) = 1.0198477. This value, being greater than 1.0, the intensity of light at that point is kept at its originally calculated value (rather than being set to 0).

    The net effect is that parts of the globe remain lit despite being in the dark side of the earth because, based on their height, their distance from the terminator, and their surface normal (if the normal isn't pointing towards the light direction then nothing would be lit since the surface at that point would be facing away from the light source), they still have light hitting them. The farther a point gets from the terminator, the less likely it is to still be lit since the sine value decreases the farther into the dark side we get from the terminator. Somewhere between 101.4 degrees and 101.5 degrees all possible lighting from this effect ceases since the sine value crosses from above 0.98 to below it (i.e. 0.97...) such that height * 0.02 can't get the value to 1 in order to pass the ( sin + height*0.02 < 1 ) test.


    Visual C++ MVP | Website | Blog | @mikebmcl | Windows Store DirectX Game Template

    • Proposed as answer by MikeBMcLMVP Tuesday, August 13, 2013 5:42 PM
    • Marked as answer by Leonard Tuesday, August 13, 2013 11:37 PM
    Tuesday, August 13, 2013 5:42 PM
  • Thank you for your detailed explanation. Now I fully understand the code.
    Tuesday, August 13, 2013 11:36 PM