Küreler oluşturmak için algoritma?


27

Birisi yordamsal laolarak enlem çizgileri, loboylam çizgileri ve yarıçapı olan bir küre oluşturmak için bir algoritma var mı r? Unity ile çalışmam gerekiyor, bu yüzden tepe konumlarının tanımlanması ve sonra da indeksler aracılığıyla tanımlanmış üçgenler ( daha fazla bilgi ) gerekiyor.


DÜZENLE

görüntü tanımını buraya girin

Kodun birlik içinde çalışmasını sağladım. Ama sanırım yanlış bir şey yapmış olabilirim. Ben açtığımda detailLevel, öyle Bütün bunları hareket etmeden daha köşeleri ve poligon eklemektir. Bir şey mi unuttum?


EDIT 2

görüntü tanımını buraya girin

Mesh'i normalleri boyunca ölçeklendirmeyi denedim. Elimde bu var. Sanırım bir şeyleri özlüyorum. Sadece belirli normları ölçeklendirmem mi gerekiyor?


1
Neden mevcut açık kaynaklı uygulamaların nasıl yapıldığına bakmıyorsunuz? Örneğin Three.js'nin kafesleri nasıl kullandığına bir bakın .
brice

3
Küçük bir not olarak: Enlem / boylam yapmak zorunda olmadığınız sürece neredeyse kesinlikle istemezsiniz , çünkü elde ettiğiniz üçgenler diğer yöntemlerle elde ettiğinizlerden çok daha üniform olacaktır. (Kuzey kutbunun yanındaki üçgenleri ekvatorun yakınında bulunanlarla karşılaştırın: her iki durumda da bir enlem çizgisi etrafında almak için aynı sayıda üçgen kullanıyorsunuz, ancak direğin yakınında bu enlem çizgisinin çok küçük bir çevresi var. bu, dünyadaki tüm çevrenizdir.) David Lively'nun cevabındaki gibi teknikler genellikle çok daha iyidir.
Steven Stadnicki

1
Alt bölmeden sonra tepe konumlarını normalleştirmiyorsunuz. Örneğime o kısmı dahil etmedim. Normalleştirme, merkezden eşit şekilde eşitlenmelerini sağlar;
3Dave

İkosahedronun merkezine bir balon şişirmeyi düşünün. Balon ağımızı iterken, balonun şekline (küre) uyar.
3Dave

4
"Normalleştirme", bir vektörün uzunluğunu 1'e ayarlamak anlamına gelir vertices[i] = normalize(vertices[i]). Bu arada, bu aynı zamanda size yeni, doğru normalleri verir, bu yüzden normals[i] = vertices[i]daha sonra yapmalısınız .
sam hocevar

Yanıtlar:


31

Böyle bir şey almak için:

görüntü tanımını buraya girin

Bir icosahedron (20 taraflı düzenli katı) oluşturun ve bir küre elde etmek için yüzleri bölün (aşağıdaki koda bakın).

