আমি কীভাবে একটি স্প্লাইন থেকে 3 ডি রেস ট্র্যাক তৈরি করতে পারি?


9

আমি একটি স্প্লাইনের চারপাশে একটি ত্রি-মাত্রিক রেস ট্র্যাক উত্পন্ন করতে চাই যা এর আকৃতিটি বর্ণনা করে। এখানে একটি চিত্রণমূলক ভিডিও

ট্র্যাকটি একটি অন্তহীন টানেল হওয়া উচিত যা 3 ডি স্প্লাইন বয়ে বেড়াতে পারে এবং কিছু প্রতিবন্ধকতা ফেলে দেওয়া হয় My আমার এখন পর্যন্ত সেরা ধারণাটি স্প্লাইন বরাবর একটি বৃত্তের আকারটি oftালাই করা হয়েছে।

আমি জ্যামিতিটি কীভাবে পরিচালনা করতে হবে অর্থাৎ লফট অপারেশন থেকে কীভাবে এটি তৈরি করতে হবে, স্মৃতি, সংঘর্ষ এবং টেক্সচারে এর 'লাইফিসাইকেল' পরিচালনা করতে হবে তার কয়েকটি পয়েন্টারও আমি চাই।


1
দেখতে অনেকটা প্রানের মতো: proun-game.com । যদি কোনও কপিরাইট সমস্যা না থাকে তবে আপনি এই গেমটির লেখকের কাছ থেকে একটি ভাল উত্তর পেতে পারেন। আপনি তার তথ্য এখানে পেতে পারেন: blog.oogst3d.net
ভাইট ফ্যালকন

হ্যাঁ আমি সে সম্পর্কে ভাবছিলাম - টিএনএক্স!
ভ্যালেন্টিন গেলা

উত্তর:


5

আপনি কোন ভাষায় কাজ করছেন তা আমি নিশ্চিত নই তবে এখানে অবস্থিত ইউনিটি 3 ডি এর জন্য একটি পদ্ধতিগত জাল এক্সট্রুশন উদাহরণ রয়েছে:

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

আমি নিশ্চিত আপনি কোডটি দেখতে এবং এটি আপনার পরিস্থিতির জন্য পুনরায় কাজ করতে পারে।

সম্পাদনা: আমি এমন একটি গেমের সাথে কাজ করছি যা আপনি শুরু করছেন এমন পদ্ধতিগত এক্সট্রুডেড রেল সিস্টেম ব্যবহার করে তবে এটি ইউনিটি 3 ডি তে সি # তে রয়েছে। আমি কিউবিক বেজিয়ার পাথের উপর ভিত্তি করে কীভাবে আমার রেল এক্সট্রুশন তৈরি করব তার একটি সংক্ষিপ্ত বিবরণ দেব যাতে রেলের জাল প্রক্রিয়াগতভাবে উত্পন্ন হয়, এটি বেজিয়ার পথের উপর ভিত্তি করে আমি একটি সম্পাদকের আগে সময়ের সংজ্ঞা দিয়েছি। এটি আপনার গেমের ক্ষেত্রে কোনও স্তরের সম্পাদকের মতো হবে, আমার ক্ষেত্রে এটি পিনবল টেবিলগুলি ডিজাইন করছে। আমি এটি কীভাবে করছি তার উদাহরণ নীচে তালিকাভুক্ত করা হল:

1.) বেজিয়ার পাথ ক্লাস তৈরি / সন্ধান করুন এবং প্রয়োগ করুন। এটি আপনাকে আপনার জাল এক্সট্রুশনের উত্স ডেটা দেবে। এখানে সি # তে একটি রয়েছে যা আপনি সি ++ তে পোর্ট করতে পারেন।

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

২) আপনার একবার বেজিয়ার পাথ তৈরি হয়ে গেলে, এই পথ থেকে ডেটা পয়েন্টগুলি নমুনা দেওয়া হয়। উপরের সরবরাহ করা ক্লাসে ইন্টারপ পদ্ধতিতে এটি করা যেতে পারে। এটি আপনাকে বেজিয়ার পথ ধরে ভেক্টর 3 পয়েন্টের একটি তালিকা / অ্যারে দেবে।

৩) ভেক্টর ৩ বেজিয়ার পাথ ডেটা ২ য় ধাপ থেকে রূপান্তর করতে একটি সহায়ক শ্রেণি তৈরি করুন এই ক্ষেত্রে, আমার নীচের সংজ্ঞায়িত হিসাবে এক্সট্রুডেড ট্রেলসেকশন নামে একটি সাধারণ ক্লাস রয়েছে:

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

    public ExtrudedTrailSection() { }
}

