मैं एक तटरेखा से 3D रेस ट्रैक कैसे उत्पन्न करूं?


9

मैं एक 3-आयामी रेस ट्रैक उत्पन्न करना चाहता हूं, जो अपने आकार का वर्णन करता है। यहाँ एक चित्रण वीडियो है

ट्रैक एक अंतहीन सुरंग होना चाहिए जो 3 डी तख़्ता के साथ स्वीप करता है, जिसमें कुछ बाधाएं डाली जाती हैं। मेरा अब तक का सबसे अच्छा विचार है कि तख़्ता के साथ एक सर्कल आकार को लुप्त करना।

मैं कुछ पॉइंटर्स को यह भी बताना चाहूंगा कि ज्यामिति का प्रबंधन कैसे किया जाता है अर्थात मचान ऑपरेशन से इसे कैसे बनाया जाए, स्मृति, टकराव और बनावट में इसके 'जीवनचक्र' का प्रबंधन करें।


1
बहुत ज्यादा proun तरह लग रहा है: proun-game.com । यदि कोई कॉपीराइट समस्याएँ नहीं हैं, तो आपको इस गेम के लेखक से अच्छा जवाब मिल सकता है। : आप अपने जानकारी यहाँ प्राप्त कर सकते blog.oogst3d.net
वाइट फाल्कन

हाँ, मैं उस के बारे में सोच रहा था - tnx!
वैलेंटाइन गैलिया

जवाबों:


5

मुझे यकीन नहीं है कि आप किस भाषा में काम कर रहे हैं, लेकिन यहां स्थित यूनिटी 3 डी के लिए एक प्रक्रियात्मक जाल बाहर निकालना उदाहरण है:

http://unity3d.com/support/resources/example-projects/procedural-examples

मुझे यकीन है कि आप कोड को देख सकते हैं और इसे अपनी स्थिति के लिए फिर से काम कर सकते हैं।

संपादित करें: मैं एक ऐसे खेल पर काम कर रहा हूं जो एक प्रक्रियात्मक एक्सट्रूडेड रेल प्रणाली का उपयोग करता है जैसे आप शुरू कर रहे हैं लेकिन यह Un # 3 डी में C # में है। मैं आपको एक अवलोकन दूंगा कि कैसे मैं क्यूबिक बेज़ियर पथ के आधार पर अपने रेल एक्सट्रूज़न का निर्माण करता हूं, हालांकि रेल का जाल प्रक्रियात्मक रूप से उत्पन्न होता है, यह बेजियर पथ पर आधारित है जिसे मैं एक संपादक में समय से पहले परिभाषित करता हूं। यह आपके खेल के मामले में एक स्तर के संपादक की तरह होगा, मेरे मामले में, यह पिनबॉल टेबल डिजाइन कर रहा है। नीचे सूचीबद्ध एक उदाहरण है कि मैं यह कैसे कर रहा हूं:

1.) एक बेजियर पाथ क्लास का निर्माण / ढूँढें और उसे लागू करें। यह आपको अपने जाल बाहर निकालना के लिए स्रोत डेटा देगा। C # में एक है जिसे आप c ++ में पोर्ट कर सकते हैं।

http://forum.unity3d.com/threads/32954-Waypoints-and-constant-variable-speed-problems?p=213942

2.) एक बार जब आप एक बेज़ियर पथ बना लेते हैं, तो इस पथ के डेटा बिंदुओं का नमूना लिया जाता है। यह ऊपर दिए गए वर्ग पर इंटरप विधि के माध्यम से किया जा सकता है। यह आपको बेज़ियर पथ के साथ वेक्टर 3 बिंदुओं की एक सूची / सरणी देगा।

3.) स्टेप 2 से वेक्टर 3 बेज़ियर पथ डेटा को परिवर्तित करने के लिए एक हेल्पर क्लास बनाएं। इस मामले में, मेरे पास एक साधारण वर्ग है जिसे एक्सट्रूडेडट्रैलाइसेशन कहा जाता है जैसा कि नीचे परिभाषित किया गया है:

public class ExtrudedTrailSection
{
    public Vector3 point;
    public Matrix4x4 matrix;
    public float time;

    public ExtrudedTrailSection() { }
}

4.) अपने वेक्टर 3 नमूना डेटा के माध्यम से Iterate करें और इसे नमूना डेटा और एक आधार मैट्रिक्स के साथ आपूर्ति करने वाले ExtrudedTrailSections की एक सरणी में परिवर्तित करें जो आपके एक्सट्रूडेड मेष का मूल स्थान होगा।

  1. निम्नलिखित कोड का उपयोग करके अंतिम मैट्रिक्स 4x4 [] की एक सरणी बनाने के लिए ExtrudedTrailSections के सरणी का उपयोग करें:

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.) अब जब हमारे पास एक रेडियल फेस मेष के लिए किनारे और केंद्र डेटा है, तो आप अपने डेटा का उपयोग करके एक मेष ऑब्जेक्ट का निर्माण कर सकते हैं। मेष में अंतिम शीर्ष केंद्र बिंदु है जिसकी हमने गणना की है। अंतिम जाल सिर्फ एक चेहरा है जो मेष एक्सट्रूज़न विधि को आपूर्ति किया जाता है जिसे मैंने एकता पैकेज के प्रोसीड्यूरल मेष एक्सट्रूज़न वर्ग में एक उदाहरण प्रदान किया है। फिर से, यह मेरी विधि है और जाहिर है कि आपको इस डेटा को ओपनजीएल में फीड करना होगा। यदि आपके पास एक 3 डी उपयोगिता पुस्तकालय है जिसे आप उपयोग कर रहे हैं या अपनी खुद की मेष कक्षा लिख ​​सकते हैं, तो यह संभवतः आपके अंतिम 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;
}

मेरे मामले में अंतिम आउटपुट इस तरह दिखता है ..

यहाँ छवि विवरण दर्ज करें

सौभाग्य, आपका खेल वास्तव में अच्छा लग रहा है! मुझे पता है अगर तुम यह पता लगाने?

चक


मुझे मुख्य रूप से ओपनजीएल और सी ++ में दिलचस्पी है, लेकिन 'स्यूडोकोड' को भी मदद करनी चाहिए :)
वैलेंटाइन गैला

मैंने अपने मूल पोस्ट को अपडेट किया है जिसमें एक समाधान शामिल है जिसे मैंने अभी पूरा किया है।
चक डी
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.