Fikir temelde:

  • Düzenli bir n-hedron (her yüzün aynı boyutta olduğu bir katı) oluşturun. Bir icosahedron kullanıyorum çünkü her yüzün aynı boyutta olduğu en fazla yüze sahip katı. (Orada bir yerde bunun için bir kanıt var. Gerçekten merak ediyorsanız Google'a çekinmeyin.) Bu size hemen hemen her yüzün aynı boyutta olduğu bir alan sunacak ve dokuyu biraz daha kolaylaştıracak.

görüntü tanımını buraya girin

  • Her yüzü dört eşit boyutta yüze bölün. Bunu her yaptığınızda, modeldeki yüz sayısını dört katına çıkarır.

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

i0, i1ve i2orijinal üçgenin köşeleridir. (Aslında, köşe arabelleğine endeksler, ancak bu başka bir konudur). m01kenarın orta noktasıdır (i0,i1), m12 kenarın orta noktasıdır (i1,12)ve m02açık bir şekilde kenarın orta noktasıdır (i0,i2).

Ne zaman bir yüze bölünürseniz, yinelenen köşeler oluşturmadığınızdan emin olun. Her orta nokta başka bir kaynak yüz tarafından paylaşılacaktır (kenarlar yüzler arasında paylaşıldığından). Aşağıdaki kod, oluşturulmuş adlandırılmış orta noktaların sözlüğünü koruyarak ve yeni bir tane oluşturmak yerine kullanılabilir olduğunda önceden oluşturulmuş bir orta noktanın dizinini döndürerek bunu açıklar.

  • Küpünüz için istediğiniz yüze ulaşana kadar tekrarlayın.

  • İşiniz bittiğinde, yüzeyi düzeltmek için tüm köşeleri normalleştirin. Bunu yapmazsanız, küre yerine daha yüksek çözünürlüklü bir icosahedron elde edersiniz.

  • İşte bu kadar! Sen bittin. Bir içine çıkan vektör ve indeks tamponlarını dönüştürme VertexBufferve IndexBufferve çizmek Device.DrawIndexedPrimitives().

Modeli oluşturmak için "Sphere" sınıfınızda kullanacağınız şey (XNA veri türleri ve C #, ancak oldukça açık olmalıdır):

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

Ve GeometryProvidersınıf

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


    }



}

Mükemmel cevap. Teşekkürler. Söyleyemem ama bu birlik kodu mu? Oh ve enlem / boylam çözünürlüğü ayarlayabildiğim sürece önemli değil.
Daniel Pendergast

Birlik (XNA) değil, ancak köşe koordinatlarını ve dizin listesini verir. Unity eşdeğeri ile Vector3 değiştirin. Çözünürlüğü Alt Bölme yineleme sayısını ayarlayarak ayarlarsınız. Her ilmek, yüz sayısını 4 ile çarpar. 2 veya 3 yineleme, güzel bir küre verecektir.
3Dave

Ah, anlıyorum. Unity C # ile neredeyse aynı. Sadece birkaç soru ... Neden endeksler tanımlandığında, onları bir intdizinin içine koyarsınız ? Ve ne yapar .Select(i => i + vertices.Count)?
Daniel Pendergast

Bu .Select(i => i + vertices.Count)benim için hiç çalışmıyor. Sadece bir XNA özelliği mi?
Daniel Pendergast

1
'System.Linq' öğesini tanımlandığı gibi kullandığınızdan emin olun. Seç, vb.
3Dave

5

Bir kürenin parametrik tanımını düşünelim:

kürenin parametrik tanımı

burada, teta ve phi olan dediğimiz ki, açılar artan iki var tve var uve R, R ve Rz, bir küre durumunda, tek olarak tanımlanacaktır, bağımsız yarıçapları (yarıçapları) her üç Kartezyen yönlerde olan yarıçapı var rad.

Şimdi ...sembolün bir döngü kullanımına işaret eden bir yinelemeye işaret ettiğini gerçeğini göz önüne alalım . Kavramı stacksve rows"kaç kez yineleyeceksin" dir. Her yineleme t veya u değerini eklediğinden, yineleme ne kadar fazla olursa, değer ne kadar küçükse, kürenin eğriliği o kadar kesin olur.

'Küre çizimi' işlevin ön şart aşağıdaki verilen parametrelere sahip olmaktır: int latitudes, int longitudes, float radius. Gönderi koşulları (çıktı) hesaplanan köşeleri döndürmek veya uygulamaktır. Bunu nasıl kullanmak istediğinize bağlı olarak, işlev bir dizi vector3(üç boyutlu vektör) döndürür veya bir tür basit OpenGL kullanıyorsanız, sürüm 2.0'dan önce, köşeleri doğrudan içeriğe uygulamak isteyebilirsiniz.

