// XnaSphere4 - XNA 球体(再帰分割slerp)
using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
namespace XnaSphere
{
class Game1 : Game
{
GraphicsDeviceManager graphics;
SpriteBatch sprite;
SpriteFont font;
BasicEffect effect;
VertexBuffer vertexBuffer;
VertexPositionColor[] vertices;
int vi = 0;
// fps
int sec;
int draw = 0;
int fps = 0;
// カメラ
int camLat = 0;
int camLong = 90;
float camDist = 5;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
graphics.PreferredBackBufferWidth = 1280;
graphics.PreferredBackBufferHeight = 720;
Content.RootDirectory = "Content";
IsMouseVisible = true;
}
protected override void LoadContent()
{
font = Content.Load<SpriteFont>("SpriteFont1");
sprite = new SpriteBatch(GraphicsDevice);
effect = new BasicEffect(GraphicsDevice);
//effect.VertexColorEnabled = true;
//effect.EnableDefaultLighting();
effect.Projection = Matrix.CreatePerspectiveFieldOfView(
MathHelper.ToRadians(45), GraphicsDevice.Viewport.AspectRatio, 1, 100);
// 頂点バッファ
int lv = 4;
vertices = new VertexPositionColor[3 * 8 * (int)Math.Pow(4, lv)];
GenerateTriangle(lv, Vector3.Up, new Vector3(1, 0, 0), new Vector3(0, 0, 1));
GenerateTriangle(lv, Vector3.Up, new Vector3(0, 0, 1), new Vector3(-1, 0, 0));
GenerateTriangle(lv, Vector3.Up, new Vector3(-1, 0, 0), new Vector3(0, 0, -1));
GenerateTriangle(lv, Vector3.Up, new Vector3(0, 0, -1), new Vector3(1, 0, 0));
GenerateTriangle(lv, Vector3.Down, new Vector3(0, 0, 1), new Vector3(1, 0, 0));
GenerateTriangle(lv, Vector3.Down, new Vector3(-1, 0, 0), new Vector3(0, 0, 1));
GenerateTriangle(lv, Vector3.Down, new Vector3(0, 0, -1), new Vector3(-1, 0, 0));
GenerateTriangle(lv, Vector3.Down, new Vector3(1, 0, 0), new Vector3(0, 0, -1));
vertexBuffer = new VertexBuffer(GraphicsDevice,
typeof(VertexPositionColor), vertices.Length, BufferUsage.WriteOnly);
vertexBuffer.SetData(vertices);
base.LoadContent();
}
void GenerateTriangle(int lv, Vector3 v1, Vector3 v2, Vector3 v3)
{
if (lv-- <= 0)
{
vertices[vi++] = new VertexPositionColor(v1, Color.Yellow);
vertices[vi++] = new VertexPositionColor(v2, Color.Yellow);
vertices[vi++] = new VertexPositionColor(v3, Color.Yellow);
return;
}
Vector3 v4 = QV(Quaternion.Slerp(VQ(v1), VQ(v2), 0.5f));
Vector3 v5 = QV(Quaternion.Slerp(VQ(v2), VQ(v3), 0.5f));
Vector3 v6 = QV(Quaternion.Slerp(VQ(v3), VQ(v1), 0.5f));
GenerateTriangle(lv, v1, v4, v6);
GenerateTriangle(lv, v2, v5, v4);
GenerateTriangle(lv, v3, v6, v5);
GenerateTriangle(lv, v4, v5, v6);
}
Quaternion VQ(Vector3 v)
{
return new Quaternion(v.X, v.Y, v.Z, 0);
}
Vector3 QV(Quaternion q)
{
return new Vector3(q.X, q.Y, q.Z);
}
protected override void Update(GameTime gameTime)
{
KeyboardState kState = Keyboard.GetState();
if (kState.IsKeyDown(Keys.Escape)) Exit();
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)) camLong = (camLong + 1) % 360;
if (kState.IsKeyDown(Keys.Right)) camLong = (camLong + 359) % 360;
if (kState.IsKeyDown(Keys.PageUp)) camDist -= 0.1f;
if (kState.IsKeyDown(Keys.PageDown)) camDist += 0.1f;
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
GraphicsDevice.RasterizerState =
new RasterizerState { FillMode = FillMode.WireFrame };
// カメラ位置
float rad = MathHelper.ToRadians(camLat);
float y = (float)Math.Sin(rad) * camDist;
float r = (float)Math.Cos(rad) * camDist;
rad = MathHelper.ToRadians(camLong);
float x = (float)Math.Cos(rad) * r;
float z = (float)Math.Sin(rad) * r;
effect.View = Matrix.CreateLookAt(new Vector3(x, y, z), Vector3.Zero, Vector3.Up);
GraphicsDevice.SetVertexBuffer(vertexBuffer);
foreach (EffectPass pass in effect.CurrentTechnique.Passes)
{
pass.Apply();
GraphicsDevice.DrawPrimitives(PrimitiveType.TriangleList,
0, vertexBuffer.VertexCount / 3);
}
// fps
draw++;
if (gameTime.TotalGameTime.Seconds != sec)
{
fps = draw;
draw = 0;
sec = gameTime.TotalGameTime.Seconds;
}
sprite.Begin();
string text = String.Format(
"fps={0} lat={1} long={2} dist={3:f1}", fps, camLat, camLong, camDist);
sprite.DrawString(font, text, new Vector2(0, 0), Color.White);
sprite.End();
base.Draw(gameTime);
}
}
}