إعادة إحياء "ميدل إيرث" باستخدام WebGL للأجهزة الجوّالة
في السابق، كان من الصعب توفير تجارب تفاعلية مستندة إلى الويب وتعتمد على الوسائط المتعددة على الأجهزة الجوّالة واللوحية. وكانت القيود الرئيسية هي الأداء وتوفّر واجهة برمجة التطبيقات والقيود المفروضة على الصوت في HTML5 على الأجهزة وعدم توفّر إمكانية تشغيل الفيديوهات المضمّنة بسلاسة.
في وقت سابق من هذا العام، بدأنا مشروعًا مع أصدقاء من Google وWarner Bros. لإنشاء تجربة ويب تعطي الأولوية للأجهزة الجوّالة لفيلم الهوبيت الجديد The Hobbit: The Desolation of Smaug. لقد كانت مهمة إنشاء تجربة Chrome على الأجهزة الجوّالة التي تتضمّن وسائط متعددة مهمة ملهمة وتحدّية حقًا.
تم تحسين التجربة في Chrome لأجهزة Android على أجهزة Nexus الجديدة التي تتيح لنا الآن استخدام WebGL وWeb Audio. ومع ذلك، يمكن الوصول إلى جزء كبير من التجربة على الأجهزة والمتصفّحات التي لا تتضمّن WebGL أيضًا، وذلك بفضل ميزة الدمج المُسرَّع بالأجهزة والرسومات المتحرّكة في CSS.
تستند التجربة بأكملها إلى خريطة تُظهر ميدل إيرث والمواقع الجغرافية والشخصيات من أفلام الهوبيت. من خلال استخدام WebGL، تمكّنا من تصوير العالم الغني لثلاثية "الهوبيت" واستكشافه والسماح للمستخدمين بالتحكّم في التجربة.
تحديات WebGL على الأجهزة الجوّالة
أولاً، مصطلح "الأجهزة الجوّالة" واسع جدًا. تختلف مواصفات الأجهزة كثيرًا. وبالتالي، عليك كمطوّر تحديد ما إذا كنت تريد إتاحة التطبيق على المزيد من الأجهزة من خلال تجربة أقل تعقيدًا، أو الاقتصار على الأجهزة التي يمكنها عرض عالم ثلاثي الأبعاد أكثر واقعية، كما فعلنا في هذه الحالة. بالنسبة إلى "رحلة عبر ميدل إيرث"، ركّزنا على أجهزة Nexus وخمسة هواتف Android ذكية شائعة.
في التجربة، استخدمنا three.js كما فعلنا في بعض مشاريع WebGL السابقة. بدأنا التنفيذ من خلال إنشاء إصدار أولي من لعبة Trollshaw التي تعمل بشكل جيد على جهاز Nexus 10 اللوحي. بعد إجراء بعض الاختبارات الأولية على الجهاز، وضعنا قائمة بالتحسينات التي تشبه إلى حد كبير ما نستخدمه عادةً في أجهزة الكمبيوتر المحمول ذات المواصفات المنخفضة:
- استخدام نماذج ذات عدد قليل من المضلّعات
- استخدام مواد ذات دقة منخفضة
- يمكنك تقليل عدد عمليات الرسم قدر الإمكان من خلال دمج الأشكال الهندسية.
- تبسيط المواد والإضاءة
- إزالة التأثيرات اللاحقة وإيقاف ميزة تمويه الحواف
- تحسين أداء JavaScript
- عرض لوحة WebGL بنصف حجمها وتكبيرها باستخدام CSS
بعد تطبيق هذه التحسينات على الإصدار الأول غير المكتمل من اللعبة، حققنا معدّلًا ثابتًا للّقطات يبلغ 30 لقطة في الثانية، ما أسعدنا كثيرًا. في تلك المرحلة، كان هدفنا هو تحسين العناصر المرئية بدون التأثير سلبًا في معدّل عرض اللقطات. لقد جرّبنا العديد من الحيل: تبيّن أنّ بعضها كان له تأثير حقيقي في الأداء، بينما لم يكن لبعض منها تأثير كبير كما كنّا نأمل.
استخدام نماذج ذات عدد قليل من المضلّعات
لنبدأ بالنماذج. يساعد استخدام النماذج ذات عدد الأسطح المنخفض بالتأكيد في وقت التنزيل، بالإضافة إلى الوقت الذي يستغرقه إعداد المشهد. تبيّن لنا أنّه يمكننا زيادة التعقيد كثيرًا بدون التأثير في الأداء كثيرًا. تتألف نماذج المتصيدين التي نستخدمها في هذه اللعبة من حوالي 5 آلاف وجه، ويضم المشهد حوالي 40 ألف وجه، وهو ما يعمل بشكل جيد.

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