NB openGL'de bir köşe uygulamak aşağıdaki işlevi çağırıyor glVertex3f(x, y, z). Köşeleri depolayacağımız durumlarda, vector3(x, y, z)kolay saklama için yeni bir ürün eklerdik.

Ayrıca, enlem ve boylam sisteminden çalışmasını istediğiniz şekilde, kürenin tanımına bir ayar yapılması gerekiyordu (temel olarak z ve y'yi değiştiriyor), ancak bu sadece tanımın çok uygun olduğunu ve etrafında dolaşmakta serbest olduğunuzu gösteriyor x, y ve z parametreleri, kürenin çizildiği yönü (enlem ve boylamların olduğu) değiştirir.

Şimdi enlem ve boylamları nasıl yapacağımıza bir bakalım. Enlemler değişken tarafından temsil edilir, u0 ila 2π radyan (360 derece) tekrar ederler. Dolayısıyla yinelemesini şöyle kodlayabiliriz:

float latitude_increment = 360.0f / latitudes;

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

Şimdi boylamlar değişken tarafından temsil edilir tve 0 - π (180 derece) arasında yinelenir. bu nedenle, aşağıdaki kod öncekine benzer:

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

(Döngüler vardır Not olduğunu Dahil parametrik entegrasyon için aralık 2n 0'dan çünkü orada terminali durumun, Inclusive . Şartlarınız dahil olmadığını eğer kısmi küre alacak.)

Şimdi, kürenin basit tanımını izleyerek değişken tanımını aşağıdaki gibi türetebiliriz (varsayılır 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)));

Bir önemli uyarı daha! Çoğu durumda OpenGL'nin bir formunu kullanacaksınız ve olmasa bile, yine de yapmanız gerekebilir. Üç boyutlu bir nesnenin tanımlanması gereken birkaç köşeye ihtiyacı vardır. Bu genellikle, hesaplanabilir bir sonraki köşe sağlayarak elde edilir.

(ilkel) bir şekli tanımlamak için çoklu köşelerin nasıl kullanıldığı

Sadece farklı koordinatlarda yukarıdaki şekildeki ne kadar x+∂ve y+∂biz kolayca istenilen kullanım için diğer üç köşe oluşturabilir. Diğer köşe noktaları 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)));

Son olarak, burada bir kürenin tüm köşelerini döndüren tam bir işleve sahip, ikincisi ise kodun çalışan bir OpenGL uygulamasını gösteriyor (bu C tarzı bir sözdizimi ve JavaScript değil, bu tüm C tarzı dillerle çalışmalı, Unity kullanırken C # dahil).

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;

}

OpenGL kodu:

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.

}

PS Bu ifadeyi fark etmiş olabilirsiniz rad = radius;. Bu, yarıçapın, yere veya açıya bağlı olarak döngüde değiştirilmesine izin verir. Bu, küreyi pürüzlendirmek için gürültüye uygulayabileceğiniz ve istenen etki gezegen benzeri bir yapıysa daha doğal görünmesini sağlayacak anlamına gelir. Örneğinfloat rad = radius * noise[x][y][z];

Claude-Henry.


Float z = (float) satırı (rad * Math.sin (Math.toRadians (t))) * Math.cos (Math.toRadians (u))); Zaten hipotenüsü olan bir X, Y hesapladınız rad. Şimdi bir üçgenin bir bacağını yapıyorsunuz ve söz konusu üçgenin hipotenüsünün de aynı olduğunu ima ediyorsunuz rad. Bu etkili bir yarıçapı verir rad * sqrt(2).
3Dave

@DavidLively gösterdiğin için teşekkürler, bunu bir süre önce yazdım, bu yüzden kötü ya da düpedüz yanlış olsa şaşırmam.
claudehenry

Yıllar öncesindeki MY yayınlarımdan birinde hata bulduğumda her zaman eğlenceli. Olur. :)
Kasım'da

4

