بادئ ذي بدء ، اسمحوا لي أن أشكو من أن كلمة "greeble" هي كلمة فظيعة يجب نفيها من القاموس.
حسنًا ، نخرج الحجر من الروح ، ننتقل إلى التفسيرات. Greeble هي تفاصيل صغيرة مكررة تضاف إلى نموذج لمنحه إحساسًا بالحجم وجماليات معينة. أصبحت الفطر شائعة بفضل أفلام الخيال العلمي الكلاسيكية ، والتي كان النحت المادي فيها غالبًا "النموذج":
إذا كنت تعرف بالفعل من خلال برنامج 
تعليمي الخاص بالبثق كيفية إخراج الشبكات الإجرائية ، فأنت تفهم كيفية إضافة الفطر. يمكن تحقيق إضافة 
عيش الغراب البسيط إلى الشبكة من خلال 
سحب كل المضلعات الشبكية 
بطول عشوائي .
ومع ذلك ، ربما لاحظت أن البرنامج التعليمي أعلاه ينظر فقط إلى مثلثات البثق ، في حين أن الصورة في بداية المقال عبارة عن فطر مربع. اضطررت إلى ضبط الشبكة بحيث تم تقسيمها إلى رباعي الزوايا ، وغالبًا ما تتكون شبكات كثيرة من مضلعات تحتوي على أكثر من ثلاثة مؤشرات. لذلك ، في هذا البرنامج التعليمي ، سنتعلم كيفية 
إخراج مضلع باستخدام مؤشرات n وتطبيق هذه الخوارزمية على الشبكة بالكامل لإنشاء الفطر. نتعلم أيضًا طريقتين لعمل اختلافات في خوارزمية الفطر للحصول على نتائج أقل اتساقًا.
السطح العادي
أولاً ، دعنا نتعرف على كيفية حساب المعدل الطبيعي للمضلع باستخدام مؤشرات n التعسفية. إذا استطعنا أن نفترض أن هذا المضلع 
مستوٍ ، أي أن كل رؤوسه موجودة على نفس المستوى ، فإن العملية لا تختلف عن حساب المعدل الطبيعي للمضلع بثلاثة مؤشرات.
السطح الطبيعي هو عمودي على وجه المضلع ، والذي يمكن حسابه عن طريق أخذ 
المنتج الموجه من متجهين يشيران على طول حافة المضلع .
بعد ذلك نقوم 
بتطبيع هذا المتجه بحيث يكون طوله 1 ، لأن من الطبيعي إلى السطح نحتاج فقط إلى الاتجاه وليس إلى الطول.
  وظيفة getFaceNormal (شبكة ، بولي)
   Vec3 v1 = mesh: getVertex (poly [1])
   Vec3 v2 = mesh: getVertex (poly [2])
   Vec3 v3 = mesh: getVertex (poly [3])
   Vec3 e1 = v2 - v1
   Vec3 e2 = v3 - v2
   Vec3 normal = e1: تقاطع (e2)
   عودة طبيعية: تطبيع ()
 نهاية 
إذا لم نتمكن من الافتراض بثقة أن المضلع هو مستو ، فإن الخوارزمية المعروضة أعلاه تفضل المستوى الذي يوجد عليه المؤشران الأوليان. للحصول على تمثيل أكثر دقة للاتجاه الذي تشير إليه المضلعات ، يمكننا بدلاً من ذلك أخذ 
متوسط جميع منتجات المتجهات للحواف :
  وظيفة getFaceNormal (شبكة ، بولي)
   Vec3 n = Vec3 (0 ، 0 ، 0)
   لأنني = 1 ، #poly -2 افعل
     Vec3 v1 = mesh: getVertex (poly [1])
     Vec3 v2 = mesh: getVertex (poly [1+ i])
     Vec3 v3 = mesh: getVertex (poly [2+ i])
     n: add ((v2 - v1): cross (v3 - v1))
   نهاية
   عودة ن: تطبيع ()
 نهاية 
مثال يوضح قذف رباعي مستو.البثق
الآن وقد أصبح لدينا معلومات عن السطح الطبيعي ، فنحن مستعدون لبثق المضلع في الاتجاه الطبيعي. ببساطة ، لبثق المضلع ، نقوم بإنشاء رؤوس جديدة عن طريق تحريك الرؤوس القديمة في اتجاه السطح الطبيعي.
مزيد من التفاصيل:
- إنشاء قمم جديدة "أعلاه" القديمة في الاتجاه الطبيعي.
 
 يمكن حساب رؤوس جديدة كما يلي:
 
   (موقف الذروة القديمة) + (الاتجاه الطبيعي)  
 
 هذا "يحول" الموقف القديم في اتجاه السطح الطبيعي.
 
 على سبيل المثال ، انظر إلى الصورة أعلاه ، حيث تتحرك v1 في الاتجاه الطبيعي إلى v5.
- قم بإنشاء رباعيات لربط الرؤوس الجديدة والقديمة.
 
 تجدر الإشارة إلى أنه لكل مؤشر في المضلع الجديد ، يتم إنشاء رباعي جديد.
 
 على سبيل المثال ، ألقِ نظرة على رباعية تم إنشاؤها من الإصدار 8 ، الإصدار 7 ، الإصدار 3 ، الإصدار 4 .
