إنشاء كرة أرضية ثلاثية الأبعاد لعجائب الدنيا

مقدمة إلى الكرة الأرضية لعجائب الدنيا ثلاثية الأبعاد

إذا كنت قد شاهدت موقع Google World Wonders الذي تم إطلاقه مؤخرًا على متصفح متوافق مع WebGL، لعلك رأيت كرة أرضية تدور خيالية أسفل الشاشة. تقدم لك هذه المقالة معلومات عن كيفية عمل الكرة الأرضية وما استخدمناه في إنشائها.

لتقديم نظرة عامة سريعة، فإن الكرة الأرضية لعجائب الدنيا هي نسخة معدّلة بشكل كبير من WebGL Globe بواسطة فريق Google Data Arts. لقد أزلنا الكرة الأرضية الأصلية، وأزلنا وحدات بت الرسم البياني الشريطي، وغيّرنا أدوات التظليل، وأضفنا علامات HTML الرائعة القابلة للنقر وهندسة قارة الأرض الطبيعية من عرض GlobeTweeter التوضيحي من Mozilla (شكرًا جزيلاً لسيدريك بينسون!) وذلك لإنشاء كرة أرضية متحركة رائعة تتوافق مع نظام ألوان الموقع وتضيف طبقة إضافية من التطور إلى الموقع.

كان موجز التصميم للكرة الأرضية هو الحصول على خريطة متحركة رائعة المظهر مع علامات قابلة للنقر موضوعة أعلى مواقع التراث العالمي. مع أخذ ذلك في الاعتبار، بدأتُ أبحث عن محتوى مناسب. أول ما تبادر إلى الذهن هو WebGL Globe الذي أنشأه فريق Google Data Arts. إنها الكرة الأرضية وتبدو رائعة. ماذا تحتاج أيضًا، أليس كذلك؟

إعداد WebGL Globe

كانت الخطوة الأولى في تصميم التطبيق المصغّر للكرة الأرضية هي تنزيل WebGL Globe وإعداده وتشغيله. يتوفر WebGL Globe على الإنترنت في Google Code، ويسهل تنزيله وتشغيله. عليك تنزيل ملف zip واستخراجه والقرص المضغوط فيه وتشغيل خادم ويب أساسي: python -m SimpleHTTPServer. (تجدر الإشارة إلى أنّ خيار UTF-8 غير مفعَّل تلقائيًا في هذا العنوان، يمكنك استخدام هذا). إذا انتقلت الآن إلى http://localhost:8000/globe/globe.html، من المفترض أن ترى WebGL Globe.

بعد تشغيل WebGL Globe، حان الوقت لقطع كل الأجزاء غير الضرورية. لقد عدَّلت HTML لإزالة وحدات بت واجهة المستخدم وأزلت عناصر إعداد الرسم البياني لشريط الكرة الأرضية من وظيفة تهيئة الكرة الأرضية. وفي نهاية هذه العملية، كان لديّ WebGL Globe مبسّط جدًا على شاشتي. يمكنك تدويرها لتبدو رائعة، ولكن هذا كل ما في الأمر.

لخفض حجم العناصر غير الضرورية، حذفتُ جميع عناصر واجهة المستخدم من ملف index.html في الكرة الأرضية وعدّلت النص البرمجي للتهيئة ليظهر على النحو التالي:

if(!Detector.webgl){
  Detector.addGetWebGLMessage();
} else {
  var container = document.getElementById('container');
  var globe = new DAT.Globe(container);
  globe.animate();
}

إضافة هندسة القارة

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

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

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

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

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

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

هذا ما يبدو عليه نظام تظليل المحيط للكرة الأرضية السوداء. أداة تظليل للأجزاء بسيطة جدًا وأداة تظليل الأجزاء "يبدو لطيفًا جدًا tweak tweak" لتظليل الأجزاء.

    'ocean' : {
      uniforms: {
        'texture': { type: 't', value: 0, texture: null }
      },
      vertexShader: [
        'varying vec3 vNormal;',
        'varying vec2 vUv;',
        'void main() {',
          'gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );',
          'vNormal = normalize( normalMatrix * normal );',
          'vUv = uv;',
        '}'
      ].join('\n'),
      fragmentShader: [
        'uniform sampler2D texture;',
        'varying vec3 vNormal;',
        'varying vec2 vUv;',
        'void main() {',
          'vec3 diffuse = texture2D( texture, vUv ).xyz;',
          'float intensity = pow(1.05 - dot( vNormal, vec3( 0.0, 0.0, 1.0 ) ), 4.0);',
          'float i = 0.8-pow(clamp(dot( vNormal, vec3( 0, 0, 1.0 )), 0.0, 1.0), 1.5);',
          'vec3 atmosphere = vec3( 1.0, 1.0, 1.0 ) * intensity;',
          'float d = clamp(pow(max(0.0,(diffuse.r-0.062)*10.0), 2.0)*5.0, 0.0, 1.0);',
          'gl_FragColor = vec4( (d*vec3(i)) + ((1.0-d)*diffuse) + atmosphere, 1.0 );',
        '}'
      ].join('\n')
    }

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

إنشاء العلامات باستخدام CSS

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

