「VCS/XnaBlock」の編集履歴(バックアップ)一覧はこちら
「VCS/XnaBlock」(2012/12/04 (火) 17:18:57) の最新版変更点
追加された行は緑色になります。
削除された行は赤色になります。
|開発環境|Microsoft Visual C# 2010 Express (SP1)|
|実行環境|Microsoft Windows XP Home Edition (SP3)|
|プロジェクトの種類|Windows Game (4.0)|
|プロジェクト名|XnaBlock|
Block Builder(仮)
Texture4.png
#ref(Texture4_2.png)
Palette16.png
#ref(Palette16.png)
Game1.cs
#highlight(c#){{
// #1
using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
namespace XnaBlock
{
class Game1 : Game
{
GraphicsDeviceManager graphics;
SpriteBatch sprite;
SpriteFont font;
Effect effect;
Texture2D texture;
// fps
DateTime prevTime;
int draw = 0;
int fps = 0;
const int gridSize = 100;
const int blockMax = 20000;
short blockNum = 0;
short[] grid;
VertexBuffer instanceBuffer;
VertexBuffer geometryBuffer;
IndexBuffer indexBuffer;
VertexDeclaration instanceVertexDeclaration;
VertexBufferBinding[] bindings;
Matrix projection;
// カメラ
Vector3 camPos = new Vector3(50.5f, 1.5f, 50.5f);
int camLat = 0;
int camLong = 225;
readonly int[] dirX = { 1, 1, 0, -1, -1, -1, 0, 1, 1 };
readonly int[] dirZ = { 0, 1, 1, 1, 0, -1, -1, -1, 0 };
struct InstanceInfo
{
public Matrix World;
public Vector2 AtlasCoordinate;
}
struct Position
{
public int X;
public int Y;
public int Z;
public Position(int x, int y, int z)
{
X = x;
Y = y;
Z = z;
}
}
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, 2000);
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[] indices = new int[36];
for (int n = 0; n < 6; n++)
{
int n6 = n * 6;
int n4 = n * 4;
indices[n6 + 0] = n4 + 0; indices[n6 + 1] = n4 + 1; indices[n6 + 2] = n4 + 2;
indices[n6 + 3] = n4 + 1; indices[n6 + 4] = n4 + 3; indices[n6 + 5] = n4 + 2;
}
indexBuffer = new IndexBuffer(GraphicsDevice, typeof(int), 36, BufferUsage.WriteOnly);
indexBuffer.SetData(indices);
}
void GenerateInstanceVertexDeclaration()
{
VertexElement[] elements = new VertexElement[5];
for (int n = 0; n < 4; n++) // Matrix = Vector4 * 4
{
elements[n] = new VertexElement(sizeof(float) * 4 * n,
VertexElementFormat.Vector4, VertexElementUsage.TextureCoordinate, n + 1);
}
elements[4] = new VertexElement(sizeof(float) * 16,
VertexElementFormat.Vector2, VertexElementUsage.TextureCoordinate, 5);
instanceVertexDeclaration = new VertexDeclaration(elements);
}
void GenerateInstanceInformation()
{
instanceBuffer = new VertexBuffer(GraphicsDevice,
instanceVertexDeclaration, blockMax, BufferUsage.None); // 読み込みもする
grid = new short[gridSize * gridSize * gridSize];
// 地面
for (int z = 0; z < gridSize; z++)
{
for (int x = 0; x < gridSize; x++)
{
SetNewBlock(x, 0, z, 4);
}
}
// 正8面体
for (int y = -10; y <= 10; y++)
{
int x1 = 10 - Math.Abs(y);
for (int x = -x1; x <= x1; x++)
{
int z1 = x1 - Math.Abs(x);
int z2 = (z1 == 0) ? 1 : z1 * 2;
for (int z = -z1; z <= z1; z += z2)
{
SetNewBlock(10 + x, 20 + y, 30 + z, 3);
}
}
}
// 太陽
for (int y = -10; y <= 10; y++)
{
for (int x = -10; x <= 10; x++)
{
for (int z = -10; z <= 10; z++)
{
int r = (x * x) + (y * y) + (z * z);
if (90 < r && r < 111) // 9.5^2 < r^2 < 10.5^2
{
SetNewBlock(30 + x, 20 + y, 10 + z, 2);
}
}
}
}
}
int GridIndex(int x, int y, int z)
{
return (y * gridSize + x) * gridSize + z;
}
void SetNewBlock(int x, int y, int z, byte color)
{
InstanceInfo[] ins = new InstanceInfo[1]; // stride = 4*(16+2)
ins[0].World = Matrix.CreateTranslation(new Vector3(x + 0.5f, y + 0.5f, z + 0.5f));
ins[0].AtlasCoordinate = new Vector2((color & 3) / 4.0f, (color >> 2) / 4.0f);
instanceBuffer.SetData<InstanceInfo>(blockNum++ * 72, ins, 0, 1, 72);
grid[GridIndex(x, y, z)] = blockNum;
}
short GetGrid(int x, int y, int z)
{
if (x < 0 || gridSize <= x ||
y < 0 || gridSize <= y ||
z < 0 || gridSize <= z) return Int16.MinValue;
return grid[GridIndex(x, y, z)];
}
Position GetForwardPos()
{
Position pos;
int dir = (camLong + 22) / 45;
pos.X = (int)camPos.X + dirX[dir];
pos.Y = (int)camPos.Y - 1;
pos.Z = (int)camPos.Z + dirZ[dir];
return pos;
}
void SetGrid(Position pos, float u, float v, short insIndex, short gridIndex)
{
InstanceInfo[] ins = new InstanceInfo[1];
int start = (insIndex - 1) * 72;
instanceBuffer.GetData<InstanceInfo>(start, ins, 0, 1, 72);
ins[0].AtlasCoordinate = new Vector2(u, v);
instanceBuffer.SetData<InstanceInfo>(start, ins, 0, 1, 72);
grid[GridIndex(pos.X, pos.Y, pos.Z)] = gridIndex;
}
void SetBlock(byte color)
{
Position pos = GetForwardPos();
short index = GetGrid(pos.X, pos.Y, pos.Z);
if (0 < index || index == Int16.MinValue) return;
if (index == 0)
{
SetNewBlock(pos.X, pos.Y, pos.Z, color);
}
else
{
// 再利用
SetGrid(pos, (color & 3) / 4.0f, (color >> 2) / 4.0f, (short)-index, index);
}
}
void DelBlock()
{
Position pos = GetForwardPos();
short index = GetGrid(pos.X, pos.Y, pos.Z);
if (index <= 0) return;
// 論理削除
SetGrid(pos, 2.0f, 0, index, (short)-index);
}
protected override void Update(GameTime gameTime)
{
KeyboardState state = Keyboard.GetState();
if (state[Keys.Escape] == KeyState.Down) Exit();
if (state[Keys.W] == KeyState.Down) MoveXZ(0);
if (state[Keys.S] == KeyState.Down) MoveXZ(180);
if (state[Keys.A] == KeyState.Down) MoveXZ(-90);
if (state[Keys.D] == KeyState.Down) MoveXZ(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) MoveY(0.1f);
if (state[Keys.PageDown] == KeyState.Down) MoveY(-0.1f);
if (state[Keys.NumPad0] == KeyState.Down) DelBlock();
if (state[Keys.NumPad1] == KeyState.Down) SetBlock(1);
if (state[Keys.NumPad2] == KeyState.Down) SetBlock(2);
if (state[Keys.NumPad3] == KeyState.Down) SetBlock(3);
if (state[Keys.NumPad4] == KeyState.Down) SetBlock(4);
if (state[Keys.NumPad5] == KeyState.Down) SetBlock(5);
if (state[Keys.NumPad6] == KeyState.Down) SetBlock(6);
if (state[Keys.NumPad7] == KeyState.Down) SetBlock(7);
if (state[Keys.NumPad8] == KeyState.Down) SetBlock(8);
base.Update(gameTime);
}
void MoveXZ(int degree)
{
float rad = MathHelper.ToRadians(camLong + degree);
float x = camPos.X + (float)Math.Cos(rad) * 0.1f;
float z = camPos.Z + (float)Math.Sin(rad) * 0.1f;
if (GetGrid((int)x, (int)camPos.Y, (int)z) <= 0)
{
camPos.X = x;
camPos.Z = z;
}
}
void MoveY(float dy)
{
float y = camPos.Y + dy;
if (GetGrid((int)camPos.X, (int)y, (int)camPos.Z) <= 0)
{
camPos.Y = y;
}
}
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.TotalMilliseconds);
effect.CurrentTechnique.Passes[0].Apply();
GraphicsDevice.SetVertexBuffers(bindings);
GraphicsDevice.DrawInstancedPrimitives(PrimitiveType.TriangleList, 0, 0, 24, 0, 12, blockNum);
// フレームレート
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 + " block=" + blockNum;
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);
}
}
}
}}
HardwareInstancing.fx
#highlight{{
/*
#1
Effect File
プロジェクトのプロパティ
[XNA Game Studio]タブ
Use HiDef to access the complete API
*/
float4x4 WVP;
texture cubeTexture;
float totalTime;
sampler TextureSampler = sampler_state
{
texture = <cubeTexture>;
mipfilter = LINEAR;
minfilter = LINEAR;
magfilter = LINEAR;
};
struct InstancingVSinput
{
float4 Position : POSITION0;
float2 TexCoord : TEXCOORD0;
};
struct InstancingVSoutput
{
float4 Position : POSITION0;
float2 TexCoord : TEXCOORD0;
};
InstancingVSoutput InstancingVS(
InstancingVSinput input, float4x4 instanceTransform : TEXCOORD1, float2 atlasCoord : TEXCOORD5)
{
InstancingVSoutput output;
float4 pos = input.Position;
pos = mul(pos, transpose(instanceTransform));
// pos.y = (pos.y + 0.01f * totalTime * atlasCoord.x) % 100.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(InstancingVSoutput input) : COLOR0
{
if (2.0f <= input.TexCoord.x) discard;
return tex2D(TextureSampler, input.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)|
|プロジェクト名|XnaBlock|
Block Builder(仮)
Texture4.png
#ref(Texture4_2.png)
Palette16.png
#ref(Palette16.png)
Game1.cs
#highlight(c#){{
// #1
using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
namespace XnaBlock
{
class Game1 : Game
{
GraphicsDeviceManager graphics;
SpriteBatch sprite;
SpriteFont font;
Effect effect;
Texture2D texture;
// fps
DateTime prevTime;
int draw = 0;
int fps = 0;
const int gridSize = 100;
const int blockMax = 20000;
short blockNum = 0;
short[] grid;
VertexBuffer instanceBuffer;
VertexBuffer geometryBuffer;
IndexBuffer indexBuffer;
VertexDeclaration instanceVertexDeclaration;
VertexBufferBinding[] bindings;
Matrix projection;
// カメラ
Vector3 camPos = new Vector3(50.5f, 1.5f, 50.5f);
int camLat = 0;
int camLong = 225;
readonly int[] dirX = { 1, 1, 0, -1, -1, -1, 0, 1, 1 };
readonly int[] dirZ = { 0, 1, 1, 1, 0, -1, -1, -1, 0 };
struct InstanceInfo
{
public Matrix World;
public Vector2 AtlasCoordinate;
}
struct Position
{
public int X;
public int Y;
public int Z;
public Position(int x, int y, int z)
{
X = x;
Y = y;
Z = z;
}
}
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, 2000);
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[] indices = new int[36];
for (int n = 0; n < 6; n++)
{
int n6 = n * 6;
int n4 = n * 4;
indices[n6 + 0] = n4 + 0; indices[n6 + 1] = n4 + 1; indices[n6 + 2] = n4 + 2;
indices[n6 + 3] = n4 + 1; indices[n6 + 4] = n4 + 3; indices[n6 + 5] = n4 + 2;
}
indexBuffer = new IndexBuffer(GraphicsDevice, typeof(int), 36, BufferUsage.WriteOnly);
indexBuffer.SetData(indices);
}
void GenerateInstanceVertexDeclaration()
{
VertexElement[] elements = new VertexElement[5];
for (int n = 0; n < 4; n++) // Matrix = Vector4 * 4
{
elements[n] = new VertexElement(sizeof(float) * 4 * n,
VertexElementFormat.Vector4, VertexElementUsage.TextureCoordinate, n + 1);
}
elements[4] = new VertexElement(sizeof(float) * 16,
VertexElementFormat.Vector2, VertexElementUsage.TextureCoordinate, 5);
instanceVertexDeclaration = new VertexDeclaration(elements);
}
void GenerateInstanceInformation()
{
instanceBuffer = new VertexBuffer(GraphicsDevice,
instanceVertexDeclaration, blockMax, BufferUsage.None); // 読み込みもする
grid = new short[gridSize * gridSize * gridSize];
// 地面
for (int z = 0; z < gridSize; z++)
{
for (int x = 0; x < gridSize; x++)
{
SetNewBlock(x, 0, z, 4);
}
}
// 正8面体
for (int y = -10; y <= 10; y++)
{
int x1 = 10 - Math.Abs(y);
for (int x = -x1; x <= x1; x++)
{
int z1 = x1 - Math.Abs(x);
int z2 = (z1 == 0) ? 1 : z1 * 2;
for (int z = -z1; z <= z1; z += z2)
{
SetNewBlock(10 + x, 20 + y, 30 + z, 3);
}
}
}
// 太陽
for (int y = -10; y <= 10; y++)
{
for (int x = -10; x <= 10; x++)
{
for (int z = -10; z <= 10; z++)
{
int r = (x * x) + (y * y) + (z * z);
if (90 < r && r < 111) // 9.5^2 < r^2 < 10.5^2
{
SetNewBlock(30 + x, 20 + y, 10 + z, 2);
}
}
}
}
}
int GridIndex(int x, int y, int z)
{
return (y * gridSize + x) * gridSize + z;
}
void SetNewBlock(int x, int y, int z, byte color)
{
InstanceInfo[] ins = new InstanceInfo[1]; // stride = 4*(16+2)
ins[0].World = Matrix.CreateTranslation(new Vector3(x + 0.5f, y + 0.5f, z + 0.5f));
ins[0].AtlasCoordinate = new Vector2((color & 3) / 4.0f, (color >> 2) / 4.0f);
instanceBuffer.SetData<InstanceInfo>(blockNum++ * 72, ins, 0, 1, 72);
grid[GridIndex(x, y, z)] = blockNum;
}
short GetGrid(int x, int y, int z)
{
if (x < 0 || gridSize <= x ||
y < 0 || gridSize <= y ||
z < 0 || gridSize <= z) return Int16.MinValue;
return grid[GridIndex(x, y, z)];
}
Position GetForwardPos()
{
Position pos;
int dir = (camLong + 22) / 45;
pos.X = (int)camPos.X + dirX[dir];
pos.Y = (int)camPos.Y - 1;
pos.Z = (int)camPos.Z + dirZ[dir];
return pos;
}
void SetGrid(Position pos, float u, float v, short index)
{
InstanceInfo[] ins = new InstanceInfo[1];
int start = (Math.Abs(index) - 1) * 72;
instanceBuffer.GetData<InstanceInfo>(start, ins, 0, 1, 72);
ins[0].AtlasCoordinate = new Vector2(u, v);
instanceBuffer.SetData<InstanceInfo>(start, ins, 0, 1, 72);
grid[GridIndex(pos.X, pos.Y, pos.Z)] = index;
}
void SetBlock(byte color)
{
Position pos = GetForwardPos();
short index = GetGrid(pos.X, pos.Y, pos.Z);
if (0 < index || index == Int16.MinValue) return;
if (index == 0)
{
SetNewBlock(pos.X, pos.Y, pos.Z, color);
}
else
{
// 再利用
SetGrid(pos, (color & 3) / 4.0f, (color >> 2) / 4.0f, (short)-index);
}
}
void DelBlock()
{
Position pos = GetForwardPos();
short index = GetGrid(pos.X, pos.Y, pos.Z);
if (index <= 0) return;
// 論理削除
SetGrid(pos, 2.0f, 0, (short)-index);
}
protected override void Update(GameTime gameTime)
{
KeyboardState state = Keyboard.GetState();
if (state[Keys.Escape] == KeyState.Down) Exit();
if (state[Keys.W] == KeyState.Down) MoveXZ(0);
if (state[Keys.S] == KeyState.Down) MoveXZ(180);
if (state[Keys.A] == KeyState.Down) MoveXZ(-90);
if (state[Keys.D] == KeyState.Down) MoveXZ(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) MoveY(0.1f);
if (state[Keys.PageDown] == KeyState.Down) MoveY(-0.1f);
if (state[Keys.NumPad0] == KeyState.Down) DelBlock();
if (state[Keys.NumPad1] == KeyState.Down) SetBlock(1);
if (state[Keys.NumPad2] == KeyState.Down) SetBlock(2);
if (state[Keys.NumPad3] == KeyState.Down) SetBlock(3);
if (state[Keys.NumPad4] == KeyState.Down) SetBlock(4);
if (state[Keys.NumPad5] == KeyState.Down) SetBlock(5);
if (state[Keys.NumPad6] == KeyState.Down) SetBlock(6);
if (state[Keys.NumPad7] == KeyState.Down) SetBlock(7);
if (state[Keys.NumPad8] == KeyState.Down) SetBlock(8);
base.Update(gameTime);
}
void MoveXZ(int degree)
{
float rad = MathHelper.ToRadians(camLong + degree);
float x = camPos.X + (float)Math.Cos(rad) * 0.1f;
float z = camPos.Z + (float)Math.Sin(rad) * 0.1f;
if (GetGrid((int)x, (int)camPos.Y, (int)z) <= 0)
{
camPos.X = x;
camPos.Z = z;
}
}
void MoveY(float dy)
{
float y = camPos.Y + dy;
if (GetGrid((int)camPos.X, (int)y, (int)camPos.Z) <= 0)
{
camPos.Y = y;
}
}
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(
0.01f * (float)gameTime.TotalGameTime.TotalMilliseconds);
effect.CurrentTechnique.Passes[0].Apply();
GraphicsDevice.SetVertexBuffers(bindings);
GraphicsDevice.DrawInstancedPrimitives(
PrimitiveType.TriangleList, 0, 0, 24, 0, 12, blockNum);
// フレームレート
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 + " block=" + blockNum;
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);
}
}
}
}}
HardwareInstancing.fx
#highlight{{
/*
#1
Effect File
プロジェクトのプロパティ
[XNA Game Studio]タブ
Use HiDef to access the complete API
*/
float4x4 WVP;
texture cubeTexture;
float totalTime;
sampler TextureSampler = sampler_state
{
texture = <cubeTexture>;
mipfilter = LINEAR;
minfilter = LINEAR;
magfilter = LINEAR;
};
struct InstancingVSinput
{
float4 Position : POSITION0;
float2 TexCoord : TEXCOORD0;
};
struct InstancingVSoutput
{
float4 Position : POSITION0;
float2 TexCoord : TEXCOORD0;
};
InstancingVSoutput InstancingVS(
InstancingVSinput input, float4x4 instanceTransform : TEXCOORD1, float2 atlasCoord : TEXCOORD5)
{
InstancingVSoutput output;
float4 pos = input.Position;
pos = mul(pos, transpose(instanceTransform));
// pos.y = (pos.y + totalTime * atlasCoord.x) % 100.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(InstancingVSoutput input) : COLOR0
{
if (2.0f <= input.TexCoord.x) discard;
return tex2D(TextureSampler, input.TexCoord);
}
technique Instancing
{
pass Pass0
{
VertexShader = compile vs_3_0 InstancingVS();
PixelShader = compile ps_3_0 InstancingPS();
}
}
}}