عند العمل باستخدام الأصول المضلعة ، يمكنك رسم كائن واحد فقط في وقت واحد (إذا كنت لا تأخذ في الاعتبار تقنيات مثل التجميع والتثبيط) ، ولكن إذا كنت تستخدم حقول المسافات بعلامة (حقول المسافة الموقعة ، SDF) ، فنحن لا نقتصر على ذلك. إذا كان لموضعين نفس الإحداثيات ، فسوف تُرجع وظائف المسافة الموقعة القيمة نفسها ، وفي حساب واحد يمكننا الحصول على عدة أرقام. لفهم كيفية تحويل المساحة المستخدمة لإنشاء حقول مسافة موقَّعة ، نوصيك بمعرفة كيفية
إنشاء أشكال باستخدام وظائف المسافة الموقعة والجمع بين أشكال sdf .
التكوين
بالنسبة لهذا البرنامج التعليمي ، أقوم بتعديل الاقتران بين المربع والدائرة ، لكن يمكنك استخدامه لأي شكل آخر. هذا مشابه لتكوين
البرنامج التعليمي السابق .
من المهم هنا أن يكون الجزء القابل للتعديل قبل استخدام المواقف لإنشاء أرقام.
Shader "Tutorial/036_SDF_Space_Manpulation/Type"{ Properties{ _InsideColor("Inside Color", Color) = (.5, 0, 0, 1) _OutsideColor("Outside Color", Color) = (0, .5, 0, 1) _LineDistance("Mayor Line Distance", Range(0, 2)) = 1 _LineThickness("Mayor Line Thickness", Range(0, 0.1)) = 0.05 [IntRange]_SubLines("Lines between major lines", Range(1, 10)) = 4 _SubLineThickness("Thickness of inbetween lines", Range(0, 0.05)) = 0.01 } SubShader{
وتبدو الوظيفة 2D_SDF.cginc الموجودة في نفس المجلد مع التظليل ، والتي سنقوم بتوسيعها ، في البداية كما يلي:
#ifndef SDF_2D #define SDF_2D
تكرار الفضاء
انعكاس المرآة
واحدة من أبسط العمليات هي عكس العالم عن المحور. لنسخها حول المحور y ، نأخذ القيمة المطلقة للمكون x في موضعنا. وبالتالي ، فإن الإحداثيات إلى يمين ويسار المحور ستكون هي نفسها.
(-1, 1)
يتحول إلى
(1, 1)
، ويظهر داخل الدائرة ، باستخدام
(1, 1)
كأصل
(1, 1)
ويبلغ نصف قطرها أكبر من 0.
في أغلب الأحيان ، سيبدو الرمز الذي يستخدم هذه الوظيفة مثل
position = mirror(position);
النسخة
position = mirror(position);
حتى نتمكن من تبسيطها قليلا. سوف نعلن ببساطة حجة الموقف كما inout. وبالتالي ، عند الكتابة إلى الوسيطة ، فإنه سيغير أيضًا المتغير الذي نمرره إلى الوظيفة. يمكن أن تكون قيمة الإرجاع من النوع "باطلة" ، لأننا ما زلنا لا نستخدم قيمة الإرجاع.
لقد اتضح أنه جيد بالفعل بالفعل ، ولكن بهذه الطريقة نحصل على محور واحد فقط للنسخ المتطابق. يمكننا توسيع الوظيفة عن طريق تدوير المساحة كما فعلنا عند تدوير الأشكال. تحتاج أولاً إلى تدوير المساحة ، ثم عكسها ، ثم إعادة تدويرها. بهذه الطريقة يمكننا أداء النسخ المتطابق فيما يتعلق بأي زاوية. نفس الشيء ممكن عند نقل المساحة وتنفيذ النقل العكسي بعد النسخ المتطابق. (إذا قمت بإجراء كلتا العمليتين ، ثم قبل النسخ المتطابق ، لا تنسَ إجراء عملية النقل أولاً ، ثم المنعطف ، وبعد ذلك يتم الدوران أولاً).
خلايا
إذا كنت تعرف كيف يعمل
توليد الضوضاء ، فأنت تفهم أنه بالنسبة للجيل الإجرائي ، فإننا غالبًا ما نكرر هذا الموقف ونحصل على خلايا صغيرة متماثلة أساسًا ، تختلف فقط في المعلمات غير المهمة. يمكننا أن نفعل الشيء نفسه بالنسبة لحقول المسافة.
نظرًا لأن وظيفة
fmod
(بالإضافة إلى استخدام٪ للقسمة على الباقي) تعطينا الباقي ، وليس تعريف الباقي ، فسوف يتعين علينا استخدام خدعة. أولاً ، نأخذ باقي تقسيم عدد صحيح بواسطة الدالة fmod. بالنسبة للأرقام الموجبة ، هذا هو بالضبط ما نحتاج إليه ، وبالنسبة للأعداد السالبة ، هذه هي النتيجة التي نحتاجها مطروحًا منها هذه الفترة. يمكنك إصلاح ذلك عن طريق إضافة فترة ومرة أخرى أخذ باقي التقسيم. ستؤدي إضافة فترة إلى إعطاء النتيجة المرغوبة لقيم المدخلات السالبة ، وقيم المدخلات الموجبة ، تكون القيمة أعلى بفترة واحدة. لن تفعل البقية الثانية من القسمة أي شيء بقيم قيم المدخلات السلبية ، لأنها موجودة بالفعل في النطاق من 0 إلى الفترة ، وبالنسبة لقيم المدخلات الإيجابية ، فإننا نطرح أساسًا فترة واحدة.
المشكلة في الخلايا هي أننا نفقد الاستمرارية التي نحب بها حقول المسافات. هذا ليس سيئًا إذا كانت الأشكال موجودة فقط في منتصف الخلايا ، ولكن في المثال الموضح أعلاه ، يمكن أن يؤدي ذلك إلى بعض التحف الفنية الهامة التي ينبغي تجنبها عند استخدام حقول المسافات لمجموعة متنوعة من المهام التي يمكن فيها عادة استخدام حقول المسافات.
هناك حل واحد لا يعمل في كل حالة ، لكن عندما ينجح ، من الرائع: عكس كل خلية أخرى. للقيام بذلك ، نحتاج إلى فهرس خلايا البكسل ، لكننا لا نزال لا نمتلك قيمة إرجاع في الوظيفة ، حتى نتمكن من استخدامها فقط لإرجاع فهرس الخلية.
لحساب مؤشر الخلية ، نقوم بتقسيم الموضع على الفترة. وبالتالي ، 0-1 هي الخلية الأولى ، 1-2 هي الثانية ، وهكذا ... ويمكننا أن نفهمها بسهولة. للحصول على فهرس الخلية ، قمنا ببساطة بتقريب القيمة لأسفل وإرجاع النتيجة. الشيء المهم هو أننا نحسب مؤشر الخلية قبل الانقسام مع الباقي لتكرار الخلايا. وإلا ، فسنحصل على مؤشر 0 في كل مكان ، لأن الموضع لا يمكن أن يتجاوز المدة.
مع هذه المعلومات ، يمكننا قلب الخلايا. لفهم ما إذا كان يجب قلبه أم لا ، نقسم معامل فهرس الخلية 2. تكون نتيجة هذه العملية بالتناوب 0 و 1 أو -1 في كل خلية ثانية. لجعل التغيير أكثر ديمومة ، نأخذ القيمة المطلقة ونحصل على قيمة تنتقل بين 0 و 1.
لاستخدام هذه القيمة للانعكاس بين الموضع العادي والمقلوب ، نحتاج إلى وظيفة لا تفعل شيئًا للقيمة 0 ، ونطرح الموضع من الفترة التي يكون فيها التقليب هو 1. وهذا هو ، ونحن نقوم بإجراء الاستيفاء الخطي من الوضع الطبيعي إلى المقلوب باستخدام متغير التقليب . نظرًا لأن المتغير flip هو ناقل ثنائي الأبعاد ، يتم قلب مكوناته بشكل فردي.
خلايا شعاعية
ميزة أخرى كبيرة هي تكرار الفضاء في نمط شعاعي.
للحصول على هذا التأثير ، نقوم أولاً بحساب الموضع الشعاعي. للقيام بذلك ، نقوم بتشفير الزاوية بالنسبة إلى مركز المحور س والمسافة من المركز على طول المحور ص.
float2 radialPosition = float2(atan2(position.x, position.y), length(position));
ثم نكرر الزاوية. نظرًا لأن نقل عدد التكرارات أسهل بكثير من زاوية كل قطعة ، فنحن أولاً نحسب حجم كل قطعة. الدائرة بأكملها هي 2 * pi ، حتى نحصل على الجزء الصحيح ، نقسم 2 * pi على حجم الخلية.
const float PI = 3.14159; float cellSize = PI * 2 / cells;
باستخدام هذه المعلومات ، يمكننا تكرار المكون x للموضع الكعبري لكل وحدات حجم الخلية. نقوم بإجراء التكرار عن طريق القسمة على الباقي ، وبالتالي ، كما كان من قبل ، فإننا نواجه مشاكل مع الأعداد السالبة ، والتي يمكن القضاء عليها بمساعدة وظيفتي تقسيم مع الباقي.
radialPosition.x = fmod(fmod(radialPosition.x, cellSize) + cellSize, cellSize);
ثم تحتاج إلى نقل الموضع الجديد مرة أخرى إلى إحداثيات س ص المعتادة. هنا نستخدم الدالة sincos مع المكون x للموضع الكعبري كزاوية لكتابة الجيب إلى إحداثي x للموقف وجيب التمام إلى إحداثي y. مع هذه الخطوة ، حصلنا على وضع طبيعي. للحصول على الاتجاه الصحيح من المركز ، تحتاج إلى ضربه بالمكون ص في الموضع الشعاعي ، وهو ما يعني الطول.
ثم يمكننا أيضًا إضافة فهرس الخلايا والنسخ المتطابق ، كما فعلنا مع الخلايا العادية.
من الضروري حساب مؤشر الخلية بعد حساب الموضع الشعاعي ، ولكن قبل استلام الباقي من القسمة. نحصل عليه بتقسيم المكون x للموضع الشعاعي وتقريب النتيجة لأسفل. في هذه الحالة ، يمكن أن يكون الفهرس سالبًا ، وهذه مشكلة إذا كان عدد الخلايا غريبًا. على سبيل المثال ، مع 3 خلايا ، نحصل على خلية واحدة بمؤشر من 0 ، وخلية واحدة بمؤشر من -1 و 2 من الخلايا النصفية مع الفهارس 1 و -2. للتغلب على هذه المشكلة ، نضيف عدد الخلايا إلى المتغير المقرب لأسفل المتغير ، ثم نقسم على حجم الخلية مع الباقي.
لعكس هذا ، نحتاج إلى أن تكون الإحداثيات بالراديان ، لذلك لتجنب إعادة حساب الإحداثيات الشعاعية خارج الوظيفة ، نضيف خيارًا لها باستخدام الوسيطة bool. عادةً ما يكون الترحيل في التظليل غير مرحب به (في حالة البناء) ، ولكن في هذه الحالة ، ستذهب جميع وحدات البكسل على الشاشة إلى نفس المسار ، لذلك هذا طبيعي.
يجب أن يحدث النسخ المتطابق بعد الإحداثي نصف الدائري ، ولكن قبل أن يتم تحويله إلى وضعه الطبيعي. سوف نكتشف ما إذا كنا بحاجة إلى قلب الخلية الحالية بتقسيم مؤشر الخلية على 2 مع الباقي ، وعادةً ما يعطينا هذا أصفارًا وأخرى ، لكن في حالتي ، تظهر عدة توائم ، وهي غريبة ، ولا يزال بإمكاننا التعامل معها. للتخلص من الثغرات ، نقوم ببساطة بطرح 1 من متغير الوجه ، ثم نأخذ القيمة المطلقة. وبالتالي ، تصبح الأصفار والقصاصات وحدات ، وتصبح الوحدات أصفارًا ، حسب حاجتنا ، بترتيب عكسي فقط.
نظرًا لأن الأصفار والأخرى بالترتيب الخاطئ ، فنحن نقوم بإجراء الاستيفاء الخطي من الإصدار رأسًا على عقب إلى الإصدار رأسًا على عقب ، وليس العكس ، كما كان من قبل. لقلب الإحداثيات ، نقوم ببساطة بطرح الموضع من حجم الخلية.
يتمايل الفضاء
ولكن لتغيير الفضاء ليس من الضروري لتكرار ذلك. على سبيل المثال ، في البرنامج التعليمي حول الأساسيات ، قمنا بتدويره ونقله وتغيير حجمه. يمكنك أيضًا القيام بما يلي: حرك كل محور على أساس الآخر بموجة جيبية. سيؤدي ذلك إلى جعل مسافات وظيفة المسافة الموقعة أقل دقة ، ولكن حتى يتأرجح كثيرًا ، سيكون كل شيء على ما يرام.
أولاً ، نحسب حجم التغير في الموضع عن طريق قلب مكونات x و y ، ثم ضربها بتردد التذبذب. ثم نأخذ جيب من هذه القيمة ونضربها بمقدار التمايل الذي نريد إضافته. بعد ذلك ، نضيف ببساطة عامل التذبذب إلى الموضع ونطبق النتيجة مرة أخرى على الموضع.
يمكننا أيضًا تحريك هذا التلويح ، وتغيير موضعه ، وتطبيق التلويح في موضع الإزاحة وإعادة المساحة مرة أخرى. بحيث لا تصبح أرقام الفاصلة العائمة كبيرة جدًا ، أقوم بالتقسيم مع الباقي pi * 2 حسب التردد المتذبذب ، وهذا يرتبط بالتذبذب (الجيوب الأنفية يكرر كل وحدة pi * 2) ، لذلك نتجنب القفزات والإزاحة الكبيرة جدًا.
شفرة المصدر
2D مكتبة قوات الدفاع الذاتى
#ifndef SDF_2D #define SDF_2D
شادر التجريبي الأساسي
Shader "Tutorial/036_SDF_Space_Manpulation/Mirror"{ Properties{ _InsideColor("Inside Color", Color) = (.5, 0, 0, 1) _OutsideColor("Outside Color", Color) = (0, .5, 0, 1) _LineDistance("Mayor Line Distance", Range(0, 2)) = 1 _LineThickness("Mayor Line Thickness", Range(0, 0.1)) = 0.05 [IntRange]_SubLines("Lines between major lines", Range(1, 10)) = 4 _SubLineThickness("Thickness of inbetween lines", Range(0, 0.05)) = 0.01 } SubShader{
الآن أنت تعرف كل أساسيات وظائف مسافة الإشارة التي يمكن أن أتذكرها. في البرنامج التعليمي التالي ، سأحاول القيام بشيء مثير للاهتمام معهم.