#region File Description
//-----------------------------------------------------------------------------
// AlphaDemo.cs
//
// Microsoft XNA Community Game Platform
// Copyright (C) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
#endregion
#region Using Statements
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using SkinnedModel;
using SimpleAnimation;
using System.Diagnostics;
#endregion
namespace XnaGraphicsDemo
{
///
/// Demo shows how to use AlphaTestEffect.
///
class AlphaDemo : MenuComponent
{
// Fields.
Tank tank = new Tank();
Model grid;
RenderTarget2D renderTarget;
AlphaTestEffect alphaTestEffect;
float cameraRotation = 0;
///
/// Constructor.
///
public AlphaDemo(DemoGame game)
: base(game)
{
Entries.Add(new MenuEntry { Text = "back", Clicked = delegate { Game.SetActiveMenu(0); } });
}
///
/// Resets the menu state.
///
public override void Reset()
{
cameraRotation = 0.85f;
base.Reset();
}
///
/// Loads content for this demo.
///
protected override void LoadContent()
{
tank.Load(Game.Content);
renderTarget = new RenderTarget2D(GraphicsDevice, 400, 400, false, SurfaceFormat.Color, DepthFormat.Depth24);
alphaTestEffect = new AlphaTestEffect(GraphicsDevice);
alphaTestEffect.AlphaFunction = CompareFunction.Greater;
alphaTestEffect.ReferenceAlpha = 128;
grid = Game.Content.Load("grid");
}
///
/// Animates the tank model.
///
public override void Update(GameTime gameTime)
{
tank.Animate(gameTime);
base.Update(gameTime);
}
///
/// Draws the AlphaTestEffect demo.
///
public override void Draw(GameTime gameTime)
{
// Compute camera matrices.
float time = (float)gameTime.TotalGameTime.TotalSeconds;
Matrix tankRotation = Matrix.CreateRotationY(time * 0.15f);
Matrix sceneRotation = Matrix.CreateRotationY(cameraRotation);
Vector3 cameraPosition = new Vector3(1250, 250, 0);
Vector3 cameraTarget = new Vector3(0, -100, 0);
Matrix view = Matrix.CreateLookAt(cameraPosition,
cameraTarget,
Vector3.Up);
Matrix projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4,
GraphicsDevice.Viewport.AspectRatio,
10,
10000);
// Draw a single copy of the tank model into a rendertarget.
DrawTankIntoRenderTarget(tankRotation, sceneRotation);
// Draw the scene background.
DrawTitle("alpha test effect", new Color(192, 192, 192), new Color(156, 156, 156));
GraphicsDevice.BlendState = BlendState.Opaque;
GraphicsDevice.RasterizerState = RasterizerState.CullCounterClockwise;
GraphicsDevice.DepthStencilState = DepthStencilState.None;
GraphicsDevice.SamplerStates[0] = SamplerState.LinearWrap;
grid.Draw(Matrix.CreateTranslation(0, -8, 0) * sceneRotation, view, projection);
// Draw many copies of the imposter sprite, faking the illusion of a more complex 3D scene with many tanks.
GraphicsDevice.DepthStencilState = DepthStencilState.Default;
GraphicsDevice.SamplerStates[0] = SamplerState.LinearClamp;
DrawImposterSprites(tankRotation, sceneRotation, cameraPosition, cameraTarget, view, projection);
base.Draw(gameTime);
}
///
/// Draws the 3D tank model into a rendertarget.
///
void DrawTankIntoRenderTarget(Matrix tankRotation, Matrix sceneRotation)
{
Matrix view = Matrix.CreateLookAt(new Vector3(1250, 650, 0),
new Vector3(0, 0, 0),
Vector3.Up);
Matrix projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4,
1,
10,
10000);
RenderTargetBinding[] previousRenderTargets = GraphicsDevice.GetRenderTargets();
GraphicsDevice.SetRenderTarget(renderTarget);
GraphicsDevice.BlendState = BlendState.Opaque;
GraphicsDevice.RasterizerState = RasterizerState.CullCounterClockwise;
GraphicsDevice.DepthStencilState = DepthStencilState.Default;
GraphicsDevice.SamplerStates[0] = SamplerState.LinearWrap;
GraphicsDevice.Clear(Color.Transparent);
tank.Draw(tankRotation * sceneRotation * Matrix.CreateScale(0.9f), view, projection, LightingMode.OneVertexLight, true);
GraphicsDevice.SetRenderTargets(previousRenderTargets);
}
///
/// Draws many copies of the rendertarget as 2D billboard sprites, positioned within the 3D scene.
///
void DrawImposterSprites(Matrix tankRotation, Matrix sceneRotation, Vector3 cameraPosition, Vector3 cameraTarget, Matrix view, Matrix projection)
{
const int start = -2;
const int end = 3;
const int count = (end - start) * (end - start);
const float size = 0.2f;
const float spacing = 240;
const float width = 120;
const float height1 = 135;
const float height2 = -135;
// Create billboard vertices.
VertexPositionTexture[] vertices = new VertexPositionTexture[count * 4];
int i = 0;
for (int x = start; x < end; x++)
{
for (int z = start; z < end; z++)
{
Matrix scale = Matrix.CreateScale(size);
Matrix translation = Matrix.CreateTranslation(x * spacing, 0, z * spacing);
Matrix world = tankRotation * scale * translation * sceneRotation;
Matrix billboard = Matrix.CreateConstrainedBillboard(world.Translation, cameraPosition, Vector3.Up, cameraTarget - cameraPosition, null);
vertices[i].Position = Vector3.Transform(new Vector3(width, height1, 0), billboard);
vertices[i++].TextureCoordinate = new Vector2(0, 0);
vertices[i].Position = Vector3.Transform(new Vector3(-width, height1, 0), billboard);
vertices[i++].TextureCoordinate = new Vector2(1, 0);
vertices[i].Position = Vector3.Transform(new Vector3(-width, height2, 0), billboard);
vertices[i++].TextureCoordinate = new Vector2(1, 1);
vertices[i].Position = Vector3.Transform(new Vector3(width, height2, 0), billboard);
vertices[i++].TextureCoordinate = new Vector2(0, 1);
}
}
// Create billboard indices.
short[] indices = new short[count * 6];
short currentVertex = 0;
i = 0;
while (i < indices.Length)
{
indices[i++] = currentVertex;
indices[i++] = (short)(currentVertex + 1);
indices[i++] = (short)(currentVertex + 2);
indices[i++] = currentVertex;
indices[i++] = (short)(currentVertex + 2);
indices[i++] = (short)(currentVertex + 3);
currentVertex += 4;
}
// Draw the billboard sprites.
alphaTestEffect.World = Matrix.Identity;
alphaTestEffect.View = view;
alphaTestEffect.Projection = projection;
alphaTestEffect.Texture = renderTarget;
alphaTestEffect.CurrentTechnique.Passes[0].Apply();
GraphicsDevice.DrawUserIndexedPrimitives(PrimitiveType.TriangleList, vertices, 0, count * 4, indices, 0, count * 2);
}
///
/// Dragging on the menu background rotates the camera.
///
protected override void OnDrag(Vector2 delta)
{
cameraRotation += delta.X / 400;
}
}
}