XNA Game Development Forums
2012/05/21 20:02:03 *
Welcome, Guest. Please login or register.

Login with username, password and session length
 
   Home   Help Search Calendar Login Register  
Pages: [1]
  Print  
Author Topic: Creating and Rendering a Planet (XNA HM Engine)  (Read 6191 times)
Suzume
Newbie
*
Offline Offline

Posts: 9


View Profile
« on: 2007/08/05 03:58:09 »

I've read an article series by Sean O'Neil over at Gamasutra which introduces procedural generation of planetary terrain. He uses a cube as a starting point and a perlin noise algorithm to generate random surface patches.
But I wonder if it was a good idea to start from a cube. Why not using an icosahedron?
Any suggestions of how to approach this task with the HM Egine?
Just collecting ideas for now. Going to experiment with code later this week.
Logged
Chr0n1x
Global Moderator
Sr. Member
*****
Offline Offline

Posts: 307


View Profile WWW
« Reply #1 on: 2007/08/08 00:22:54 »

This may help in your question, "why not an icosahedron".
Firstly, its one of the more obscure shapes, I can guarantee you that many people will reply with a "wtf" when you mention it. Secondly, how do you generate one in code? He is doing a little guide there to explain it, to bring up a shape that not everyone knows and try to put calculations on it, would be too confusing for a tutorial/guide.

As for the rest, its similar to how he does it, youre working with vertices pretty much just like in native DirectX and shaders are the same. This would be good to see though so good luck with the code.
« Last Edit: 2007/08/16 00:38:40 by chr0n1x » Logged

mikeschuld
Administrator
Sr. Member
*****
Offline Offline

Posts: 389


View Profile WWW
« Reply #2 on: 2007/08/14 00:00:26 »

Icosahedrons have fairly generalized algorithms for their generation, (icosphere might be easier to find one for), but other than generating the initial point set, all of the other techniques could be the same as in the article.
Logged
Suzume
Newbie
*
Offline Offline

Posts: 9


View Profile
« Reply #3 on: 2007/08/28 06:50:54 »

Didn't have that much time over the past few weeks. But I read some articles about icosahedrons (and the other platonic bodies).
There I stumbled across an interesting property of this figure.
It can be surrounded by a cube. 2 vertices of the icosahedron rest on each side (in the middle) of the cube - 6 sides of the cube... makes for 12 vertices of the icosahedron.
4 vertices of the icosahedron resting on 2 sides of the cube that are parallel to each other form a rectangle which penetrates the cube. Makes 3 such rectangles.
All of them are equal shaped and have the following proportion: b : a = (1+sqrt(5)) : 2
Knowing this one can construct the vertex-positions of the icosahedron using the theorems of Pythagoras.
I wanted the size of the icosahedron to be dependend on the radius (diameter/2 of the inscribed rectangle):

// substituting b in the above equation
b = a(1+sqrt(5))/2

// inserting
d? = a? + b?
d? = a? + a? * ((1+sqrt(5))/2)?
d? = a? * (1 + ((1+sqrt(5))/2)?)
// calculating the right term - making this a constant in the code so
// we don't need to recalculate it
d? = a? * 3.6180339887498948482045868343656

(Hope this is right, didn't take my notebook with me where I wrote it down)

Well, equipped with the math I tried to create the vertex-positions. Here's the code:

Code:
using System;
using Microsoft.Xna.Framework;

namespace Geosphere
{
    /*********************************
     * Formulas for an Icosahedron:  *
     * Faces = 20 * F?              *
     * Edges = 30 * F?              *
     * Points = 10 * F? + 2         *
     *
     *
     *     (b)
     * 1 + sqrt(5)
     * -----------
     * |      ***|
     * |   ***   | 2 (a)
     * |***      |
     * -----------
     *
     * *** = (d) = 2 * mRadius
     *
     * d? = a? + b?
     *
     *********************************/
   
    public class Icosahedron
    {
        private const double mConstant = 3.6180339887498948482045868343656;
        private float mRadius;
        private int mFrequency;
        private Vector3[] mVertices;

        public Icosahedron()
        {
            mRadius = 1.0f;
            mFrequency = 1;
            mVertices = new Vector3[12];

            createIcosahedron();
        }

        public Icosahedron(float Radius, int Frequency)
        {
            mRadius = Radius;
            mFrequency = Frequency;
            mVertices = new Vector3[(10 * (mFrequency * mFrequency)) + 2];

            createIcosahedron();
        }

        public Vector3[] Vertices
        {
            get { return this.mVertices; }
        }

        private void createIcosahedron()
        {
            // Calculating vertices for icosahedron of frequency 1
            // d is the diagonal of the rectangle
            // a is the short edge of the rectangle (2)
            // b is the long edge of the rectangle (1 + sqrt(5))
            double d = 4 * mRadius * mRadius;
            // a and b squared
            double a = d / mConstant;
            double b = d - a;
            // getting the square root of a and b
            // dividing by 2 to get the final vertex position
            a = Math.Sqrt(a) / 2;
            b = Math.Sqrt(b) / 2;

            double test = a / b;
            double zapp = 2 / (1 + Math.Sqrt(5));

            // a = short edge in z-direction (depth of screen/monitor)
            // b = long edge in x-direction
            mVertices[0] = new Vector3((float)b, 0, (float)a);
            mVertices[1] = new Vector3((float)b, 0, -(float)a);
            mVertices[2] = new Vector3(-(float)b, 0, (float)a);
            mVertices[3] = new Vector3(-(float)b, 0, -(float)a);

            // a = short edge in y-direction
            // b = long edge in z-direction
            mVertices[4] = new Vector3(0, (float)a, (float)b);
            mVertices[5] = new Vector3(0, (float)a, -(float)b);
            mVertices[6] = new Vector3(0, -(float)a, (float)b);
            mVertices[7] = new Vector3(0, -(float)a, -(float)b);

            // a = short edge in x-direction
            // b = long edge in y-direction
            mVertices[8] = new Vector3((float)a, (float)b, 0);
            mVertices[9] = new Vector3((float)a, -(float)b, 0);
            mVertices[10] = new Vector3(-(float)a, (float)b, 0);
            mVertices[11] = new Vector3(-(float)a, -(float)b, 0);
        }
    }
}

First question:
Is this right so far?

Second question:
Now how do I display the vertices using the XNA Framework and draw triangles between them? Haven't done something like this before.
Sadly the "How-To: Draw 3D Primitives" tutorial in XNA GSE doesn't explain vertex buffers, index buffers and the like so amateurs like me can come up with something on their own.
Any literature or tutorials you can point me to?
Logged
muchrejoicing
Newbie
*
Offline Offline

Posts: 46


View Profile
« Reply #4 on: 2007/08/28 14:21:39 »

I think Riemer talks about {Index, Vertex}Buffers in his tutorials. Here's one, for example:
http://www.riemers.net/eng/Tutorials/XNA/Csharp/Series1/Indices.php

He does TriangleStrips later on, I forget where. You'll probably find more of this stuff in general DirectX tutorials -- a lot of the XNA guides seem to be focused on the less technical aspects of the API.
Logged
mikeschuld
Administrator
Sr. Member
*****
Offline Offline

Posts: 389


View Profile WWW
« Reply #5 on: 2007/08/28 23:23:10 »

You can use a method similar to those used to draw the textured quad as well
Logged
Suzume
Newbie
*
Offline Offline

Posts: 9


View Profile
« Reply #6 on: 2007/08/30 11:28:02 »

Oh well,
thank you for pointing me to Riemer's excellent tutorials. At least that gave me something to start from. I knew of the basics (basically: indexing saves you from generating vertex overload on the graphics card memory side)... but I didn't know anything about how XNA does this stuff.
I think I managed to display the icosahedron. Why I cannot say that for sure? Because I had no camera movement and no shading applied to the scene - I just stared at a hexagon.
But from what I could see compared to my view in 3dsmax (which I used to work out the basic vertex-indexing) it looked good.
Sadly all the indexing was done manually by typing in the drawing order by hand. But that's something I want to avoid in the future. The vertex data has to be generated on the fly - I don't even dare to think of it for now.

Code:
using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace Geosphere
{
    /*********************************
     * Formulas for an Icosahedron:  *
     * Faces = 20 * F?              *
     * Edges = 30 * F?              *
     * Points = 10 * F? + 2         *
     *
     *
     *     (b)
     * 1 + sqrt(5)
     * -----------
     * |      ***|
     * |   ***   | 2 (a)
     * |***      |
     * -----------
     *
     * *** = (d) = 2 * mRadius
     *
     * d? = a? + b?
     *
     *********************************/

    public class Icosahedron
    {
        private const double mConstant = 3.6180339887498948482045868343656;
        private float mRadius;
        private int mFrequency;
        private int mTriangleCount;
        private int mEdgeCount;
        private int mVertexCount;
        private Vector3[] mVertexPositions;
        private VertexPositionColor[] mVertices;
        private short[] mIndices;
       
        public Icosahedron()
        {
            mRadius = 1.0f;
            mFrequency = 1;
            mTriangleCount = 20;
            mEdgeCount = 30;
            mVertexCount = 12;
            mVertexPositions = new Vector3[mVertexCount];
            mVertices = new VertexPositionColor[mVertexCount];

            createIcosahedron();
        }

        public Icosahedron(float Radius, int Frequency)
        {
            mRadius = Radius;
            mFrequency = Frequency;
            mTriangleCount = 20 * mFrequency * mFrequency;
            mEdgeCount = 30 * mFrequency * mFrequency;
            mVertexCount = (10 * (mFrequency * mFrequency)) + 2;
            mVertexPositions = new Vector3[mVertexCount];

            createIcosahedron();
        }

        public Vector3[] VertexPositions
        {
            get { return mVertexPositions; }
        }

        public VertexPositionColor[] Vertices
        {
            get { return mVertices; }
        }

        public short[] Indices
        {
            get { return mIndices; }
        }

        private void createIcosahedron()
        {
            // Calculating vertices for icosahedron of frequency 1
            // d is the diagonal of the rectangle
            // a is the short edge of the rectangle (2)
            // b is the long edge of the rectangle (1 + sqrt(5))
            double d = 4 * mRadius * mRadius;
            // a and b squared
            double a = d / mConstant;
            double b = d - a;
            // getting the square root of a and b
            // dividing by 2 to get the final vertex position
            a = Math.Sqrt(a) / 2;
            b = Math.Sqrt(b) / 2;

            double test = a / b;
            double zapp = 2 / (1 + Math.Sqrt(5));

            // a = short edge in z-direction (depth of screen/monitor)
            // b = long edge in x-direction
            mVertexPositions[0] = new Vector3((float)b, 0, (float)a);
            mVertexPositions[1] = new Vector3((float)b, 0, -(float)a);
            mVertexPositions[2] = new Vector3(-(float)b, 0, (float)a);
            mVertexPositions[3] = new Vector3(-(float)b, 0, -(float)a);

            // a = short edge in y-direction
            // b = long edge in z-direction
            mVertexPositions[4] = new Vector3(0, (float)a, (float)b);
            mVertexPositions[5] = new Vector3(0, (float)a, -(float)b);
            mVertexPositions[6] = new Vector3(0, -(float)a, (float)b);
            mVertexPositions[7] = new Vector3(0, -(float)a, -(float)b);

            // a = short edge in x-direction
            // b = long edge in y-direction
            mVertexPositions[8] = new Vector3((float)a, (float)b, 0);
            mVertexPositions[9] = new Vector3((float)a, -(float)b, 0);
            mVertexPositions[10] = new Vector3(-(float)a, (float)b, 0);
            mVertexPositions[11] = new Vector3(-(float)a, -(float)b, 0);

            setupVertexBuffer();
            setupIndexBuffer();
        }

        private void setupVertexBuffer()
        {
            for (int i = 0; i < mVertexCount; i++)
            {
                mVertices[i] = new VertexPositionColor(mVertexPositions[i], Color.White);
            }
        }

        private void setupIndexBuffer()
        {
            short[] indices = new short[60];

            // northern hemisphere (+z = north)
            indices[0] = 10;
            indices[1] = 4;
            indices[2] = 8;

            indices[3] = 10;
            indices[4] = 8;
            indices[5] = 5;

            indices[6] = 10;
            indices[7] = 5;
            indices[8] = 3;

            indices[9] = 10;
            indices[10] = 3;
            indices[11] = 2;

            indices[12] = 10;
            indices[13] = 2;
            indices[14] = 4;

            // southern hemisphere (-z = south)
            indices[15] = 9;
            indices[16] = 0;
            indices[17] = 6;

            indices[18] = 9;
            indices[19] = 6;
            indices[20] = 11;

            indices[21] = 9;
            indices[22] = 11;
            indices[23] = 7;

            indices[24] = 9;
            indices[25] = 7;
            indices[26] = 1;

            indices[27] = 9;
            indices[28] = 1;
            indices[29] = 0;

            // equator
            indices[30] = 4;
            indices[31] = 6;
            indices[32] = 0;

            indices[33] = 0;
            indices[34] = 8;
            indices[35] = 4;

            indices[36] = 4;
            indices[37] = 2;
            indices[38] = 6;

            indices[39] = 6;
            indices[40] = 2;
            indices[41] = 11;

            indices[42] = 11;
            indices[43] = 2;
            indices[44] = 3;

            indices[45] = 3;
            indices[46] = 7;
            indices[47] = 11;

            indices[48] = 3;
            indices[49] = 5;
            indices[50] = 7;

            indices[51] = 7;
            indices[52] = 5;
            indices[53] = 1;

            indices[54] = 1;
            indices[55] = 5;
            indices[56] = 8;

            indices[57] = 8;
            indices[58] = 0;
            indices[59] = 1;

            mIndices = indices;
        }
    }
}

Code:
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;

namespace Geosphere
{
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        ContentManager content;
        Icosahedron mIco;
        BasicEffect mIcoEffect;
        Matrix mWorld;
        Matrix mView;
        Matrix mProjection;
        VertexDeclaration mVertexDec;
       
        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            content = new ContentManager(Services);           
        }

        protected override void Initialize()
        {
            mIco = new Icosahedron();
            mView = Matrix.CreateLookAt(new Vector3(0f, 0f, 10f),
                Vector3.Zero, Vector3.Up);
            mProjection = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4,
                4.0f / 3.0f, 1f, 100f);

            base.Initialize();
        }

        protected override void LoadGraphicsContent(bool loadAllContent)
        {
            if (loadAllContent)
            {
                mIcoEffect = new BasicEffect(graphics.GraphicsDevice, null);
                mIcoEffect.EnableDefaultLighting();

                mIcoEffect.World = Matrix.Identity;
                mIcoEffect.View = mView;
                mIcoEffect.Projection = mProjection;
            }

            mVertexDec = new VertexDeclaration(graphics.GraphicsDevice,
                VertexPositionColor.VertexElements);
        }

        protected override void UnloadGraphicsContent(bool unloadAllContent)
        {
            if (unloadAllContent)
            {
                content.Unload();
            }
        }


        protected override void Update(GameTime gameTime)
        {
            base.Update(gameTime);
        }

        protected override void Draw(GameTime gameTime)
        {
            graphics.GraphicsDevice.Clear(Color.CornflowerBlue);

            DrawIcosahedron();

            base.Draw(gameTime);
        }

        private void DrawIcosahedron()
        {
            graphics.GraphicsDevice.VertexDeclaration = mVertexDec;

            mIcoEffect.Begin();

            foreach (EffectPass pass in mIcoEffect.CurrentTechnique.Passes)
            {
                pass.Begin();

                graphics.GraphicsDevice.DrawUserIndexedPrimitives<VertexPositionColor>(
                    PrimitiveType.TriangleList, mIco.Vertices, 0, 12, mIco.Indices,
                    0, 20);

                pass.End();
            }

            mIcoEffect.End();
        }
    }
}


