|開発環境|Microsoft Visual C# 2010 Express (SP1)| |実行環境|Microsoft Windows XP Home Edition (SP3)| |プロジェクトの種類|Windows Game (4.0)| |プロジェクト名|XnaSphere| 参考 -[[続・ポリゴンできれいな球を作る (Weblog on mebius.tokaichiba.jp)>http://ynomura.dip.jp/archives/2009/04/post_36.html]] Game1.cs #highlight(c#){{ // XnaSphere - XNA 球体(緯度法) 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; IndexBuffer indexBuffer; // 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 stackNum = 16; // 輪切りの数 VertexPositionColor[] vertices = new VertexPositionColor[stackNum * stackNum + 2]; int i = 0; vertices[i++] = new VertexPositionColor(new Vector3(0, 1, 0), Color.Yellow); for (int stack = 1; stack < stackNum; stack++) { float rad = ((stackNum - 2 * stack) / (float)stackNum) * MathHelper.PiOver2; float y = (float)Math.Sin(rad); float r = (float)Math.Cos(rad); int sliceNum = 4 * Math.Min(stack, stackNum - stack); // 放射頂点の数 for (int slice = 0; slice < sliceNum; slice++) { rad = (slice / (float)sliceNum) * MathHelper.TwoPi; float x = (float)Math.Cos(rad) * r; float z = (float)Math.Sin(rad) * r; Vector3 normal = Vector3.Normalize(new Vector3(x, y, z)); vertices[i++] = new VertexPositionColor( normal, (slice & 1) == 0 ? Color.Red : Color.Yellow); } } vertices[i++] = new VertexPositionColor(new Vector3(0, -1, 0), Color.Yellow); vertexBuffer = new VertexBuffer(GraphicsDevice, typeof(VertexPositionColor), vertices.Length, BufferUsage.WriteOnly); vertexBuffer.SetData(vertices); // 索引バッファ short[] indices = new short[stackNum * stackNum * 6]; i = 0; int prevHead = 0; // 前の先頭頂点番号 int prevVtx = 1; // 前の頂点数 for (int stack = 0; stack < stackNum / 2; stack++) { int currHead = prevHead + prevVtx; // 現在の先頭頂点番号 int currVtx = 4 * (stack + 1); // 現在の頂点数 for (int quad = 0; quad < 4; quad++) // 4象限 { int prevQuad = quad * stack; // 前の象限オフセット int currQuad = quad * (stack + 1); // 現在の象限オフセット for (int n = 0; ; n++) { indices[i++] = (short)(prevHead + (prevQuad + n) % prevVtx); indices[i++] = (short)(currHead + (currQuad + n)); indices[i++] = (short)(currHead + (currQuad + n + 1) % currVtx); if (stack <= n) break; indices[i++] = (short)(prevHead + (prevQuad + n)); indices[i++] = (short)(currHead + (currQuad + n + 1)); indices[i++] = (short)(prevHead + (prevQuad + n + 1) % prevVtx); } } prevHead = currHead; prevVtx = currVtx; } for (int stack = stackNum / 2 - 1; 0 <= stack; stack--) { int currHead = prevHead + prevVtx; int currVtx = Math.Max(4 * stack, 1); for (int quad = 0; quad < 4; quad++) // 4象限 { int prevQuad = quad * (stack + 1); int currQuad = quad * stack; for (int n = 0; ; n++) { indices[i++] = (short)(currHead + (currQuad + n) % currVtx); indices[i++] = (short)(prevHead + (prevQuad + n + 1) % prevVtx); indices[i++] = (short)(prevHead + (prevQuad + n)); if (stack <= n) break; indices[i++] = (short)(currHead + (currQuad + n)); indices[i++] = (short)(currHead + (currQuad + n + 1) % currVtx); indices[i++] = (short)(prevHead + (prevQuad + n + 1)); } } prevHead = currHead; prevVtx = currVtx; } indexBuffer = new IndexBuffer(GraphicsDevice, typeof(short), indices.Length, BufferUsage.WriteOnly); indexBuffer.SetData(indices); base.LoadContent(); } protected override void Update(GameTime gameTime) { KeyboardState kState = Keyboard.GetState(); if (kState.IsKeyDown(Keys.Escape)) Exit(); if (kState.IsKeyDown(Keys.Up)) camLat++; if (kState.IsKeyDown(Keys.Down)) camLat--; 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); GraphicsDevice.Indices = indexBuffer; foreach (EffectPass pass in effect.CurrentTechnique.Passes) { pass.Apply(); GraphicsDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, vertexBuffer.VertexCount, 0, indexBuffer.IndexCount / 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); } } } }}