Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spiked vertexes on generated Icosphere

Tags:

c#

mesh

xna

vertex

I've been working on a program to generate an icosphere. (A sphere with evenly distributed vertexes across the face, to be used for terrain deformation)

I have pretty much everything done, the sphere is generated, subdivided and drawn. The problem I am running into is that somewhere in the code, some of the vertices (the twelve starting vertexes, I believe) are being set to twice the radius, rather than just the radius.

Here are three images, showing the icosphere at zero, one and two refinement passes:

http://i41.photobucket.com/albums/e262/cstgirllover/Cho/Ico0Refinement.png

http://i41.photobucket.com/albums/e262/cstgirllover/Cho/Ico1Refinement.png

http://i41.photobucket.com/albums/e262/cstgirllover/Cho/Ico2Refinement.png

and here is the code that generates the icosahedron, and then breaks it down into the icosphere:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace Icosahedron_Test
{
class Icosahedron
{
    int radius;  // radius of the planet
    int refinement;  // number of times to refine the traingles
    int faces = 20;
    Vector3[] basePositions; // Vertex points for three defining rectangles
    TriXYZ[] vertices;  // Vertex points for triangles which define the spherical surface

    public Icosahedron(int tRadius, int tRefinement, TriXYZ[] tVertices)
    {
        radius = tRadius;
        refinement = tRefinement;
        vertices = tVertices;
    }

    public TriXYZ[] InitializeArray()
    {
        double t = radius*((1+Math.Sqrt(5))/2);

        Vector3[] basePositions = 
        {
            //First Rectangle
            new Vector3(-radius, (float)t, 0),
            new Vector3(radius, (float)t, 0),
            new Vector3(-radius, (float)-t, 0),
            new Vector3(radius, (float)-t, 0),

            //Seconds Rectangle
            new Vector3(0, -radius, (float)t),
            new Vector3(0, radius, (float)t),
            new Vector3(0, -radius, (float)-t),
            new Vector3(0, radius, (float)-t),

            //Third Rectangle
            new Vector3((float)t, 0, -radius),
            new Vector3((float)t, 0, radius),
            new Vector3((float)-t, 0, -radius),
            new Vector3((float)-t, 0, radius)
        };

        TriXYZ[] vertices =
        {
            new TriXYZ(basePositions[5], basePositions[11], basePositions[0], 1),
            new TriXYZ(basePositions[1], basePositions[5], basePositions[0], 1),
            new TriXYZ(basePositions[7], basePositions[1], basePositions[0], 1),
            new TriXYZ(basePositions[10], basePositions[7], basePositions[0], 1),
            new TriXYZ(basePositions[11], basePositions[10], basePositions[0], 1),

            new TriXYZ(basePositions[9], basePositions[5], basePositions[1], 1),
            new TriXYZ(basePositions[4], basePositions[11], basePositions[5], 1),
            new TriXYZ(basePositions[2], basePositions[10], basePositions[11], 1),
            new TriXYZ(basePositions[6], basePositions[7], basePositions[10], 1),
            new TriXYZ(basePositions[8], basePositions[1], basePositions[7], 1),

            new TriXYZ(basePositions[4], basePositions[9], basePositions[3], 1),
            new TriXYZ(basePositions[2], basePositions[4], basePositions[3], 1),
            new TriXYZ(basePositions[6], basePositions[2], basePositions[3], 1),
            new TriXYZ(basePositions[8], basePositions[6], basePositions[3], 1),
            new TriXYZ(basePositions[9], basePositions[8], basePositions[3], 1),

            new TriXYZ(basePositions[5], basePositions[9], basePositions[4], 1),
            new TriXYZ(basePositions[11], basePositions[4], basePositions[2], 1),
            new TriXYZ(basePositions[10], basePositions[2], basePositions[6], 1),
            new TriXYZ(basePositions[7], basePositions[6], basePositions[8], 1),
            new TriXYZ(basePositions[1], basePositions[8], basePositions[9], 1),

        };

        return vertices;
    }

    public TriXYZ[] Refine(TriXYZ[] rVertices, int rRefinement, float radius)
    {
        TriXYZ[] tVertices;  // Temp list of triangles

        Vector3 vertex1; // position of first vertex of base triangle
        Vector3 vertex2; // position of second vertex of base triangle
        Vector3 vertex3; // position of third vertex of base triangle
        int tDepth; // depth of the current triangle

        //int listPos = 0; // base list position integer
        int nListPos = 0; // new list position integer

        int cRefine = 0; // current refinement iteration

        while(cRefine < rRefinement)  // loop until the icosphere has been refined the inputted number of times
        {

            tVertices = new TriXYZ[20 + (4*rVertices.Length)]; // make the temporary list empty, and long enough for the original 20 triangles, plus four per triangle for each level of refinement.

            for (int listPos = 0; listPos < rVertices.Length; listPos++ )  // Loop through every triangle in the list
            {
                TriXYZ cTriangle = rVertices[listPos];

                tDepth = cTriangle.GetDepth;
                vertex1 = cTriangle.GetVertex1;  // point 0
                vertex2 = cTriangle.GetVertex2;  // point 1
                vertex3 = cTriangle.GetVertex3;  // point 2

                if (tDepth == cRefine + 1)  // if the depth of this triangle in the list equals the current refinement iteration; 
                // depth one for first refinement pass, depth two for second, etc; subdivide the triangle
                // This prevents unnecessarily re-refining old triangles
                {
                    TriXYZ[] parts = new TriXYZ[5];

                    parts = cTriangle.subDivide(radius);

                    tVertices[nListPos] = parts[0];  // Put the original larger triangle at the front if the list
                    tVertices[nListPos + 1] = parts[1]; // First subdivided triangle
                    tVertices[nListPos + 2] = parts[2]; // Second subdivided triangle
                    tVertices[nListPos + 3] = parts[3]; // Third subdivided triangle
                    tVertices[nListPos + 4] = parts[4];  // Fourth subdivided triangle

                    nListPos = nListPos + 5;  // Move forward in the new triangle list so the next set of triangles doesn't overwrite this set.

                }
                else if (tDepth < cRefine + 1)  // Ifthe triangle's depth is less than the current refinement iteration (depth 1 on refinement 2) then add the current triangle to the new list at nListPos
                {
                    tVertices[nListPos] = new TriXYZ(vertex1, vertex2, vertex3, tDepth);
                    nListPos++;
                }
                // it shouldn't be possible for the tDepth to be greater than cRefine
            }   // end for loop: either move to the next triangel in the original list, or move on to the next level of refinement


            rVertices = tVertices;  // Replace the old list with the new one, so that the next time it
                                    // runs through the refinement process, it will refine the new
                                    // traingles
            cRefine++;  // increase refinement interation variable so that it will either refine the next set of triangles, or exit the refinement loop.
            nListPos = 0;  // reset the new list position integer so it overwrites the exiting data

        } // end while loop: either move on to the next refinement set, or exit the loop

        vertices = rVertices; // make sure the class=level vertices 

        return rVertices;
    }  // End Refinement Class

    public int Length
    {
        get { return vertices.Length; }
        private set { }
    }

    public VertexPositionColor[] BuildList(TriXYZ[] tList, int tDepth)
    {
        VertexPositionColor[] finalList = new VertexPositionColor[tList.Length*3];  // final list to be returned for drawing
        int listPos = 0; // current position in the final list (where the vector 3 is being applied)

        Vector3 pos1; // Vertex 1 position of TriXYZ triangle
        Vector3 pos2; // Vertex 2 position of TriXYZ triangle
        Vector3 pos3; // Vertex 3 position of TriXYZ triangle
        int depth;

        for(int cTri = 0; cTri<tList.Length; cTri+=1) // Loop through the TriXYZ list and get all the vertexes from it, then apply them to the final draw list
        {
            pos1 = tList[cTri].GetVertex1;
            pos2 = tList[cTri].GetVertex2;
            pos3 = tList[cTri].GetVertex3;
            depth = tList[cTri].GetDepth;

            if (depth == tDepth)
            {
                finalList[listPos] = new VertexPositionColor(pos1, Color.Blue);
                finalList[listPos + 1] = new VertexPositionColor(pos2, Color.Red);
                finalList[listPos + 2] = new VertexPositionColor(pos3, Color.Green);

                listPos = listPos + 3;

            }
        }

        return finalList;
    }


}
}

