গোলক তৈরির জন্য অ্যালগরিদম?


27

laঅক্ষাংশ রেখার loপরিমাণ, দ্রাঘিমাংশ রেখার পরিমাণ এবং একটি ব্যাসার্ধের পরিমাণের সাথে কার্যত গোলক তৈরির জন্য কারও কি অ্যালগরিদম আছে r? ইউনিটির সাথে কাজ করার জন্য আমার এটি দরকার, সুতরাং ভার্টেক্স অবস্থানগুলি সংজ্ঞায়িত করা দরকার এবং তারপরে সূচিগুলির মাধ্যমে আরও ত্রিভুজগুলি সংজ্ঞায়িত করা হবে ( আরও তথ্য )।


সম্পাদনা

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

আমি কোডটি unityক্যে কাজ করতে সক্ষম হয়েছি। তবে আমি মনে করি আমি হয়ত কিছু ভুল করেছি। আমি যখন সক্রিয় করি তখন detailLevelএগুলি কেবল চারপাশে না ঘুরে আরও বেশি শীর্ষে এবং বহুভুজ যুক্ত করা হয়। আমি কি কিছু ভুলে গেছি?


সম্পাদনা 2

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

আমি জালটিকে স্বাভাবিক অবস্থায় বানাতে চেষ্টা করেছি। এই যে আমি পেয়েছিলাম। আমি মনে করি আমি কিছু মিস করছি। আমার কি কিছু নির্দিষ্ট নরমাল স্কেল করার কথা রয়েছে?


1
বিদ্যমান ওপেন সোর্স বাস্তবায়ন এটি কী করে তা আপনি কেন দেখেন না? উদাহরণস্বরূপ, থ্রি.জেএস কীভাবে এটি মেস ব্যবহার করে তা দেখুন ।
brice

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

1
আপনি মহকুমার পরে ভারটেক্স অবস্থানগুলি স্বাভাবিক করছেন না normal আমি সেই অংশটি আমার উদাহরণে অন্তর্ভুক্ত করি নি। সাধারণকরণগুলি সেগুলি কেন্দ্র থেকে সমস্তকে সামঞ্জস্যপূর্ণ করে তোলে, যা আপনি খুঁজছেন এমন বক্ররেখা তৈরি করে।
ডিভে

আইকোসহেড্রনের কেন্দ্রে একটি বেলুনকে স্ফীত করে দেওয়ার কথা ভাবুন। বেলুনটি আমাদের জালকে ধাক্কা দিলে এটি বেলুন (গোলক) এর আকারের সাথে মেলে।
ডিভে

4
"নরমালাইজিং" এর অর্থ একটি ভেক্টরের দৈর্ঘ্য 1 নির্ধারণ করা You আপনার মতো কিছু করা দরকার vertices[i] = normalize(vertices[i])। ঘটনাচক্রে, এটি আপনাকে আপনার নতুন, সঠিক নরমালও দেয়, সুতরাং আপনার normals[i] = vertices[i]পরে এটি করা উচিত ।
সাম হোচেভার

উত্তর:


31

এরকম কিছু পেতে:

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

একটি গোলক (নীচের কোড দেখুন) পেতে মুখগুলিকে উপ-বিভাগ করুন এবং একটি আইকোশেড্রন তৈরি করুন (20-তরফা নিয়মিত কঠিন) Create

ধারণাটি মূলত:

  • একটি নিয়মিত এন-হেড্রন তৈরি করুন (এমন একটি দৃ where় যেখানে প্রতিটি মুখ একই আকারের হয়)। আমি একটি আইকোশেড্রন ব্যবহার করি কারণ এটি সর্বাধিক সংখ্যক মুখের সাথে শক্ত যেখানে প্রতিটি মুখ একই আকার। (এর বাইরেও কোথাও এর প্রমাণ রয়েছে Google গুগলে নিখরচায় যদি আপনি কৌতূহলী হন)) এটি আপনাকে এমন একটি গোলক দেবে যেখানে প্রায় প্রতিটি মুখ সমান হয়, টেক্সচারটি একটু সহজ করে তোলে।

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

  • প্রতিটি মুখকে সমান আকারের চারটি মুখের মধ্যে ভাগ করুন। প্রতিবার আপনি এটি করবেন, এটি মডেলের মুখগুলির সংখ্যা চতুর্থাংশ করবে।

    ///      i0
    ///     /  \
    ///    m02-m01
    ///   /  \ /  \
    /// i2---m12---i1

i0,, i1এবং i2মূল ত্রিভুজটির শীর্ষবিন্দু। (প্রকৃতপক্ষে, ভারটিেক্স বাফারে সূচকগুলি, তবে এটি অন্য একটি বিষয়)। m01প্রান্তটির মধ্যবিন্দু (i0,i1), এম 12 হ'ল প্রান্তের মধ্যবিন্দু (i1,12)এবং m02স্পষ্টতই, প্রান্তটির মধ্যবিন্দু (i0,i2)

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

  • আপনি আপনার কিউবের জন্য পছন্দসই সংখ্যক মুখগুলি না পৌঁছা পর্যন্ত পুনরাবৃত্তি করুন।

  • আপনার কাজ শেষ হয়ে গেলে, পৃষ্ঠটি মসৃণ করতে সমস্ত শীর্ষেকে স্বাভাবিক করুন। আপনি যদি এটি না করেন তবে আপনি একটি গোলকের পরিবর্তে একটি উচ্চ-রেসকিউ আইসোশেড্রন পাবেন।

  • ভাল খবর! তুমি করেছ. ফলাফল ভেক্টর এবং সূচক বাফারগুলিকে একটি VertexBufferএবং এ রূপান্তর করুন IndexBufferএবং এর সাথে আঁকুন Device.DrawIndexedPrimitives()

