ما هي مادة كاوية؟
المواد الكاوية هي أنماط ضوئية تحدث عندما ينكسر الضوء وينعكس من سطح ما ، في حالتنا ، عند حدود الماء والهواء.
نظرًا لأن الانعكاس والانكسار يحدثان على موجات الماء ، فإن الماء يعمل كعدسة ديناميكية هنا ، مما يخلق أنماط الضوء هذه.

في هذا المنشور ، سنركز على المواد الكاوية التي يسببها انكسار الضوء ، وهو ما يحدث عادة تحت الماء.
لتحقيق معدل ثابت يبلغ 60 إطارًا في الثانية ، نحتاج إلى حسابه على بطاقة رسومات (GPU) ، لذلك سنحسب فقط المواد الكاوية باستخدام تظليل مكتوب بلغة GLSL.
لحسابه نحتاج:
- احسب الأشعة المنكسرة على سطح الماء (في GLSL هذا سهل ، لأن هناك وظيفة مضمنة لهذا )
- يحسب ، باستخدام خوارزمية التقاطع ، النقاط التي تصطدم فيها هذه الأشعة بالبيئة
- احسب سطوع المادة الكاوية عن طريق فحص نقاط التقاء الأشعة

عرض تجريبي للمياه معروف على WebGL
لطالما كنت مندهشًا من هذا العرض التوضيحي لإيفان والاس الذي يعرض كاويات مائية واقعية بصريًا على WebGL: madebyevan.com/webgl-water

أوصي بقراءة مقالته المتوسطة ، والتي تشرح كيفية حساب المواد الكاوية في الوقت الفعلي باستخدام الشبكة الأمامية الخفيفة ووظائف GLSL PD . تنفيذها سريع للغاية ويبدو لطيفًا للغاية ، ولكن به بعض العيوب: إنه يعمل فقط مع تجمع مكعب وكرة بلياردو كروية . إذا وضعت سمكة قرش تحت الماء ، فلن يعمل العرض التوضيحي: فمن الثابت في الظلال أن هناك كرة كروية تحت الماء.
لقد وضع كرة تحت الماء لأن حساب التقاطع بين شعاع الضوء المنكسر والكرة مهمة سهلة تستخدم رياضيات بسيطة للغاية.
كل هذا جيد للعرض التوضيحي ، لكنني أردت إنشاء حل أكثر عمومية. لحساب المواد الكاوية بحيث يمكن أن تكون أي شبكات غير منظمة مثل القرش في البركة.