(الحجم الأصلي 512×512 بكسل)
تبسيط المواد والإضاءة
يمكن أن يؤثر اختيار المواد أيضًا بشكل كبير في الأداء، ويجب إدارته بحكمة على الأجهزة الجوّالة. من بين الإجراءات التي استخدمناها لتحسين الأداء استخدام MeshLambertMaterial
(لكل عملية حسابية للضوء في رأس المضلع) في three.js بدلاً من MeshPhongMaterial
(لكل عملية حسابية للضوء في وحدة البكسل). لقد حاولنا استخدام مواد مظللة بسيطة قدر الإمكان مع أقل عدد ممكن من عمليات احتساب الإضاءة.
لمعرفة مدى تأثير المواد التي تستخدمها في أداء المشهد، يمكنك إلغاء مواد المشهد باستخدام MeshBasicMaterial
. سيساعدك ذلك في إجراء مقارنة جيدة.
scene.overrideMaterial = new THREE.MeshBasicMaterial({color:0x333333, wireframe:true});
تحسين أداء JavaScript
عند إنشاء ألعاب للأجهزة الجوّالة، لا تكون وحدة معالجة الرسومات دائمًا أكبر عقبة. يتمّ إنفاق الكثير من الوقت على وحدة المعالجة المركزية، لا سيما في ما يتعلّق بقوانين الفيزياء والرسوم المتحرّكة للعظام. من الحيل التي تساعد أحيانًا، استنادًا إلى المحاكاة، هي عدم تنفيذ هذه العمليات الحسابية المُكلفة إلا كل لقطة أخرى. يمكنك أيضًا استخدام أساليب تحسين JavaScript المتاحة عندما يتعلق الأمر بتجميع العناصر وجمع المهملات وإنشاء العناصر.
إنّ تعديل العناصر المخصّصة مسبقًا في الحلقات بدلاً من إنشاء عناصر جديدة هو خطوة مهمة لتجنُّب "المشاكل" في جمع المهملات أثناء اللعبة.
على سبيل المثال، راجِع الرمز التالي:
var currentPos = new THREE.Vector3();
function gameLoop() {
currentPos = new THREE.Vector3(0+offsetX,100,0);
}
يتجنّب إصدار محسّن من هذه الحلقة إنشاء عناصر جديدة يجب جمعها:
var originPos = new THREE.Vector3(0,100,0);
var currentPos = new THREE.Vector3();
function gameLoop() {
currentPos.copy(originPos).x += offsetX;
//or
currentPos.set(originPos.x+offsetX,originPos.y,originPos.z);
}
يجب أن تعدّل معالجات الأحداث السمات فقط قدر الإمكان، وأن تترك requestAnimationFrame
حلقة التقديم تتولى تعديل المرحلة.
نصيحة أخرى هي تحسين و/أو احتساب عمليات بث الأشعة مسبقًا. على سبيل المثال، إذا كنت بحاجة إلى إرفاق جسم بشبكة أثناء حركة مسار ثابت، يمكنك "تسجيل" المواضع خلال حلقة واحدة ثم القراءة من هذه البيانات بدلاً من بث الأشعة على الشبكة. أو كما نفعل في تجربة Rivendell، يمكنك استخدام تقنية "إلقاء أشعة" للبحث عن تفاعلات الماوس باستخدام شبكة غير مرئية بسيطة منخفضة العناصر. إنّ البحث عن تصادمات في شبكة ذات عدد كبير من المضلّعات يكون بطيئًا جدًا ويجب تجنُّبه في حلقة اللعب بشكل عام.
عرض لوحة WebGL بنصف حجمها وتكبيرها باستخدام CSS
يُحتمل أن يكون حجم لوحة WebGL هو المَعلمة الأكثر فعالية التي يمكنك تعديلها لتحسين الأداء. كلما زاد حجم اللوحة التي تستخدمها لرسم المشهد الثلاثي الأبعاد، زاد عدد البكسلات التي يجب رسمها في كل إطار. يؤثر ذلك بالطبع في الأداء.على جهاز Nexus 10 الذي يتميز بشاشة عالية الكثافة بدقة 2560 × 1600 بكسل عرض 4 أضعاف عدد وحدات البكسل مقارنةً بجهاز لوحي منخفض الكثافة. لتحسين هذا الأداء على الأجهزة الجوّالة، نستخدم خدعة حيث نضبط اللوحة على نصف الحجم (%50) ثم نوسّعها إلى الحجم المطلوب (%100) باستخدام عمليات التحويل الثلاثية الأبعاد في CSS المُسرَّعة بالأجهزة. الجانب السلبي لهذا الإجراء هو ظهور الصورة بشكل مجزّأ، ما قد يتسبب في ظهور خطوط رفيعة، ولكنّ التأثير ليس سيئًا على الشاشة العالية الدقة. إنّ الأداء الإضافي الذي تحصل عليه يستحقّ العناء.