মডেলটি তৈরি করতে আপনি আপনার "গোলক" শ্রেণিতে যা ব্যবহার করবেন তা এখানে রয়েছে (এক্সএনএ ডেটাটাইপস এবং সি #, তবে এটি বেশ পরিষ্কার হওয়া উচিত):

        var vectors = new List<Vector3>();
        var indices = new List<int>();

        GeometryProvider.Icosahedron(vectors, indices);

        for (var i = 0; i < _detailLevel; i++)
            GeometryProvider.Subdivide(vectors, indices, true);

        /// normalize vectors to "inflate" the icosahedron into a sphere.
        for (var i = 0; i < vectors.Count; i++)
            vectors[i]=Vector3.Normalize(vectors[i]);

এবং GeometryProviderক্লাস

public static class GeometryProvider
{

    private static int GetMidpointIndex(Dictionary<string, int> midpointIndices, List<Vector3> vertices, int i0, int i1)
    {

        var edgeKey = string.Format("{0}_{1}", Math.Min(i0, i1), Math.Max(i0, i1));

        var midpointIndex = -1;

        if (!midpointIndices.TryGetValue(edgeKey, out midpointIndex))
        {
            var v0 = vertices[i0];
            var v1 = vertices[i1];

            var midpoint = (v0 + v1) / 2f;

            if (vertices.Contains(midpoint))
                midpointIndex = vertices.IndexOf(midpoint);
            else
            {
                midpointIndex = vertices.Count;
                vertices.Add(midpoint);
                midpointIndices.Add(edgeKey, midpointIndex);
            }
        }


        return midpointIndex;

    }

    /// <remarks>
    ///      i0
    ///     /  \
    ///    m02-m01
    ///   /  \ /  \
    /// i2---m12---i1
    /// </remarks>
    /// <param name="vectors"></param>
    /// <param name="indices"></param>
    public static void Subdivide(List<Vector3> vectors, List<int> indices, bool removeSourceTriangles)
    {
        var midpointIndices = new Dictionary<string, int>();

        var newIndices = new List<int>(indices.Count * 4);

        if (!removeSourceTriangles)
            newIndices.AddRange(indices);

        for (var i = 0; i < indices.Count - 2; i += 3)
        {
            var i0 = indices[i];
            var i1 = indices[i + 1];
            var i2 = indices[i + 2];

            var m01 = GetMidpointIndex(midpointIndices, vectors, i0, i1);
            var m12 = GetMidpointIndex(midpointIndices, vectors, i1, i2);
            var m02 = GetMidpointIndex(midpointIndices, vectors, i2, i0);

            newIndices.AddRange(
                new[] {
                    i0,m01,m02
                    ,
                    i1,m12,m01
                    ,
                    i2,m02,m12
                    ,
                    m02,m01,m12
                }
                );

        }

        indices.Clear();
        indices.AddRange(newIndices);
    }

    /// <summary>
    /// create a regular icosahedron (20-sided polyhedron)
    /// </summary>
    /// <param name="primitiveType"></param>
    /// <param name="size"></param>
    /// <param name="vertices"></param>
    /// <param name="indices"></param>
    /// <remarks>
    /// You can create this programmatically instead of using the given vertex 
    /// and index list, but it's kind of a pain and rather pointless beyond a 
    /// learning exercise.
    /// </remarks>

    /// note: icosahedron definition may have come from the OpenGL red book. I don't recall where I found it. 
    public static void Icosahedron(List<Vector3> vertices, List<int> indices)
    {

        indices.AddRange(
            new int[]
            {
                0,4,1,
                0,9,4,
                9,5,4,
                4,5,8,
                4,8,1,
                8,10,1,
                8,3,10,
                5,3,8,
                5,2,3,
                2,7,3,
                7,10,3,
                7,6,10,
                7,11,6,
                11,0,6,
                0,1,6,
                6,1,10,
                9,0,11,
                9,11,2,
                9,2,5,
                7,2,11 
            }
            .Select(i => i + vertices.Count)
        );

        var X = 0.525731112119133606f;
        var Z = 0.850650808352039932f;

        vertices.AddRange(
            new[] 
            {
                new Vector3(-X, 0f, Z),
                new Vector3(X, 0f, Z),
                new Vector3(-X, 0f, -Z),
                new Vector3(X, 0f, -Z),
                new Vector3(0f, Z, X),
                new Vector3(0f, Z, -X),
                new Vector3(0f, -Z, X),
                new Vector3(0f, -Z, -X),
                new Vector3(Z, X, 0f),
                new Vector3(-Z, X, 0f),
                new Vector3(Z, -X, 0f),
                new Vector3(-Z, -X, 0f) 
            }
        );


    }



}

দুর্দান্ত উত্তর। ধন্যবাদ। আমি বলতে পারছি না তবে কি এই codeক্য কোড? ওহ, এবং যতক্ষণ না আমি রেজোলিউশনটি সেট করতে পারি ততক্ষণ / ল্যাটের বিষয়টি বিবেচ্য নয়।
ড্যানিয়েল পেন্ডারগাস্ট

এটি ইউনিটি (এক্সএনএ) নয় তবে এটি আপনাকে শীর্ষবিন্দু স্থানাঙ্ক এবং সূচি তালিকা দেবে। Ectorক্য সমতুল্য যা কিছু তা দিয়ে ভেক্টর 3 প্রতিস্থাপন করুন। আপনি সাবডিভাইড পুনরাবৃত্তির সংখ্যা সামঞ্জস্য করে রেজোলিউশন সেট করেছেন। প্রতিটি লুপ মুখের সংখ্যা 4 দ্বারা গুণ করে 2 বা 3 বা পুনরাবৃত্তি একটি সুন্দর গোলক দেবে।
ডিভে

আহ আমি দেখি. এটি ইউনিটি সি # তে প্রায় অভিন্ন। মাত্র কয়েকটি প্রশ্ন ... সূচকগুলি যখন সংজ্ঞায়িত করা হয় তখন আপনি এগুলি একটি intঅ্যারের ভিতরে রেখে দেন ? এবং কি করে .Select(i => i + vertices.Count)?
ড্যানিয়েল পেন্ডারগাস্ট

.Select(i => i + vertices.Count)এ সব আমার জন্য কাজ করে না। এটি কি কেবল এক্সএনএ বৈশিষ্ট্যযুক্ত?
ড্যানিয়েল পেন্ডারগাস্ট

1
নিশ্চিত করুন যে আপনি 'সিস্টেম.লিনক ব্যবহার করছেন' যেমন এটি সংজ্ঞায়িত করেছে। নির্বাচন করুন, ইত্যাদি
ডিভে

5

আসুন আমরা একটি গোলকের প্যারামেট্রিক সংজ্ঞা বিবেচনা করি:

একটি গোলকের প্যারামেট্রিক সংজ্ঞা

যেখানে থেটা এবং Phi দুই নয়, কোণ বৃদ্ধিশীল আমরা যেমন উল্লেখ করব var tএবং var uএবং Rx, Ry এবং Rz স্বাধীন ব্যাসার্ধ (radiuses) সমস্ত তিনটি কার্টিজিয়ান নির্দেশাবলী মধ্যে, যা, একটি গোলক ক্ষেত্রে, একটি একক হিসেবে সংজ্ঞায়িত করা হবে ব্যাসার্ধ var rad

আসুন এখন এই বিষয়টি বিবেচনা করুন যে ...প্রতীকটি একটি পুনরাবৃত্তি নির্দেশ করে যা লুপের ব্যবহারকে ইঙ্গিত দেয়। "আপনি কতবার পুনরাবৃত্তি করবেন" এর ধারণা stacksএবং rowsএটি। যেহেতু প্রতিটি পুনরাবৃত্তি টি টি বা ইউ এর মান যুক্ত করে, তত বেশি পুনরাবৃত্তি হয়, তত কম মান হয়, সুতরাং গোলকের বক্রতা আরও নিখুঁত হয়।

'গোলক অঙ্কন' ফাংশনের পূর্বশর্ত নিম্নলিখিত দেওয়া পরামিতি আছে হল: int latitudes, int longitudes, float radius। পোস্টের শর্তাদি (আউটপুট) হ'ল ফিরতে হয়, বা গণনা করা শীর্ষকোষ প্রয়োগ করে। আপনি এটি কীভাবে ব্যবহার করতে চান তার উপর নির্ভর করে ফাংশনটি vector3(ত্রিমাত্রিক ভেক্টর) একটি অ্যারে প্রদান করতে পারে বা আপনি যদি সংস্করণ ২.০ এর আগে কিছু সরল ওপেনএল ব্যবহার করছেন, আপনি সরাসরি প্রসঙ্গে প্রান্তটি প্রয়োগ করতে চাইতে পারেন।

এনবি ওপেনজিএলে একটি শীর্ষবিন্দু প্রয়োগ করে নীচের ফাংশনটি কল করছে glVertex3f(x, y, z)। আমরা যেখানে শীর্ষে অবস্থান করব সেখানে আমরা vector3(x, y, z)সহজেই সংরক্ষণের জন্য একটি নতুন যুক্ত করব ।

এছাড়াও, আপনি যেভাবে অক্ষাংশ এবং দ্রাঘিমাংশ সিস্টেমকে কাজ করার জন্য অনুরোধ করেছেন তার জন্য গোলকের সংজ্ঞা (মূলত জেড এবং ওয়াই স্যুইচ করা) এর একটি সমন্বয় প্রয়োজন, তবে এটি কেবল এটিই দেখায় যে সংজ্ঞাটি খুব মারাত্মক, এবং আপনি চারপাশে পরিবর্তন করতে মুক্ত হন গোলকটি আঁকানো দিকটি (যেখানে অক্ষাংশ এবং দ্রাঘিমাংশ হয়) পরিবর্তনের জন্য x, y এবং z পরামিতি।

এখন আসুন আমরা কীভাবে অক্ষাংশ এবং দ্রাঘিমাংশ করতে চলেছি তা দেখুন। অক্ষাংশগুলি চলক দ্বারা প্রতিনিধিত্ব করা হয় u, তারা 0 থেকে 2π রেডিয়ান (360 ডিগ্রি) থেকে পুনরাবৃত্তি করে। অতএব আমরা এর পুনরাবৃত্তিটি এর মতো কোড করতে পারি:

float latitude_increment = 360.0f / latitudes;

for (float u = 0; u < 360.0f; u += latitude_increment) {
    // further code ...
}

দ্রাঘিমাংশটি চলক দ্বারা প্রতিনিধিত্ব করা হয় tএবং 0 থেকে π (180 ডিগ্রি) এর জন্য পুনরাবৃত্তি হয়। অতএব নিম্নলিখিত কোডটি আগেরটির মতো দেখায়:

float latitude_increment = 360.0f / latitudes;
float longitude_increment = 180.0f / longitudes;

for (float u = 0; u <= 360.0f; u += latitude_increment) {
    for (float t = 0; t <= 180.0f; t += longitude_increment) {
        // further code ...
    }
}

(নোট যে লুপ হয় সমেত , সেখানে টার্মিনাল অবস্থার কারণ স্থিতিমাপ ইন্টিগ্রেশন জন্য বিরতি 2π 0 থেকে হয় সমেত । যদি আপনার অবস্থার অ-সমেত আপনি একটি আংশিক গোলক পাবেন।)

এখন, গোলকের সরল সংজ্ঞা অনুসরণ করে আমরা নিম্নলিখিত পরিবর্তনগুলি সংজ্ঞায়িত করতে পারি (অনুমান float rad = radius;):

float x = (float) (rad * Math.sin(Math.toRadians(t)) * Math.sin(Math.toRadians(u)));
float y = (float) (rad * Math.cos(Math.toRadians(t)));
float z = (float) (rad * Math.sin(Math.toRadians(t)) * Math.cos(Math.toRadians(u)));

আরও একটি গুরুত্বপূর্ণ সতর্কতা! বেশিরভাগ ক্ষেত্রে আপনি ওপেনজিএল এর কিছু ফর্ম ব্যবহার করবেন, এবং তা না হলেও, আপনার এখনও এটি করার প্রয়োজন হতে পারে। ত্রি-মাত্রিক একটি অবজেক্টের সংজ্ঞায়িত করার জন্য বেশ কয়েকটি সূচকের প্রয়োজন। এটি সাধারণত পরের প্রান্তিকটি গণনাযোগ্য করে সরবরাহ করে providing

একটি (আদিম) আকৃতি নির্ধারণ করতে একাধিক শীর্ষকে কীভাবে ব্যবহার করা হয়

উপরের চিত্রটিতে বিভিন্ন স্থানাঙ্কগুলি কীভাবে রয়েছে x+∂এবং y+∂আমরা সহজেই যে কোনও পছন্দসই ব্যবহারের জন্য অন্য তিনটি শীর্ষ কোণ তৈরি করতে পারি। অন্যান্য অনুভূমিকাগুলি (অনুমান float rad = radius;):

float x = (float) (rad * Math.sin(Math.toRadians(t + longitude_increment)) * Math.sin(Math.toRadians(u)));
float y = (float) (rad * Math.cos(Math.toRadians(t + longitude_increment)));
float z = (float) (rad * Math.sin(Math.toRadians(t + longitude_increment)) * Math.cos(Math.toRadians(u)));

float x = (float) (rad * Math.sin(Math.toRadians(t)) * Math.sin(Math.toRadians(u + latitude_increment)));
float y = (float) (rad * Math.cos(Math.toRadians(t)));
float z = (float) (rad * Math.sin(Math.toRadians(t)) * Math.cos(Math.toRadians(u + latitude_increment)));

float x = (float) (rad * Math.sin(Math.toRadians(t + longitude_increment)) * Math.sin(Math.toRadians(u + latitude_increment)));
float y = (float) (rad * Math.cos(Math.toRadians(t + longitude_increment)));
float z = (float) (rad * Math.sin(Math.toRadians(t + longitude_increment)) * Math.cos(Math.toRadians(u + latitude_increment)));

পরিশেষে, এখানে একটি কার্যকরী পূর্ণ ফাংশন যা একটি গোলকের সমস্ত অনুভূতি ফেরত দেবে, এবং দ্বিতীয়টি কোডটির একটি কার্যকরী ওপেনজিএল বাস্তবায়ন দেখায় (এটি সি-স্টাইলের বাক্য গঠন এবং জাভাস্ক্রিপ্ট নয়, এটি সমস্ত সি-স্টাইলের ভাষাগুলির সাথে কাজ করা উচিত, ইউনিটি ব্যবহার করার সময় সি # সহ))

static Vector3[] generateSphere(float radius, int latitudes, int longitudes) {

    float latitude_increment = 360.0f / latitudes;
    float longitude_increment = 180.0f / longitudes;

    // if this causes an error, consider changing the size to [(latitude + 1)*(longitudes + 1)], but this should work.
    Vector3[] vertices = new Vector3[latitude*longitudes];

    int counter = 0;

    for (float u = 0; u < 360.0f; u += latitude_increment) {
        for (float t = 0; t < 180.0f; t += longitude_increment) {

            float rad = radius;

            float x = (float) (rad * Math.sin(Math.toRadians(t)) * Math.sin(Math.toRadians(u)));
            float y = (float) (rad * Math.cos(Math.toRadians(t)));
            float z = (float) (rad * Math.sin(Math.toRadians(t)) * Math.cos(Math.toRadians(u)));

            vertices[counter++] = new Vector3(x, y, z);

        }
    }

    return vertices;

}

ওপেনজিএল কোড:

static int createSphereBuffer(float radius, int latitudes, int longitudes) {

    int lst;

    lst = glGenLists(1);

    glNewList(lst, GL_COMPILE);
    {

        float latitude_increment = 360.0f / latitudes;
        float longitude_increment = 180.0f / longitudes;

        for (float u = 0; u < 360.0f; u += latitude_increment) {

            glBegin(GL_TRIANGLE_STRIP);

            for (float t = 0; t < 180.0f; t += longitude_increment) {

                float rad = radius;

                float x = (float) (rad * Math.sin(Math.toRadians(t)) * Math.sin(Math.toRadians(u)));
                float y = (float) (rad * Math.cos(Math.toRadians(t)));
                float z = (float) (rad * Math.sin(Math.toRadians(t)) * Math.cos(Math.toRadians(u)));

                vertex3f(x, y, z);

                float x1 = (float) (rad * Math.sin(Math.toRadians(t + longitude_increment)) * Math.sin(Math.toRadians(u + latitude_increment)));
                float y1 = (float) (rad * Math.cos(Math.toRadians(t + longitude_increment)));
                float z1 = (float) (rad * Math.sin(Math.toRadians(t + longitude_increment)) * Math.cos(Math.toRadians(u + latitude_increment)));

                vertex3f(x1, y1, z1);

            }

            glEnd();

        }

    }
    glEndList()

    return lst;

}

// to render VVVVVVVVV

// external variable in main file
static int sphereList = createSphereBuffer(desired parameters)

// called by the main program
void render() {

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glCallList(sphereList);

    // any additional rendering and buffer swapping if not handled already.

}

পিএস আপনি এই বিবৃতি লক্ষ্য করতে পারে rad = radius;। এটি অবস্থান বা কোণের ভিত্তিতে ব্যাসার্ধটিকে লুপে পরিবর্তিত করতে দেয়। এর অর্থ হ'ল আপনি গোলকের গোলমালের জন্য গোলমালটি প্রয়োগ করতে পারেন, যদি এটি পছন্দসই প্রভাবটি গ্রহের মতো একটি হয় তবে এটি আরও প্রাকৃতিক দেখায়। যেমনfloat rad = radius * noise[x][y][z];

ক্লদ-হেনরি।


লাইন `ফ্লোট জেড = (ফ্লোট) (রেড * ম্যাথ.সিন (ম্যাথ টোরেডিয়ানস (টি)) * ম্যাথকোসস (ম্যাথ টোরেডিয়ানস (ইউ)))` ভুল। আপনি ইতিমধ্যে একটি X, Y এর অনুমান সহ গণনা করেছেন rad। এখন আপনি একটি ত্রিভুজের একটি পা তৈরি করছেন, এবং বোঝাচ্ছেন যে ত্রিভুজটির অনুমানটিও রয়েছে rad। এটি কার্যকরভাবে আপনাকে একটি ব্যাসার্ধ দেয় rad * sqrt(2)
ডিভে

@ ডেভিডলাইভলি এটিকে নির্দেশ করার জন্য ধন্যবাদ, আমি এটি কিছুক্ষণ আগে লিখেছিলাম যাতে এর খারাপ বা এমনকি সম্পূর্ণ ভুল হলে আমি অবাক হই না।
ক্লোহেডেনারী

কয়েক বছর আগে থেকে আমার কোনও পোস্টে আমি যখন ভুল খুঁজে পাই তখন সর্বদা মজাদার। এটা হয়। :)
ডিভে

4

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

public static void makeSphere(float sphereRadius, Vector3f center, float heightStep, float degreeStep) {
    for (float y = center.y - sphereRadius; y <= center.y + sphereRadius; y+=heightStep) {
        double radius = SphereRadiusAtHeight(sphereRadius, y - center.y); //get the radius of the sphere at this height
        if (radius == 0) {//for the top and bottom points of the sphere add a single point
            addNewPoint((Math.sin(0) * radius) + center.x, y, (Math.cos(0) * radius) + center.z));
        } else { //otherwise step around the circle and add points at the specified degrees
            for (float d = 0; d <= 360; d += degreeStep) {
                addNewPoint((Math.sin(d) * radius) + center.x, y, (Math.cos(d) * radius) + center.z));
            }
        }
    }
}

