開発環境 |
Microsoft Visual C# 2010 Express (SP1) |
実行環境 |
Microsoft Windows XP Home Edition (SP3) |
プロジェクトの種類 |
Windows Game (4.0) |
プロジェクト名 |
XnaBillboard |
参考
snowflake1.png
Game1.cs
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
namespace XnaBillboard
{
class Game1 : Game
{
GraphicsDeviceManager graphics;
SpriteBatch sprite;
SpriteFont font;
VertexBuffer vertexBuffer;
Effect effect;
EffectParameter fxPosition;
Texture2D texture;
List<Vector3> positions;
Matrix projection;
// fps
int fpsSec;
int fpsDraw = 0;
int fpsCount = 0;
// カメラ
Vector3 camPos = new Vector3(0, 0, 0);
int camLat = 30;
int camLon = 45;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
graphics.PreferredBackBufferWidth = 1280;
graphics.PreferredBackBufferHeight = 720;
Content.RootDirectory = "Content";
IsMouseVisible = true;
}
protected override void LoadContent()
{
sprite = new SpriteBatch(GraphicsDevice);
font = Content.Load<SpriteFont>("SpriteFont1");
texture = Content.Load<Texture2D>("snowflake1");
projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(45),
GraphicsDevice.Viewport.AspectRatio, 1, 200);
effect = Content.Load<Effect>("Billboard");
effect.Parameters["BillboardWidth"].SetValue(1);
effect.Parameters["BillboardHeight"].SetValue(1);
effect.Parameters["Texture"].SetValue(texture);
effect.Parameters["Projection"].SetValue(projection);
fxPosition = effect.Parameters["Position"];
// 頂点
VertexPositionTexture[] vertices = new VertexPositionTexture[4];
vertices[0].TextureCoordinate = new Vector2(0, 0);
vertices[1].TextureCoordinate = new Vector2(1, 0);
vertices[2].TextureCoordinate = new Vector2(0, 1);
vertices[3].TextureCoordinate = new Vector2(1, 1);
vertexBuffer = new VertexBuffer(GraphicsDevice,
typeof(VertexPositionTexture), 4, BufferUsage.WriteOnly);
vertexBuffer.SetData(vertices);
// 雪
Random rnd = new Random();
positions = new List<Vector3>();
for (int n = 0; n < 5000; n++)
{
Vector3 pos = new Vector3(rnd.Next(100), rnd.Next(100), rnd.Next(100));
positions.Add(pos);
}
base.LoadContent();
}
protected override void Update(GameTime gameTime)
{
KeyboardState kState = Keyboard.GetState();
if (kState.IsKeyDown(Keys.Escape)) Exit();
if (kState.IsKeyDown(Keys.W)) Move(0, 0);
if (kState.IsKeyDown(Keys.S)) Move(180, 0);
if (kState.IsKeyDown(Keys.A)) Move(0, -90);
if (kState.IsKeyDown(Keys.D)) Move(0, 90);
if (kState.IsKeyDown(Keys.Up)) camLat = Math.Min(camLat + 1, 89);
if (kState.IsKeyDown(Keys.Down)) camLat = Math.Max(camLat - 1, -89);
if (kState.IsKeyDown(Keys.Left)) camLon = (camLon + 359) % 360;
if (kState.IsKeyDown(Keys.Right)) camLon = (camLon + 1) % 360;
if (kState.IsKeyDown(Keys.PageUp)) Move(90, 0);
if (kState.IsKeyDown(Keys.PageDown)) Move(-90, 0);
base.Update(gameTime);
}
void Move(int lat, int lon)
{
Vector3 move = new Vector3();
float rad = MathHelper.ToRadians(camLat + lat);
if (lon == 0)
{
move.Y = (float)Math.Sin(rad) * 0.2f;
}
float r = (float)Math.Cos(rad) * 0.2f;
rad = MathHelper.ToRadians(camLon + lon);
move.X = (float)Math.Cos(rad) * r;
move.Z = (float)Math.Sin(rad) * r;
camPos += move;
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
Vector3 target;
float rad = MathHelper.ToRadians(camLat);
target.Y = (float)Math.Sin(rad);
float r = (float)Math.Cos(rad);
rad = MathHelper.ToRadians(camLon);
target.X = (float)Math.Cos(rad) * r;
target.Z = (float)Math.Sin(rad) * r;
Matrix view = Matrix.CreateLookAt(camPos, camPos + target, Vector3.Up);
Vector3 rightVector = Vector3.Cross(target, Vector3.Up);
rightVector.Normalize();
Vector3 upVector = Vector3.Cross(rightVector, target);
GraphicsDevice.SetVertexBuffer(vertexBuffer);
effect.Parameters["View"].SetValue(view);
effect.Parameters["RightVector"].SetValue(rightVector);
effect.Parameters["UpVector"].SetValue(upVector);
foreach (EffectPass pass in effect.CurrentTechnique.Passes)
{
foreach (Vector3 pos in positions)
{
fxPosition.SetValue(pos);
pass.Apply();
GraphicsDevice.DrawPrimitives(PrimitiveType.TriangleStrip, 0, 2);
}
}
// fps
fpsDraw++;
if (gameTime.TotalGameTime.Seconds != fpsSec)
{
fpsCount = fpsDraw;
fpsDraw = 0;
fpsSec = gameTime.TotalGameTime.Seconds;
}
sprite.Begin();
string text = string.Format("fps={0} lat={1} lon={2}", fpsCount, camLat, camLon);
sprite.DrawString(font, text, new Vector2(0, 0), Color.White);
text = string.Format("x={0:f1} y={1:f1} z={2:f1}", camPos.X, camPos.Y, camPos.Z);
sprite.DrawString(font, text, new Vector2(0, 20), Color.White);
sprite.End();
base.Draw(gameTime);
}
}
}
Billboard.fx
float4x4 View;
float4x4 Projection;
float3 Position;
float3 RightVector;
float3 UpVector;
float BillboardWidth;
float BillboardHeight;
texture Texture;
sampler TextureSampler = sampler_state
{
Texture = (Texture);
};
struct VS_INPUT
{
float2 TexCoord : TEXCOORD0;
};
struct VS_OUTPUT
{
float4 Position : POSITION0;
float2 TexCoord : TEXCOORD0;
};
VS_OUTPUT VertexShaderFunction(VS_INPUT input)
{
VS_OUTPUT output;
float3 position = Position;
position += (input.TexCoord.x - 0.5f) * RightVector * BillboardWidth;
position += (0.5f - input.TexCoord.y) * UpVector * BillboardHeight;
float4 viewPosition = mul(float4(position, 1), View);
output.Position = mul(viewPosition, Projection);
output.TexCoord = input.TexCoord;
return output;
}
float4 PixelShaderFunction(float2 texCoord : TEXCOORD0) : COLOR0
{
return tex2D(TextureSampler, texCoord);
}
technique Billboards
{
pass
{
VertexShader = compile vs_2_0 VertexShaderFunction();
PixelShader = compile ps_2_0 PixelShaderFunction();
}
}
最終更新:2012年12月23日 20:48