৪) আপনার ভেক্টর ৩ নমুনা ডেটার মধ্য দিয়ে ইটারেট করুন এবং এক্সট্রুডড ট্রাইলসেকশনগুলির একটি অ্যারে রূপান্তর করুন এটি স্যাম্পল ডেটা এবং একটি বেস ম্যাট্রিক্স সরবরাহ করে যা আপনার এক্সট্রুড জালের মূল অবস্থান হবে।

  1. ) নিম্নলিখিত কোড ব্যবহার করে চূড়ান্ত ম্যাট্রিক্স 4x4 [] এর অ্যারে তৈরি করতে এক্সট্রুডেড ট্রাইলসেকশনের অ্যারে ব্যবহার করুন:

ম্যাট্রিক্স 4 এক্স 4 ওয়ার্ল্ডটলোকাল = রুট ট্রান্সফর্ম.ওয়ার্ল্ডটোলোকালামাত্রিক্স;

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

).) এখন আপনার কাছে ম্যাট্রিক্স ৪x৪ এর একটি অ্যারে রয়েছে এবং আপনি একটি জাল ফেলতে পারেন তবে প্রথমে আমাদের বের করার জন্য একটি রেফারেন্স জাল প্রয়োজন। আমার কাছে একটি ইউটিলিটি ক্লাস রয়েছে যা একটি বৃত্তাকার জাল মুখ তৈরি করবে যা আমরা জাল এক্সট্রুশন পদ্ধতিতে সরবরাহ করব।

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

)) এই ডেটার কেন্দ্রটি সন্ধান করুন:

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

৮) এখন আমাদের কাছে রেডিয়াল ফেস জালটির প্রান্ত এবং কেন্দ্রের ডেটা রয়েছে, আপনি নিজের ডেটা ব্যবহার করে একটি জাল বস্তুটি তৈরি করতে পারেন। জালটিতে চূড়ান্ত শীর্ষটি হল আমাদের গণনা করা কেন্দ্র পয়েন্ট। চূড়ান্ত জাল কেবল এমন একটি মুখ যা আমি জাল এক্সট্রুশন পদ্ধতিতে সরবরাহ করি যা আমি ইউনিটি প্যাকেজের প্রসিডুয়াল জাল এক্সট্রুশন শ্রেণিতে একটি উদাহরণ সরবরাহ করেছি। আবার এটি আমার পদ্ধতি এবং স্পষ্টতই আপনাকে এই ডেটা ওপেনগিএলে ফিড করতে হবে। আপনি যদি একটি 3 ডি ইউটিলিটি লাইব্রেরি ব্যবহার করেন যা আপনি ব্যবহার করছেন বা নিজের জাল ক্লাসটি লিখতে পারেন তবে সম্ভবত আপনার চূড়ান্ত এক্সট্রুডেড জাল জেনারেট করা আরও ভাল কাজ করবে কারণ এই ডেটা রেন্ডারিংয়ের জন্য ওপেনগল দ্বারা সত্যই প্রয়োজন নেই। এই মুখের জালটি কেবল জাল ছাড়ার জন্য রেফারেন্স হিসাবে ব্যবহৃত হয়।

    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.) জাল এক্সট্রুশন পদ্ধতির দ্বারা প্রয়োজনীয় হিসাবে বিজ্ঞপ্তি জালটির বাইরের প্রান্তগুলি সন্ধান করুন। আবার, এই কোডটি 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[];
}

১০.) জাল এক্সট্রুশন পদ্ধতিতে এই সমস্ত ডেটা ফিড করুন ..

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

আমার ক্ষেত্রে চূড়ান্ত আউটপুটটি দেখতে এরকম দেখাচ্ছে ..

এখানে চিত্র বর্ণনা লিখুন

শুভকামনা, আপনার খেলাটি দুর্দান্ত দেখায়! আপনি যদি এটি খুঁজে বের করতে আমাকে জানাবেন?

প্রি়


আমি প্রাথমিকভাবে ওপেনগিএল এবং সি ++ তে আগ্রহী, তবে 'সিউডোকোড' এও সহায়তা করা উচিত :)
ভ্যালেন্টিন গালিয়া

আমি স্রেফ সম্পূর্ণ করেছি এমন একটি সমাধান অন্তর্ভুক্ত করার জন্য আমি আমার মূল পোস্টটি আপডেট করেছি।
চক ডি
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.