تتكون علامات CSS من اثنين من عناصر div في موضعها المطلق مع خاصية تحويل CSS. تتميز خلفية العلامات بتدرج CSS وجزء المثلث من العلامة عبارة عن علامة div مستديرة. وتحتوي العلامات على ظل قطر صغير لإظهارها من الخلفية. كانت أكبر مشكلة في العلامات هي جعلها تعمل بشكل جيد بما فيه الكفاية. قد يبدو الأمر محزنًا، إلا أن رسم بضع عشرات من علامات div التي تتحرك وتغيير مؤشر z في كل إطار يعد طريقة جيدة جدًا لإظهار جميع أنواع أخطاء عرض المتصفح.

إن طريقة مزامنة العلامات مع المشهد ثلاثي الأبعاد ليست معقدة للغاية. تحتوي كل علامة على Object3D مقابل في المشهد Three.js، والذي يستخدم لتتبع العلامات. للحصول على إحداثيات مساحة الشاشة، آخذ المصفوفات Three.js للكرة الأرضية والعلامة، وأضرب الخط المتجه صفرًا بهذه المصفوفات. من ذلك أحصل على موضع مشهد العلامة. للحصول على موضع الشاشة لمحدّد الموقع، أعرض موضع المشهد من خلال الكاميرا. يحتوي المتجه المتوقع على إحداثيات مساحة الشاشة للعلامة، وهو جاهز للاستخدام في CSS.

var mat = new THREE.Matrix4();
var v = new THREE.Vector3();

for (var i=0; i<locations.length; i++) {
  mat.copy(scene.matrix);
  mat.multiplySelf(locations[i].point.matrix);
  v.set(0,0,0);
  mat.multiplyVector3(v);
  projector.projectVector(v, camera);
  var x = w * (v.x + 1) / 2; // Screen coords are between -1 .. 1, so we transform them to pixels.
  var y = h - h * (v.y + 1) / 2; // The y coordinate is flipped in WebGL.
  var z = v.z;
}

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

عند النقر على إحدى العلامات، يتم توسيعها إلى قائمة بأسماء أماكن قابلة للنقر. تعد هذه كلها عناصر HTML DOM عادية، لذا كانت كتابتها سهلة للغاية. تعمل جميع الروابط وعرض النصوص بدون أيّ مجهود إضافي من جانبنا.

الضغط على حجم الملف

مع تشغيل العرض التوضيحي ومشاركته ببقية موقع World Wonders، لا تزال هناك مشكلة كبيرة يجب حلها. وكان حجم الشبكة المتداخلة بتنسيق JSON لليابسة الأرضية نحو 3 ميغا بكسل. ليس جيدًا للصفحة الأولى في موقع عرض صور. من الجيد أن ضغط الشبكة باستخدام gzip، انخفض إلى 350 كيلو بايت. لكن مهلاً، لا يزال 350 كيلو بايت كبيرًا بعض الشيء. بعد إرسال بضع رسائل إلكترونية، تمكنا من توظيف "وون تشون"، الذي عمل على ضغط الشبكات الضخمة لجسم Google، بهدف مساعدتك في ضغط هذه الشبكات. وقد ضغط على الشبكة المتداخلة من قائمة مثلثات كبيرة مسطحة يتم تحديدها كإحداثيات JSON إلى إحداثيات مضغوطة 11 بت تتضمّن مثلثات مفهرسة، كما تم ضغط حجم الملف حتى يصل إلى 95 كيلو بايت.

لا يؤدي استخدام الشبكات المضغوطة إلى توفير معدّل نقل البيانات فحسب، بل يمكن أيضًا تحليل الشبكات بشكل أسرع. يتطلب تحويل 3 ميغ من الأرقام النصية إلى أرقام أصلية عملاً أكثر بكثير من تحليل مائة كيلوبايت من البيانات الثنائية. ويكون التقليل الناتج عن الصفحة البالغ 250 كيلو بايت رائع جدًا، كما يتم تسجيل وقت التحميل الأولي في أقل من ثانية عند اتصال 2 ميغابت في الثانية. أسرع وأصغر، رائع!

وفي الوقت نفسه، كنت أجرّب تحميل ملفات أشكال Earth الأصلية التي تم اشتقاق شبكة GlobeTweeter المتداخلة منها. تمكنت من تحميل ملفّات الأشكال ولكن عرضها على شكل يابسة مسطّحة يتطلّب إجراء شكل مثلث فيها (مع إضافة ثقوب للبحيرات، وناتش). حصلت على الأشكال ثلاثية الشكل باستخدام استخدام THREE.js ولكن ليس الثقوب. وكانت للشبكات الناتجة حواف طويلة جدًا، الأمر الذي تطلّب تقسيم الشبكة إلى أجزاء أصغر حجمًا. باختصار، لم أتمكّن من تشغيل الجهاز في الوقت المناسب، لكن الشيء المميّز هو أنّ تنسيق ملف Shapefile المضغوط بشكلٍ أكبر كان سيمنحك نموذج مساحة يابسة مقداره 8 كيلو بايت. حسنًا، ربما في المرة القادمة.

العمل المستقبلي

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

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

ملخّص

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

المراجع