Monday, May 9, 2011

Environmental Reflections

Shiny objects in your game should be able to reflect the environment around them. Don't think that you can use a mirror technique everywhere, the reflections on a car will require a high number of directions to reflect so it will become almost impossible to compute them. We can use a cube map to simulate the reflections of the environment around the object. Cube mapping helps us because we don't need to actually reflect the items, we just have to do a texture look-up and that's it.

 For this tutorial you will find the source code here. It already has a sky box, a camera that rotates around a skull using our own effect which renders a cube map on it. What we will have to do is calculate the reflection vector and use that as our look up vector.

The reflected vector is symmetrical with the original vector (in out case the surface normal is the symmetry axis):

In the above image the black vector is the incident vector, the red vector is the reflected vector and the blue one is the surface normal. The incident vector will be the vector from the object to the observer, to calculate the reflected vector we will use the intrinsic reflect function. So, we will need the position of the observer in out shader, also we will need the World coordinates of the object position and normal to get the accurate calculations, because of this we will also need the world transform in our shader. I will still send the 3 transforms coupled together for the usual coordinates transform.

float3 eyePosition;
float4x4 World;
float4x4 WVP;

Because we will need the world position in our pixel shader and the normal in world coordinates we have to transform them only by the world transform and send them to the pixel shader. For this we will have to add a world position vertex shader output. The position will have a straightforward transformation, but the normal must NOT be translated (we should only rotate normals). To make sure it is not translated we only multiply it by the first 3x3 of our world matrix as the translation factors are on the last line (or column, depending on the way you consider them mathematically) of the matrix.

struct VertexShaderOutput
    float4 Position  : POSITION0;
    float3 PositionW : TEXCOORD1;
    float3 Normal    : TEXCOORD2;
VertexShaderOutput VSGeneral(VertexShaderInput input)
    VertexShaderOutput output = (VertexShaderOutput)0;
    output.Position = mul(input.Position, WVP);
    output.PositionW = mul(input.Position,World);
    output.Normal = mul(input.Normal,(float3x3)World);
    return output;

Now on to the pixel shader. Because we are transforming our normal, it may get changed in size (our world matrix could have scale) so we will need to normalize it. Also our incident vector will most probably have a length different of one so we will also normalize it

    float3 N = normalize(input.Normal);
    float3 I = input.PositionW - eyePosition;
    I = normalize(I);

Now we will use the intrinsic reflect function, the first parameter to the function is the normalized incident vector and the second one is the normal to the surface. Why normalize the incident vector? Because the reflect function uses a dot product, so in some cases it could have some unwanted effects. After we calculate the reflected vector we only have to use it to sample our cube map:

    float3 R = reflect(I,N);
    float3 reflectedColor = texCUBE(cubeSampler,R);

With this we will have a very simple environmental reflection using cube maps (click here for download). The resulting application should like:


  1. Ai cumva tutoriale de pe Ziggyware? din cate am tot vazut, erau o gramada de tutoriale excelente. Pentru chestii care nu le prea gaseai in alta parte.

    Si daca te rog, imi dai un e-mail pe andreilng [a ] ? as avea vreo 2-3 intrebari, si nu gasesc pe blog mailu` tau.

  2. My effect/texture is upside/down. ?

  3. Try downlaoding my code an comparing them one by one. If that doesn't work give me a message on facebook ( and I'll give you my email.

    I won't be able to answera till the 23rd as my HDD died.