Bir süre önce küpler yapmak, eğlence ve bilim için böyle bir şey yarattım. Çok zor değil. Temel olarak, köşelerden oluşan bir daire oluşturan bir işlev alırsınız, daha sonra küre yapmak için gereken yarıçapta her bir yükseklikte daire oluşturmak istediğiniz yükseklik artışlarını gerçekleştirirsiniz. İşte kodu küpler için olmayacak şekilde değiştirdim:

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

Şimdi bu kod sadece enlem için puan yaratacaktır. Ancak, boylam çizgileri oluşturmak için neredeyse aynı kodu kullanabilirsiniz. Ancak, her yineleme arasında dönmeniz ve her birinde tam bir daire çizmeniz gerekir degreeStep.

Maalesef bu tam bir cevap veya Unity'ye özgü değil, ama umarım başlamanıza yardımcı olur.


Uzun / uzun bir küreye ihtiyacınız varsa, bu oldukça iyidir, ancak son adıma kadar küresel koordinatlarda çalışarak biraz basitleştirebilirsiniz.
3Dave

1
@David teşekkürler. Kabul ediyorum, küresel kodları kullanarak bir sürüm yazacak olursam, buraya gönderirim.
MichaelHouse

3

Sadece basit bir şekille başlayamaz mıydınız, merkezden köşeye kadar mesafeli bir kutu olabilir. Daha ayrıntılı bir küre yapmak için, tüm çokgenleri alt bölümlere ayırın ve sonra vektörleri geçerli konumlarından geçirerek, köşeleri merkezden uzağa doğru hareket ettirin.

Zevkiniz için yeterince küresel olana kadar tekrar etmeye devam edin.


Bu aslında ikosahedral yaklaşımla aynıdır, sadece farklı bir başlangıç ​​şekli ile. Bahsetmediğim bir küple başlamanın bir avantajı: Bir UV haritası oluşturmak oldukça kolaydır, çünkü bir küp haritası kullanabilir ve doku dikişlerinizin küre ağınızdaki kenarlarla mükemmel bir şekilde hizalanacağını bilirsiniz.
Steven Stadnicki

@StevenStadnicki küplerle ilgili tek sorunum, birkaç alt bölümden sonra yüzlerin çok farklı boyutlarda olma eğilimi göstermesidir.
3Dave

@DavidLively Bu, nasıl bölüştüğünüze bağlıdır - küpünüzün kare yüzlerini eşit bir ızgaraya bölerseniz ve sonra dışa / normalleştirerek yansıtırsanız, bu doğrudur, ancak yüzlerinizi düzgün olmayan bir şekilde ızgara yaparsanız, gerçekte çıkıntı, kenarların yayları boyunca eşit aralıklarla yerleştirilebilir; Bu oldukça iyi sonuçlandı.
Steven Stadnicki

@StevenStadnicki şık!
3Dave

@EricJohansson btw, bir öğretmen olarak, bunun daha önce alt bölme yöntemini görmemiş biri için oldukça önemli bir içgörü olduğunu söylemeye mecbur olduğumu hissediyorum. Önümüzdeki 12 saat boyunca insanlığa olan inancımı değiştirdin.
3Dave

2

3D geometriye mi yoksa sadece şekle mi ihtiyacınız var?

Tek bir dörtlü kullanarak 'sahte' bir küre yapabilirsiniz. Sadece üzerine bir daire çiz ve doğru şekilde gölgele. Bu, kamera veya çözünürlük mesafesine bakılmaksızın tam olarak gereken çözünürlüğe sahip olma avantajına sahiptir.

Burada bir öğretici var .


1
Güzel kesmek, ancak doku gerekiyorsa başarısız olur.
3Dave

@DavidLively Çokgenleri tek tek tek tek dokuya koymanız gerekmedikçe, piksel başına düşen doku koordinatlarını, döndürme değerine göre hesaplamak mümkün olmalıdır.
David C. Bishop,

