Non sono sicuro in quale lingua stai lavorando, ma qui c'è un esempio procedurale di estrusione di mesh per Unity3D:
http://unity3d.com/support/resources/example-projects/procedural-examples
Sono sicuro che potresti guardare il codice e rielaborarlo per la tua situazione.
EDIT: sto lavorando a un gioco che utilizza un sistema ferroviario estruso procedurale come quello che stai iniziando ma è in C # in Unity3d. Ti darò una panoramica di come creo la mia estrusione di rotaie basata su un percorso cubico di Bezier, quindi sebbene la mesh del binario sia generata proceduralmente, si basa sul percorso di Bezier che definisco in anticipo in un editor. Sarebbe come un editor di livelli nel caso del tuo gioco, nel mio caso, sta progettando tavoli da flipper. Di seguito è riportato un esempio di come lo sto facendo:
1.) Costruire / trovare e implementare una classe percorso Bezier. Questo ti fornirà i dati di origine per l'estrusione della mesh. Ce n'è uno in C # che puoi portare su c ++.
http://forum.unity3d.com/threads/32954-Waypoints-and-constant-variable-speed-problems?p=213942
2.) Dopo aver creato un percorso Bezier, i punti dati da questo percorso vengono campionati. Questo può essere fatto tramite il metodo Interp sulla classe fornita sopra. Questo ti darà un elenco / matrice di punti Vector3 lungo il percorso di Bezier.
3.) Creare una classe di supporto per convertire i dati del percorso Vector3 Bezier dal passaggio 2. In questo caso, ho una classe semplice chiamata ExtrudedTrailSection come definita di seguito:
public class ExtrudedTrailSection
{
public Vector3 point;
public Matrix4x4 matrix;
public float time;
public ExtrudedTrailSection() { }
}
4.) Scorrere i dati campione Vector3 e convertirli in una matrice di ExtrudedTrailSections che fornisce i dati campione e una matrice di base che sarebbe la posizione principale della mesh estrusa.
- ) Utilizzare l'array di ExtrudedTrailSections per creare un array di Matrix4x4 [] finale utilizzando il seguente codice:
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.) Ora hai una matrice di Matrix4x4 [] e puoi estrudere una mesh ma prima abbiamo bisogno di una mesh di riferimento da cui estrudere. Ho una classe di utilità che creerà una faccia mesh circolare che forniremo al metodo di estrusione mesh.
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.) Trova il centro di questi dati:
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.) Ora che abbiamo i dati del bordo e del centro per una mesh di faccia radiale, puoi costruire un oggetto mesh usando i tuoi dati. Il vertice finale nella mesh è il punto centrale che abbiamo calcolato. La mesh finale è solo una faccia fornita al metodo di estrusione mesh di cui ho fornito un esempio nella classe di estrusione mesh procedurale del pacchetto Unity. Ancora una volta, questo è il mio metodo e ovviamente dovresti inserire questi dati in OpenGL. Se si dispone di una libreria di utilità 3d che si sta utilizzando o è possibile scrivere la propria classe mesh, probabilmente funzionerebbe meglio per generare la mesh estrusa finale poiché questi dati non sono realmente necessari da opengl per il rendering. Questa mesh facciale viene utilizzata come riferimento per l'estrusione della mesh.
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.) Trova i bordi esterni della mesh circolare come richiesto dal metodo di estrusione mesh. Ancora una volta, questo codice è fornito nel pacchetto unity.
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.) Alimenta tutti questi dati nel metodo Mesh Extrusion.
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;
}
L'output finale nel mio caso è simile al seguente ..
Buona fortuna, il tuo gioco sembra davvero fantastico! Fammi sapere se lo capisci?
Mandrino