#region Using Statements
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Storage;
#endregion
namespace XNAGame
{
///
/// This is the main type for your game
///
public class Game1 : Microsoft.Xna.Framework.Game
{
private GraphicsDeviceManager graphics;
private ContentManager content;
//Camera functions
private Matrix worldMatrix;
private Matrix viewMatrix;
private Matrix projectionMatrix;
//Position of the Camera in world space, for our view matrix
private Vector3 cameraPosition = new Vector3(0.0f, 10.0f, 55.0f);
//for the custom .fx file
private Effect effect;
//Our models
private Model FarmModel;
Texture2D[] FarmTextures;
private Model BarrelModel;
Texture2D[] BarrelTextures;
private Model HouseModel;
Texture2D HouseTexture;
private Model ToiletModel;
Texture2D[] ToiletTextures;
//Lamp positions
Vector4[] lampPostPos;
//Terrain variables
private Terrain terrain;
//Sky variables
private Sky sky;
//Water variables
private Water water;
//HUD variables
private HUD hud;
//Texture variables
private Texture2D texture;
//Movement variables
private Vector3 avatarPosition = new Vector3(0, 0, -20);
private float forwardSpeed = 50.0f / 60.0f;
private MouseState previousMouseState;
Vector3 moveVector = new Vector3();
//Camera variables
private Vector3 cameraReference = new Vector3(0, -10, -55);
private float mouseX, mouseY;
static float nearClip = 1.0f;
static float farClip = 10000.0f;
static float viewAngle = MathHelper.PiOver4;
//Lighting variables
Vector4 lightpos = new Vector4(-18, 2, 5, 1);
private float lightpower;
private Texture2D carLight;
//Variable for the shadow mapping
private Matrix lightworldviewproj;
//Variables to enable shadows as textures
private RenderTarget2D renderTarget;
private Texture2D texturedRenderedTo;
//Variables to enable refraction mapping on the water
RenderTarget2D refractionRenderTarget;
Texture2D refractionMap;
//Variables to enable reflection mapping on the water
private RenderTarget2D reflectionRenderTarget;
private Texture2D reflectionMap;
private Matrix reflectionViewMatrix;
//Water variables
private float waterHeight = 20.0f;
//Realizes moving water and clouds
private float elapsedTime;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
content = new ContentManager(Services);
if (GraphicsAdapter.DefaultAdapter.GetCapabilities(DeviceType.Hardware).MaxPixelShaderProfile < ShaderProfile.PS_2_0)
{
graphics.PreparingDeviceSettings += new EventHandler(SetToReference);
}
}
private void initializeXNADevice()
{
graphics.PreferredBackBufferWidth = 1000;
graphics.PreferredBackBufferHeight = 500;
graphics.IsFullScreen = false;
graphics.ApplyChanges();
Window.Title = "Riemer's XNA Tutorials -- Series 3";
renderTarget = new RenderTarget2D(graphics.GraphicsDevice, 512, 512, 1, SurfaceFormat.Color);
refractionRenderTarget = new RenderTarget2D(graphics.GraphicsDevice, 512, 512, 1, SurfaceFormat.Color);
reflectionRenderTarget = new RenderTarget2D(graphics.GraphicsDevice, 512, 512, 1, SurfaceFormat.Color);
}
void SetToReference(object sender, PreparingDeviceSettingsEventArgs e)
{
e.GraphicsDeviceInformation.CreationOptions = CreateOptions.SoftwareVertexProcessing;
e.GraphicsDeviceInformation.DeviceType = DeviceType.Reference;
e.GraphicsDeviceInformation.PresentationParameters.MultiSampleType = MultiSampleType.None;
}
private void initializeEffect()
{
effect = content.Load("effect");
effect.Parameters["xMaxDepth"].SetValue(60);
effect.Parameters["xAmbient"].SetValue(0.4f);
cameraPosition = new Vector3(-25, 18, 13);
viewMatrix = Matrix.CreateLookAt(cameraPosition, new Vector3(0, 12, 2), new Vector3(0, 0, 1));
projectionMatrix = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4, (float)this.Window.ClientBounds.Width / (float)this.Window.ClientBounds.Height, 1.0f, 200.0f);
effect.Parameters["xUserTexture"].SetValue(texture);
}
private void initializeModels()
{
//Load the farm model from a file
FarmModel = content.Load("Models\\farm1\\farm1");
// Initialize the farm effects
FarmTextures = new Texture2D[14];
int j = 0;
foreach (ModelMesh mesh in FarmModel.Meshes)
foreach (BasicEffect currenteffect in mesh.Effects)
FarmTextures[j++] = currenteffect.Texture;
foreach (ModelMesh modmesh in FarmModel.Meshes)
foreach (ModelMeshPart modmeshpart in modmesh.MeshParts)
modmeshpart.Effect = effect.Clone(graphics.GraphicsDevice);
//Load the barrel model from a file
BarrelModel = content.Load("Models\\barrel\\barrel");
// Initialize the barrel effects
BarrelTextures = new Texture2D[14];
j = 0;
foreach (ModelMesh mesh in BarrelModel.Meshes)
foreach (BasicEffect currenteffect in mesh.Effects)
BarrelTextures[j++] = currenteffect.Texture;
foreach (ModelMesh modmesh in BarrelModel.Meshes)
foreach (ModelMeshPart modmeshpart in modmesh.MeshParts)
modmeshpart.Effect = effect.Clone(graphics.GraphicsDevice);
//Load the house model from a file
HouseModel = content.Load("Models\\house1\\house1");
// Initialize the house effects
foreach (ModelMesh mesh in HouseModel.Meshes)
foreach (BasicEffect currenteffect in mesh.Effects)
HouseTexture = currenteffect.Texture;
foreach (ModelMesh modmesh in HouseModel.Meshes)
foreach (ModelMeshPart modmeshpart in modmesh.MeshParts)
modmeshpart.Effect = effect.Clone(graphics.GraphicsDevice);
//Load the toilet model from a file
ToiletModel = content.Load("Models\\toilet\\klo_uv");
// Initialize the toilet effects
ToiletTextures = new Texture2D[14];
j = 0;
foreach (ModelMesh mesh in ToiletModel.Meshes)
foreach (BasicEffect currenteffect in mesh.Effects)
ToiletTextures[j++] = currenteffect.Texture;
foreach (ModelMesh modmesh in ToiletModel.Meshes)
foreach (ModelMeshPart modmeshpart in modmesh.MeshParts)
modmeshpart.Effect = effect.Clone(graphics.GraphicsDevice);
}
private void initializeTerrain()
{
terrain = new Terrain();
terrain.Initialize(graphics.GraphicsDevice, content);
}
private void initializeSky()
{
sky = new Sky();
sky.Initialize(graphics.GraphicsDevice, content);
}
private void initializeWater()
{
water = new Water(waterHeight);
water.Initialize(graphics.GraphicsDevice, content);
}
private void initializeHUD()
{
hud = new HUD();
hud.Initialize(graphics.GraphicsDevice, content, Window);
}
private void initializeMouse()
{
Mouse.SetPosition(Window.ClientBounds.Width / 2, Window.ClientBounds.Height / 2);
previousMouseState = Mouse.GetState();
}
///
/// Allows the game to perform any initialization it needs to before starting to run.
/// This is where it can query for any required services and load any non-graphic
/// related content. Calling base.Initialize will enumerate through any components
/// and initialize them as well.
///
protected override void Initialize()
{
base.Initialize();
}
///
/// Load your graphics content. If loadAllContent is true, you should
/// load content from both ResourceManagementMode pools. Otherwise, just
/// load ResourceManagementMode.Manual content.
///
/// Which type of content to load.
protected override void LoadGraphicsContent(bool loadAllContent)
{
if (loadAllContent)
{
HouseTexture = content.Load("Models\\house1\\fw12b");
initializeXNADevice();
initializeEffect();
initializeTerrain();
initializeSky();
initializeHUD();
initializeModels();
initializeMouse();
}
}
///
/// Unload your graphics content. If unloadAllContent is true, you should
/// unload content from both ResourceManagementMode pools. Otherwise, just
/// unload ResourceManagementMode.Manual content. Manual content will get
/// Disposed by the GraphicsDevice during a Reset.
///
/// Which type of content to unload.
protected override void UnloadGraphicsContent(bool unloadAllContent)
{
if (unloadAllContent == true)
{
content.Unload();
}
}
private void ProcessInput(float amountOfMovement)
{
Vector3 moveVector = new Vector3();
KeyboardState keys = Keyboard.GetState();
if (keys.IsKeyDown(Keys.W))
{
moveVector.Y += amountOfMovement * forwardSpeed;
}
if (keys.IsKeyDown(Keys.S))
{
moveVector.Y -= amountOfMovement * forwardSpeed;
}
if (keys.IsKeyDown(Keys.A))
{
moveVector.X -= amountOfMovement * forwardSpeed;
}
if (keys.IsKeyDown(Keys.D))
{
moveVector.X += amountOfMovement * forwardSpeed;
}
Matrix cameraRotation = Matrix.CreateRotationX(mouseY) * Matrix.CreateRotationZ(mouseX);
cameraPosition += Vector3.Transform(moveVector, cameraRotation);
if (keys.IsKeyDown(Keys.LeftShift))
{
forwardSpeed = 3.0f;
}
else
{
forwardSpeed = 50.0f / 60.0f;
}
if (keys.IsKeyDown(Keys.Escape))
{
this.Exit();
}
//Mouse input
MouseState currentMouseState = Mouse.GetState();
if (currentMouseState.X != previousMouseState.X)
{
mouseX -= amountOfMovement / 80.0f * (currentMouseState.X - previousMouseState.X);
}
if (currentMouseState.Y != previousMouseState.Y)
{
mouseY -= amountOfMovement / 80.0f * (currentMouseState.Y - previousMouseState.Y);
}
Mouse.SetPosition(Window.ClientBounds.Width / 2, Window.ClientBounds.Height / 2);
}
private void processMouse(float amountOfMovement)
{
MouseState currentMouseState = Mouse.GetState();
if (currentMouseState.X != previousMouseState.X)
{
mouseX -= amountOfMovement / 80.0f * (currentMouseState.X - previousMouseState.X);
}
if (currentMouseState.Y != previousMouseState.Y)
{
mouseY -= amountOfMovement / 80.0f * (currentMouseState.Y - previousMouseState.Y);
}
Mouse.SetPosition(Window.ClientBounds.Width / 2, Window.ClientBounds.Height / 2);
}
private void UpdateCamera()
{
Matrix rotationMatrix = Matrix.CreateRotationX(mouseY) * Matrix.CreateRotationZ(mouseX);
Vector3 cameraLookat = cameraPosition + Vector3.Transform(new Vector3(0, 1, 0), rotationMatrix);
Vector3 upVector = Vector3.Transform(new Vector3(0, 0, 1), rotationMatrix);
viewMatrix = Matrix.CreateLookAt(cameraPosition, cameraLookat, upVector);
projectionMatrix = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4, (float)this.Window.ClientBounds.Width / (float)this.Window.ClientBounds.Height, 1.0f, 1000.0f);
//Determine the reflection coordinates
float reflectionCamZCoord = -cameraPosition.Z + 2 * waterHeight;
Vector3 reflectionCamPosition = new Vector3(cameraPosition.X, cameraPosition.Y, reflectionCamZCoord);
float reflectionTargetZCoord = -cameraLookat.Z + 2 * waterHeight;
Vector3 reflectionCamTarget = new Vector3(cameraLookat.X, cameraLookat.Y, reflectionTargetZCoord);
//Determine the up vector
Vector3 forwardVector = reflectionCamTarget - reflectionCamPosition;
Vector3 sideVector = Vector3.Transform(new Vector3(1, 0, 0), rotationMatrix);
Vector3 reflectionCamUp = Vector3.Cross(sideVector, forwardVector);
reflectionViewMatrix = Matrix.CreateLookAt(reflectionCamPosition, reflectionCamTarget, reflectionCamUp);
}
public void updateLightData(Vector4 lightpos)
{
this.lightpos = lightpos;
lampPostPos = new Vector4[2];
lampPostPos[0] = new Vector4(3.0f, 5.0f, 11f, 1);
lampPostPos[1] = new Vector4(3.0f, 35.0f, 11f, 1);
lightpower = 2f;
lightworldviewproj = Matrix.CreateLookAt(new Vector3(lightpos.X, lightpos.Y, lightpos.Z), new Vector3(-2, 10, -3), new Vector3(0, 0, 1)) * Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver2, (float)this.Window.ClientBounds.Width / (float)this.Window.ClientBounds.Height, 1f, 100f);
}
///
/// Allows the game to run logic such as updating the world,
/// checking for collisions, gathering input and playing audio.
///
/// Provides a snapshot of timing values.
protected override void Update(GameTime gameTime)
{
// Allows the default game to exit on Xbox 360 and Windows
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();
ProcessInput((float)gameTime.ElapsedGameTime.Milliseconds / 30.0f);
UpdateCamera();
lightpos.Y += 0.01f;
updateLightData(new Vector4(-18, lightpos.Y, 5, 1));
elapsedTime += (float)gameTime.ElapsedGameTime.Milliseconds / 100000.0f;
base.Update(gameTime);
}
private void drawModel(string technique, Model currentModel, Matrix worldMatrix, Texture2D[] textures, bool useBrownInsteadOfTextures)
{
int i = 0;
Matrix[] transforms = new Matrix[currentModel.Bones.Count];
currentModel.CopyAbsoluteBoneTransformsTo(transforms);
foreach (ModelMesh modmesh in currentModel.Meshes)
{
foreach (Effect currenteffect in modmesh.Effects)
{
currenteffect.CurrentTechnique = effect.Techniques[technique];
currenteffect.Parameters["xCameraViewProjection"].SetValue(viewMatrix * projectionMatrix);
currenteffect.Parameters["xUserTexture"].SetValue(textures[i++]);
currenteffect.Parameters["xUseBrownInsteadOfTextures"].SetValue(useBrownInsteadOfTextures);
//Set lighting data
currenteffect.Parameters["xLightPos"].SetValue(lightpos);
currenteffect.Parameters["xLightPower"].SetValue(lightpower);
currenteffect.Parameters["xWorld"].SetValue(transforms[modmesh.ParentBone.Index] * worldMatrix);
//Set shadow data
currenteffect.Parameters["xLightViewProjection"].SetValue(lightworldviewproj);
currenteffect.Parameters["xShadowMap"].SetValue(texturedRenderedTo);
//Set ambient light data
currenteffect.Parameters["xLampPostPos"].SetValue(lampPostPos);
currenteffect.Parameters["xCameraPos"].SetValue(new Vector4(cameraPosition.X, cameraPosition.Y, cameraPosition.Z, 1));
}
modmesh.Draw();
}
}
//Method to map a given model on the underlying terrain
//Useful for placing houses, trees etc.
private void drawModelOnTerrain(string technique, Model currentModel, Matrix worldMatrix, float x, float y, Texture2D[] textures, bool useBrownInsteadOfTextures)
{
//generate the right worldMatrix
Vector3 modelPos = terrain.getHeightValue(x, y);
worldMatrix *= Matrix.CreateTranslation(modelPos);
worldMatrix *= Matrix.CreateTranslation(new Vector3(0.0f, 0.0f, currentModel.Root.Transform.M43 * 2));
drawModel(technique, currentModel, worldMatrix, textures, useBrownInsteadOfTextures);
}
private void drawModelWithSingleTexture(string technique, Model currentModel, Matrix worldMatrix, Texture2D texture)
{
Matrix[] transforms = new Matrix[currentModel.Bones.Count];
currentModel.CopyAbsoluteBoneTransformsTo(transforms);
foreach (ModelMesh modmesh in currentModel.Meshes)
{
foreach (Effect currenteffect in modmesh.Effects)
{
currenteffect.CurrentTechnique = effect.Techniques[technique];
currenteffect.Parameters["xCameraViewProjection"].SetValue(viewMatrix * projectionMatrix);
currenteffect.Parameters["xUserTexture"].SetValue(texture);
//Set lighting data
currenteffect.Parameters["xLightPos"].SetValue(lightpos);
currenteffect.Parameters["xLightPower"].SetValue(lightpower);
currenteffect.Parameters["xWorld"].SetValue(transforms[modmesh.ParentBone.Index] * worldMatrix);
//Set shadow data
currenteffect.Parameters["xLightViewProjection"].SetValue(lightworldviewproj);
currenteffect.Parameters["xShadowMap"].SetValue(texturedRenderedTo);
//Set ambient light data
currenteffect.Parameters["xLampPostPos"].SetValue(lampPostPos);
currenteffect.Parameters["xCameraPos"].SetValue(new Vector4(cameraPosition.X, cameraPosition.Y, cameraPosition.Z, 1));
}
modmesh.Draw();
}
}
private void drawModelOnTerrainWithSingleTexture(string technique, Model currentModel, Matrix worldMatrix, float x, float y, float scale, Texture2D texture)
{
//generate the right worldMatrix
Vector3 modelPos = terrain.getHeightValue(x, y);
worldMatrix *= Matrix.CreateTranslation(modelPos);
worldMatrix *= Matrix.CreateTranslation(new Vector3(0.0f, 0.0f, (scale * Math.Abs(currentModel.Root.Transform.M43)) * 1.5f));
drawModelWithSingleTexture(technique, currentModel, worldMatrix, texture);
}
private void drawScene(string technique)
{
effect.CurrentTechnique = effect.Techniques[technique];
effect.Parameters["xCameraViewProjection"].SetValue(viewMatrix * projectionMatrix);
effect.Parameters["xLightPos"].SetValue(lightpos);
effect.Parameters["xLightPower"].SetValue(lightpower);
effect.Parameters["xWorld"].SetValue(Matrix.Identity);
effect.Parameters["xLightViewProjection"].SetValue(lightworldviewproj);
effect.Parameters["xShadowMap"].SetValue(texturedRenderedTo);
effect.Parameters["xLampPostPos"].SetValue(lampPostPos);
effect.Parameters["xCameraPos"].SetValue(new Vector4(cameraPosition.X, cameraPosition.Y, cameraPosition.Z, 1));
//draw the farm into the level
worldMatrix = Matrix.CreateScale(1.0f, 1.0f, 1.0f) * Matrix.CreateRotationX((float)Math.PI / 2) * Matrix.CreateRotationZ((float)Math.PI / 2);
drawModelOnTerrain(technique, FarmModel, worldMatrix, 5, 80, FarmTextures, false);
worldMatrix = Matrix.CreateScale(1.0f, 1.0f, 1.0f) * Matrix.CreateRotationX((float)Math.PI / 2) * Matrix.CreateRotationZ(2.0f * (float)Math.PI / 2);
drawModelOnTerrain(technique, FarmModel, worldMatrix, 5, 75, FarmTextures, false);
worldMatrix = Matrix.CreateScale(1.0f, 1.0f, 1.0f) * Matrix.CreateRotationX((float)Math.PI / 2) * Matrix.CreateRotationZ(2.2f * (float)Math.PI / 2);
drawModelOnTerrain(technique, FarmModel, worldMatrix, 5, 60, FarmTextures, false);
worldMatrix = Matrix.CreateScale(1.0f, 1.0f, 1.0f) * Matrix.CreateRotationX((float)Math.PI / 2) * Matrix.CreateRotationZ(2.7f * (float)Math.PI / 2);
drawModelOnTerrain(technique, FarmModel, worldMatrix, 10, 78, FarmTextures, false);
worldMatrix = Matrix.CreateScale(1.0f, 1.0f, 1.0f) * Matrix.CreateRotationX((float)Math.PI / 2) * Matrix.CreateRotationZ(1.8f * (float)Math.PI / 2);
drawModelOnTerrain(technique, FarmModel, worldMatrix, 10, 84, FarmTextures, false);
//Barrel Tile
float x = 10.0f;
float y = 86.0f;
worldMatrix = Matrix.CreateScale(0.02f, 0.02f, 0.02f) * Matrix.CreateRotationX((float)Math.PI / 2) * Matrix.CreateRotationZ(1.3f * (float)Math.PI / 2);
drawModelOnTerrain(technique, BarrelModel, worldMatrix, x, y, BarrelTextures, false);
worldMatrix *= Matrix.CreateRotationY((float)Math.PI / 2);
drawModelOnTerrain(technique, BarrelModel, worldMatrix, x, (y + .2f), BarrelTextures, false);
x = 5.0f;
y = 81.0f;
worldMatrix = Matrix.CreateScale(0.02f, 0.02f, 0.02f) * Matrix.CreateRotationX((float)Math.PI / 2) * Matrix.CreateRotationZ(1.3f * (float)Math.PI / 2);
drawModelOnTerrain(technique, BarrelModel, worldMatrix, x, y, BarrelTextures, false);
worldMatrix *= Matrix.CreateRotationY((float)Math.PI / 2);
drawModelOnTerrain(technique, BarrelModel, worldMatrix, x, (y + .2f), BarrelTextures, false);
//Houses
worldMatrix = Matrix.CreateScale(0.01f, 0.01f, 0.01f) * Matrix.CreateRotationX((float)Math.PI / 2) * Matrix.CreateRotationZ(1.8f * (float)Math.PI / 2);
//We need an extra parameter scale = 0.01f to tell the model that its size has been modified.
//This is needed, because otherwise the translation will not fit to the terrain anymore.
drawModelOnTerrainWithSingleTexture(technique, HouseModel, worldMatrix, 10, 88, 0.01f, HouseTexture);
worldMatrix = Matrix.CreateScale(0.01f, 0.01f, 0.01f) * Matrix.CreateRotationX((float)Math.PI / 2) * Matrix.CreateRotationZ(2.8f * (float)Math.PI / 2);
//We need an extra parameter scale = 0.01f to tell the model that its size has been modified.
//This is needed, because otherwise the translation will not fit to the terrain anymore.
drawModelOnTerrainWithSingleTexture(technique, HouseModel, worldMatrix, 10, 68, 0.01f, HouseTexture);
worldMatrix = Matrix.CreateScale(0.01f, 0.01f, 0.01f) * Matrix.CreateRotationX((float)Math.PI / 2) * Matrix.CreateRotationZ(1.3f * (float)Math.PI / 2);
//We need an extra parameter scale = 0.01f to tell the model that its size has been modified.
//This is needed, because otherwise the translation will not fit to the terrain anymore.
drawModelOnTerrainWithSingleTexture(technique, HouseModel, worldMatrix, 15, 70, 0.01f, HouseTexture);
worldMatrix = Matrix.CreateScale(0.01f, 0.01f, 0.01f) * Matrix.CreateRotationX((float)Math.PI / 2) * Matrix.CreateRotationZ(2.4f * (float)Math.PI / 2);
//We need an extra parameter scale = 0.01f to tell the model that its size has been modified.
//This is needed, because otherwise the translation will not fit to the terrain anymore.
drawModelOnTerrainWithSingleTexture(technique, HouseModel, worldMatrix, 8, 76, 0.01f, HouseTexture);
//Toilets
worldMatrix = Matrix.CreateScale(0.01f, 0.01f, 0.01f) * Matrix.CreateRotationX((float)Math.PI / 2) * Matrix.CreateRotationZ(1.8f * (float)Math.PI / 2);
//We need an extra parameter scale = 0.01f to tell the model that its size has been modified.
//This is needed, because otherwise the translation will not fit to the terrain anymore.
drawModelOnTerrain(technique, ToiletModel, worldMatrix, 10, 90, ToiletTextures, false);
}
private void drawRefractionMap(GameTime gameTime, Matrix viewMatrix, Matrix projectionMatrix)
{
Vector3 planeNormalDirection = new Vector3(0, 0, -1);
planeNormalDirection.Normalize();
Vector4 planeCoefficients = new Vector4(planeNormalDirection, waterHeight + 1.0f);
Matrix invCamMatrix = Matrix.Invert(viewMatrix * projectionMatrix);
invCamMatrix = Matrix.Transpose(invCamMatrix);
planeCoefficients = Vector4.Transform(planeCoefficients, invCamMatrix);
Plane refractionClipPlane = new Plane(planeCoefficients);
graphics.GraphicsDevice.ClipPlanes[0].Plane = refractionClipPlane;
graphics.GraphicsDevice.ClipPlanes[0].IsEnabled = true;
graphics.GraphicsDevice.SetRenderTarget(0, refractionRenderTarget);
graphics.GraphicsDevice.Clear(ClearOptions.Target | ClearOptions.DepthBuffer, Color.Black, 1.0f, 0);
terrain.Draw(gameTime, viewMatrix, projectionMatrix);
graphics.GraphicsDevice.ResolveRenderTarget(0);
refractionMap = refractionRenderTarget.GetTexture();
graphics.GraphicsDevice.SetRenderTarget(0, null);
graphics.GraphicsDevice.ClipPlanes[0].IsEnabled = false;
}
private void DrawReflectionMap(GameTime gameTime, Matrix viewMatrix, Matrix projectionMatrix)
{
Vector3 planeNormalDirection = new Vector3(0, 0, 1);
planeNormalDirection.Normalize();
Vector4 planeCoefficients = new Vector4(planeNormalDirection, -waterHeight + 1.0f);
Matrix camMatrix = reflectionViewMatrix * projectionMatrix;
Matrix invCamMatrix = Matrix.Invert(camMatrix);
invCamMatrix = Matrix.Transpose(invCamMatrix);
planeCoefficients = Vector4.Transform(planeCoefficients, invCamMatrix);
Plane refractionClipPlane = new Plane(planeCoefficients);
graphics.GraphicsDevice.ClipPlanes[0].Plane = refractionClipPlane;
graphics.GraphicsDevice.ClipPlanes[0].IsEnabled = true;
graphics.GraphicsDevice.SetRenderTarget(0, reflectionRenderTarget);
graphics.GraphicsDevice.Clear(ClearOptions.Target | ClearOptions.DepthBuffer, Color.CornflowerBlue, 1.0f, 0);
terrain.Draw(gameTime, reflectionViewMatrix, projectionMatrix);
sky.Draw(gameTime, reflectionViewMatrix, projectionMatrix, cameraPosition);
drawScene("ShadowMap");
drawScene("ShadowedScene");
graphics.GraphicsDevice.ResolveRenderTarget(0);
reflectionMap = reflectionRenderTarget.GetTexture();
graphics.GraphicsDevice.SetRenderTarget(0, null);
graphics.GraphicsDevice.ClipPlanes[0].IsEnabled = false;
}
///
/// This is called when the game should draw itself.
///
/// Provides a snapshot of timing values.
protected override void Draw(GameTime gameTime)
{
drawRefractionMap(gameTime, viewMatrix, projectionMatrix);
DrawReflectionMap(gameTime, viewMatrix, projectionMatrix);
//Clear the device, otherwise we see the blue reflection stripes.
graphics.GraphicsDevice.Clear(ClearOptions.Target | ClearOptions.DepthBuffer, Color.CornflowerBlue, 1.0f, 0);
//Draw the objects
graphics.GraphicsDevice.SetRenderTarget(0, renderTarget);
drawScene("ShadowMap");
graphics.GraphicsDevice.ResolveRenderTarget(0);
texturedRenderedTo = renderTarget.GetTexture();
graphics.GraphicsDevice.SetRenderTarget(0, null);
graphics.GraphicsDevice.Clear(ClearOptions.Target | ClearOptions.DepthBuffer, Color.CornflowerBlue, 1.0f, 0);
drawScene("ShadowedScene");
//Draw the terrain
graphics.GraphicsDevice.RenderState.CullMode = CullMode.None;
terrain.Draw(gameTime, viewMatrix, projectionMatrix);
sky.Draw(gameTime, viewMatrix, projectionMatrix, cameraPosition);
initializeWater();
//If we go under water, we want to look through the water if we tilt our head.
graphics.GraphicsDevice.RenderState.CullMode = CullMode.CullCounterClockwiseFace;
water.Draw(viewMatrix, projectionMatrix, reflectionViewMatrix, reflectionMap, refractionMap, cameraPosition, elapsedTime);
hud.Draw(gameTime);
base.Draw(gameTime);
}
}
}