Kami memperumit model Sci-fi secara prosedural: apa itu Greeble dan bagaimana menggunakannya

gambar

Sebagai permulaan, izinkan saya mengeluh bahwa "greeble" adalah kata yang mengerikan untuk dibuang dari kamus.

Nah, menghilangkan batu dari jiwa, kita beralih ke penjelasannya. Greeble adalah detail kecil berulang yang ditambahkan ke model untuk memberikan rasa skala dan estetika tertentu. Jamur telah menjadi populer berkat film-film fiksi ilmiah klasik, di mana patung fisik sering menjadi "model":


Jika Anda sudah tahu dari tutorial ekstrusi saya cara mengusir jerat prosedural, maka Anda mengerti cara menambahkan jamur. Menambahkan jamur sederhana ke jala dapat dilakukan dengan mengekstrusi semua poligon jala ke panjang acak .

Namun, Anda mungkin telah memperhatikan bahwa tutorial di atas hanya melihat mengekstrusi segitiga, sedangkan gambar di awal artikel adalah jamur persegi. Saya harus menyesuaikan mesh sehingga dibagi menjadi empat persegi, dan banyak jerat sering terdiri dari poligon dengan lebih dari tiga indeks. Oleh karena itu, dalam tutorial ini kita akan belajar cara mengekstraksi poligon dengan indeks n dan menerapkan algoritma ini ke seluruh jala untuk membuat jamur. Kami juga belajar beberapa cara untuk membuat variasi dalam algoritma menjamur untuk mendapatkan hasil yang kurang seragam.

Permukaan normal


Pertama, mari kita cari tahu bagaimana normal suatu poligon dengan indeks n sembarang dihitung. Jika kita dapat berasumsi bahwa poligon ini adalah planar , yaitu, semua simpulnya berada pada bidang yang sama, maka prosesnya tidak berbeda dengan menghitung normal poligon dengan tiga indeks.

Permukaan normal adalah tegak lurus terhadap permukaan poligon, yang dapat dihitung dengan mengambil produk vektor dari dua vektor yang menunjuk di sepanjang tepi poligon .

Kemudian kita menormalkan vektor ini sehingga panjangnya adalah 1, karena dari normal ke permukaan kita hanya perlu arah, bukan panjang.

  function getFaceNormal (mesh, poly)
   Vec3 v1 = mesh: getVertex (poli [1])
   Vec3 v2 = jala: getVertex (poli [2])
   Vec3 v3 = jala: getVertex (poli [3])
   Vec3 e1 = v2 - v1
   Vec3 e2 = v3 - v2
   Vec3 normal = e1: cross (e2)
   kembali normal: menormalkan ()
 akhir 

Jika kita tidak dapat dengan yakin berasumsi bahwa poligon adalah planar, maka algoritma yang disajikan di atas lebih memilih bidang di mana dua indeks pertama berada. Untuk representasi yang lebih akurat dari arah titik poligon, kita dapat mengambil rata - rata semua produk vektor tepian :

  function getFaceNormal (mesh, poly)
   Vec3 n = Vec3 (0, 0, 0)
   untuk i = 1, #poly -2 do
     Vec3 v1 = mesh: getVertex (poli [1])
     Vec3 v2 = jala: getVertex (poli [1+ i])
     Vec3 v3 = jala: getVertex (poli [2+ i])
     n: add ((v2 - v1): cross (v3 - v1))
   akhir
   return n: normalize ()
 akhir 


Contoh yang menunjukkan ekstrusi quadrangle planar.

Mengekstrusi


Sekarang kami memiliki informasi tentang permukaan normal, kami siap untuk mengusir poligon ke arah normal. Sederhananya, untuk mengekstraksi poligon, kami membuat simpul baru dengan menggerakkan simpul lama ke arah permukaan normal.