الآن دعنا ننتقل إلى تقنيتي. لهذه المادة، وسوف نفترض أن كنت تعرف أساسيات تقديم 3D مع التنقيط، والتي كنت معتادا على كيفية تظليل قمة الرأس و تظليل جزء العمل معا لتقديم الأوليات (المثلثات) على الشاشة.
العمل مع قيود GLSL
في التظليل المكتوب بلغة GLSL (لغة تظليل OpenGL) ، لا يمكننا الوصول إلا إلى كمية محدودة من المعلومات حول المشهد ، على سبيل المثال:
- سمات الرأس المرسوم حاليًا (الموضع: متجه ثلاثي الأبعاد ، عادي: متجه ثلاثي الأبعاد ، إلخ). يمكننا تمرير سمات GPU الخاصة بنا ، ولكن يجب أن تكون من النوع المدمج في GLSL.
- موحد ، أي الثوابت للشبكة المعروضة حاليًا بالكامل في الإطار الحالي. يمكن أن تكون هذه الأنسجة ، مصفوفة عرض الكاميرا ، اتجاه الإضاءة ، إلخ. يجب أن تحتوي على نوع مدمج: int ، float ، sampler2D للقوام ، vec2 ، vec3 ، vec4 ، mat3 ، mat4.
ومع ذلك ، لا توجد طريقة للوصول إلى الشبكات الموجودة في المشهد.
هذا هو السبب في أن العرض التوضيحي webgl-water لا يمكن أن يتم إلا بمشهد بسيط ثلاثي الأبعاد. من الأسهل حساب تقاطع شعاع منكسر وشكل بسيط للغاية يمكن تمثيله باستخدام التوحيد. في حالة الكرة ، يمكن تحديدها من خلال الموضع (متجه ثلاثي الأبعاد) ونصف القطر (عائم) ، لذلك يمكن تمرير هذه المعلومات إلى التظليل باستخدام الزي الموحد ، ويتطلب حساب التقاطعات عمليات حسابية بسيطة للغاية ، ويمكن تنفيذها بسهولة وسرعة في التظليل.
بعض تقنيات تتبع الأشعة التي يتم إجراؤها في التظليل تجعل الشبكات في الأنسجة ، ولكن في عام 2020 لا يمكن تطبيق هذا الحل على العرض في الوقت الفعلي على WebGL. يجب أن نتذكر أنه من أجل الحصول على نتيجة جيدة ، يجب أن نحسب 60 صورة في الثانية مع الكثير من الأشعة. إذا قمنا بحساب المواد الكاوية باستخدام أشعة 256 × 256 = 65536 ، فحينئذٍ يتعين علينا كل ثانية إجراء قدر كبير من حسابات التقاطع (والتي تعتمد أيضًا على عدد الشبكات في المشهد).
نحن بحاجة إلى إيجاد طريقة لتمثيل البيئة تحت الماء بشكل موحد وحساب التقاطع مع الحفاظ على السرعة الكافية.
إنشاء خريطة بيئية
عندما يكون حساب الظلال الديناميكية مطلوبًا ، فإن تعيين الظل هو أسلوب معروف جيدًا . غالبًا ما يتم استخدامه في ألعاب الفيديو ، ويبدو جيدًا وسريع التنفيذ.
رسم خرائط الظل هو أسلوب ذو مسارين:
- أولاً ، يتم تقديم المشهد ثلاثي الأبعاد من حيث مصدر الضوء. هذا النسيج لا يحتوي على ألوان الشظايا ، ولكن عمق الأجزاء (المسافة بين مصدر الضوء والجزء). يسمى هذا النسيج بخريطة الظل.
- ثم يتم استخدام خريطة الظل عند عرض المشهد ثلاثي الأبعاد. عند رسم جزء على الشاشة ، نعلم ما إذا كان هناك جزء آخر بين مصدر الضوء والجزء الحالي. إذا كان الأمر كذلك ، فنحن نعلم أن الجزء الحالي في الظل ، ونحتاج إلى رسمه بشكل أغمق قليلاً.
يمكنك قراءة المزيد حول تعيين الظل في هذا البرنامج التعليمي الممتاز لبرنامج OpenGL: www.opengl-tutorial.org/intermediate-tutorials/tutorial-16-shadow-mapping .
يمكنك أيضًا مشاهدة مثال تفاعلي على ThreeJS (اضغط على T لعرض خريطة الظل في الزاوية اليسرى السفلية): threejs.org/examples/؟q=shadowm#webgl_shadowmap .
في معظم الحالات ، تعمل هذه التقنية بشكل جيد. يمكن أن تعمل مع أي شبكة غير منظمة في المشهد.
في البداية اعتقدت أنه يمكنني استخدام نهج مماثل للمواد الكاوية المائية ، أي تحويل البيئة تحت الماء أولاً إلى نسيج ، ثم استخدام هذا النسيج لحساب التقاطع بين الأشعة والبيئة.... بدلاً من عرض أعماق الأجزاء فقط ، أقوم أيضًا بعرض موضع الأجزاء في خريطة البيئة.
إليك نتيجة إنشاء خريطة البيئة:

خريطة Env: يتم تخزين موضع XYZ في قنوات RGB ، والعمق في قناة ألفا
كيفية حساب تقاطع شعاع ومحيطه
الآن بعد أن أصبح لدي خريطة للبيئة تحت الماء ، أحتاج إلى حساب التقاطع بين الأشعة المنكسرة والبيئة.
تعمل الخوارزمية على النحو التالي:
- المرحلة الأولى: تبدأ عند نقطة التقاطع بين شعاع الضوء وسطح الماء
- المرحلة 2: حساب الانكسار باستخدام دالة الانكسار
- المرحلة 3: الانتقال من الموضع الحالي في اتجاه الشعاع المنكسر ، بكسل واحد في نسيج خريطة البيئة.
- المرحلة 4: قارن عمق المحيط المسجل (المخزن في البكسل الحالي لنسيج المحيط) بالعمق الحالي. إذا كان عمق البيئة أكبر من العمق الحالي ، فنحن بحاجة إلى المضي قدمًا ، لذلك نطبق الخطوة 3 مرة أخرى . إذا كان عمق البيئة أقل من العمق الحالي ، فهذا يعني أن الشعاع اصطدم بالبيئة عند قراءة الموضع من نسيج البيئة ووجدنا تقاطعًا مع البيئة.

العمق الحالي أقل عمقًا من العمق المحيط: تابع

العمق الحالي أكبر من العمق المحيط: وجدنا التقاطع
مادة كاوية
بعد إيجاد التقاطع ، يمكننا حساب النصوع الكاوية (ونسيج الإنارة الكاوية) باستخدام التقنية التي وصفها إيفان والاس في مقالته . يبدو النسيج الناتج مثل هذا:

نسيج الإنارة الكاوية (لاحظ أن تأثير المادة الكاوية أقل أهمية على سمك القرش لأنه أقرب إلى سطح الماء ، مما يقلل من تقارب أشعة الضوء)
يحتوي هذا النسيج على معلومات حول شدة الضوء لكل نقطة في الفضاء ثلاثي الأبعاد. عند عرض المشهد النهائي ، يمكننا قراءة شدة الضوء من النسيج الكاوية والحصول على النتيجة التالية:


يمكن العثور على تطبيق لهذه التقنية في مستودع Github: github.com/martinRenou/threejs-caustics . أعطها نجمة إذا أحببت ذلك!
إذا كنت تريد رؤية نتائج حساب المواد الكاوية ، فيمكنك تشغيل العرض التوضيحي: martinrenou.github.io/threejs-caustics .
حول خوارزمية التقاطع هذه
هذا القرار يعتمد بشكل كبير على دقة نسيج البيئة . كلما كان النسيج أكبر ، كانت دقة الخوارزمية أفضل ، ولكن كلما استغرق الأمر وقتًا أطول للعثور على حل (قبل العثور عليه ، تحتاج إلى حساب ومقارنة عدد أكبر من وحدات البكسل).
أيضًا ، قراءة النسيج في التظليل أمر مقبول طالما أنك لا تفعل ذلك كثيرًا ؛ هنا نقوم بإنشاء حلقة تستمر في قراءة وحدات البكسل الجديدة من النسيج ، وهو أمر غير مستحسن.
علاوة على ذلك ، لا يُسمح باستخدام حلقات while في WebGL.(ولسبب وجيه) ، لذلك نحن بحاجة إلى تنفيذ خوارزمية في حلقة for يمكن للمترجم توسيعها. هذا يعني أننا بحاجة إلى شرط إنهاء الحلقة المعروف في وقت الترجمة ، عادةً قيمة "الحد الأقصى للتكرار" ، والتي تجبرنا على التوقف عن البحث عن حل إذا لم نعثر عليه ضمن الحد الأقصى لعدد المحاولات. يؤدي هذا القيد إلى نتائج كاوية غير صحيحة إذا كان الانكسار مهمًا للغاية.
أسلوبنا ليس بالسرعة التي يقترحها الأسلوب المبسط الذي اقترحه إيفان والاس ، ولكنه أكثر مرونة بكثير من أسلوب تتبع الشعاع الكامل ويمكن استخدامه أيضًا للعرض في الوقت الفعلي. ومع ذلك ، لا تزال السرعة تعتمد على بعض الظروف - اتجاه الضوء وسطوع الانكسارات ودقة النسيج المحيط.
إغلاق الاستعراض التجريبي
في هذه المقالة ، نظرنا في حساب المادة الكاوية للماء ، ولكن تم استخدام تقنيات أخرى في العرض التوضيحي.
عند عرض سطح الماء ، استخدمنا نسيج مربع السماء وخرائط مكعب للحصول على انعكاسات. قمنا أيضًا بتطبيق الانكسار على سطح الماء باستخدام الانكسار البسيط في مساحة الشاشة (راجع هذه المقالة حول الانعكاسات والانكسارات في مساحة الشاشة) ، هذه التقنية غير صحيحة جسديًا ، ولكنها مقنعة بصريًا وسريعة. أضفنا أيضًا الانحراف اللوني لمزيد من الواقعية.
لدينا المزيد من الأفكار لتحسين المنهجية ، بما في ذلك:
- الانحراف اللوني على المواد الكاوية: نحن الآن نطبق الانحراف اللوني على سطح الماء ، ولكن هذا التأثير يجب أن يكون مرئيًا أيضًا على المواد الكاوية تحت الماء.
- تشتت الضوء في حجم الماء.
- كما نصح مارتن جيرارد وآلان وولف على Twitter ، يمكننا تحسين الأداء باستخدام خرائط البيئة الهرمية (والتي سيتم استخدامها كأشجار رباعية للعثور على التقاطعات). كما نصحوا أيضًا بتقديم خرائط البيئة من حيث الأشعة المنكسرة (على افتراض أنها مسطحة تمامًا) ، مما يجعل الأداء مستقلاً عن زاوية حدوث الإضاءة.
شكر وتقدير
تم تنفيذ هذا العمل على تصور واقعي للمياه في الوقت الحقيقي في QuantStack وبتمويل من ERDC .