「VCS/XnaSnow」の編集履歴(バックアップ)一覧はこちら

VCS/XnaSnow - (2012/12/05 (水) 21:35:08) の1つ前との変更点

追加された行は緑色になります。

削除された行は赤色になります。

|開発環境|Microsoft Visual C# 2010 Express (SP1)| |実行環境|Microsoft Windows XP Home Edition (SP3)| |プロジェクトの種類|Windows Game (4.0)| |プロジェクト名|XnaSnow| Game1.cs #highlight(c#){{ using System; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input; namespace XnaSnow { class Game1 : Game { GraphicsDeviceManager graphics; SpriteBatch sprite; SpriteFont font; Effect effect; Texture2D texture; // fps DateTime prevTime; int draw = 0; int fps = 0; const int blockMax = 30000; VertexBuffer instanceBuffer; VertexBuffer geometryBuffer; IndexBuffer indexBuffer; VertexDeclaration instanceVertexDeclaration; VertexBufferBinding[] bindings; Matrix projection; // カメラ Vector3 camPos = new Vector3(-50, -96, -50); int camLat = 0; int camLong = 0; struct InstanceInfo { public Vector4 InitPos; public Vector4 Motion; public Vector4 Rotation; public Vector2 AtlasCoordinate; } public Game1() { graphics = new GraphicsDeviceManager(this); graphics.PreferredBackBufferWidth = 1280; graphics.PreferredBackBufferHeight = 720; Content.RootDirectory = "Content"; IsMouseVisible = true; } protected override void Initialize() { sprite = new SpriteBatch(GraphicsDevice); prevTime = DateTime.Now; base.Initialize(); } protected override void LoadContent() { // ソリューション エクスプローラーの(Content)に追加しておく font = Content.Load<SpriteFont>("SpriteFont1"); // 新しい項目:Sprite Font effect = Content.Load<Effect>("HardwareInstancing"); // 新しい項目:Effect File (.fx) texture = Content.Load<Texture2D>("Palette16"); // 既存の項目:Palette16.png GenerateGeometryBuffers(0.5f); GenerateInstanceVertexDeclaration(); GenerateInstanceInformation(); bindings = new VertexBufferBinding[2]; bindings[0] = new VertexBufferBinding(geometryBuffer, 0); bindings[1] = new VertexBufferBinding(instanceBuffer, 0, 1); projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(45), GraphicsDevice.Viewport.AspectRatio, 0.1f, 200); effect.CurrentTechnique = effect.Techniques["Instancing"]; effect.Parameters["cubeTexture"].SetValue(texture); base.LoadContent(); } void GenerateGeometryBuffers(float size) { VertexPositionTexture[] vertices = new VertexPositionTexture[24]; for (int n = 0; n < 4; n++) { float u = size * ((n & 1) * 2 - 1); float v = size * ((n & 2) - 1); vertices[0 + n].Position = new Vector3(u, size, v); vertices[4 + n].Position = new Vector3(u, -size, -v); vertices[8 + n].Position = new Vector3(-size, -v, u); vertices[12 + n].Position = new Vector3(u, -v, size); vertices[16 + n].Position = new Vector3(size, -v, -u); vertices[20 + n].Position = new Vector3(-u, -v, -size); } for (int n = 0; n < 24; n++) { vertices[n].TextureCoordinate = new Vector2(n & 1, (n >> 1) & 1); } geometryBuffer = new VertexBuffer(GraphicsDevice, typeof(VertexPositionTexture), 24, BufferUsage.WriteOnly); geometryBuffer.SetData(vertices); int[] squareVert = { 0, 1, 2, 1, 3, 2 }; int[] indices = new int[36]; for (int n = 0; n < 36; n++) { indices[n] = (n / 6) * 4 + squareVert[n % 6]; } indexBuffer = new IndexBuffer(GraphicsDevice, typeof(int), 36, BufferUsage.WriteOnly); indexBuffer.SetData(indices); } void GenerateInstanceVertexDeclaration() { int f4Num = 3; VertexElement[] elements = new VertexElement[f4Num + 1]; int n; for (n = 0; n < f4Num; n++) { elements[n] = new VertexElement(sizeof(float) * 4 * n, VertexElementFormat.Vector4, VertexElementUsage.TextureCoordinate, n + 1); } elements[n] = new VertexElement(sizeof(float) * 4 * n, VertexElementFormat.Vector2, VertexElementUsage.TextureCoordinate, n + 1); instanceVertexDeclaration = new VertexDeclaration(elements); } void GenerateInstanceInformation() { InstanceInfo[] instances = new InstanceInfo[blockMax]; // 地面 int n = 0; for (int x = -100; x < 0; x++) { for (int z = -100; z < 0; z++) { instances[n].InitPos = new Vector4(x, -98, z, 1); instances[n].Motion = new Vector4(); instances[n].Rotation = new Vector4(); instances[n].AtlasCoordinate = new Vector2(3 / 4.0f, 1 / 4.0f); n++; } } Random rnd = new Random(); for (; n < blockMax; n++) { instances[n].InitPos = new Vector4( rnd.Next(-100, 0), rnd.Next(-100, 0), rnd.Next(-100, 0), 1); instances[n].Motion = new Vector4( (float)rnd.NextDouble() - 0.5f, (float)rnd.NextDouble() - 1.5f, (float)rnd.NextDouble() - 0.5f, 1); instances[n].Rotation = new Vector4( (float)rnd.NextDouble() - 0.5f, (float)rnd.NextDouble() - 0.5f, (float)rnd.NextDouble() - 0.5f, 1); instances[n].AtlasCoordinate = new Vector2(3 / 4.0f, 1 / 4.0f); } instanceBuffer = new VertexBuffer(GraphicsDevice, instanceVertexDeclaration, blockMax, BufferUsage.WriteOnly); instanceBuffer.SetData(instances); } protected override void Update(GameTime gameTime) { KeyboardState state = Keyboard.GetState(); if (state[Keys.Escape] == KeyState.Down) Exit(); if (state[Keys.W] == KeyState.Down) Move(0, 0); if (state[Keys.S] == KeyState.Down) Move(180, 0); if (state[Keys.A] == KeyState.Down) Move(0, -90); if (state[Keys.D] == KeyState.Down) Move(0, 90); if (state[Keys.Up] == KeyState.Down) camLat++; if (state[Keys.Down] == KeyState.Down) camLat--; if (state[Keys.Left] == KeyState.Down) camLong = (camLong + 359) % 360; if (state[Keys.Right] == KeyState.Down) camLong = (camLong + 1) % 360; if (state[Keys.PageUp] == KeyState.Down) Move(90, 0); if (state[Keys.PageDown] == KeyState.Down) Move(-90, 0); base.Update(gameTime); } void Move(int degLat, int degLong) { float rad = MathHelper.ToRadians(camLat + degLat); if (degLong == 0) { camPos.Y += (float)Math.Sin(rad) * 0.2f; } float r = (float)Math.Cos(rad) * 0.2f; rad = MathHelper.ToRadians(camLong + degLong); camPos.X += (float)Math.Cos(rad) * r; camPos.Z += (float)Math.Sin(rad) * r; } protected override void Draw(GameTime gameTime) { GraphicsDevice.Clear(Color.CornflowerBlue); GraphicsDevice.DepthStencilState = DepthStencilState.Default; float rad = MathHelper.ToRadians(camLat); float y = (float)Math.Sin(rad) + camPos.Y; float r = (float)Math.Cos(rad); rad = MathHelper.ToRadians(camLong); float x = camPos.X + (float)Math.Cos(rad) * r; float z = camPos.Z + (float)Math.Sin(rad) * r; Matrix view = Matrix.CreateLookAt(camPos, new Vector3(x, y, z), Vector3.Up); GraphicsDevice.Indices = indexBuffer; effect.Parameters["WVP"].SetValue(view * projection); effect.Parameters["totalTime"].SetValue((float)gameTime.TotalGameTime.TotalSeconds); effect.CurrentTechnique.Passes[0].Apply(); GraphicsDevice.SetVertexBuffers(bindings); GraphicsDevice.DrawInstancedPrimitives(PrimitiveType.TriangleList, 0, 0, 24, 0, 12, blockMax); // フレームレート draw++; DateTime now = DateTime.Now; TimeSpan t = now - prevTime; if (t.TotalMilliseconds >= 1000) { fps = draw; draw = 0; prevTime = now; } sprite.Begin(); string text = "fps=" + fps + " lat=" + camLat + " long=" + camLong; sprite.DrawString(font, text, new Vector2(0, 0), Color.Lime); 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.Lime); sprite.End(); base.Draw(gameTime); } } } }} HardwareInstancing.fx #highlight{{ float4x4 WVP; texture cubeTexture; float totalTime; sampler TextureSampler = sampler_state { texture = <cubeTexture>; minfilter = linear; magfilter = linear; }; struct InstancingVSInOut { float4 Position : POSITION; float2 TexCoord : TEXCOORD; }; InstancingVSInOut InstancingVS( InstancingVSInOut input, float4 initPos : TEXCOORD1, float4 motion : TEXCOORD2, float4 rotation : TEXCOORD3, float2 atlasCoord : TEXCOORD4) { InstancingVSInOut output; float4 pos = input.Position; // 複製元の座標 float rad = rotation.x * totalTime; float s = sin(rad); float c = cos(rad); float4x4 Rx = { { 1, 0, 0, 0}, { 0, c,-s, 0}, { 0, s, c, 0}, { 0, 0, 0, 1}}; rad = rotation.y * totalTime; s = sin(rad); c = cos(rad); float4x4 Ry = { { c, 0, s, 0}, { 0, 1, 0, 0}, {-s, 0, c, 0}, { 0, 0, 0, 1}}; rad = rotation.z * totalTime; s = sin(rad); c = cos(rad); float4x4 Rz = { { c,-s, 0, 0}, { s, c, 0, 0}, { 0, 0, 1, 0}, { 0, 0, 0, 1}}; pos = mul(pos, mul(Rz, mul(Rx, Ry))); pos.xyz += initPos.xyz; pos.xyz += motion.xyz * totalTime; pos.y %= 100.0f; if (pos.y < -98.0f || -2.0f < pos.y) atlasCoord.x = 2.0f; pos = mul(pos, WVP); // スクリーン座標に変換 output.Position = pos; output.TexCoord = float2( atlasCoord.x + (input.TexCoord.x / 4.0f), atlasCoord.y + (input.TexCoord.y / 4.0f)); return output; } float4 InstancingPS(float2 texCoord : TEXCOORD) : COLOR { if (2.0f <= texCoord.x) discard; return tex2D(TextureSampler, texCoord); } technique Instancing { pass Pass0 { VertexShader = compile vs_3_0 InstancingVS(); PixelShader = compile ps_3_0 InstancingPS(); } } }}
|開発環境|Microsoft Visual C# 2010 Express (SP1)| |実行環境|Microsoft Windows XP Home Edition (SP3)| |プロジェクトの種類|Windows Game (4.0)| |プロジェクト名|XnaSnow| Dice6.png #ref(Dice6.png) Game1.cs #highlight(c#){{ using System; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input; namespace XnaSnow { class Game1 : Game { GraphicsDeviceManager graphics; SpriteBatch sprite; SpriteFont font; Effect effect; Texture2D texture; // fps DateTime prevTime; int draw = 0; int fps = 0; const int blockMax = 30000; VertexBuffer instanceBuffer; VertexBuffer geometryBuffer; IndexBuffer indexBuffer; VertexDeclaration instanceVertexDeclaration; VertexBufferBinding[] bindings; Matrix projection; // カメラ Vector3 camPos = new Vector3(-50, -96, -50); int camLat = 0; int camLong = 0; struct InstanceInfo { public Vector4 InitPos; public Vector4 Motion; public Vector4 Rotation; public Vector2 AtlasCoordinate; } public Game1() { graphics = new GraphicsDeviceManager(this); graphics.PreferredBackBufferWidth = 1280; graphics.PreferredBackBufferHeight = 720; Content.RootDirectory = "Content"; IsMouseVisible = true; } protected override void Initialize() { sprite = new SpriteBatch(GraphicsDevice); prevTime = DateTime.Now; base.Initialize(); } protected override void LoadContent() { // ソリューション エクスプローラーの(Content)に追加しておく font = Content.Load<SpriteFont>("SpriteFont1"); // 新しい項目:Sprite Font effect = Content.Load<Effect>("HardwareInstancing"); // 新しい項目:Effect File (.fx) texture = Content.Load<Texture2D>("Dice6"); // 既存の項目:Dice6.png GenerateGeometryBuffers(0.5f); GenerateInstanceVertexDeclaration(); GenerateInstanceInformation(); bindings = new VertexBufferBinding[2]; bindings[0] = new VertexBufferBinding(geometryBuffer, 0); bindings[1] = new VertexBufferBinding(instanceBuffer, 0, 1); projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(45), GraphicsDevice.Viewport.AspectRatio, 0.1f, 200); effect.CurrentTechnique = effect.Techniques["Instancing"]; effect.Parameters["cubeTexture"].SetValue(texture); base.LoadContent(); } void GenerateGeometryBuffers(float size) { VertexPositionTexture[] vertices = new VertexPositionTexture[24]; for (int n = 0; n < 4; n++) { float u = size * ((n & 1) * 2 - 1); float v = size * ((n & 2) - 1); vertices[0 + n].Position = new Vector3(u, size, v); // 1 Up vertices[4 + n].Position = new Vector3(-u, -v, -size); // 2 West vertices[8 + n].Position = new Vector3(-size, -v, u); // 3 South vertices[12 + n].Position = new Vector3(size, -v, -u); // 4 North vertices[16 + n].Position = new Vector3(u, -v, size); // 5 East vertices[20 + n].Position = new Vector3(u, -size, -v); // 6 Down } for (int n = 0; n < 24; n++) { vertices[n].TextureCoordinate = new Vector2( (n / 4 % 4) + (n & 1), (n / 16) + ((n >> 1) & 1)); } geometryBuffer = new VertexBuffer(GraphicsDevice, typeof(VertexPositionTexture), 24, BufferUsage.WriteOnly); geometryBuffer.SetData(vertices); int[] squareVert = { 0, 1, 2, 1, 3, 2 }; int[] indices = new int[36]; for (int n = 0; n < 36; n++) { indices[n] = (n / 6) * 4 + squareVert[n % 6]; } indexBuffer = new IndexBuffer(GraphicsDevice, typeof(int), 36, BufferUsage.WriteOnly); indexBuffer.SetData(indices); } void GenerateInstanceVertexDeclaration() { int f4Num = 3; VertexElement[] elements = new VertexElement[f4Num + 1]; int n; for (n = 0; n < f4Num; n++) { elements[n] = new VertexElement(sizeof(float) * 4 * n, VertexElementFormat.Vector4, VertexElementUsage.TextureCoordinate, n + 1); } elements[n] = new VertexElement(sizeof(float) * 4 * n, VertexElementFormat.Vector2, VertexElementUsage.TextureCoordinate, n + 1); instanceVertexDeclaration = new VertexDeclaration(elements); } void GenerateInstanceInformation() { InstanceInfo[] instances = new InstanceInfo[blockMax]; // 地面 int n = 0; for (int x = -100; x < 0; x++) { for (int z = -100; z < 0; z++) { instances[n].InitPos = new Vector4(x, -97, z, 1); instances[n].Motion = new Vector4(); instances[n].Rotation = new Vector4(); instances[n].AtlasCoordinate = new Vector2(); n++; } } Random rnd = new Random(); for (; n < blockMax; n++) { instances[n].InitPos = new Vector4( rnd.Next(-100, 0), rnd.Next(-100, 0), rnd.Next(-100, 0), 1); instances[n].Motion = new Vector4( (float)rnd.NextDouble() - 0.5f, (float)rnd.NextDouble() - 1.5f, (float)rnd.NextDouble() - 0.5f, 1); instances[n].Rotation = new Vector4( (float)(rnd.NextDouble() - 0.5f) * MathHelper.TwoPi, (float)(rnd.NextDouble() - 0.5f) * MathHelper.TwoPi, (float)(rnd.NextDouble() - 0.5f) * MathHelper.TwoPi, 1); instances[n].AtlasCoordinate = new Vector2(); } instanceBuffer = new VertexBuffer(GraphicsDevice, instanceVertexDeclaration, blockMax, BufferUsage.WriteOnly); instanceBuffer.SetData(instances); } protected override void Update(GameTime gameTime) { KeyboardState state = Keyboard.GetState(); if (state[Keys.Escape] == KeyState.Down) Exit(); if (state[Keys.W] == KeyState.Down) Move(0, 0); if (state[Keys.S] == KeyState.Down) Move(180, 0); if (state[Keys.A] == KeyState.Down) Move(0, -90); if (state[Keys.D] == KeyState.Down) Move(0, 90); if (state[Keys.Up] == KeyState.Down) camLat++; if (state[Keys.Down] == KeyState.Down) camLat--; if (state[Keys.Left] == KeyState.Down) camLong = (camLong + 359) % 360; if (state[Keys.Right] == KeyState.Down) camLong = (camLong + 1) % 360; if (state[Keys.PageUp] == KeyState.Down) Move(90, 0); if (state[Keys.PageDown] == KeyState.Down) Move(-90, 0); base.Update(gameTime); } void Move(int degLat, int degLong) { float rad = MathHelper.ToRadians(camLat + degLat); if (degLong == 0) { camPos.Y += (float)Math.Sin(rad) * 0.2f; } float r = (float)Math.Cos(rad) * 0.2f; rad = MathHelper.ToRadians(camLong + degLong); camPos.X += (float)Math.Cos(rad) * r; camPos.Z += (float)Math.Sin(rad) * r; } protected override void Draw(GameTime gameTime) { GraphicsDevice.Clear(Color.CornflowerBlue); GraphicsDevice.DepthStencilState = DepthStencilState.Default; float rad = MathHelper.ToRadians(camLat); float y = (float)Math.Sin(rad) + camPos.Y; float r = (float)Math.Cos(rad); rad = MathHelper.ToRadians(camLong); float x = camPos.X + (float)Math.Cos(rad) * r; float z = camPos.Z + (float)Math.Sin(rad) * r; Matrix view = Matrix.CreateLookAt(camPos, new Vector3(x, y, z), Vector3.Up); GraphicsDevice.Indices = indexBuffer; effect.Parameters["WVP"].SetValue(view * projection); effect.Parameters["totalTime"].SetValue((float)gameTime.TotalGameTime.TotalSeconds); effect.CurrentTechnique.Passes[0].Apply(); GraphicsDevice.SetVertexBuffers(bindings); GraphicsDevice.DrawInstancedPrimitives(PrimitiveType.TriangleList, 0, 0, 24, 0, 12, blockMax); // フレームレート draw++; DateTime now = DateTime.Now; TimeSpan t = now - prevTime; if (t.TotalMilliseconds >= 1000) { fps = draw; draw = 0; prevTime = now; } sprite.Begin(); string text = "fps=" + fps + " lat=" + camLat + " long=" + camLong; sprite.DrawString(font, text, new Vector2(0, 0), Color.Lime); 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.Lime); sprite.End(); base.Draw(gameTime); } } } }} HardwareInstancing.fx #highlight{{ float4x4 WVP; texture cubeTexture; float totalTime; sampler TextureSampler = sampler_state { texture = <cubeTexture>; minfilter = linear; magfilter = linear; }; struct InstancingVSInOut { float4 Position : POSITION; float2 TexCoord : TEXCOORD; }; InstancingVSInOut InstancingVS( InstancingVSInOut input, float4 initPos : TEXCOORD1, float4 motion : TEXCOORD2, float4 rotation : TEXCOORD3, float2 atlasCoord : TEXCOORD4) { InstancingVSInOut output; float4 pos = input.Position; // 複製元の座標 float rad = rotation.x * totalTime; float s = sin(rad); float c = cos(rad); float4x4 Rx = { { 1, 0, 0, 0}, { 0, c,-s, 0}, { 0, s, c, 0}, { 0, 0, 0, 1}}; rad = rotation.y * totalTime; s = sin(rad); c = cos(rad); float4x4 Ry = { { c, 0, s, 0}, { 0, 1, 0, 0}, {-s, 0, c, 0}, { 0, 0, 0, 1}}; rad = rotation.z * totalTime; s = sin(rad); c = cos(rad); float4x4 Rz = { { c,-s, 0, 0}, { s, c, 0, 0}, { 0, 0, 1, 0}, { 0, 0, 0, 1}}; pos = mul(pos, mul(Rz, mul(Rx, Ry))); pos.xyz += initPos.xyz; pos.xyz += motion.xyz * totalTime; pos.y %= 100.0f; if (pos.y < -98.0f || -2.0f < pos.y) atlasCoord.x = 2.0f; pos = mul(pos, WVP); // スクリーン座標に変換 output.Position = pos; output.TexCoord = float2( atlasCoord.x + (input.TexCoord.x / 4.0f), atlasCoord.y + (input.TexCoord.y / 4.0f)); return output; } float4 InstancingPS(float2 texCoord : TEXCOORD) : COLOR { if (2.0f <= texCoord.x) discard; return tex2D(TextureSampler, texCoord); } technique Instancing { pass Pass0 { VertexShader = compile vs_3_0 InstancingVS(); PixelShader = compile ps_3_0 InstancingPS(); } } }}

表示オプション

横に並べて表示:
変化行の前後のみ表示: