Thursday, July 12, 2012

How to create a sphere programmatically in XNA


I "discovered" an easy but silly way to create a sphere programmatically in XNA, it is very simple. The idea came to me when I wanted to create huge planets in XNA to make an endless map. Any way the method is very simple, I don't know If someone knows it or it was used before, but till now it is working and efficient. You can control the resolution or how "round" the sphere is.
The code is written in C# with microsoft's XNA 4.0.
Here is a high resolution sphere in wire frame:
The sphere contains 8100 vertices and 48600 indices.

Code:

    public class Sphere
    {
        VertexPositionColor[] vertices; //later, I will provide another example with VertexPositionNormalTexture
        VertexBuffer vbuffer;
        short[] indices; //my laptop can only afford Reach, no HiDef :(
        IndexBuffer ibuffer;
        float radius;
        int nvertices, nindices;
        BasicEffect effect;
        GraphicsDevice graphicd;
        public Sphere(float Radius, GraphicsDevice graphics)
        {
            radius = Radius;
            graphicd = graphics;
            effect = new BasicEffect(graphicd);
            nvertices = 90 * 90; // 90 vertices in a circle, 90 circles in a sphere
            nindices = 90 * 90 * 6;
            vbuffer = new VertexBuffer(graphics, typeof(VertexPositionNormalTexture), nvertices, BufferUsage.WriteOnly);
            ibuffer = new IndexBuffer(graphics, IndexElementSize.SixteenBits, nindices, BufferUsage.WriteOnly);
            createspherevertices();
            createindices();
            vbuffer.SetData<VertexPositionColor>(vertices);
            ibuffer.SetData<short>(indices);
            effect.VertexColorEnabled = true;
        }
        void createspherevertices()
        {
            vertices = new VertexPositionColor[nvertices];
            Vector3 center = new Vector3(0, 0, 0);
            Vector3 rad = new Vector3((float)Math.Abs(radius), 0, 0);
            for (int x = 0; x < 90; x++) //90 circles, difference between each is 4 degrees
            {
                float difx = 360.0f / 90.0f;
                for (int y = 0; y < 90; y++) //90 veritces, difference between each is 4 degrees 
                {
                    float dify = 360.0f / 90.0f;
                    Matrix zrot = Matrix.CreateRotationZ(MathHelper.ToRadians(y * dify)); rotate vertex around z
                    Matrix yrot = Matrix.CreateRotationY(MathHelper.ToRadians(x * difx)); rotate circle around y
                    Vector3 point = Vector3.Transform(Vector3.Transform(rad, zrot), yrot);//transformation

                    vertices[x + y * 90] = new VertexPositionColor(point, Color.Black);
                }
            }
        }
        void createindices()
        {
            indices = new short[nindices];
            int i = 0;
            for (int x = 0; x < 90; x++)
            {
                for (int y = 0; y < 90; y++)
                {
                    int s1 = x == 89 ? 0 : x + 1;
                    int s2 = y == 89 ? 0 : y + 1;
                    short upperLeft = (short)(x * 90 + y);
                    short upperRight = (short)(s1 * 90 + y);
                    short lowerLeft = (short)(x * 90 + s2);
                    short lowerRight = (short)(s1 * 90 + s2);
                    indices[i++] = upperLeft;
                    indices[i++] = upperRight;
                    indices[i++] = lowerLeft;
                    indices[i++] = lowerLeft;
                    indices[i++] = upperRight;
                    indices[i++] = lowerRight;
                }
            }
        }
        public void Draw(Camera cam) // the camera class contains the View and Projection Matrices
        {
            effect.View = cam.View;
            effect.Projection =  cam.Projection;
            graphicd.RasterizerState = new RasterizerState() { FillMode = FillMode.WireFrame }; // Wireframe as in the picture
            foreach (EffectPass pass in effect.CurrentTechnique.Passes)
            {
                pass.Apply();
                graphicd.DrawUserIndexedPrimitives<VertexPositionColor>(PrimitiveType.TriangleList, vertices, 0, nvertices, indices, 0, indices.Length / 3);
            }
        }
    }

12 comments:

  1. Hello,
    this is interesting. I just tried your class and it works. Though I had to modify the draw()-function... How do you call it in your Game and where? When I call it in the Game Draw() Function and there are more Primitives to draw, I get exceptions...
    I also have a suggestion:
    I added a static int, to set the number of vertices / circles!

    Greetings and thanks for your code!

    ReplyDelete
    Replies
    1. Interesting, what types of exceptions did you get?

      Delete
  2. Hi, thanks for posting the code. I implement your code and it works. I just have a problem on the DrawingSurface (i'm using a silverlight project on VS2012). In fact if I don't make it exactly squared, the sphere become an ellipse. Do you have any idea of what could be the problem. Thanks

    ReplyDelete
    Replies
    1. That's a problem with the View Matrix or the camera not the ellipse. When you stretch the view port you should change the aspect ratio of the camera.

      Delete
    2. sorry, sphere not ellipse.

      Delete
  3. thank you very much it works.

    ReplyDelete
  4. Hello, thanks for posting the example. I tried to run the code but I could not get the draw function. it appears the camera is not known by the setting I have. I added "using System.Windows.Media.Media3D;" but then again it could not recognise the view and the projection parameters of the camera. can you tell me what I am not doing to make it work? or can you kindly share the code with all the namespaces needed? Thank you so much

    ReplyDelete
  5. Hello,
    Thank you very much, it works fine for me.
    Just a question: did anyone try to colour it, rather than having it as a plain sphere?
    I tried doing t in different ways, it always ended up as a sort of spiral, and always coloured red and black. Does someone have any ideas?

    ReplyDelete
  6. Thank You and that i have a nifty offer: What Home Renovation Shows Are On Netflix home interior renovation

    ReplyDelete