public static double SphereRadiusAtHeight(double SphereRadius, double Height) {
    return Math.sqrt((SphereRadius * SphereRadius) - (Height * Height));
}

এখন এই কোডটি কেবল অক্ষাংশের জন্য পয়েন্ট তৈরি করবে। তবে দ্রাঘিমাংশের রেখাগুলি তৈরি করতে আপনি প্রায় একই কোডটি ব্যবহার করতে পারেন। আপনার প্রতিটি পুনরাবৃত্তির মধ্যে ঘোরানো এবং প্রতিটিটিতে একটি সম্পূর্ণ বৃত্ত তৈরি করতে হবে degreeStep

দুঃখিত এটি একটি সম্পূর্ণ উত্তর বা ইউনিটি নির্দিষ্ট নয়, তবে আশা করি এটি আপনাকে শুরু করবে।


আপনার যদি দীর্ঘ / দীর্ঘ গোলকের প্রয়োজন হয় তবে এটি বেশ ভাল তবে আপনি শেষ ধাপ পর্যন্ত গোলাকার স্থানাঙ্কে কাজ করে এটি কিছুটা সহজ করতে পারেন।
ডিভে

1
ধন্যবাদ @ ডেভিড আমি সম্মত, আমি যদি গোলাকৃতির কর্ডগুলি ব্যবহার করে কোনও সংস্করণ লেখার চেষ্টা করি তবে আমি এটি এখানে পোস্ট করব।
মাইকেলহাউস

3

আপনি কেবল একটি সাধারণ আকার দিয়ে শুরু করতে পারেননি, মাঝখানে থেকে কোণে r দূরত্ব সহ একটি বাক্স হতে পারে। আরও বিশদ গোলক তৈরি করতে, সমস্ত বহুভুজকে উপ-বিভাগ করুন এবং তারপরে ভেক্টরকে তাদের বর্তমান অবস্থানের মধ্য দিয়ে রেখে কেন্দ্র থেকে দূরত্বের দিকে বের করে দিন।

আপনার স্বাদগুলির জন্য পর্যাপ্ত পরিমাণে গোলাকার না হওয়া পর্যন্ত পুনরাবৃত্তি করুন।


এটি মূলত আইকোসেহেড্রাল পদ্ধতির মতোই, কেবলমাত্র ভিন্ন শুরুর আকারের সাথে। আমি মনে করি না এমন ঘনক্ষেত্র দিয়ে শুরু করার একটি সুবিধা যা উল্লেখ করা হয়নি: আপনি একটি ঘনক্ষেত্র ব্যবহার করতে পারেন এবং জানেন যে আপনার টেক্সচার seams আপনার ক্ষেত্রের জালের প্রান্তগুলি দিয়ে পুরোপুরি সারিবদ্ধ হবে।
স্টিভেন স্টাডনিকি

@ স্টিভেনস্ট্যাডনিকিই কেবলমাত্র আমার কিউবসের সাথে সম্পর্কিত সমস্যাটি হ'ল কয়েকটি উপ-বিভাগের পরে মুখগুলি খুব আলাদা আকারের হয়ে যায়।
ডিভে

@ ডেভিডলাইভলি এটি কীভাবে আপনার উপ-বিভাগের উপর নির্ভর করে - আপনি যদি নিজের ঘনক্ষেত্রের বর্গক্ষেত্রগুলিকে একটি এমনকি গ্রিডে কাটা করেন এবং তারপরে বাহ্যিক / স্বাভাবিককরণ প্রজেক্ট করেন তবে এটি সত্য, তবে আপনি যদি নিজের মুখগুলি অ-অবিচ্ছিন্নভাবে গ্রিড করেন তবে আপনি আসলে এটি তৈরি করতে পারেন প্রজেকশনটি প্রান্তের আরাকের সাথে সমানভাবে ব্যবধান করা উচিত; এটি বেশ ভাল কাজ করে।
স্টিভেন স্টাডনিকি

পুনঃটুইট
ডিভে

@ এরিক জোহানসন বিটিডব্লিউ, একজন শিক্ষক হিসাবে আমি উল্লেখ করতে বাধ্য হতে পারি যে এটি এমন কোনও ব্যক্তির পক্ষে স্পষ্টত তাৎপর্যপূর্ণ অন্তর্দৃষ্টি, যা সম্ভবত মহকুমা পদ্ধতিটি আগে দেখা যায়নি। আপনি আগামী 12 ঘন্টা মানবতার প্রতি আমার বিশ্বাসকে নতুন করে তৈরি করেছেন।
ডিভে

2

আপনার কি আসলে 3 ডি জ্যামিতি বা কেবল আকারের প্রয়োজন?

আপনি একক কোয়াড ব্যবহার করে একটি 'নকল' গোলক তৈরি করতে পারেন। এটির উপরে কেবল একটি বৃত্ত রাখুন এবং এটি সঠিকভাবে শেড করুন। এটির সুবিধাটি হ'ল ক্যামেরা বা রেজোলিউশনের দূরত্ব নির্বিশেষে এর যথাযথ রেজোলিউশনের প্রয়োজন হবে।

এখানে একটি টিউটোরিয়াল আছে


1
দুর্দান্ত হ্যাক, তবে আপনার যদি এটি টেক্সচারের প্রয়োজন হয় তবে ব্যর্থ।
ডিভে

@ ডেভিডলাইভলি আপনার পৃথকভাবে বহুভুজগুলি টেক্সচার করার প্রয়োজন না হলে এটি প্রতি ঘূর্ণনের উপর ভিত্তি করে টেক্সচার কোঅর্ডিনেটগুলি গণনা করা সম্ভব।
ডেভিড সি বিশপ

@ ডেভিডসিবিশপ আপনার পৃষ্ঠার "লেন্সিং" এর জন্য অ্যাকাউন্ট করতে হবে - টেক্সেল কর্ডগুলি দৃষ্টিকোণের কারণে বৃত্তের সীমানার কাছাকাছি চেপে ধরতে হবে - যে মুহুর্তে আপনি ঘুরছেন। এছাড়াও, এর মধ্যে পিক্সেল শেডারটিতে আরও অনেক কাজ সঞ্চারিত রয়েছে যা ভার্টেক্স শ্যাডারে সঞ্চালিত হতে পারে (এবং আমরা সকলেই জানি যে ভিএস অনেক বেশি সস্তা!)।
ডিভে

0

এখানে গোলকের সমান ব্যবধানে যে কোনও সংখ্যক অংশের জন্য কিছু কোড রয়েছে এটি কমলা খোসার মতো এটি একটি গোলাকৃতির গোলকের চারপাশে বিন্দুগুলির একটি রেখা বাতাস করে। এরপরে আপনি কীভাবে শীর্ষে যোগদান করবেন তা আপনার উপর নির্ভর করে। আপনি প্রতিটি ত্রিভুজের 2 হিসাবে লুপে প্রতিবেশী বিন্দু ব্যবহার করতে পারেন এবং তারপরে তৃতীয়টিটি গোলকের চারপাশে উপরের বা নীচের দিকে প্রায় সমানুপাতিকভাবে একটি বাঁক হবে ... আপনি লুপ এবং এর নিকটবর্তী প্রতিবেশী দ্বারা ত্রিভুজগুলিও করতে পারেন, কেউ কি একটি ভাল উপায় জানেন?