استخدام العناصر كوحدات أساسية
لنتمكّن من إنشاء المتاهة الكبيرة في قلعة دول غولديور ووادي ريفنديل الذي لا ينتهي أبدًا، أنشأنا مجموعة من النماذج الثلاثية الأبعاد لوحدات البناء التي يمكننا إعادة استخدامها. تتيح لنا إعادة استخدام العناصر التأكّد من إنشاء العناصر وتحميلها في بداية التجربة، وليس في منتصفها.

في Rivendell، لدينا عدد من الأقسام الأرضية التي نغيّر موقعها باستمرار في العمق (Z) مع تقدّم رحلة المستخدِم. وعندما يمر المستخدم بالمقاطع، تتم إعادة وضعها في مسافة بعيدة.
بالنسبة إلى قلعة دول غولدِر، أردنا إعادة إنشاء المتاهة في كل لعبة. ولإجراء ذلك، أنشأنا نصًا برمجيًا يعيد إنشاء المتاهة.
يؤدي دمج البنية بأكملها في شبكة كبيرة واحدة من البداية إلى إنشاء مشهد كبير جدًا وأداء ضعيف. لحلّ هذه المشكلة، قرّرنا إخفاء الوحدات الأساسية وعرضها بناءً على ما إذا كانت تظهر في العرض. منذ البداية، كانت لدينا فكرة عن استخدام نص برمجي لجهاز تصويب أشعة ثنائي الأبعاد، ولكن في النهاية استخدمنا أداة الاقتصاص المضمّنة في three.js. أعدنا استخدام نص raycaster لتكبير "الخطر" الذي يواجهه اللاعب.
العنصر التالي المهمّ الذي يجب التعامل معه هو تفاعل المستخدِم. على أجهزة الكمبيوتر المكتبي، يمكنك استخدام الماوس ولوحة المفاتيح، بينما يتفاعل المستخدمون على الأجهزة الجوّالة من خلال اللمس والتمرير السريع والتصغير/التكبير وتغيير اتجاه الجهاز وما إلى ذلك.
استخدام التفاعل باللمس في تجارب الويب على الأجهزة الجوّالة
إنّ إضافة ميزة اللمس إلى تطبيقك ليس بالأمر الصعب. تتوفّر مقالات رائعة حول هذا الموضوع. ولكن هناك بعض الأمور الصغيرة التي يمكن أن تجعل الأمر أكثر تعقيدًا.
يمكنك استخدام كلاهما، أي اللمس والماوس. يتيح جهاز Chromebook Pixel والأجهزة المحمولة الأخرى المزوّدة بشاشة تعمل باللمس استخدام الماوس والشاشة معًا. من الأخطاء الشائعة التحقّق مما إذا كان الجهاز مزوّدًا بشاشة تعمل باللمس ثم إضافة أدوات معالجة أحداث اللمس فقط بدون إضافة أي أدوات معالجة لأحداث الماوس.
لا تعدِّل العرض في أدوات معالجة الأحداث. احفظ أحداث اللمس في متغيّرات بدلاً من ذلك واستجِب لها في حلقة عرض requestAnimationFrame. يؤدي ذلك إلى تحسين الأداء ودمج الأحداث المتعارضة أيضًا. تأكَّد من إعادة استخدام العناصر بدلاً من إنشاء عناصر جديدة في أدوات معالجة الأحداث.
تذكَّر أنّه يتم استخدام تقنية اللمس المتعدّد: event.touches هي صفيف لجميع اللمسات. في بعض الحالات، من الأفضل الاطّلاع على event.targetTouches أو event.changedTouches بدلاً من ذلك والتفاعل فقط مع اللمسات التي تهمّك. لفصل النقرات عن التمريرات السريعة، نستخدم مهلة قبل التحقّق مما إذا كانت اللمسة قد تحرّكت (تمرير سريع) أو ما إذا كانت لا تزال ثابتة (نقر). للحصول على حركة التصغير/التكبير، نقيس المسافة بين لمستَين أوليتين ومدى تغيُّرها بمرور الوقت.
في العالم الثلاثي الأبعاد، عليك تحديد كيفية تفاعل الكاميرا مع إجراءات الماوس مقابل إجراءات التمرير السريع. من الطرق الشائعة لإضافة حركة للكاميرا هي اتّباع حركة الماوس. ويمكن إجراء ذلك إما من خلال التحكّم المباشر باستخدام موضع الماوس أو من خلال حركة دلتا (تغيير الموضع). قد لا تريد دائمًا أن يكون السلوك على الجهاز الجوّال مطابقًا للسلوك في متصفّح الكمبيوتر المكتبي. أجرينا اختبارات مكثفة لتحديد ما يناسب كل إصدار.
عند التعامل مع الشاشات الصغيرة والشاشات التي تعمل باللمس، ستلاحظ أنّ أصابع المستخدم ورسومات التفاعل مع واجهة المستخدم غالبًا ما تحجب ما تريد عرضه. وهذا أمر اعتدنا عليه عند تصميم التطبيقات المتوافقة مع الأجهزة الجوّالة، ولكن لم نكن نأخذه في الاعتبار من قبل عند تصميم تجارب الويب. يشكّل ذلك تحديًا حقيقيًا للمصمّمين ومصمّمي تجربة المستخدم.
ملخّص
تبيّن لنا من خلال تجربتنا الإجمالية في هذا المشروع أنّ WebGL يعمل بشكل جيد جدًا على الأجهزة الجوّالة، لا سيما على الأجهزة الجديدة المتطوّرة. في ما يتعلق بالأداء، يبدو أنّ عدد المضلّعات وحجم النسيج يؤثران في معظم الأحيان في وقتَي التنزيل والإعداد، وأنّ المواد وتأثيرات التظليل وحجم لوحة WebGL هي الأجزاء الأكثر أهمية لتحسين الأداء على الأجهزة الجوّالة. ومع ذلك، فإنّ مجموع الأجزاء هو ما يؤثر في الأداء، لذا فإنّ كل ما يمكنك فعله لتحسين الأداء مهم.
يعني استهداف الأجهزة الجوّالة أيضًا أنّك يجب أن تعتاد على التفكير في التفاعلات باللمس وأنّ الأمر لا يقتصر على حجم البكسل، بل يشمل أيضًا الحجم الفعلي للشاشة. في بعض الحالات، كان علينا تحريك الكاميرا الثلاثية الأبعاد إلى مسافة أقرب لمعرفة ما يحدث.
تم إطلاق التجربة وكانت رحلة رائعة. نتمنّى لك الاستفادة من هذه المعلومات.
هل تريد تجربتها؟ يمكنك السفر إلى الأرض الوسطى.