Lebih detail:

  1. Buat puncak baru "di atas" yang lama ke arah normal.

    Simpul baru dapat dihitung sebagai berikut:

      (posisi puncak lama) + (arah normal) 

    Ini "menggeser" posisi lama ke arah permukaan normal.

    Sebagai contoh, lihat gambar di atas, di atasnya v1 bergerak ke arah normal ke v5.
  2. Buat quadrangles untuk menghubungkan simpul baru dan lama.

    Perlu dicatat bahwa untuk setiap indeks dalam poligon baru, satu segiempat baru dibuat.

    Sebagai contoh, lihat quad yang dibuat dari v8, v7, v3 dan v4 .
  3. Ganti poligon lama dengan poligon baru yang dibuat oleh simpul baru. Sebagai contoh, lihat quad yang dibuat dari v5, v6, v7 dan v8.


  fungsi extrudePoly (mesh, polyIndex, panjang)
   int [] poly = mesh.polys [polyIndex]
   int [] newPoly = []
   Vec3 n = getFaceNormal (mesh, poly)

   - (1) Buat verdi diekstrusi
   untuk j = 1, #poly do
     p = mesh lokal: getVertex (poli [j])
     newPoly [#newPoly + 1] = # mesh.verts
     - panjang menentukan panjang ekstrusi
     mesh: addVertex (p + (n * panjang))
   akhir

   - (2) Jahit sisi ekstrusi dengan paha depan
   untuk j0 = 1, #poly do
     j1 lokal = j0% #poly + 1
     jala: addQuad (
       poli [j0],
       poli [j1],
       newPoly [j1],
       baruPoly [j0]
     )
   akhir

   - (3) Pindahkan wajah yang ada ke vertikal yang diekstrusi
   untuk j = 1, #poly do
     mesh.polys [pi] [j] = newPoly [j]
   akhir
 akhir 


Jamur seragam.

Semua jamur menjamur


Sekarang kita memiliki fungsi getSurfaceNormal () dan fungsi mengusir (), menjamur sangat mudah! Kami cukup menerapkan fungsi extrude () untuk setiap poligon mesh . Kami menggunakan ekstrusi dengan panjang acak sehingga setiap poligon yang diekstrusi memiliki ukuran yang sedikit berbeda, yang menciptakan perasaan tekstur. Algoritma yang ditunjukkan di bawah ini diterapkan pada kubus yang disajikan di atas, yang seluruhnya terdiri dari segi empat.

  fungsi greeble (jala)
   untuk i = 1, # mesh.poli lakukan
     - nilai acak ini arbitrer: p
     panjang float = acak: getUniformRange (0.1, 1.0)
     extrudePoly (jala, i, panjang)
   akhir
   kembali jala
 akhir 

Selamat, menjamur kami. Tapi kita bisa berbuat lebih banyak! Sekarang jamur cukup seragam. Berikut adalah dua contoh modifikasi agar lebih menarik.


Modifikasi 1: keberadaan fungling tergantung pada kesempatan


Ini cukup sederhana: hanya menggulung dadu untuk menentukan apakah jamur harus diterapkan pada setiap poligon. Berkat ini, menjamur menjadi kurang seragam. Algoritma yang ditunjukkan di bawah ini diterapkan pada kubus di atas.

  untuk i = 1, # mesh.poli lakukan
    <strong> jika acak: kebetulan (0,33) maka </strong>
      panjang float = acak (0,1, 1,0)
      extrudePoly (jala, i, panjang)
    akhir
  akhir
  kembali jala
 akhir 


Modifikasi 2: Tambahkan Skala Ekstrusi


Ini membutuhkan perubahan algoritma ekstrusi. Ketika kita membuat simpul dari poligon yang diekstrusi, kita dapat menguranginya ke pusat poligon dengan jumlah acak untuk membuat objek terlihat lebih menarik.

Untuk memulainya, fungsi extrude () kami harus menerima parameter tambahan yang menentukan jumlah penyempitan poligon baru. Kami akan mendefinisikannya sebagai scale disebut Vec3. Untuk memindahkan titik menuju pusat, kami menginterpolasi posisi titik antara posisi aslinya dan pusat poligon dengan nilai scale .

(Jika Anda perlu mengetahui algoritma untuk menemukan pusat poligon, saya sarankan untuk segera beralih ke tutorial tentang triangulasi dan membaca tentang triangulasi centroid.)

  - temukan pusat poli
 Vec3 c = mesh: getFaceCentroid (poli)
 untuk j = 1, #poly do
   p = mesh lokal: getVertex (poli [j])
   newPoly [#newPoly + 1] = # mesh.verts
   diri: addVertex (
     math.lerp (cx, px, scale.x) + panjang nx *,
     math.lerp (cy, py, scale.y) + ny * panjang,
     math.lerp (cz, pz, scale.z) + nz * panjangnya
   )
   mesh: addVertex (p + (n * panjang))
 akhir 

Sekarang Anda dapat menggunakannya dalam algoritma menjamur dengan penskalaan dengan nilai acak untuk setiap poligon. Jadi kita mendapatkan gambar yang ditunjukkan di atas.

  fungsi greeble (jala)
   untuk i = 1, # mesh.poli lakukan
     panjang float = acak: getUniformRange (0.1, 1.0)
     Skala Vec3 = (acak: getUniformRange (0.1, 1.0),
                   acak: getUniformRange (0,1, 1,0),
                   acak: getUniformRange (0.1, 1.0))
     extrudePoly (mesh, i, panjang, skala)
   akhir
   kembali jala
 akhir 

Akhirnya


Bagus, kita sampai akhir! Saya harap tutorial ini bermanfaat bagi Anda.

Source: https://habr.com/ru/post/id482316/


All Articles