Kyle Hayward's


Camera Animation


This project was a series of tutorials on my graphics programming blog [link]. It presents key frame animation for cameras based on natural cubic spline interpolation, and also includes water rendering with reflection and refraction. It allows the user to navigate the scene and save key frames and build the camera path at run time. The application was developed in C# with the XNA framework. Another example of camera animation can be found in the dual-paraboloid mapping project. The cubic spline interpolation is derived from:


  • Linear and cubic spline interpolation for camera animation

  • Water with reflection and refraction based on the Fresnel term

  • Allows playing, pausing, rewinding, and free navigation

Screen Shots


Source Snippet

//Water.fx effect shader
float4 WaterPS2(float3 toEyeW        : TEXCOORD0,
                float2 tex0            : TEXCOORD1,
                float2 tex1            : TEXCOORD2,
                float4 projTexC        : TEXCOORD3,
                float  eyeVertDist    : TEXCOORD4,
                float4 pos            : TEXCOORD5) : COLOR
{ /= projTexC.w;            
    projTexC.x =  0.5f*projTexC.x + 0.5f; 
    projTexC.y = -0.5f*projTexC.y + 0.5f;
    projTexC.z = .1f / projTexC.z;
    toEyeW         = normalize(toEyeW);
    SunDirection = normalize(SunDirection);
    // Light vector is opposite the direction of the light.
    float3 lightVecW = -SunDirection;
    // Sample normal map.
    float3 normalT0 = tex2D(WaveMapS0, tex0);
    float3 normalT1 = tex2D(WaveMapS1, tex1);
    //unroll the normals retrieved from the normalmaps
    normalT0.yz = normalT0.zy;
    normalT1.yz = normalT1.zy;
    normalT0 = 2.0f*normalT0 - 1.0f;
    normalT1 = 2.0f*normalT1 - 1.0f;
    float3 normalT = normalize(0.5f*(normalT0 + normalT1));
    float3 n1 = float3(0,1,0); //just use unit y to calculate fresnel
    //get the reflection vector from the eye
    float3 R = normalize(reflect(toEyeW,normalT));
    float4 finalColor;
    finalColor.a = 1;

    //compute the fresnel term to blend reflection and refraction maps
    float ang = saturate(dot(-toEyeW,n1));
    float f = R0 + (1.0f-R0) * pow(1.0f-ang,5.0);    
    //also blend based on distance
    f = min(1.0f, f + 0.007f * EyePos.y);    
    //compute the reflection from sunlight, hacked in color, should be a variable
    float3 sunlight = 1.5f * pow(saturate(dot(R, lightVecW)),250.0f) * SunColor;

    float4 refl = tex2D(ReflectMapS,projTexC.xy+projTexC.z*normalT.xz);
    float4 refr = tex2D(RefractMapS, projTexC.xy-projTexC.z*normalT.xz);
    //only use the refraction map if we're under water
    if(EyePos.y < pos.y)
        f = 0.0f;
    float4 WaterColor = float4(0.5f, 0.79f, 0.75f, 1.00f);
    //interpolate the reflection and refraction maps based on the fresnel term and add the sunlight
    finalColor.rgb = WaterColor * lerp( refr, refl, f) + sunlight;
    return finalColor;


Binary: XNA 3.0 Redist and .Net 3.5 Framework is required to be installed in order to run the demo.

Source: XNA Game Studio 3.0 and DirectX is required to be installed in order to build and run the source.