Esempio n. 1
0
        /// <summary>Updates the reflected image on the water surface</summary>
        /// <param name="gameTime">Snapshot of the game's timing values</param>
        /// <param name="camera">Camera through which the scene is being viewed</param>
        /// <param name="reflectedSceneDrawer">
        ///   Delegate that will be called to draw the scene in its reflected state
        /// </param>
        /// <remarks>
        ///   <para>
        ///     When the delegate is called, the scene should be drawn normally using
        ///     the provided game time and camera. The view matrix of the provided camera
        ///     will have been adjusted to draw the scene upside-down and the graphics device
        ///     will be configured to clip off anything that's below the water surface.
        ///   </para>
        ///   <para>
        ///     Some adjustments can be made, like rendering the reflection with reduced
        ///     detail, cheaper effects or even leaving our parts of the scene to improve
        ///     performance since the reflection will not be clearly displayed anyway.
        ///   </para>
        /// </remarks>
        public void UpdateReflection(
            GameTime gameTime, Camera camera, SceneDrawDelegate reflectedSceneDrawer
            )
        {
            // Create a matrix that undoes the view and projection transforms. We don't
            // involve any world matrix here because the water plane exists in
            // the world coordinate frame, its world matrix is always the identity matrix.
            Matrix viewProjection        = camera.View * camera.Projection;
            Matrix inverseViewProjection = Matrix.Invert(viewProjection);

            // The water plane in world coordinates. We want to clip away everything that's
            // below the water surface (as only things above it should be reflected)
            Vector4 worldWaterPlane = new Vector4(Vector3.Down, 0.0f);

            // The water plane as sent through the inverse view and projection transforms.
            // This is neccessary because the plane will be transformed by those two
            // matrices when it is applied to the scene. Don't ask me why.
            Vector4 projectedWaterPlane = Vector4.Transform(
                worldWaterPlane, Matrix.Transpose(inverseViewProjection)
                );

#if XNA_4
            this.graphicsDevice.SetRenderTarget(this.reflectionRenderTarget);
#else
            this.graphicsDevice.SetRenderTarget(0, this.reflectionRenderTarget);
#endif
            try {
                // Set up a clipping plane that only draws those parts of the scene that
                // are above the water because that's the only thing we want to appear in
                // the reflection on the water surface.
#if !XNA_4 // TODO: Move this to the shader for both XNA 3.1 and XNA 4.0
                this.graphicsDevice.ClipPlanes[0].Plane     = new Plane(projectedWaterPlane);
                this.graphicsDevice.ClipPlanes[0].IsEnabled = true;
                try {
#endif
                Matrix reflectionMatrix = Matrix.CreateReflection(new Plane(worldWaterPlane));

                this.reflectionCamera.View       = reflectionMatrix * camera.View;
                this.reflectionCamera.Projection = camera.Projection;

                reflectedSceneDrawer(gameTime, this.reflectionCamera);
#if !XNA_4
            }
            finally {
                this.graphicsDevice.ClipPlanes[0].IsEnabled = false;
            }
#endif
            }
            finally {
#if XNA_4
                this.graphicsDevice.SetRenderTarget(null);
#else
                this.graphicsDevice.SetRenderTarget(0, null);
                this.reflectionTexture = reflectionRenderTarget.GetTexture();
#endif
            }
        }
Esempio n. 2
0
    /// <summary>Updates the reflected image on the water surface</summary>
    /// <param name="gameTime">Snapshot of the game's timing values</param>
    /// <param name="camera">Camera through which the scene is being viewed</param>
    /// <param name="reflectedSceneDrawer">
    ///   Delegate that will be called to draw the scene in its reflected state
    /// </param>
    /// <remarks>
    ///   <para>
    ///     When the delegate is called, the scene should be drawn normally using
    ///     the provided game time and camera. The view matrix of the provided camera
    ///     will have been adjusted to draw the scene upside-down and the graphics device
    ///     will be configured to clip off anything that's below the water surface.
    ///   </para>
    ///   <para>
    ///     Some adjustments can be made, like rendering the reflection with reduced
    ///     detail, cheaper effects or even leaving our parts of the scene to improve
    ///     performance since the reflection will not be clearly displayed anyway.
    ///   </para>
    /// </remarks>
    public void UpdateReflection(
      GameTime gameTime, Camera camera, SceneDrawDelegate reflectedSceneDrawer
    ) {

      // Create a matrix that undoes the view and projection transforms. We don't
      // involve any world matrix here because the water plane exists in
      // the world coordinate frame, its world matrix is always the identity matrix.
      Matrix viewProjection = camera.View * camera.Projection;
      Matrix inverseViewProjection = Matrix.Invert(viewProjection);

      // The water plane in world coordinates. We want to clip away everything that's
      // below the water surface (as only things above it should be reflected)
      Vector4 worldWaterPlane = new Vector4(Vector3.Down, 0.0f);

      // The water plane as sent through the inverse view and projection transforms.
      // This is neccessary because the plane will be transformed by those two
      // matrices when it is applied to the scene. Don't ask me why.
      Vector4 projectedWaterPlane = Vector4.Transform(
        worldWaterPlane, Matrix.Transpose(inverseViewProjection)
      );

#if XNA_4
      this.graphicsDevice.SetRenderTarget(this.reflectionRenderTarget);
#else
      this.graphicsDevice.SetRenderTarget(0, this.reflectionRenderTarget);
#endif
      try {

        // Set up a clipping plane that only draws those parts of the scene that
        // are above the water because that's the only thing we want to appear in
        // the reflection on the water surface.
#if !XNA_4 // TODO: Move this to the shader for both XNA 3.1 and XNA 4.0
        this.graphicsDevice.ClipPlanes[0].Plane = new Plane(projectedWaterPlane);
        this.graphicsDevice.ClipPlanes[0].IsEnabled = true;
        try {
#endif
        Matrix reflectionMatrix = Matrix.CreateReflection(new Plane(worldWaterPlane));

        this.reflectionCamera.View = reflectionMatrix * camera.View;
        this.reflectionCamera.Projection = camera.Projection;

        reflectedSceneDrawer(gameTime, this.reflectionCamera);
#if !XNA_4
        }
        finally {
          this.graphicsDevice.ClipPlanes[0].IsEnabled = false;
        }
#endif
      }
      finally {
#if XNA_4
        this.graphicsDevice.SetRenderTarget(null);
#else
        this.graphicsDevice.SetRenderTarget(0, null);
        this.reflectionTexture = reflectionRenderTarget.GetTexture();
#endif
      }

    }