尖刺顶点生成Icosphere

时间:2011-07-21 14:50:40

标签: c# xna mesh vertex

我一直致力于一个生成icosphere的计划。 (在面上具有均匀分布的顶点的球体,用于地形变形)

我已经做了很多事情,球体被生成,细分和绘制。我遇到的问题是代码中的某个地方,一些顶点(十二个起始顶点,我相信)被设置为半径的两倍,而不仅仅是半径。

以下是三张图片,显示了零,一和两个细化过程中的icosphere:

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

以下是生成二十面体的代码,然后将其分解为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;
    }


}
}

这里是TriXYZ类,它包含三角形数据:

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;
    }

}
}

任何帮助都将非常感激。我想这很简单,我似乎无法找到问题。

1 个答案:

答案 0 :(得分:1)

这绝对是最初的载体。如果记忆服务(因为我处理了二十面体等已经有一段时间了),你只需使用黄金比例创建一个边长为2的边(你正在做)。也许在乘以半径之前对矢量进行归一化?我说的原因是因为那些顶点永远不会在你的代码中更新,所以它必须是初始值(除非我错过了一些东西,这是可能的)。