var spherevertices = vector3 generic list...

public var numvertices= 1234;
var size = .03;  

function sphere ( N:float){//<--- N is the number of vertices i.e 123

var inc =  Mathf.PI  * (3 - Mathf.Sqrt(5));
var off = 2 / N;
for (var k = 0; k < (N); k++)
{
    var y = k * off - 1 + (off / 2);
    var r = Mathf.Sqrt(1 - y*y);
    var phi = k * inc;
    var pos = Vector3((Mathf.Cos(phi)*r*size), y*size, Mathf.Sin(phi)*r*size); 

    spherevertices   add pos...

}

};


-1

যদিও ডেভিড তার উত্তরে একেবারে সঠিক, তবে আমি অন্য দৃষ্টিকোণটি দিতে চাই।

পদ্ধতিগত বিষয়বস্তু উত্পন্ন করার জন্য আমার অ্যাসাইনমেন্টের জন্য, আমি আরও অন্যান্য traditionalতিহ্যবাহী মহকুমা ক্ষেত্রের বিপরীতে আইসোশেড্রন (অন্যান্য জিনিসের মধ্যে) দেখেছি। এই পদ্ধতিগতভাবে উত্পন্ন ক্ষেত্রগুলি দেখুন:

দারুণ গোলক

উভয় পুরোপুরি বৈধ গোলকের মত চেহারা, তাই না? ঠিক আছে, আসুন তাদের ওয়্যারফ্রেমগুলি দেখুন:

বাহ যে ঘন

বাহ, সেখানে কি হয়েছে? দ্বিতীয় গোলকের ওয়্যারফ্রেম সংস্করণটি এত ঘন যে এটি টেক্সচারযুক্ত দেখায়! আমি আপনাকে একটি গোপনীয়তাতে রাখব: দ্বিতীয় সংস্করণটি আইকোশেড্রন। এটি প্রায় নিখুঁত ক্ষেত্র, তবে এটি একটি উচ্চ মূল্যে আসে।

গোলক 1 টি মোট অক্ষরে 31 অক্ষ এবং 31 টি মহকুমা z-axis এ মোট 3,844 টি মুখের জন্য ব্যবহার করে।

স্ফিয়ার 2 টি মোট 109,220 মুখের জন্য 5 পুনরাবৃত্ত মহকুমা ব্যবহার করে ।

তবে ঠিক আছে, এটা আসলে ন্যায্য নয়। আসুন মানটি যথেষ্ট পরিমাণে কমিয়ে দিন:

পিণ্ডময়

গোলক 1 টি সর্বমোট 100 টি মুখের জন্য এক্স-অক্ষের উপর 5 টি উপ-বিভাগ এবং জেড-অক্ষের 5 টি উপ-বিভাগ ব্যবহার করে।

ক্ষেত্র 2 মোট 0 টি মুখের জন্য 0 পুনরাবৃত্ত মহকুমা ব্যবহার করে।

তারা একই পরিমাণে মুখ ব্যবহার করে তবে আমার মতে বাম দিকে গোলকটি আরও ভাল দেখায়। এটি দেখতে কম গলদা এবং আরও অনেক গোলাকার দেখাচ্ছে। আসুন আমরা দুটি পদ্ধতিতে কয়টি মুখ উত্পন্ন করি তা একবার দেখে নেওয়া যাক।

Icosahedron:

  • স্তর 0 - 100 মুখ
  • স্তর 1 - 420 মুখ
  • স্তর 2 - 1,700 মুখ
  • স্তর 3 - 6,820 মুখ
  • স্তর 4 - 27,300 মুখ
  • স্তর 5 - 109,220 মুখ

মহকুমা গোলক:

  • YZ: 5 - 100 মুখ
  • YZ: 10 - 400 মুখ faces
  • YZ: 15 - 900 মুখ faces
  • YZ: 20 - 1,600 মুখ
  • YZ: 25 - 2,500 মুখ
  • YZ: 30 - 3,600 মুখ

আপনি দেখতে পাচ্ছেন, আইসোস্যাড্রন তৃতীয় শক্তি হিসাবে তাত্পর্যপূর্ণ হারে মুখগুলিতে বৃদ্ধি পায়! এটি কারণ প্রতিটি ত্রিভুজটির জন্য আমাদের অবশ্যই তাদের তিনটি নতুন ত্রিভুজগুলিতে বিভক্ত করতে হবে।

সত্য হল: আপনি না প্রয়োজন স্পষ্টতা একটি icosahedron আপনাকে দিতে হবে। কারণ তারা উভয়ই খুব বেশি জটিল সমস্যাটি লুকিয়ে রাখেন: 3 ডি স্পোয়ারে 2D প্লেন টেক্সচার করে। শীর্ষগুলি দেখতে দেখতে এখানে:

শীর্ষ স্তন্যপান

উপরের বাম দিকে, আপনি টেক্সচারটি ব্যবহৃত হচ্ছে তা দেখতে পারেন। কাকতালীয়ভাবে, এটি প্রক্রিয়াগতভাবেও উত্পন্ন হচ্ছে। (আরে, এটি পদ্ধতিগত প্রজন্মের একটি কোর্স ছিল, তাই না?)

দেখতে ভয়ঙ্কর লাগছে তাইনা? ঠিক আছে, এটি যেমনটি পেতে চলেছে ততই ভাল। আমি আমার টেক্সচার ম্যাপিংয়ের শীর্ষস্থানীয় স্থান পেয়েছি, কারণ বেশিরভাগ মানুষ এমনকি এটি অধিকার পান না।

সুতরাং দয়া করে, গোলক তৈরি করতে কোসাইন এবং সাইন ব্যবহার বিবেচনা করুন। এটি একই পরিমাণের বিশদ জন্য অনেক কম মুখ উত্পন্ন করে।


6
আমি ভয় করি আমি কেবল এটিকেই কমিয়ে দিতে পারি। আইকোস্ফিয়ারের স্কেলগুলি তাত্ক্ষণিকভাবে? এটি কেবল কারণ আপনি স্থির করেছেন যে আপনার দ্রুত স্কেল করা উচিত। একটি ইউভি গোলকটি একই পরিমাণের বিশদ জন্য আইকোস্ফিয়ারের চেয়ে কম মুখ উত্পন্ন করে? এটি সম্পূর্ণ পিছনে ভুল, একেবারে ভুল।
সাম হোশেভার

4
মহকুমার পুনরাবৃত্তি হওয়ার দরকার নেই। আপনি একটি ত্রিভুজ প্রান্তটি আপনার ইচ্ছামত সমান অংশে ভাগ করতে পারেন। Nঅংশগুলি ব্যবহার করা আপনাকে N*Nনতুন ত্রিভুজ দেয়, যা চতুর্ভুজ, ঠিক যেমন আপনি ইউভি-গোলকের সাথে করেন।
সাম হোচেভার

6
আমার অবশ্যই এটি যোগ করা উচিত যে আপনি যে গোলকটি বলছেন তাকে "কম গলদা এবং আরও অনেক গোলাকার" দেখাচ্ছে সেরা দৃষ্টিকোণ থেকে, সেই দাবিকেও অসতর্ক করে তোলে। আমি কী বলতে চাইছি তা দেখতে উপরে থেকে দেখা গোলকের সাথে একই স্ক্রিনশটটি করুন।
সাম হোচেভার

4
এছাড়াও, আপনার আইকোশেড্রন নম্বরগুলি সঠিক দেখাচ্ছে না। স্তর 0 হ'ল 20 টি মুখ (সংজ্ঞায়িত), তারপরে 80, 320, 1280 ইত্যাদি You আপনি যে কোনও সংখ্যায় এবং যে কোনও প্যাটার্নে চান তা উপ-বিভাগ করতে পারেন। চূড়ান্ত ফলাফলের মুখগুলির সংখ্যা এবং বিতরণ দ্বারা মডেলটির সাবলীলতা শেষ পর্যন্ত নির্ধারিত হবে (তাদের উত্পন্ন করার পদ্ধতিটি নির্বিশেষে) এবং আমরা প্রতিটি মুখের আকার যতটা সম্ভব সমান রাখতে চাই (কোনও মেরু নেই) স্কোইজিং) দেখার কোণটি নির্বিশেষে একটি ধারাবাহিক প্রোফাইল বজায় রাখতে। এটিকে যুক্ত করুন যে মহকুমা কোডটি অনেক সহজ (
imho

