نقوم بتعقيد نماذج الخيال العلمي من الناحية الإجرائية: ما هي قابلية استخدامها وكيفية استخدامها

صورة

بادئ ذي بدء ، اسمحوا لي أن أشكو من أن كلمة "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))
   نهاية
   عودة ن: تطبيع ()
 نهاية 


مثال يوضح قذف رباعي مستو.

البثق


الآن وقد أصبح لدينا معلومات عن السطح الطبيعي ، فنحن مستعدون لبثق المضلع في الاتجاه الطبيعي. ببساطة ، لبثق المضلع ، نقوم بإنشاء رؤوس جديدة عن طريق تحريك الرؤوس القديمة في اتجاه السطح الطبيعي.

مزيد من التفاصيل:

  1. إنشاء قمم جديدة "أعلاه" القديمة في الاتجاه الطبيعي.

    يمكن حساب رؤوس جديدة كما يلي:

      (موقف الذروة القديمة) + (الاتجاه الطبيعي) 

    هذا "يحول" الموقف القديم في اتجاه السطح الطبيعي.

    على سبيل المثال ، انظر إلى الصورة أعلاه ، حيث تتحرك v1 في الاتجاه الطبيعي إلى v5.
  2. قم بإنشاء رباعيات لربط الرؤوس الجديدة والقديمة.

    تجدر الإشارة إلى أنه لكل مؤشر في المضلع الجديد ، يتم إنشاء رباعي جديد.

    على سبيل المثال ، ألقِ نظرة على رباعية تم إنشاؤها من الإصدار 8 ، الإصدار 7 ، الإصدار 3 ، الإصدار 4 .
  3. استبدل المضلع القديم بمضلع جديد تم إنشاؤه بواسطة رؤوس جديدة. على سبيل المثال ، ألقِ نظرة على رباعية تم إنشاؤها من 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 (شبكة ، أنا ، الطول ، مقياس)
   نهاية
   شبكة العودة
 نهاية 

النهاية


عظيم ، وصلنا إلى النهاية! آمل أن يكون هذا البرنامج التعليمي مفيدًا لك.

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


All Articles