@DavidCBishop Yüzeyin "merceklenmesini" hesaba katmak zorundasınız - tekstürlü kodlayıcılar, perspektif nedeniyle daire sınırına yakın sıkılmış - hangi noktada rotasyon yapıyorsunuz. Ayrıca, bu, tepe gölgelendiricisinde gerçekleştirilebilecek piksel gölgelendiricisine çok daha fazla iş taşınmasını gerektirir (ve hepimizin VS'lerin daha ucuz olduğunu biliyoruz!).
3Dave

0

Burada, bir kürenin eşit sayıda aralıklı köşeleri için bazı kodlar, onun bir portakal kabuğu gibi bir spiralin bir kürenin etrafına bir nokta çizgileri sarmasıdır. Daha sonra, köşelere nasıl katılacağınız size kalmış. döngüdeki komşu noktaları her üçgenin 2'si olarak kullanabilir ve daha sonra üçüncünün kürenin etrafındaki yukarı veya aşağı doğru çevrilmiş bir orantılı olacağını görürsünüz ... ayrıca üçgenler döngü ve en yakın komşu üzerinde yapabilir daha iyi bir yol biliyor musun?

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

David'in cevabında kesinlikle doğru olmasına rağmen, farklı bir bakış açısı sunmak istiyorum.

Prosedürel içerik oluşturma görevim için, (diğer şeylerin yanı sıra) daha geleneksel alt bölümlere ayrılmış alanlara karşı icosahedron'a baktım. Prosedürel olarak oluşturulan bu alanlara bakın:

Müthiş küreler

Her ikisi de mükemmel geçerli kürelere benziyor, değil mi? Peki, onların tel kafeslerine bakalım:

Vay bu yoğun

Vay, orada ne oldu? İkinci kürenin tel kafes versiyonu çok yoğun görünüyor ve dokulu görünüyor! Sana bir sır vereyim: ikinci versiyon bir icosahedron. Neredeyse mükemmel bir küre, ancak yüksek bir fiyata geliyor.

Küre 1, x-ekseninde 31 alt bölümü ve z-ekseninde 31 alt bölümünü toplam 3,844 yüz için kullanmaktadır.

Küre 2, toplam 109.220 yüz için 5 özyinelemeli alt bölüm kullanmaktadır .

Ama tamam, bu gerçekten adil değil. Kaliteyi önemli ölçüde azaltalım:

Topaklı

Küre 1, toplam 100 yüz için, x ekseninde 5 alt bölümü ve z ekseninde 5 alt bölümünü kullanır.

Küre 2, toplam 100 yüz için 0 özyinelemeli alt bölüm kullanır.

Aynı miktarda yüz kullanıyorlar, ama bence soldaki küre daha iyi görünüyor. Daha az topaklı ve çok daha yuvarlak görünüyor. Her iki yöntemle de kaç yüz oluşturduğumuza bir göz atalım.

ikosahedron:

  • Seviye 0 - 100 yüzler
  • Seviye 1 - 420 yüzler
  • Seviye 2 - 1,700 yüzler
  • Seviye 3 - 6,820 yüzler
  • Seviye 4 - 27.300 yüzler
  • Seviye 5 - 109,220 yüzler

Bölünmüş küre:

  • YZ: 5 - 100 yüzler
  • YZ: 10 - 400 yüzler
  • YZ: 15 - 900 yüzler
  • YZ: 20 - 1.600 yüzler
  • YZ: 25 - 2,500 yüzler
  • YZ: 30 - 3.600 yüz

Gördüğünüz gibi, ikosahedron yüzlerde üssel bir hızda, üçüncü bir güce yükseliyor! Çünkü her üçgen için onları üç yeni üçgene bölmeliyiz.

Gerçek şu ki: Bir icosahedron'un size vereceği kesinliğe ihtiyacınız yok . Çünkü ikisi de daha zor bir problemi gizliyor: 3B kürede 2B bir düzlemin tekstüre edilmesi. İşte tepedeki gibi:

En berbat

Sol üstte, kullanılan dokuyu görebilirsiniz. Tesadüfen, aynı zamanda usule göre üretiliyor. (Hey, yordamsal üretim üzerine bir kurstu, değil mi?)

Berbat görünüyor, değil mi? Bu alacağı kadar iyi. Doku haritalamam için en iyi notlarım var çünkü çoğu insan bu işi doğru yapamıyor.

Bu nedenle, lütfen bir küre oluşturmak için kosinüs ve sinüs kullanmayı düşünün. Aynı miktarda ayrıntı için çok daha az yüz oluşturur.


6
Korkarım bunu sadece aşağıya çekebilirim. Icosphere katlanarak ölçeklenir? Yani tek nedeni var sen senin katlanarak ölçek gerektiğine karar verdi. Bir UV küresi, aynı miktarda ayrıntı için bir ikosferden daha az yüz oluşturur? Bu yanlış, kesinlikle yanlış, tamamen geriye doğru.
sam hocevar

4
Alt bölümün özyinelemeli olması gerekmez. Bir üçgenin kenarını istediğiniz kadar eşit parçaya bölebilirsiniz. NParçaları kullanmak N*N, UV küre ile yaptığınız gibi, ikinci dereceden yeni üçgenler verecektir .
sam hocevar

6
Ayrıca, söylediğiniz kürenin "daha az topaklı ve daha fazla yuvarlak" göründüğünü en iyi açıdan gördüğünü eklemeliyim ki bu da dürüst değil. Sadece ne demek istediğimi görmek için yukarıdan izlenen kürelerle aynı ekran görüntüsünü yapın.
sam hocevar

4
Ayrıca, icosahedron numaralarınız doğru görünmüyor. Seviye 0, 20 yüzdür (tanım gereği), sonra 80, 320, 1280, vb. İstediğiniz sayıda ve istediğiniz herhangi bir düzende bölebilirsiniz. Sonunda modelin düzgünlüğü nihai sonuçta yüzlerin sayısı ve dağılımı ile belirlenir (bunları üretmek için kullanılan yöntemden bağımsız olarak) ve her yüzün boyutunu mümkün olduğu kadar tek tip tutmak istiyoruz (kutupsuz) sıkma) bakış açısına bakılmaksızın tutarlı bir profili korumak için. Buna ek olarak, alt bölüm kodunun çok daha basit (
imho

2
Bu cevaba bazı çalışmalar yapılmıştır, bu da beni aşağıya indirmekte kötü hissetmemi sağlıyor. Ama bu tamamen ve tamamen yanlıştır, bu yüzden yapmak zorundayım. FullHD'de tüm ekranı dolduran kusursuz görünümlü yuvarlak bir Icosphere, 5 alt bölüme ihtiyaç duyuyor, alt bölümleri olmayan temel bir icosahedron gerekiyor. Alt bölümleri olmayan bir icosahedron 100 yüze sahip değil, 20 tane. Icosa = 20. Bu isim! Her alt bölüm yüz sayısını 4 ile çarpar, yani 1-> 80, 2-> 320, 3-> 1280, 4-> 5120, 5-> 20,480. Bir jeosfer ile eşit derecede yuvarlak bir küre elde etmek için en az 40.000 yüze ihtiyacımız var.
Peter

-1

Aşağıdaki komut dosyası, n Çokgenli ... taban 12'li bir Icosahedron oluşturacaktır. Ayrıca çokgenleri ayrı kafeslere bölüp, toplam kopya-çoğaltılmış ve çokgenleri hesaplar.

Benzer bir şey bulamadım, bu yüzden bunu yarattım. Sadece betiği bir GameObject dosyasına ekleyin ve alt bölümleri Editör'de ayarlayın. Daha sonra gürültü modifikasyonu üzerinde çalışmak.


/* 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;
    }
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.