2
কিছু উত্তর এই উত্তরে রাখা হয়েছে, যা আমাকে এটি ডাউনভোটিং সম্পর্কে কিছুটা খারাপ মনে করে। তবে এটি পুরোপুরি এবং সম্পূর্ণ ভুল, তাই আমাকেও করতে হবে। পুরোপুরি বৃত্তাকার দেখতে আইকোস্ফিয়ার যা পুরো এইচডি পুরো স্ক্রিনটি পূরণ করে, সেখানে একটি মৌলিক আইকোস্যাড্রন নেই যার কোনও বিভাগ রয়েছে with মহকুমাবিহীন আইকোস্যাড্রনটির 100 টি মুখ নেই, এর 20 টি রয়েছে I Icosa = 20. এটি নাম! প্রতিটি মহকুমা মুখের সংখ্যা 4 দ্বারা গুন করে, তাই 1-> 80, 2-> 320, 3-> 1280, 4-> 5120, 5-> 20,480। একটি ভূগোলের সাহায্যে সমান বৃত্তাকার গোলক পেতে আমাদের কমপক্ষে 40'000 মুখের প্রয়োজন।
পিটার

-1

নীচের স্ক্রিপ্টটি এন বহুভুজ ... বেস 12 দিয়ে একটি আইকোসেহেড্রন তৈরি করবে এটি বহুভুজকে পৃথক পৃথক মেসে ভাগ করবে এবং মোট ভার্টস-নকল এবং বহুভুজ গণনা করবে।

আমি অনুরূপ কিছু খুঁজে পাইনি তাই এটি তৈরি করেছিলাম। স্ক্রিপ্টটি কেবল একটি গেমওজেক্টের সাথে সংযুক্ত করুন এবং সম্পাদকের উপ-বিভাগগুলি সেট করুন। পরবর্তী শব্দ শোধন নিয়ে কাজ করা।


/* Creates an initial Icosahedron with 12 vertices...
 * ...Adapted from https://medium.com/@peter_winslow/creating-procedural-icosahedrons-in-unity-part-1-df83ecb12e91
 * ...And a couple other Icosahedron C# for Unity scripts
 * 
 * Allows an Icosahedron to be created with multiple separate polygon meshes
 * I used a dictionary of Dictionary<int, List<Vector3>> to represent the 
 * Polygon index and the vertice index
 * polygon[0] corresponds to vertice[0]
 * so that all vertices in dictionary vertice[0] will correspond to the polygons in polygon[0]
 * 
 * If you need help understanding Dictionaries
 * https://msdn.microsoft.com/en-us/library/xfhwa508(v=vs.110).aspx
 * 
 * --I used dictionaries because I didn't know what programming instrument to use, so there may be more
 * elegant or efficient ways to go about this.
 * 
 * Essentially int represents the index, and 
 * List<Vector3> represents the actual Vector3 Transforms of the triangle
 * OR List<Vector3> in the polygon dictionary will act as a reference to the indice/index number of the vertices
 * 
 * For example the polygon dictionary at key[0] will contain a list of Vector3's representing polygons
 * ... Vector3.x , Vector3.y, Vector3.z in the polygon list would represent the 3 indexes of the vertice[0] list
 * AKA the three Vector3 transforms that make up the triangle
 *    .
 *  ./_\.
 * 
 * Create a new GameObject and attach this script
 *  -The folders for the material and saving of the mesh data will be created automatically 
 *    -Line 374/448
 * 
 * numOfMainTriangles will represent the individual meshes created
 * numOfSubdivisionsWithinEachTriangle represents the number of subdivisions within each mesh
 * 
 * Before running with Save Icosahedron checked be aware that it can take several minutes to 
 *   generate and save all the meshes depending on the level of divisions
 * 
 * There may be a faster way to save assets - Line 430 - AssetDatabase.CreateAsset(asset,path);
 * */

using System.Collections.Generic;
using UnityEngine;
using UnityEditor;

public class UnityIcosahedronGenerator : MonoBehaviour {
    IcosahedronGenerator icosahedron;
    public const int possibleSubDivisions = 7;
    public static readonly int[] supportedChunkSizes = { 20, 80, 320, 1280, 5120, 20480, 81920};

    [Range(0, possibleSubDivisions - 1)]
    public int numOfMainTriangles = 0;
    [Range(0,possibleSubDivisions - 1)]
    public int numOfSubdivisionsWithinEachTriangle = 0;
    public bool saveIcosahedron = false;

    // Use this for initialization
    void Start() {
        icosahedron = ScriptableObject.CreateInstance<IcosahedronGenerator>();

        // 0 = 12 verts, 20 tris
        icosahedron.GenBaseIcosahedron();
        icosahedron.SeparateAllPolygons();

        // 0 = 12 verts, 20 tris - Already Generated with GenBaseIcosahedron()
        // 1 = 42 verts, 80 tris
        // 2 = 162 verts, 320 tris
        // 3 = 642 verts, 1280 tris
        // 5 = 2562 verts, 5120 tris
        // 5 = 10242 verts, 20480 tris
        // 6 = 40962verts, 81920 tris
        if (numOfMainTriangles > 0) {
            icosahedron.Subdivide(numOfMainTriangles);
        }
        icosahedron.SeparateAllPolygons();

        if (numOfSubdivisionsWithinEachTriangle > 0) {
            icosahedron.Subdivide(numOfSubdivisionsWithinEachTriangle);
        }

        icosahedron.CalculateMesh(this.gameObject, numOfMainTriangles,numOfSubdivisionsWithinEachTriangle, saveIcosahedron);
        icosahedron.DisplayVertAndPolygonCount();
    }
}

public class Vector3Dictionary {
    public List<Vector3> vector3List;
    public Dictionary<int, List<Vector3>> vector3Dictionary;

    public Vector3Dictionary() {
        vector3Dictionary = new Dictionary<int, List<Vector3>>();
        return;
    }

    public void Vector3DictionaryList(int x, int y, int z) {
        vector3List = new List<Vector3>();

        vector3List.Add(new Vector3(x, y, z));
        vector3Dictionary.Add(vector3Dictionary.Count, vector3List);

        return;
    }

    public void Vector3DictionaryList(int index, Vector3 vertice) {
        vector3List = new List<Vector3>();

        if (vector3Dictionary.ContainsKey(index)) {
            vector3List = vector3Dictionary[index];
            vector3List.Add(vertice);
            vector3Dictionary[index] = vector3List;
        } else {
            vector3List.Add(vertice);
            vector3Dictionary.Add(index, vector3List);
        }

        return;
    }

    public void Vector3DictionaryList(int index, List<Vector3> vertice, bool list) {
        vector3List = new List<Vector3>();

        if (vector3Dictionary.ContainsKey(index)) {
            vector3List = vector3Dictionary[index];
            for (int a = 0; a < vertice.Count; a++) {
                vector3List.Add(vertice[a]);
            }
            vector3Dictionary[index] = vector3List;
        } else {
            for (int a = 0; a < vertice.Count; a++) {
                vector3List.Add(vertice[a]);
            }
            vector3Dictionary.Add(index, vector3List);
        }

        return;
    }

    public void Vector3DictionaryList(int index, int x, int y, int z) {
        vector3List = new List<Vector3>();

        if (vector3Dictionary.ContainsKey(index)) {
            vector3List = vector3Dictionary[index];
            vector3List.Add(new Vector3(x, y, z));
            vector3Dictionary[index] = vector3List;
        } else {
            vector3List.Add(new Vector3(x, y, z));
            vector3Dictionary.Add(index, vector3List);
        }

        return;
    }

