الجسيمات اللينة في WebGL و OpenGL ES

تعد أنظمة الجسيمات من أسهل الطرق لجعل المشهد ثلاثي الأبعاد أكثر ثراءً بصريًا. في أحد تطبيقات Android الخاصة بنا ، فإن 3D Buddha Live Wallpaper هو مشهد بسيط إلى حد ما ، والذي سيكون لطيفًا لإضافة المزيد من التفاصيل. وعندما فكرنا في كيفية إضافة تنوع للصورة ، كان القرار الأكثر وضوحًا لملء المساحة الفارغة حول تمثال بوذا هو إضافة نفث من الدخان أو الضباب. بفضل استخدام الجزيئات اللينة ، حققنا نتيجة جيدة. في هذه المقالة ، سنصف بالتفصيل تنفيذ الجسيمات اللينة على WebGL / OpenGL ES النقي دون استخدام مكتبات الطرف الثالث ومحركات 3D الجاهزة.

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



الجسيمات اللينة


فما هي هذه الجسيمات اللينة؟ قد تتذكر أنه في العديد من الألعاب القديمة (Quake 3 و CS 1.6) كانت تأثيرات الدخان والانفجارات حدودًا مسطحة واضحة جدًا عند تقاطع الجسيمات مع هندسة مختلفة. لم تعد جميع الألعاب الحديثة تحتوي على مثل هذه القطع الأثرية بسبب استخدام الجسيمات اللينة - أي الجسيمات ذات الضبابية ، والحواف "الناعمة" حول الأشياء المجاورة.

استدعاء


ما هو المطلوب لجعل الجسيمات ناعمة؟ أولاً ، نحتاج إلى معلومات حول عمق المشهد من أجل تحديد تقاطع الجسيمات مع الأشياء الأخرى وتخفيفها. ثم نحتاج إلى تحديد تقاطع المشهد وهندسة الجسيمات من خلال مقارنة أعماق المشهد والجسيم في تظليل الشظايا - التقاطعات حيث تكون الأعماق متشابهة. بعد ذلك ، سنلقي نظرة على عملية التقديم خطوة بخطوة. كلا تطبيقي المشهد لـ Android OpenGL ES و WebGL متماثلان ، والفرق الرئيسي هو فقط في تحميل الموارد. التطبيق على WebGL مفتوح المصدر ويمكنك الحصول عليه هنا - https://github.com/keaukraine/webgl-buddha .

عرض خريطة العمق


لتقديم خريطة عمق المشهد ، نحتاج أولاً إلى إنشاء مواد لخريطة العمق واللون وتعيينها إلى FBO محدد. يتم ذلك في الطريقة initOffscreen () في الملف BuddhaRenderer.js .
يتم تنفيذ العرض الفعلي لكائنات المشهد على خريطة العمق نفسها في طريقة drawDepthObjects () ، التي ترسم تمثال بوذا ومستوى أرضية. ومع ذلك ، هناك خدعة واحدة لتحسين الأداء. نظرًا لأنه في هذه المرحلة من العرض ، لا نحتاج إلى معلومات اللون ، ولكن فقط العمق ، يتم تعطيل العرض إلى المخزن المؤقت للألوان عن طريق استدعاء gl.colorMask (false ، false ، false ، false) ، ثم تشغيله مرة أخرى عن طريق استدعاء gl.colorMask (true ، true ، true ، صحيح) . GlcolorMask () وظيفةيمكن تشغيل وإيقاف تسجيل مكونات الأحمر والأخضر والألفا بشكل منفصل ، لذلك من أجل إيقاف التسجيل تمامًا في المخزن المؤقت للألوان ، نقوم بضبط جميع المكونات على خطأ ثم تشغيلها لعرضها على الشاشة ، وتعريضها جميعًا إلى حقيقة. يمكن رؤية نتيجة التقديم إلى نسيج العمق من خلال إلغاء تعليق الاستدعاء drawTestDepth () في أسلوب drawScene () . نظرًا لأن نسيج خريطة العمق يحتوي على قناة واحدة فقط ، فإنه يُنظر إليه بمجرد أن تكون القنوات الحمراء والأزرق والأخضر صفرًا. يبدو تصور الخريطة العميقة لمشهدنا كما يلي:


تجسيد الجسيمات