Logged
Suzume
Newbie
*
Offline Offline

Posts: 9


View Profile
« Reply #7 on: 2007/09/02 08:48:14 »

Just a small update:
Managed to transfer the code into the HMEngine. Thx for reminding me of the textured quad.
Had to inverse the indices of all 20 triangles (normals were flipped inwards).
Still no shading though. I guess I need to generate vertex normals and texture coordinates next.
And I probably have to come up with a more atomic structure first - basically triangles that need to be capable of "knowing their neighbours" if I want to make an on-the-fly-tesselation... well, unsure about that... need to read some more online papers, forums, mailing lists etc.
Logged
Pages: [1]
  Print  
 
Jump to:  

Related Topics
Subject Started by Replies Views Last post
MOVED: XNA Tutorials :: Game Engine and Game Development :: Tutorial 1 Hazy Mind 3D Engine mikeschuld 0 2365 Last post 2006/10/30 21:35:32
by mikeschuld
Depth buffering and order of rendering??? Hazy Mind XNA Engine 5parrowhawk 1 1439 Last post 2007/02/28 08:02:01
by mikeschuld
I can't see anything on tutorial 4 More Rendering, Vertices and Indexes Hazy Mind 3D Engine moonsvista 5 2906 Last post 2007/03/30 14:37:05
by moonsvista
Effectively Rendering Point Sprites General Discussion DaphydTheBard 11 4318 Last post 2007/08/05 11:37:33
by Nemo Krad
Rendering to Background General Discussion inbreed 1 1599 Last post 2007/05/02 00:13:17
by Chr0n1x
Creating your objects Hazy Mind XNA Engine listentorick 2 1702 Last post 2007/08/14 21:31:18
by mikeschuld
Physics simulation: BulletX (Bullet for XNA) physics and Hazy Mind Xna Engine Hazy Mind XNA Engine Yubastard 6 5561 Last post 2007/08/12 08:57:21
by Yubastard
Creating Splitscreen for multiplayer Hazy Mind XNA Engine ChunkyBrewster 2 1648 Last post 2007/09/09 14:43:30
by ChunkyBrewster
XNA ENgine sources/pdf General Discussion Maverick 3 2656 Last post 2008/04/17 01:59:11
by Maverick
Powered by MySQL Powered by PHP Powered by SMF 1.1.12 | SMF © 2006-2009, Simple Machines LLC Valid XHTML 1.0! Valid CSS!
Page created in 1.101 seconds with 18 queries.