    public void Vector3DictionaryList(int index, float x, float y, float z, bool replace) {
        if (replace) {
            vector3List = new List<Vector3>();

            vector3List.Add(new Vector3(x, y, z));
            vector3Dictionary[index] = vector3List;
        }

        return;
    }
}

public class IcosahedronGenerator : ScriptableObject {
    public Vector3Dictionary icosahedronPolygonDict;
    public Vector3Dictionary icosahedronVerticeDict;
    public bool firstRun = true;

    public void GenBaseIcosahedron() {
        icosahedronPolygonDict = new Vector3Dictionary();
        icosahedronVerticeDict = new Vector3Dictionary();

        // An icosahedron has 12 vertices, and
        // since it's completely symmetrical the
        // formula for calculating them is kind of
        // symmetrical too:

        float t = (1.0f + Mathf.Sqrt(5.0f)) / 2.0f;

        icosahedronVerticeDict.Vector3DictionaryList(0, new Vector3(-1, t, 0).normalized);
        icosahedronVerticeDict.Vector3DictionaryList(0, new Vector3(1, t, 0).normalized);
        icosahedronVerticeDict.Vector3DictionaryList(0, new Vector3(-1, -t, 0).normalized);
        icosahedronVerticeDict.Vector3DictionaryList(0, new Vector3(1, -t, 0).normalized);
        icosahedronVerticeDict.Vector3DictionaryList(0, new Vector3(0, -1, t).normalized);
        icosahedronVerticeDict.Vector3DictionaryList(0, new Vector3(0, 1, t).normalized);
        icosahedronVerticeDict.Vector3DictionaryList(0, new Vector3(0, -1, -t).normalized);
        icosahedronVerticeDict.Vector3DictionaryList(0, new Vector3(0, 1, -t).normalized);
        icosahedronVerticeDict.Vector3DictionaryList(0, new Vector3(t, 0, -1).normalized);
        icosahedronVerticeDict.Vector3DictionaryList(0, new Vector3(t, 0, 1).normalized);
        icosahedronVerticeDict.Vector3DictionaryList(0, new Vector3(-t, 0, -1).normalized);
        icosahedronVerticeDict.Vector3DictionaryList(0, new Vector3(-t, 0, 1).normalized);

        // And here's the formula for the 20 sides,
        // referencing the 12 vertices we just created.
        // Each side will be placed in it's own dictionary key.
        // The first number is the key/index, and the next 3 numbers reference the vertice index
        icosahedronPolygonDict.Vector3DictionaryList(0, 0, 11, 5);
        icosahedronPolygonDict.Vector3DictionaryList(1, 0, 5, 1);
        icosahedronPolygonDict.Vector3DictionaryList(2, 0, 1, 7);
        icosahedronPolygonDict.Vector3DictionaryList(3, 0, 7, 10);
        icosahedronPolygonDict.Vector3DictionaryList(4, 0, 10, 11);
        icosahedronPolygonDict.Vector3DictionaryList(5, 1, 5, 9);
        icosahedronPolygonDict.Vector3DictionaryList(6, 5, 11, 4);
        icosahedronPolygonDict.Vector3DictionaryList(7, 11, 10, 2);
        icosahedronPolygonDict.Vector3DictionaryList(8, 10, 7, 6);
        icosahedronPolygonDict.Vector3DictionaryList(9, 7, 1, 8);
        icosahedronPolygonDict.Vector3DictionaryList(10, 3, 9, 4);
        icosahedronPolygonDict.Vector3DictionaryList(11, 3, 4, 2);
        icosahedronPolygonDict.Vector3DictionaryList(12, 3, 2, 6);
        icosahedronPolygonDict.Vector3DictionaryList(13, 3, 6, 8);
        icosahedronPolygonDict.Vector3DictionaryList(14, 3, 8, 9);
        icosahedronPolygonDict.Vector3DictionaryList(15, 4, 9, 5);
        icosahedronPolygonDict.Vector3DictionaryList(16, 2, 4, 11);
        icosahedronPolygonDict.Vector3DictionaryList(17, 6, 2, 10);
        icosahedronPolygonDict.Vector3DictionaryList(18, 8, 6, 7);
        icosahedronPolygonDict.Vector3DictionaryList(19, 9, 8, 1);

        return;
    }

    public void SeparateAllPolygons(){
        // Separates all polygons and vertex keys/indicies into their own key/index
        // For example if the numOfMainTriangles is set to 2,
        // This function will separate each polygon/triangle into it's own index
        // By looping through all polygons in each dictionary key/index

        List<Vector3> originalPolygons = new List<Vector3>();
        List<Vector3> originalVertices = new List<Vector3>();
        List<Vector3> newVertices = new List<Vector3>();
        Vector3Dictionary tempIcosahedronPolygonDict = new Vector3Dictionary();
        Vector3Dictionary tempIcosahedronVerticeDict = new Vector3Dictionary();

        // Cycles through the polygon list
        for (int i = 0; i < icosahedronPolygonDict.vector3Dictionary.Count; i++) {
            originalPolygons = new List<Vector3>();
            originalVertices = new List<Vector3>();

            // Loads all the polygons in a certain index/key
            originalPolygons = icosahedronPolygonDict.vector3Dictionary[i];

            // Since the original script was set up without a dictionary index
            // It was easier to loop all the original triangle vertices into index 0
            // Thus the first time this function runs, all initial vertices will be 
            // redistributed to the correct indicies/index/key

            if (firstRun) {
                originalVertices = icosahedronVerticeDict.vector3Dictionary[0];
            } else {
                // i - 1 to account for the first iteration of pre-set vertices
                originalVertices = icosahedronVerticeDict.vector3Dictionary[i];
            }

            // Loops through all the polygons in a specific Dictionary key/index
            for (int a = 0; a < originalPolygons.Count; a++){
                newVertices = new List<Vector3>();

                int x = (int)originalPolygons[a].x;
                int y = (int)originalPolygons[a].y;
                int z = (int)originalPolygons[a].z;

                // Adds three vertices/transforms for each polygon in the list
                newVertices.Add(originalVertices[x]);
                newVertices.Add(originalVertices[y]);
                newVertices.Add(originalVertices[z]);

                // Overwrites the Polygon indices from their original locations
                // index (20,11,5) for example would become (0,1,2) to correspond to the
                // three new Vector3's added to the list.
                // In the case of this function there will only be 3 Vector3's associated to each dictionary key
                tempIcosahedronPolygonDict.Vector3DictionaryList(0, 1, 2);

                // sets the index to the size of the temp dictionary list
                int tempIndex = tempIcosahedronPolygonDict.vector3Dictionary.Count;
                // adds the new vertices to the corresponding same key in the vertice index
                // which corresponds to the same key/index as the polygon dictionary
                tempIcosahedronVerticeDict.Vector3DictionaryList(tempIndex - 1, newVertices, true);
            }
        }
        firstRun = !firstRun;

        // Sets the temp dictionarys as the main dictionaries
        icosahedronVerticeDict = tempIcosahedronVerticeDict;
        icosahedronPolygonDict = tempIcosahedronPolygonDict;
    }

    public void Subdivide(int recursions) {
        // Divides each triangle into 4 triangles, and replaces the Dictionary entry

        var midPointCache = new Dictionary<int, int>();
        int polyDictIndex = 0;
        List<Vector3> originalPolygons = new List<Vector3>();
        List<Vector3> newPolygons;

        for (int x = 0; x < recursions; x++) {
            polyDictIndex = icosahedronPolygonDict.vector3Dictionary.Count;
            for (int i = 0; i < polyDictIndex; i++) {
                newPolygons = new List<Vector3>();
                midPointCache = new Dictionary<int, int>();
                originalPolygons = icosahedronPolygonDict.vector3Dictionary[i];

                for (int z = 0; z < originalPolygons.Count; z++) {
                    int a = (int)originalPolygons[z].x;
                    int b = (int)originalPolygons[z].y;
                    int c = (int)originalPolygons[z].z;

                    // Use GetMidPointIndex to either create a
                    // new vertex between two old vertices, or
                    // find the one that was already created.
                    int ab = GetMidPointIndex(i,midPointCache, a, b);
                    int bc = GetMidPointIndex(i,midPointCache, b, c);
                    int ca = GetMidPointIndex(i,midPointCache, c, a);

                    // Create the four new polygons using our original
                    // three vertices, and the three new midpoints.
                    newPolygons.Add(new Vector3(a, ab, ca));
                    newPolygons.Add(new Vector3(b, bc, ab));
                    newPolygons.Add(new Vector3(c, ca, bc));
                    newPolygons.Add(new Vector3(ab, bc, ca));
                }
                // Replace all our old polygons with the new set of
                // subdivided ones.
                icosahedronPolygonDict.vector3Dictionary[i] = newPolygons;
            }
        }
        return;
    }