and here is the TriXYZ class, that holds the triangle data:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace Icosahedron_Test
{
class TriXYZ
{
    Vector3 vertex1;
    Vector3 vertex2;
    Vector3 vertex3;
    int depth;
    float material1; // float for first material value amount (in %)  deals with blending
    float material2; // float for second material value amount (in %)  deals with blending

    public TriXYZ(Vector3 pos1, Vector3 pos2, Vector3 pos3, int tDepth)
    {
        vertex1 = pos1;
        vertex2 = pos2;
        vertex3 = pos3;
        depth = tDepth;
    }

    public TriXYZ(Vector3 pos1, Vector3 pos2, Vector3 pos3, int tDepth, float tMaterial1, float tMaterial2)
    {
        vertex1 = pos1;
        vertex2 = pos2;
        vertex3 = pos3;
        depth = tDepth;
        material1 = tMaterial1;
        material2 = tMaterial2;
    }

    // public access to triangle data, read-write

    public Vector3 GetVertex1
    {
        get { return vertex1; }
        set { vertex1 = value; }
    }
    public Vector3 GetVertex2
    {
        get { return vertex2; }
        set { vertex2 = value; }
    }
    public Vector3 GetVertex3
    {
        get { return vertex3; }
        set { vertex3 = value; }
    }
    public int GetDepth
    {
        get { return depth; }
        set { depth = value; }
    }



    public static Vector3 Midpoint(Vector3 pos1, Vector3 pos2, float radius)
    {
        Vector3 midpoint;  // returned midpoint between the two inputted vectors
        float x;
        float y;
        float z;

        x = (pos1.X + pos2.X)/2;
        y = (pos1.Y + pos2.Y)/2;
        z = (pos1.Z + pos2.Z)/2;

        midpoint = new Vector3(x, y, z);
        midpoint.Normalize();
        midpoint = midpoint * radius;

        return midpoint;
    }

    public TriXYZ[] subDivide(float radius)
    {
        Vector3 r; // placeholder for new vertex position, aligned to planet sphere radius
        Vector3 UV;  // new vector position

        TriXYZ[] nTriangle = new TriXYZ[5]; // array of triangle values to return

        Vector3 mid1 = Midpoint(vertex1, vertex2, radius);
        Vector3 mid2 = Midpoint(vertex2, vertex3, radius);
        Vector3 mid3 = Midpoint(vertex3, vertex1, radius);

        nTriangle[0] = new TriXYZ(vertex1, vertex2, vertex3, depth);  // Put the original larger triangle at the front if the list
        nTriangle[1] = new TriXYZ(vertex1, mid1, mid3, depth + 1); // First subdivided triangle
        nTriangle[2] = new TriXYZ(mid1, vertex2, mid2, depth + 1); // Second subdivided triangle
        nTriangle[3] = new TriXYZ(mid3, mid2, vertex3, depth + 1); // Third subdivided triangle
        nTriangle[4] = new TriXYZ(mid3, mid1, mid2, depth + 1);  // Fourth subdivided triangle

        return nTriangle;
    }

}
}

Any help will be greatly appreciate. I imagine it's something simple, I just cannot seem to find the problem.

like image 984
Patrick Reynolds Avatar asked Jan 30 '26 13:01

Patrick Reynolds


1 Answers

It's definitely the initial vectors. If memory serves (it's been a while since I've dealt with icosahedrons, etc.), you just use the golden ratio to create one with and edge length of 2 (which you're doing). Perhaps normalize the vectors before multiplying by the radius? The reason I say that is because those vertices never get updated in your code, so it has to be the initial values (unless of course I missed something, which is possible).

like image 67
JaCraig Avatar answered Feb 01 '26 01:02

JaCraig



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!