بعد تعلّم المعلومات الرئيسية عن الفضاء ثلاثي الأبعاد والإضاءة، تعجّلنا في نهاية الدرس السابق لكي نحصل على صورة ثلاثية الأبعاد، إلا أنني سأعود قليلًا إلى الوراء وأشرح كائنات threeJS بالتفصيل قبل إعادة عرض الناتج مجددًا.
التفاصيل
أنشأنا في نهاية الدرس السابق جسمًا كرويًا نمثّل به لكوكب المريخ:
let marsGeo = new THREE.SphereGeometry (500, 32, 32);
تدعم مكتبة threeJS أشكالا هندسية مختلفة، من بينها الشكل الكروي الذي يُتحصَّل عليه بالدالة SphereGeometry
. نمرّر للدالة في المعطى الأول قيمة نصف قطر الكرة (500
)، عدد القطع الأفقية المكونة للكرة (32
) وعدد القطع العموديّة (32
). يُنشَأ كل جسمٍ افتراضيًا في نقطة المبدأ (0, 0, 0
)، لذا لا حاجة إلى نقل الجسم.
ماذا يحدث لو قلّلنا عدد القطع إلى 4 في كل اتجاه من الكرة؟ الصورة الآتية تعرض أثر اختلاف عدد القطع (من اليسار إلى اليمين: 4
ثم 8
ثم 16
ثم 32
قطعة أفقيًا وشاقوليًا لكل جسم).
يمكنك أن تلاحظ أنَّ حافة الجسم تصبح «خشنةً» كلما قلّ عدد القطع؛ ويبدو الجزء الأمامي من الجسم كرويًا بسبب الأضواء والمُظلِّلات (shaders، سأتحدث عن المُظلِّلات بعد قليل).
كقاعدة عامة: كلما ازدادت عدد القطع الموجودة في أحد الأجسام كان «أنعم»؛ لكن زيادة عدد القطع له سلبياته، فالعدد الكبير من القطع يؤدي إلى زيادة وقت المعالجة اللازم لإظهار المشهد إضافةً إلى زيادة حجم الذاكرة اللازمة لعرضه.
عليك الموازنة بين الأمرين وذلك بتحديد دقة التفاصيل التي تحتاج لها في الجسم؛ فلو كانت الكرة بعيدةً جدًا أو صغيرةً جدًا، فلن تحتاج إلى قطعٍ كثيرة لكي تجعلها تبدو كرويةً، لكن إذا أردتَ إنشاء مشهدٍ يصوِّر الكوكب عن قرب، فعليك زيادة عدد القطع لتضمن أنَّ حواف الكرة ستبقى ناعمةً حتى لو اقتربنا كثيرًا من الكوكب.
تركيب «المواد»
طبّقنا في آخر مثال مادة Phong (Phong material) إلى الكرة:
marsMaterial = new THREE.MeshPhongMaterial( { color: 0xff6600 } ),
Phong هي خوارزمية تظليل (Shader algorithm) كتبها أحد باحثي رسوميات الحاسوب الفيتناميين. الغرض من المُظلِّل هو تعريف كيفية تفاعل الضوء مع السطح ثلاثي الأبعاد: وكانت خوارزمية Phong سريعةً وكفاءتها عالية، ومثاليةً لعرض السطوح الناعمة.
يجب أن تُدمَج المادة مع كائن ثلاثي الأبعاد في threeJS لإنشاء mesh:
marsMesh = new THREE.Mesh(marsGeo, marsMaterial);
الناتج المعروض في المثال السابق بسيطٌ جدًا ولا يناسب غرضنا، فنحن نريد إنشاء كوكب، وليس كرةً برتقاليةً لامعة. ولإنشاء هذا الشعور، فعلينا تضمين المزيد من المواد ووضعها على الكرة، وذلك عبر Texture Loader:
let loader = new THREE.TextureLoader();
هنالك الكثير من الجوانب التي تتعلق بالمواد المُشكِّلة للجسم، وأبرزها – في حالة كوكب المريخ – هو اللون، لكن سطح كوكب المريخ متنوع جدًا ولا يمكن تمثيله بلونٍ واحد. فالحل هو أخذ إحدى الخرائط التي أنشأتها المكوكات الفضائية واستعمالها على الكرة. استعملتُ في هذا المثال صورًا من Celestia ثم ضبطُها لتكوِّن خريطةً المواد لسطح الكوكب:
marsMaterial.map = loader.load(imgLoc+"mars-map.jpg");
ربما تتذكر من أوّل درس في هذه السلسلة أننا عرّفنا المتغير imgLoc
الذي يحتوي على مسار تخزين الصور.
قياس الخريطة المستعملة مع WebGL
على النقيض من عدد القطع التي تُشكِّل الجسم، من المستحسن استخدام خرائط ذات دقة عالية، لأنها تعطي شعورًا بدقة تفاصيل الجسم؛ لكن ذلك يؤدي إلى نفس المشاكل: استخدام ذاكرة أكثر، وتقليل الأداء.
أجرتَ WebGL موازنة بين ما سبق عبر وضع شرطين للخرائط المستعملة:
- يجب أن يكون عرض وارتفاع الخريطة من قوى العدد 2: أي 1 أو 2 أو 4 أو 8 أو 16 أو 32 أو 64 أو 128 أو 256 أو 512 أو 1024 أو 2048 أو 4096 أو 8192 بكسل طولًا أو عرضًا (يمكن أن تختلف الأرقام. فمن الممكن أن تكون الخريطة بعرض 1024 وبارتفاع 512).
- هنالك حدٌّ أقصى لما تستطيع متصفحات الهاتف استعماله لخرائط الأجسام، وهذا الحد يرتفع مع مرور الوقت (نظام iOS 10 يدعم خريطةً بأبعاد 4096×4096، ويمكنك تجربة مختلف الأجهزة والأنظمة في webglreport.com).
سأعيد تحجيم الخريطة التي سأستعملها إلى 4096×2048 بكسل:
من المهم أن تكون الخريطة سلسة الحواف (seamless): أي عندما توضع على كرة، فلن تكون حدودها واضحةً.
العرض
لإنتاج أيّ مشهد فعلينا «عرضه» (render)، وذلك باستخدام شفرة ذات خمسة أسطر، على النحو التالي:
let renderer = new THREE.WebGLRenderer({antialiasing : true});
marsloc.appendChild(renderer.domElement);
function render(){
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.clear();
renderer.render(scene, camera);
}
استعملنا الخيار antialiasing
لتنعيم شكل كوكب المريخ عند تعريف المتغير renderer
(الذي يملك خياراتٍ كثيرة أخرى).
المتغير marsLoc
هو العنصر الذي سيحتوي على مشهد WebGL والذي أنشأناه في الجزء الأول، حيث أضفنا renderer
إليه.
أما داخل الدالة render
فكانت أبعاد المشهد مساويةً لأبعاد نافذة المتصفح؛ ثم مسحنا كل ما كان موجودًا في لوح الرسم، ثم عرضنا المشهد باستخدام الكاميرا التي عرَّفناها سابقًا.
ستلاحظ الآن أنَّ النتيجة تبدو مسطحةً ولامعةً، وثابتةً في الفضاء، وغير متجاوبة؛ وسنتخذ التدابير اللازمة في الدرس القادم من هذه السلسلة لحلّ تلك المشاكل.
ترجمة –وبتصرّف– للمقال A WebGL Tour of the Solar System: Mars, Part ThreeلصاحبهDudley Storey
أفضل التعليقات
لا توجد أية تعليقات بعد
انضم إلى النقاش
يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.