    int GetMidPointIndex(int polyIndex, Dictionary<int, int> cache, int indexA, int indexB) {
        // We create a key out of the two original indices
        // by storing the smaller index in the upper two bytes
        // of an integer, and the larger index in the lower two
        // bytes. By sorting them according to whichever is smaller
        // we ensure that this function returns the same result
        // whether you call
        // GetMidPointIndex(cache, 5, 9)
        // or...
        // GetMidPointIndex(cache, 9, 5)

        int smallerIndex = Mathf.Min(indexA, indexB);
        int greaterIndex = Mathf.Max(indexA, indexB);
        int key = (smallerIndex << 16) + greaterIndex;

        // If a midpoint is already defined, just return it.
        int ret;
        if (cache.TryGetValue(key, out ret))
            return ret;

        // If we're here, it's because a midpoint for these two
        // vertices hasn't been created yet. Let's do that now!
        List<Vector3> tempVertList = icosahedronVerticeDict.vector3Dictionary[polyIndex];

        Vector3 p1 = tempVertList[indexA];
        Vector3 p2 = tempVertList[indexB];
        Vector3 middle = Vector3.Lerp(p1, p2, 0.5f).normalized;

        ret = tempVertList.Count;
        tempVertList.Add(middle);
        icosahedronVerticeDict.vector3Dictionary[polyIndex] = tempVertList;

        cache.Add(key, ret);
        return ret;
    }

    public void CalculateMesh(GameObject icosahedron, int numOfMainTriangles, int numOfSubdivisionsWithinEachTriangle, bool saveIcosahedron) {
        GameObject meshChunk;
        List<Vector3> meshPolyList;
        List<Vector3> meshVertList;
        List<int> triList;

        CreateFolders(numOfMainTriangles, numOfSubdivisionsWithinEachTriangle);
        CreateMaterial();

        // Loads a material from the Assets/Resources/ folder so that it can be saved with the prefab later
        Material material = Resources.Load("BlankSphere", typeof(Material)) as Material;

        int polyDictIndex = icosahedronPolygonDict.vector3Dictionary.Count;

        // Used to assign the child objects as well as to be saved as the .prefab
        // Sets the name
        icosahedron.gameObject.name = "Icosahedron" + numOfMainTriangles + "Recursion" + numOfSubdivisionsWithinEachTriangle;

        for (int i = 0; i < polyDictIndex; i++) {
            meshPolyList = new List<Vector3>();
            meshVertList = new List<Vector3>();
            triList = new List<int>();
            // Assigns the polygon and vertex indices
            meshPolyList = icosahedronPolygonDict.vector3Dictionary[i];
            meshVertList = icosahedronVerticeDict.vector3Dictionary[i];

            // Sets the child gameobject parameters
            meshChunk = new GameObject("MeshChunk");
            meshChunk.transform.parent = icosahedron.gameObject.transform;
            meshChunk.transform.localPosition = new Vector3(0, 0, 0);
            meshChunk.AddComponent<MeshFilter>();
            meshChunk.AddComponent<MeshRenderer>();
            meshChunk.GetComponent<MeshRenderer>().material = material;
            meshChunk.AddComponent<MeshCollider>();
            Mesh mesh = meshChunk.GetComponent<MeshFilter>().mesh;

            // Adds the triangles to the list
            for (int z = 0; z < meshPolyList.Count; z++) {
                triList.Add((int)meshPolyList[z].x);
                triList.Add((int)meshPolyList[z].y);
                triList.Add((int)meshPolyList[z].z);
            }

            mesh.vertices = meshVertList.ToArray();
            mesh.triangles = triList.ToArray();
            mesh.uv = new Vector2[meshVertList.Count];

            /*
            //Not Needed because all normals have been calculated already
            Vector3[] _normals = new Vector3[meshVertList.Count];
            for (int d = 0; d < _normals.Length; d++){
                _normals[d] = meshVertList[d].normalized;
            }
            mesh.normals = _normals;
            */

            mesh.normals = meshVertList.ToArray();

            mesh.RecalculateBounds();

            // Saves each chunk mesh to a specified folder
            // The folder must exist
            if (saveIcosahedron) {
                string sphereAssetName = "icosahedronChunk" + numOfMainTriangles + "Recursion" + numOfSubdivisionsWithinEachTriangle + "_" + i + ".asset";
                AssetDatabase.CreateAsset(mesh, "Assets/Icosahedrons/Icosahedron" + numOfMainTriangles + "Recursion" + numOfSubdivisionsWithinEachTriangle + "/" + sphereAssetName);
                AssetDatabase.SaveAssets();
            }
        }

        // Removes the script for the prefab save
        // Saves the prefab to a specified folder
        // The folder must exist
        if (saveIcosahedron) {
            DestroyImmediate(icosahedron.GetComponent<UnityIcosahedronGenerator>());
            PrefabUtility.CreatePrefab("Assets/Icosahedrons/Icosahedron" + numOfMainTriangles + "Recursion" + numOfSubdivisionsWithinEachTriangle + "/Icosahedron" + numOfMainTriangles + "Recursion" + numOfSubdivisionsWithinEachTriangle + ".prefab", icosahedron);
        }

        return;
    }

    void CreateFolders(int numOfMainTriangles, int numOfSubdivisionsWithinEachTriangle){
        // Creates the folders if they don't exist
        if (!AssetDatabase.IsValidFolder("Assets/Icosahedrons")) {
            AssetDatabase.CreateFolder("Assets", "Icosahedrons");
        }
        if (!AssetDatabase.IsValidFolder("Assets/Icosahedrons/Icosahedron" + numOfMainTriangles + "Recursion" + numOfSubdivisionsWithinEachTriangle)) {
            AssetDatabase.CreateFolder("Assets/Icosahedrons", "Icosahedron" + numOfMainTriangles + "Recursion" + numOfSubdivisionsWithinEachTriangle);
        }
        if (!AssetDatabase.IsValidFolder("Assets/Resources")) {
            AssetDatabase.CreateFolder("Assets", "Resources");
        }

        return;
    }

    static void CreateMaterial() {
        if (Resources.Load("BlankSphere", typeof(Material)) == null) {
            // Create a simple material asset if one does not exist
            Material material = new Material(Shader.Find("Standard"));
            material.color = Color.blue;
            AssetDatabase.CreateAsset(material, "Assets/Resources/BlankSphere.mat");
        }

        return;
    }

    // Displays the Total Polygon/Triangle and Vertice Count
    public void DisplayVertAndPolygonCount(){
        List<Vector3> tempVertices;
        HashSet<Vector3> verticeHash = new HashSet<Vector3>();

        int polygonCount = 0;
        List<Vector3> tempPolygons;

        // Saves Vertices to a hashset to ensure no duplicate vertices are counted
        for (int a = 0; a < icosahedronVerticeDict.vector3Dictionary.Count; a++) {
            tempVertices = new List<Vector3>();
            tempVertices = icosahedronVerticeDict.vector3Dictionary[a];
            for (int b = 0; b < tempVertices.Count; b++) {
                verticeHash.Add(tempVertices[b]);
            }
        }

        for (int a = 0; a < icosahedronPolygonDict.vector3Dictionary.Count; a++) {
            tempPolygons = new List<Vector3>();
            tempPolygons = icosahedronPolygonDict.vector3Dictionary[a];
            for (int b = 0; b < tempPolygons.Count; b++) {
                polygonCount++;
            }
        }

        Debug.Log("Vertice Count: " + verticeHash.Count);
        Debug.Log("Polygon Count: " + polygonCount);

        return;
    }
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.