我一直致力于一个生成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;
}
}
}
任何帮助都将非常感激。我想这很简单,我似乎无法找到问题。
答案 0 :(得分:1)
这绝对是最初的载体。如果记忆服务(因为我处理了二十面体等已经有一段时间了),你只需使用黄金比例创建一个边长为2的边(你正在做)。也许在乘以半径之前对矢量进行归一化?我说的原因是因为那些顶点永远不会在你的代码中更新,所以它必须是初始值(除非我错过了一些东西,这是可能的)。