Quantcast
Channel: Active questions tagged xna-4.0 - Game Development Stack Exchange
Viewing all articles
Browse latest Browse all 33

Combine 3D objects in XNA 4

$
0
0

Currently I am writing on my thesis for university, the theme I am working on is 3D Visualization of hierarchical structures using cone trees.

I want to do is to draw a cone and arrange a number of spheres at the bottom of the cone. The spheres should be arranged according to the radius and the number of spheres correctly.

As you can imagine I need a lot of these cone/sphere combinations.

First Attempt

I was able to find some tutorials that helped with drawing cones and spheres.

Cone

    public Cone(GraphicsDevice device, float height, int tessellation, string name, List<Sphere> children)    {        //prepare children and calculate the children spacing and radius of the cone        if (children == null || children.Count == 0)        {            throw new ArgumentNullException("children");        }        this.Height = height;        this.Name = name;        this.Children = children;        //create the cone        if (tessellation < 3)        {            throw new ArgumentOutOfRangeException("tessellation");        }        //Create a ring of triangels around the outside of the cones bottom        for (int i = 0; i < tessellation; i++)        {            Vector3 normal = this.GetCircleVector(i, tessellation);            // add the vertices for the top of the cone            base.AddVertex(Vector3.Up * height, normal);            //add the bottom circle            base.AddVertex(normal * this.radius + Vector3.Down * height, normal);            //Add indices            base.AddIndex(i * 2);            base.AddIndex(i * 2 + 1);            base.AddIndex((i * 2 + 2) % (tessellation * 2));            base.AddIndex(i * 2 + 1);            base.AddIndex((i * 2 + 3) % (tessellation * 2));            base.AddIndex((i * 2 + 2) % (tessellation * 2));        }        //create flate triangle to seal the bottom        this.CreateCap(tessellation, height, this.Radius, Vector3.Down);        base.InitializePrimitive(device);    }

Sphere

    public void Initialize(GraphicsDevice device, Vector3 qi)    {        int verticalSegments = this.Tesselation;        int horizontalSegments = this.Tesselation * 2;        //single vertex on the bottom        base.AddVertex((qi * this.Radius) + this.lowering, Vector3.Down);        for (int i = 0; i < verticalSegments; i++)        {            float latitude = ((i + 1) * MathHelper.Pi / verticalSegments) - MathHelper.PiOver2;            float dy = (float)Math.Sin(latitude);            float dxz = (float)Math.Cos(latitude);            //Create a singe ring of latitudes            for (int j = 0; j < horizontalSegments; j++)            {                float longitude = j * MathHelper.TwoPi / horizontalSegments;                float dx = (float)Math.Cos(longitude) * dxz;                float dz = (float)Math.Sin(longitude) * dxz;                Vector3 normal = new Vector3(dx, dy, dz);                base.AddVertex(normal * this.Radius, normal);            }        }        // Finish with a single vertex at the top of the sphere.        AddVertex((qi * this.Radius) + this.lowering, Vector3.Up);        // Create a fan connecting the bottom vertex to the bottom latitude ring.        for (int i = 0; i < horizontalSegments; i++)        {            AddIndex(0);            AddIndex(1 + (i + 1) % horizontalSegments);            AddIndex(1 + i);        }        // Fill the sphere body with triangles joining each pair of latitude rings.        for (int i = 0; i < verticalSegments - 2; i++)        {            for (int j = 0; j < horizontalSegments; j++)            {                int nextI = i + 1;                int nextJ = (j + 1) % horizontalSegments;                base.AddIndex(1 + i * horizontalSegments + j);                base.AddIndex(1 + i * horizontalSegments + nextJ);                base.AddIndex(1 + nextI * horizontalSegments + j);                base.AddIndex(1 + i * horizontalSegments + nextJ);                base.AddIndex(1 + nextI * horizontalSegments + nextJ);                base.AddIndex(1 + nextI * horizontalSegments + j);            }        }        // Create a fan connecting the top vertex to the top latitude ring.        for (int i = 0; i < horizontalSegments; i++)        {            base.AddIndex(CurrentVertex - 1);            base.AddIndex(CurrentVertex - 2 - (i + 1) % horizontalSegments);            base.AddIndex(CurrentVertex - 2 - i);        }        base.InitializePrimitive(device);    }

The tricky part now is to arrange the spheres at the bottom of the cone. I tried is to draw just the cone and then draw the spheres. I need a lot of these cones, so it would be pretty hard to calculate all the positions correctly.

Second Attempt

So the second try was to generate a object that builds all vertices of the cone and all of the spheres at once. So I was hoping to render a cone with all its spheres arranged correctly. After a short debug I found out that the cone is created and the first sphere, when it turn of the second sphere I am running into an OutOfBoundsException of ushort.MaxValue.

Cone and Spheres

    public ConeWithSpheres(GraphicsDevice device, float height, float coneDiameter, float sphereDiameter,        int coneTessellation, int sphereTessellation, int numberOfSpheres)    {        if (coneTessellation < 3)        {            throw new ArgumentException(string.Format("{0} is to small for the tessellation of the cone. The number must be greater or equal to 3", coneTessellation));        }        if (sphereTessellation < 3)        {            throw new ArgumentException(string.Format("{0} is to small for the tessellation of the sphere. The number must be greater or equal to 3", sphereTessellation));        }        //set properties        this.Height = height;        this.ConeDiameter = coneDiameter;        this.SphereDiameter = sphereDiameter;        this.NumberOfChildren = numberOfSpheres;        //end set properties        //generate the cone        this.GenerateCone(device, coneTessellation);        //generate the spheres        //vector that defines the Y position of the sphere on the cones bottom        Vector3 lowering = new Vector3(0, 0.888f, 0);        this.GenerateSpheres(device, sphereTessellation, numberOfSpheres, lowering);    }    // ------ GENERATE CONE ------    private void GenerateCone(GraphicsDevice device, int coneTessellation)    {        int doubleTessellation = coneTessellation * 2;        //Create a ring of triangels around the outside of the cones bottom        for (int index = 0; index < coneTessellation; index++)        {            Vector3 normal = this.GetCircleVector(index, coneTessellation);            //add the vertices for the top of the cone            base.AddVertex(Vector3.Up * this.Height, normal);            //add the bottom of the cone            base.AddVertex(normal * this.ConeRadius + Vector3.Down * this.Height, normal);            //add indices            base.AddIndex(index * 2);            base.AddIndex(index * 2 + 1);            base.AddIndex((index * 2 + 2) % doubleTessellation);            base.AddIndex(index * 2 + 1);            base.AddIndex((index * 2 + 3) % doubleTessellation);            base.AddIndex((index * 2 + 2) % doubleTessellation);        }        //create flate triangle to seal the bottom        this.CreateCap(coneTessellation, this.Height, this.ConeRadius, Vector3.Down);        base.InitializePrimitive(device);    }    // ------ GENERATE SPHERES ------    private void GenerateSpheres(GraphicsDevice device, int sphereTessellation, int numberOfSpheres, Vector3 lowering)    {        int verticalSegments = sphereTessellation;        int horizontalSegments = sphereTessellation * 2;        for (int childCount = 1; childCount < numberOfSpheres; childCount++)        {            //single vertex at the bottom of the sphere            base.AddVertex((this.GetCircleVector(childCount, this.NumberOfChildren) * this.SphereRadius) + lowering,                Vector3.Down);            for (int verticalSegmentsCount = 0; verticalSegmentsCount < verticalSegments; verticalSegmentsCount++)            {                float latitude = ((verticalSegmentsCount + 1) * MathHelper.Pi / verticalSegments) - MathHelper.PiOver2;                float dy = (float)Math.Sin(latitude);                float dxz = (float)Math.Cos(latitude);                //create a single ring of latitudes                for (int horizontalSegmentsCount = 0; horizontalSegmentsCount < horizontalSegments; horizontalSegmentsCount++)                {                    float longitude = horizontalSegmentsCount * MathHelper.TwoPi / horizontalSegments;                    float dx = (float)Math.Cos(longitude) * dxz;                    float dz = (float)Math.Sin(longitude) * dxz;                    Vector3 normal = new Vector3(dx, dy, dz);                    base.AddVertex((normal * this.SphereRadius) + lowering, normal);                }            }            //finish with a single vertex at the top of the sphere            base.AddVertex((this.GetCircleVector(childCount, this.NumberOfChildren) * this.SphereRadius) + lowering,                Vector3.Up);            //create a fan connecting the bottom vertex to the bottom latitude ring            for (int i = 0; i < horizontalSegments; i++)            {                base.AddIndex(0);                base.AddIndex(1 + (i + 1) % horizontalSegments);                base.AddIndex(1 + i);            }            //Fill the sphere body with triangles joining each pair of latitude rings            for (int i = 0; i < verticalSegments - 2; i++)            {                for (int j = 0; j < horizontalSegments; j++)                {                    int nextI = i + 1;                    int nextJ = (j + 1) % horizontalSegments;                    base.AddIndex(1 + i * horizontalSegments + j);                    base.AddIndex(1 + i * horizontalSegments + nextJ);                    base.AddIndex(1 + nextI * horizontalSegments + j);                    base.AddIndex(1 + i * horizontalSegments + nextJ);                    base.AddIndex(1 + nextI * horizontalSegments + nextJ);                    base.AddIndex(1 + nextI * horizontalSegments + j);                }            }            //create a fan connecting the top vertiex to the top latitude            for (int i = 0; i < horizontalSegments; i++)            {                base.AddIndex(this.CurrentVertex - 1);                base.AddIndex(this.CurrentVertex - 2 - (i + 1) % horizontalSegments);                base.AddIndex(this.CurrentVertex - 2 - i);            }            base.InitializePrimitive(device);        }    }

Any ideas how I could fix this?


Viewing all articles
Browse latest Browse all 33

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>