يوجد كود التظليل المستخدم لتقديم الجسيمات في الملف SoftDiffuseColoredShader.js . دعونا نرى كيف يعمل.

الفكرة الرئيسية لإيجاد تقاطع هندسة الجسيمات والمشهد هي مقارنة قيمة عمق الشظية الحالي بالقيمة المخزنة من خريطة العمق.

تتمثل الخطوة الأولى في مقارنة الأعماق في جعل الخطوط العميقة خطية ، لأن القيم الأصلية أسية. يتم ذلك باستخدام دالة calc_depth () . هذه التقنية موصوفة جيدًا هنا - https://community.khronos.org/t/soft-blending-do-it-yourself-solved/58190 . لقيم الخطية ، نحتاج إلى متغير Uniform vec2 uCameraRangeالتي تحتوي مكوناتها x و y على قيم طائرتي القطع القريبتين والبعيدين للكاميرا. ثم يحسب التظليل الفرق الخطي بين عمق الجسيم والمشهد - يتم تخزين هذه القيمة في المتغير أ. ومع ذلك ، إذا طبقنا هذه القيمة على لون الجزء ، نحصل على جزيئات شفافة للغاية - سيتلاشى اللون بشكل خطي من أي هندسة خلف الجسيم ، ويتلاشى بسرعة كبيرة. هذه هي الطريقة التي يبدو بها تصور الاختلاف الخطي في العمق (يمكنك فك التعليق عن السطر المقابل من التعليمات البرمجية في التظليل ورؤيته):


لجعل الجسيمات أكثر شفافية فقط بالقرب من حد التقاطع (في المنطقة a = 0) ، نقوم بتطبيق دالة GLSL smoothstep () على قيمة المتغير a مع قيمة الانتقال من 0 إلى المعامل المحدد في زي uTransitionSize ، الذي يحدد عرض الانتقال الشفاف. إذا كنت ترغب في معرفة المزيد عن وظيفة softstep () ورؤية بعض الأمثلة المثيرة للاهتمام حول استخدامها ، فإننا نوصي بقراءة هذه المقالة - http://www.fundza.com/rman_shaders/smoothstep/ . يتم تخزين المعامل النهائي في المتغير ب. من أجل وضع خلط الألوان المستخدم في المشهد الخاص بنا ، ما عليك سوى مضاعفة لون الجسيمات المأخوذة من الملمس بواسطة هذا المعامل ؛ في تطبيقات الجسيمات الأخرى ، قد تحتاج إلى تغيير ، على سبيل المثال ، قناة ألفا فقط. إذا ألغيت تعليق سطر الكود في التظليل لتصور هذا المعامل ، فستبدو النتيجة كما يلي:


مقارنة القيم المختلفة لمعامل "ليونة" الجسيمات:

العفريت تحسين الأداء


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


عادة ما تسمى نماذج الجسيمات هذه لوحة. بالطبع ، لا يمكن تقديمها كبدائل لـ GL_POINTS ، لذلك يتم رسم كل جسيم بشكل منفصل. هذا لا يخلق الكثير من مكالمات drawElements ، في المشهد بأكمله لا يوجد سوى 18 جزيء من الضباب. يجب وضعها في إحداثيات عشوائية ، تحجيمها ولكن تدويرها بطريقة تكون دائمًا متعامدة مع الكاميرا بغض النظر عن موقعها. يتم تحقيق ذلك عن طريق تعديل المصفوفة الموصوفة في هذه الإجابة على StackOverflow . توجد طريقة calculateMVPMatrixForSprite () في ملف BuddhaRenderer.js التي تنشئ مصفوفات MVP لنماذج لوحة الإعلانات. ينفذ جميع التحولات المعتادة للإزاحة والتحجيم ثم يستخدمresetMatrixRotations () لإعادة تعيين مكون التدوير في مصفوفة عرض النموذج قبل ضربه في مصفوفة الإسقاط. تقوم المصفوفة الناتجة بتحويل ونتيجة لذلك يتم توجيه النموذج دائمًا إلى الكاميرا بالضبط.

نتيجة


يمكن رؤية النتيجة النهائية مباشرة هنا .

يمكنك تعلم وإعادة استخدام التعليمات البرمجية المصدر من Github لمشاريعك .

All Articles