- استبدل المضلع القديم بمضلع جديد تم إنشاؤه بواسطة رؤوس جديدة. على سبيل المثال ، ألقِ نظرة على رباعية تم إنشاؤها من v5 و v6 و v7 و v8.
  وظيفة extrudePoly (شبكة ، polyIndex ، طول)
   int [] poly = mesh.polys [polyIndex]
   int [] newPoly = []
   Vec3 n = getFaceNormal (شبكة ، بولي)
   - (1) إنشاء verts مقذوف
   ل j = 1 ، #poly القيام به
     ع المحلية = شبكة: getVertex (بولي [ي])
     newPoly [#newPoly + 1] = # mesh.verts
     - طول يحدد طول البثق
     شبكة: addVertex (ع + (طول ن *))
   نهاية
   - (2) الجانبين قذف غرزة مع الكواد
   ل j0 = 1 ، #poly القيام به
     j1 المحلي = j0٪ #poly + 1
     شبكة: addQuad (
       بولي [j0] ،
       بولي [j1] ،
       newPoly [j1] ،
       newPoly [j0]
     )
   نهاية
   - (3) نقل الوجه الموجود إلى الحقائق المقذوفة
   ل j = 1 ، #poly القيام به
     mesh.polys [pi] [j] = newPoly [j]
   نهاية
 نهاية 
الفطر موحد.كل شبكة الفطر
الآن بعد أن أصبح لدينا وظيفة getSurfaceNormal () ووظيفة extrude () ، أصبح الفطر سهل للغاية! نحن ببساطة 
نطبق الدالة extrude () على كل مضلع شبكي . نحن نستخدم البثق 
بطول عشوائي بحيث يكون لكل مضلع مقذوف حجم مختلف قليلاً ، مما يخلق شعوراً بالملمس. يتم تطبيق الخوارزمية الموضحة أدناه على المكعب الموضح أعلاه ، والذي يتكون بالكامل من رباعي الزوايا.
  وظيفة greeble (شبكة)
   لأني = 1 ، # شبكة
     - هذه القيم العشوائية تعسفية: ص
     طول العائمة = عشوائي: getUniformRange (0.1 ، 1.0)
     extrudePoly (شبكة ، أنا ، الطول)
   نهاية
   شبكة العودة
 نهاية 
مبروك ، لدينا الفطر المكتسبة. ولكن يمكننا أن نفعل أكثر! الآن الفطر موحد جدا. فيما يلي مثالان على التعديلات لجعلها أكثر إثارة للاهتمام.
التعديل 1: وجود الفطريات يعتمد على الصدفة
إنه أمر بسيط جدًا: ما عليك سوى لف القالب لتحديد ما إذا كان يجب تطبيق الفطر على كل مضلع. بفضل هذا ، يصبح الفطر أقل اتساقًا. يتم تطبيق الخوارزمية الموضحة أدناه على المكعب أعلاه.
  لأني = 1 ، # شبكة
    <strong> إذا كان عشوائيًا: فرصة (0.33) ثم </strong>
      طول العائمة = عشوائي (0.1 ، 1.0)
      extrudePoly (شبكة ، أنا ، الطول)
    نهاية
  نهاية
  شبكة العودة
 نهاية 
التعديل 2: إضافة مقياس النتوء
وهذا يتطلب تغيير خوارزمية البثق. عندما ننشئ رؤوس مضلع مبثوق ، يمكننا 
تقليلها باتجاه مركز المضلع بمقدار عشوائي لجعل الكائن يبدو أكثر تشويقًا.
بادئ ذي بدء ، يجب أن تتلقى دالة extrude () معلمة إضافية تحدد مقدار تضييق المضلع الجديد. سوف نحدده باسم Vec3 يسمى 
scale . لتحريك قمة الرأس نحو الوسط ، نقوم 
بتحريف موضع القمة بين 
موضعها الأصلي ومركز المضلع بقيمة 
scale .
(إذا كنت بحاجة إلى معرفة الخوارزمية للعثور على مركز المضلع ، فإنني أوصي سريعًا بالانتقال إلى 
البرنامج التعليمي حول التثليث وقراءة التثليث النقطي الوسطى).
  - العثور على مركز بولي
 Vec3 ج = شبكة: getFaceCentroid (بولي)
 ل j = 1 ، #poly القيام به
   ع المحلية = شبكة: getVertex (بولي [ي])
   newPoly [#newPoly + 1] = # mesh.verts
   النفس: addVertex (
     math.lerp (cx، px، scale.x) + nx * length ،
     math.lerp (cy، py، scale.y) + ny * length،
     math.lerp (cz، pz، scale.z) + nz * length
   )
   شبكة: addVertex (ع + (طول ن *))
 نهاية 
يمكنك الآن استخدامه في خوارزمية الفطر عن طريق التحجيم بقيمة عشوائية لكل مضلع. حتى نحصل على الصورة الموضحة أعلاه.
  وظيفة greeble (شبكة)
   لأني = 1 ، # شبكة
     طول العائمة = عشوائي: getUniformRange (0.1 ، 1.0)
     مقياس Vec3 = (عشوائي: getUniformRange (0.1 ، 1.0) ،
                   عشوائي: getUniformRange (0.1 ، 1.0) ،
                   عشوائي: getUniformRange (0.1 ، 1.0))
     extrudePoly (شبكة ، أنا ، الطول ، مقياس)
   نهاية
   شبكة العودة
 نهاية 
النهاية
عظيم ، وصلنا إلى النهاية! آمل أن يكون هذا البرنامج التعليمي مفيدًا لك.