ฉันไม่แน่ใจว่าคุณใช้ภาษาใด แต่มีตัวอย่างการบีบอัดตาข่ายสำหรับ Unity3D ที่นี่:
http://unity3d.com/support/resources/example-projects/procedural-examples
ฉันแน่ใจว่าคุณสามารถดูรหัสและทำใหม่สำหรับสถานการณ์ของคุณ
แก้ไข: ฉันกำลังทำงานกับเกมที่ใช้ระบบรถไฟแบบ extruded ขั้นตอนเช่นเดียวกับที่คุณกำลังเริ่มต้น แต่มันอยู่ใน C # ใน Unity3d ฉันจะให้ภาพรวมของวิธีที่ฉันสร้างการอัดขึ้นรูปรางของฉันตามเส้นทาง Cubic Bezier ดังนั้นแม้ว่าตาข่ายของรางจะถูกสร้างขึ้นตามขั้นตอน แต่ก็ขึ้นอยู่กับเส้นทาง Bezier ที่ฉันกำหนดไว้ล่วงหน้าในการแก้ไข มันจะเป็นเหมือนเครื่องมือแก้ไขเลเวลในกรณีของเกมของคุณในกรณีของฉันมันออกแบบตารางพินบอล รายการด้านล่างเป็นตัวอย่างของวิธีการที่ฉันทำ:
1. ) สร้าง / ค้นหาและใช้คลาสพา ธ Bezier สิ่งนี้จะทำให้คุณมีแหล่งข้อมูลสำหรับการอัดขึ้นรูปตาข่ายของคุณ มีหนึ่งใน C # ที่นี่ซึ่งคุณสามารถพอร์ตไปยัง c ++
http://forum.unity3d.com/threads/32954-Waypoints-and-constant-variable-speed-problems?p=213942
2. ) เมื่อคุณสร้างเส้นทาง Bezier แล้วจุดข้อมูลจากเส้นทางนี้จะถูกสุ่มตัวอย่าง ซึ่งสามารถทำได้ผ่านวิธีการ Interp ในชั้นเรียนที่ระบุไว้ข้างต้น นี่จะให้รายการ / อาเรย์ของจุด Vector3 ตามเส้นทาง Bezier
3. ) สร้างคลาสผู้ช่วยเพื่อแปลงข้อมูลพา ธ Vector3 Bezier จากขั้นตอนที่ 2 ในกรณีนี้ฉันมีคลาสแบบง่าย ๆ ที่เรียกว่า ExtrudedTrailSection ตามที่กำหนดไว้ด้านล่าง:
public class ExtrudedTrailSection
{
public Vector3 point;
public Matrix4x4 matrix;
public float time;
public ExtrudedTrailSection() { }
}
4. ) วนซ้ำตามข้อมูลตัวอย่าง Vector3 ของคุณและแปลงไปยังอาร์เรย์ของ ExtrudedTrailSections ที่ให้ข้อมูลตัวอย่างและเมทริกซ์ฐานที่จะเป็นตำแหน่งรูทของตาข่ายของคุณ
- ) ใช้อาร์เรย์ของ ExtrudedTrailSections เพื่อสร้างอาร์เรย์สุดท้ายของ Matrix4x4 [] โดยใช้รหัสต่อไปนี้:
Matrix4x4 worldToLocal = rootTransform.worldToLocalMatrix;
for (int i = 0; i < trailSections.Count; i++)
{
if (i == 0)
{
direction = trailSections[0].point - trailSections[1].point;
rotation = Quaternion.LookRotation(direction, Vector3.up);
previousRotation = rotation;
finalSections[i] = worldToLocal * Matrix4x4.TRS(position, rotation, Vector3.one);
}
// all elements get the direction by looking up the next section
else if (i != trailSections.Count - 1)
{
direction = trailSections[i].point - trailSections[i + 1].point;
rotation = Quaternion.LookRotation(direction, Vector3.up);
// When the angle of the rotation compared to the last segment is too high
// smooth the rotation a little bit. Optimally we would smooth the entire sections array.
if (Quaternion.Angle(previousRotation, rotation) > 20)
rotation = Quaternion.Slerp(previousRotation, rotation, 0.5f);
previousRotation = rotation;
finalSections[i] = worldToLocal * Matrix4x4.TRS(trailSections[i].point, rotation, Vector3.one);
}
// except the last one, which just copies the previous one
else
{
finalSections[i] = finalSections[i - 1];
}
}
6. ) ตอนนี้คุณมีอาร์เรย์ของ Matrix4x4 [] และสามารถขับไล่ตาข่าย แต่ก่อนอื่นเราต้องใช้ตาข่ายอ้างอิงเพื่อขับไล่จาก ฉันมีคลาสยูทิลิตี้ที่จะสร้างหน้าตาข่ายแบบวงกลมที่เราจะจัดหาให้กับวิธีการรีดตาข่าย
public static List<Vector2> CreateCircle (double radius, int sides)
{
List<Vector2> vectors = new List<Vector2> ();
const float max = 2.0f * Mathf.PI;
float step = max / sides;
for (float theta = 0.0f; theta < max; theta += step) {
vectors.Add (new Vector2 ((float)(radius * Mathf.Cos (theta)), (float)(radius * Mathf.Sin (theta))));
}
return vectors;
}
7. ) ค้นหาศูนย์กลางของข้อมูลนี้:
public static Vector2 CalculateCentroid(List<Vector2> vectorList)
{
//////////////////////////////////////////////////////////////////////////
// Local variables.
float fArea = 0.0f, fDistance = 0.0f;
Vector2 vCenter = Vector2.zero;
int nIndex = 0, nLastPointIndex = vectorList.Count - 1;
//
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
// Run through the list of positions.
for (int i = 0; i <= nLastPointIndex; ++i)
{
//////////////////////////////////////////////////////////////////////////
// Cacluate index.
nIndex = (i + 1) % (nLastPointIndex + 1);
// Calculate distance.
fDistance = vectorList[i].x * vectorList[nIndex].y - vectorList[nIndex].x * vectorList[i].y;
// Acculmate area.
fArea += fDistance;
// Move center positions based on positions and distance.
vCenter.x += (vectorList[i].x + vectorList[nIndex].x) * fDistance;
vCenter.y += (vectorList[i].y + vectorList[nIndex].y) * fDistance;
}
//
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
// Calculate the final center position.
fArea *= 0.5f;
vCenter.x *= 1.0f / (6.0f * fArea);
vCenter.y *= 1.0f / (6.0f * fArea);
//
//////////////////////////////////////////////////////////////////////////
return vCenter;
}
8. ) ตอนนี้เรามีข้อมูลขอบและศูนย์สำหรับตาข่ายหน้าเรเดียลคุณสามารถสร้างวัตถุตาข่ายโดยใช้ข้อมูลของคุณ จุดสุดยอดสุดท้ายในตาข่ายคือจุดศูนย์กลางที่เราคำนวณ ตาข่ายสุดท้ายเป็นเพียงใบหน้าที่มอบให้กับวิธีการอัดรีดแบบตาข่ายที่ฉันให้ตัวอย่างไว้ในคลาสการบีบอัดตาข่ายแบบขั้นตอนของแพ็คเกจ Unity นี่เป็นวิธีการของฉันและแน่นอนว่าคุณต้องป้อนข้อมูลนี้ใน OpenGL หากคุณมีไลบรารียูทิลิตี้ 3 มิติที่คุณกำลังใช้หรือสามารถเขียนคลาส mesh ของคุณเองมันน่าจะดีกว่าที่จะสร้าง mesh extruded สุดท้ายเพราะ opengl ไม่จำเป็นต้องใช้ข้อมูลนี้ในการแสดงผล ตาข่ายหน้านี้ใช้เป็นข้อมูลอ้างอิงสำหรับการอัดขึ้นรูปตาข่ายเท่านั้น
List<Vector3> levelVerts = new List<Vector3>();
List<Vector2> levelUVBary = new List<Vector2>();
List<Vector2> levelUVs = new List<Vector2>();
List<int> levelTris = new List<int>();
int verticesPerNode = 4;
int edgeCount = sourceMeshData.Count;
List<Vector3> sourceVerts = new List<Vector3>();
//Debug.Log("smd.c:" + sourceMeshData.Count);
for (int i = 0; i < edgeCount; i++)
{
//Debug.Log("adding:"+levelShapeData[i].x+"/"+levelShapeData[i].y);
sourceVerts.Add(new Vector3(sourceMeshData[i].x, sourceMeshData[i].y, 0));
levelUVs.Add(new Vector2(0, 0));
//sourceVerts.Add(new Vector3(levelShapeData[i].x, levelShapeData[i].y, modelLength / 2f));
}
sourceVerts.Add(new Vector3(sourceMeshCenter.x, sourceMeshCenter.y, 0));
levelUVs.Add(new Vector2(0, 0));
for (int i = 0; i < edgeCount - 1; i++)
{ //0, 1, 2, 3
levelTris.Add(sourceVerts.Count - 1); //4, 4, 4, 4
levelTris.Add(i); //0, 1, 2,
levelTris.Add(i + 1); //1, 2, 3,
}
levelTris.Add(sourceVerts.Count - 1);
levelTris.Add(edgeCount - 1);
levelTris.Add(0);
9. ) ค้นหาขอบด้านนอกของตาข่ายวงกลมตามที่ต้องการโดยวิธีการรีดตาข่าย อีกครั้งรหัสนี้มีให้ในแพ็คเกจสามัคคี
public class Edge
{
// The indiex to each vertex
public int[] vertexIndex = new int[2];
// The index into the face.
// (faceindex[0] == faceindex[1] means the edge connects to only one triangle)
public int[] faceIndex = new int[2];
}
public static Edge[] BuildManifoldEdges (Mesh mesh)
{
// Build a edge list for all unique edges in the mesh
Edge[] edges = BuildEdges(mesh.vertexCount, mesh.triangles);
// We only want edges that connect to a single triangle
ArrayList culledEdges = new ArrayList();
foreach (Edge edge in edges)
{
if (edge.faceIndex[0] == edge.faceIndex[1])
{
culledEdges.Add(edge);
}
}
return culledEdges.ToArray(typeof(Edge)) as Edge[];
}
10. ) ดึงข้อมูลทั้งหมดนี้เข้าสู่วิธีการอัดขึ้นรูปตาข่าย ..
public static void ExtrudeMesh (Mesh srcMesh, Mesh extrudedMesh, Matrix4x4[] extrusion, Edge[] edges, bool invertFaces)
{
int extrudedVertexCount = edges.Length * 2 * extrusion.Length;
int triIndicesPerStep = edges.Length * 6;
int extrudedTriIndexCount = triIndicesPerStep * (extrusion.Length -1);
Vector3[] inputVertices = srcMesh.vertices;
Vector2[] inputUV = srcMesh.uv;
int[] inputTriangles = srcMesh.triangles;
//Debug.Log("inputUV:" + inputUV.Length);
Vector3[] vertices = new Vector3[extrudedVertexCount + srcMesh.vertexCount * 2];
Vector2[] uvs = new Vector2[vertices.Length];
int[] triangles = new int[extrudedTriIndexCount + inputTriangles.Length * 2];
// Build extruded vertices
int v = 0;
for (int i=0;i<extrusion.Length;i++)
{
Matrix4x4 matrix = extrusion[i];
float vcoord = (float)i / (extrusion.Length -1);
foreach (Edge e in edges)
{
//Debug.Log(e.vertexIndex.Length);
vertices[v+0] = matrix.MultiplyPoint(inputVertices[e.vertexIndex[0]]);
vertices[v+1] = matrix.MultiplyPoint(inputVertices[e.vertexIndex[1]]);
uvs[v+0] = new Vector2 (inputUV[e.vertexIndex[0]].x, vcoord);
uvs[v+1] = new Vector2 (inputUV[e.vertexIndex[1]].x, vcoord);
v += 2;
}
}
// Build cap vertices
// * The bottom mesh we scale along it's negative extrusion direction. This way extruding a half sphere results in a capsule.
for (int c=0;c<2;c++)
{
Matrix4x4 matrix = extrusion[c == 0 ? 0 : extrusion.Length-1];
int firstCapVertex = c == 0 ? extrudedVertexCount : extrudedVertexCount + inputVertices.Length;
for (int i=0;i<inputVertices.Length;i++)
{
vertices[firstCapVertex + i] = matrix.MultiplyPoint(inputVertices[i]);
uvs[firstCapVertex + i] = inputUV[i];
}
}
// Build extruded triangles
for (int i=0;i<extrusion.Length-1;i++)
{
int baseVertexIndex = (edges.Length * 2) * i;
int nextVertexIndex = (edges.Length * 2) * (i+1);
for (int e=0;e<edges.Length;e++)
{
int triIndex = i * triIndicesPerStep + e * 6;
triangles[triIndex + 0] = baseVertexIndex + e * 2;
triangles[triIndex + 1] = nextVertexIndex + e * 2;
triangles[triIndex + 2] = baseVertexIndex + e * 2 + 1;
triangles[triIndex + 3] = nextVertexIndex + e * 2;
triangles[triIndex + 4] = nextVertexIndex + e * 2 + 1;
triangles[triIndex + 5] = baseVertexIndex + e * 2 + 1;
}
}
// build cap triangles
int triCount = inputTriangles.Length / 3;
// Top
{
int firstCapVertex = extrudedVertexCount;
int firstCapTriIndex = extrudedTriIndexCount;
for (int i=0;i<triCount;i++)
{
triangles[i*3 + firstCapTriIndex + 0] = inputTriangles[i * 3 + 1] + firstCapVertex;
triangles[i*3 + firstCapTriIndex + 1] = inputTriangles[i * 3 + 2] + firstCapVertex;
triangles[i*3 + firstCapTriIndex + 2] = inputTriangles[i * 3 + 0] + firstCapVertex;
}
}
// Bottom
{
int firstCapVertex = extrudedVertexCount + inputVertices.Length;
int firstCapTriIndex = extrudedTriIndexCount + inputTriangles.Length;
for (int i=0;i<triCount;i++)
{
triangles[i*3 + firstCapTriIndex + 0] = inputTriangles[i * 3 + 0] + firstCapVertex;
triangles[i*3 + firstCapTriIndex + 1] = inputTriangles[i * 3 + 2] + firstCapVertex;
triangles[i*3 + firstCapTriIndex + 2] = inputTriangles[i * 3 + 1] + firstCapVertex;
}
}
if (invertFaces)
{
for (int i=0;i<triangles.Length/3;i++)
{
int temp = triangles[i*3 + 0];
triangles[i*3 + 0] = triangles[i*3 + 1];
triangles[i*3 + 1] = temp;
}
}
extrudedMesh.vertices = vertices;
extrudedMesh.uv = uvs;
extrudedMesh.triangles = triangles;
}
ผลลัพธ์สุดท้ายในกรณีของฉันมีลักษณะเช่นนี้ ..
โชคดีเกมของคุณดูเท่จริงๆ! แจ้งให้เราทราบหากคุณคิดออก?
เชย