1. قبل البدء
يعلّمك هذا الدرس التطبيقي حول كيفية استخدام الميزات المستندة إلى WebGL في واجهة برمجة تطبيقات JavaScript ل"خرائط Google" للتحكّم على الخريطة الموجّهة وعرضها في ثلاثة أبعاد.
المتطلّبات الأساسية
يفترض هذا الدرس التطبيقي حول الترميز أن لديك معرفة متوسطة بلغة JavaScript وواجهة برمجة تطبيقات JavaScript للخرائط. للتعرُّف على أساسيات استخدام واجهة برمجة تطبيقات JavaScript JS، جرّب الدرس التطبيقي حول إضافة خريطة إلى موقعك الإلكتروني (JavaScript).
ما ستتعرَّف عليه
- إنشاء رقم تعريف خريطة مع تفعيل الخريطة المتجهة لـ JavaScript.
- التحكم في الخريطة من خلال الإمالة والتدوير الآليين.
- عرض العناصر الثلاثية الأبعاد على الخريطة باستخدام
WebGLOverlayView
وthree.js. - صورة متحركة لحركات الكاميرا باستخدام
moveCamera
.
الأشياء التي تحتاج إليها
- حساب Google Cloud Platform تم تفعيل الفوترة به
- مفتاح API لمنصة "خرائط Google" مع تفعيل واجهة برمجة تطبيقات JavaScript ل"خرائط Google"
- معرفة متوسطة بجافا سكريبت وHTML وCSS
- محرِّر نصوص أو IDE من اختيارك
- Node.js
2. الإعداد
بالنسبة إلى خطوة التفعيل أدناه، عليك تفعيل واجهة برمجة تطبيقات JavaScript للخرائط.
إعداد "منصة خرائط Google"
إذا لم يكن لديك حساب على Google Cloud Platform ومشروع تم تفعيل الفوترة فيه، يُرجى الاطّلاع على دليل بدء استخدام "منصة خرائط Google" لإنشاء حساب فوترة ومشروع.
- في Cloud Console، انقر على القائمة المنسدلة للمشروع واختَر المشروع الذي تريد استخدامه لهذا الدرس التطبيقي.
- فعِّل واجهات برمجة تطبيقات ومنصة SDK لمنصة "خرائط Google" المطلوبة لهذا الدرس التطبيقي في Google Cloud Marketplace. ولإجراء ذلك، اتّبِع الخطوات الواردة في هذا الفيديو أو هذه المستندات.
- يمكنك إنشاء مفتاح واجهة برمجة تطبيقات في صفحة بيانات الاعتماد في Cloud Console. يمكنك اتّباع الخطوات الواردة في هذا الفيديو أو هذه المستندات. تتطلب جميع الطلبات إلى "منصة خرائط Google" مفتاح واجهة برمجة تطبيقات.
إعداد Node.js
وإذا لم يتوفّر لديك ذلك، يمكنك الانتقال إلى https://nodejs.org/ لتنزيل وقت تشغيل Node.js وتثبيته على جهاز الكمبيوتر.
يتوفّر برنامج Node.js مع مدير حزمة npm، والذي تحتاج إلى تثبيت تبعيات لهذا الدرس التطبيقي حول الترميز.
تنزيل نموذج بدء تشغيل المشروع
قبل بدء هذا الدرس التطبيقي، يُرجى اتّباع الخطوات التالية لتنزيل نموذج المشروع للمبتدئين، بالإضافة إلى رمز الحلّ الكامل:
- نزِّل إعادة اختبار GitHub أو تشعّبها لهذا الدرس التطبيقي على https://github.com/googlecodelabs/maps-platform-101-webgl/. يقع مشروع المبتدئين في الدليل
/starter
ويشمل بنية الملف الأساسية التي تحتاجها لإكمال الدرس التطبيقي حول الترميز. ستجد كل ما تحتاج إليه للعمل في دليل/starter/src
. - بعد تنزيل مشروع التفعيل، يمكنك تشغيل
npm install
في الدليل/starter
. يؤدي ذلك إلى تثبيت جميع التبعيات المطلوبة المدرجة فيpackage.json
. - بعد تثبيت تبعيات الأجهزة، يمكنك تشغيل
npm start
في الدليل.
تم إعداد مشروع المبتدئين لك لاستخدام webpack-dev-server، الذي يجمع ويشغِّل الرمز الذي تكتبه محليًا. وستتم أيضًا إعادة تحميل تطبيقك في المتصفح تلقائيًا في أي وقت تجري فيه تغييرات على الرمز.
إذا كنت تريد عرض رمز الحل بالكامل، يمكنك إكمال خطوات الإعداد أعلاه في دليل /solution
.
إضافة مفتاح واجهة برمجة التطبيقات
يتضمن تطبيق المبتدئين كل الرموز اللازمة لتحميل الخريطة باستخدام برنامج تحميل واجهة برمجة تطبيقات جافا سكريبت، بحيث كل ما تحتاج إليه هو تقديم مفتاح واجهة برمجة التطبيقات ورقم تعريف الخريطة. أداة التحميل JS API هي مكتبة بسيطة تزيل الطريقة التقليدية لتحميل واجهة برمجة تطبيقات JS API المضمنة في نموذج HTML بعلامة script
، مما يسمح لك بالتعامل مع كل شيء في رمز JavaScript.
لإضافة مفتاح واجهة برمجة التطبيقات، يجب تنفيذ ما يلي في مشروع إجراء التفعيل:
- فتح
app.js
- في الكائن
apiOptions
، اضبط مفتاح واجهة برمجة التطبيقات كقيمةapiOptions.apiKey
.
3- إنشاء واستخدام رقم تعريف الخريطة
لاستخدام الميزات المستندة إلى WebGL في واجهة برمجة تطبيقات JavaScript ل"خرائط Google"، تحتاج إلى رقم تعريف على الخريطة تم تفعيل ربط المتّجه إليه.
جارٍ إنشاء رقم تعريف للخريطة
- في Google Cloud Console، انتقِل إلى "منصة خرائط Google" ' > "إدارة الخرائط'؛.
- انقر على "إنشاء معرّف خريطة جديد"'؛
- في حقل "اسم الخريطة"، انقر على اسم لرقم تعريف الخريطة.
- في القائمة المنسدلة "نوع الخريطة"، انقر على "JavaScript'". ستظهر خيارات جافا سكريبت'؛.
- ضمن "خيارات جافا سكريبت '؛؛" اختَر زر الاختيار "Vector'"، ومربّع الاختيار "إمالة'" ومربع التدوير.
- Optional. في حقل "الوصف&39"، أدخِل وصفًا لمفتاح واجهة برمجة التطبيقات.
- انقر على الزر "التالي'؛ ستظهر صفحة "تفاصيل رقم تعريف الخريطة، رقم 39".
- انسخ رقم تعريف الخريطة. ستستخدم هذا في الخطوة التالية لتحميل الخريطة.
استخدام رقم تعريف الخريطة
لتحميل الخريطة الموجّهة، عليك تقديم رقم تعريف على الخريطة كموقع في الخيارات عند إنشاء الخريطة على الفور. ويمكنك أيضًا اختياريًا تقديم رقم تعريف الخريطة نفسه عند تحميل واجهة برمجة تطبيقات JavaScript للخرائط.
لتحميل الخريطة باستخدام رقم تعريف الخريطة، يمكنك إجراء ما يلي:
- اضبط رقم تعريف الخريطة كقيمة
mapOptions.mapId
.
يؤدي تقديم رقم تعريف الخريطة عند إنشاء خريطة إلى تزويد Google Maps Platform بخرائطك التي سيتم تحميلها لمثيل معين. ويمكنك إعادة استخدام رقم تعريف الخريطة نفسه في تطبيقات متعددة أو ملفات شخصية متعددة داخل التطبيق نفسه.const mapOptions = { "tilt": 0, "heading": 0, "zoom": 18, "center": { lat: 35.6594945, lng: 139.6999859 }, "mapId": "YOUR_MAP_ID" };
تحقّق من أن التطبيق قيد التشغيل في المتصفّح. من المفترض أن يتم تحميل خريطة المتّجه التي تم تفعيل الإمالة والتدوير فيها بنجاح. للتحقّق مما إذا كانت ميزة الإمالة والتدوير مفعّلة، اضغط مع الاستمرار على مفتاح shift واسحب باستخدام الماوس أو استخدِم مفاتيح الأسهم على لوحة المفاتيح.
إذا لم يتم تحميل الخريطة، تأكّد من تقديم مفتاح صالح لواجهة برمجة التطبيقات في apiOptions
. إذا لم تتم إمالة الخريطة وتدويرها، تأكد من تقديم معرّف خريطة مع تفعيل الإمالة والتدوير في apiOptions
وmapOptions
.
من المفترض أن يظهر ملف app.js
على النحو التالي:
import { Loader } from '@googlemaps/js-api-loader';
const apiOptions = {
"apiKey": 'YOUR_API_KEY',
};
const mapOptions = {
"tilt": 0,
"heading": 0,
"zoom": 18,
"center": { lat: 35.6594945, lng: 139.6999859 },
"mapId": "YOUR_MAP_ID"
}
async function initMap() {
const mapDiv = document.getElementById("map");
const apiLoader = new Loader(apiOptions);
await apiLoader.load();
return new google.maps.Map(mapDiv, mapOptions);
}
function initWebGLOverlayView (map) {
let scene, renderer, camera, loader;
// WebGLOverlayView code goes here
}
(async () => {
const map = await initMap();
})();
4. تنفيذ WebGLOverlayView
يتيح لك WebGLOverlayView
الوصول المباشر إلى سياق عرض WebGL نفسه المستخدَم لعرض الخريطة الأساسية للمتّجه. وهذا يعني أنه يمكنك عرض الكائنات الثنائية الأبعاد والثلاثية الأبعاد على الخريطة مباشرةً على الخريطة باستخدام WebGL، بالإضافة إلى مكتبات الرسومات المستندة إلى WebGL الشائعة.
تعرض WebGLOverlayView
خمس عناصر خطية في دورة حياة سياق عرض الخريطة على الخريطة التي يمكنك استخدامها. في ما يلي وصف سريع لكل خطف وما يجب فعله:
onAdd()
: يتم طلب هذا عند إضافة التراكب إلى خريطة عن طريق استدعاءsetMap
في مثيلWebGLOverlayView
. وهذا هو الموضع الذي عليك فيه تنفيذ أي عمل ذي صلة بـ WebGL ولا يتطلب الدخول المباشر إلى سياق WebGL.onContextRestored()
: يتم استدعاء عندما يصبح سياق WebGL متاحًا ولكن قبل عرض أي عنصر. وفي هذه الحالة، يجب إعداد العناصر وحالة الربط وتنفيذ أي إجراء آخر يحتاج إلى الوصول إلى سياق WebGL ولكن يمكن تنفيذه خارج استدعاءonDraw()
. ويسمح لك ذلك بإعداد كل ما تحتاجه بدون إضافة حمل زائد على العرض الفعلي للخريطة، وهو ما يستهلك الكثير من وحدة معالجة الرسومات.onDraw()
: يتم الاتصال مرة واحدة لكل إطار بعد بدء WebGL بعرض الخريطة وأي شيء آخر طلبته. يجب أن تبذل أقل قدر ممكن من الجهود فيonDraw()
لتجنب حدوث مشكلة في الأداء في عرض الخريطة.onContextLost()
: يتم طلب ذلك عند فقدان سياق عرض WebGL لأي سبب.onRemove()
: يتم طلب هذا عند إزالة التراكب من الخريطة من خلال استدعاءsetMap(null)
في مثيلWebGLOverlayView
.
في هذه الخطوة، ستنشئ مثيلًا لـ WebGLOverlayView
وتنفّذ ثلاث علامات تبويب دورة الحياة: onAdd
وonContextRestored
وonDraw
. للحفاظ على تنظيم العناصر وسهولة متابعته، سيتم التعامل مع كل رموز التراكب في دالة initWebGLOverlayView()
المُقدَّمة في نموذج إجراء التفعيل لهذا الدرس التطبيقي حول الترميز.
- إنشاء مثيل
WebGLOverlayView()
.
يتم توفير التراكب بواسطة واجهة برمجة تطبيقات JavaScript JS فيgoogle.maps.WebGLOverlayView
. للبدء، أنشئ مثيلاً من خلال انتظار ما يلي إلىinitWebGLOverlayView()
:const webGLOverlayView = new google.maps.WebGLOverlayView();
- تنفيذ الخطافات المناسبة لدورة الحياة.
تنفيذ العناصر التي تتم إضافتها في دورة الحياة، أضِف ما يلي إلىinitWebGLOverlayView()
:webGLOverlayView.onAdd = () => {}; webGLOverlayView.onContextRestored = ({gl}) => {}; webGLOverlayView.onDraw = ({gl, coordinateTransformer}) => {};
- إضافة مثيل التراكب إلى الخريطة.
يمكنك الآن استدعاء تطبيقsetMap()
على مثيل التراكب وتمريره في الخريطة من خلال إلحاق ما يلي بـinitWebGLOverlayView()
:webGLOverlayView.setMap(map)
- تواصل هاتفيًا مع "
initWebGLOverlayView
".
الخطوة الأخيرة هي تنفيذinitWebGLOverlayView()
من خلال إضافة ما يلي إلى الدالة التي تم استدعاؤها على الفور في أسفلapp.js
:initWebGLOverlayView(map);
من المفترض أن تبدو الدالة initWebGLOverlayView
والاستدعاء المُفعَّل على الفور بهذا الشكل:
async function initWebGLOverlayView (map) {
let scene, renderer, camera, loader;
const webGLOverlayView = new google.maps.WebGLOverlayView();
webGLOverlayView.onAdd = () => {}
webGLOverlayView.onContextRestored = ({gl}) => {}
webGLOverlayView.onDraw = ({gl, coordinateTransformer}) => {}
webGLOverlayView.setMap(map);
}
(async () => {
const map = await initMap();
initWebGLOverlayView(map);
})();
هذا كل ما تحتاج إليه لتنفيذ WebGLOverlayView
. بعد ذلك، سيكون عليك إعداد كل ما تحتاج إليه لعرض كائن ثلاثي الأبعاد على الخريطة باستخدام Three.js.
5. إعداد مشهد الثلاث.js
قد يكون استخدام WebGL معقّدًا للغاية لأنه يتطلب منك تحديد جميع جوانب كل عنصر يدويًا ثم بعضها. ولتسهيل هذه الأمور، ستستخدم هذا الدرس التطبيقي مع الترميز Three.js، وهو مكتبة رسومية رائجة توفّر طبقة مبسّطة عن فكرة مجرّد WebGL. يوفر Three.js مجموعة متنوعة من الوظائف السهلة التي تؤدي كل المهام بدءًا من إنشاء عارض WebGL إلى رسم الأشكال الشائعة ثنائية الأبعاد وثلاثية الأبعاد للتحكم في الكاميرات وعمليات تحويل الأشياء وغير ذلك الكثير.
هناك ثلاثة أنواع أساسية من العناصر في Three.js مطلوبة لعرض أي شيء:
- المشهد: A "container" حيث يتم عرض جميع العناصر والمصادر الخفيفة والزخارف وما إلى ذلك.
- الكاميرا: كاميرا تمثل نقطة المنظر تتوفّر أنواع متعددة من الكاميرات، ويمكن إضافة كاميرا واحدة أو أكثر إلى مشهد واحد.
- العارض: عارض يتعامل مع معالجة جميع العناصر في الموقع وعرضها. في Three.js، يكون
WebGLRenderer
هو الأكثر استخدامًا، ولكن يتوفر البعض الآخر كقيم احتياطية في حال كان البرنامج لا يدعم WebGL.
في هذه الخطوة، ستتمكّن من تحميل جميع تبعيات ملف 3.js المطلوبة وإعداد مشهد أساسي.
- تحميل three.js
ستحتاج إلى تبعيَّتين لهذا الدرس التطبيقي، هما مكتبة Three.js وGLTF Loader، وهي فئة تتيح لك تحميل عناصر ثلاثية الأبعاد بتنسيق GL Trasmission (gLTF). يوفر Three.js أدوات تحميل متخصصة للعديد من تنسيقات الكائنات الثلاثية الأبعاد المختلفة ولكن يُنصَح باستخدام gLTF.
في الرمز الوارد أدناه، يتم استيراد مكتبة Three.js بالكامل. في أحد تطبيقات الإنتاج، قد ترغب في استيراد الصفوف التي تحتاج إليها فقط، ولكن بالنسبة إلى هذا الدرس التطبيقي حول الترميز، يمكنك استيراد المكتبة بالكامل للحفاظ على بساطة الأمور. لاحظ أيضًا أن برنامج تحميل GLTF غير مضمّن في المكتبة التلقائية، ويجب استيراده من مسار منفصل في التبعية - وهو المسار الذي يمكنك من خلاله الوصول إلى جميع برامج التحميل التي يوفرها Three.js.
لاستيراد Three.js وGLTF Loader، أضِف ما يلي إلى أعلىapp.js
:import * as THREE from 'three'; import {GLTFLoader} from 'three/examples/jsm/loaders/GLTFLoader.js';
- أنشِئ مشهدًا بتنسيق ثلاثة.js.
لإنشاء مشهد، يمكنك إنشاء فئةScene
.js من خلال إلحاق ما يلي بخطافonAdd
:scene = new THREE.Scene();
- أضف كاميرا إلى المشهد.
كما ذكرنا سابقًا، تمثّل الكاميرا منظور المنظر في المشهد، وتحدّد طريقة تعامل Three.js مع العرض المرئي للعناصر في المشهد. وما مِن كاميرا في الواقع، لا يتم عرض المشهد في الواقع، ما يعني أن المحتوى لن يظهر لأنه لن يتم عرضه.
يوفّر تطبيق Three.js مجموعة متنوعة من الكاميرات التي تؤثر في كيفية تعامل العارض مع العناصر في ما يتعلق بعوامل مثل المنظور والعمق. في هذا المشهد، ستستخدمPerspectiveCamera
، وهو نوع الكاميرا الأكثر استخدامًا في Three.js، والذي تم تصميمه لمحاكاة نظرة عين الإنسان إلى المشهد. وهذا يعني أنّ العناصر البعيدة عن الكاميرا ستظهر أصغر من العناصر التي تكون أقرب إليك، وسيختفي المشهد من نقطة النهاية والمزيد.
لإضافة كاميرا منظور إلى المشهد، يمكنك إلحاق ما يلي بالخطّاط فيonAdd
:
باستخدامcamera = new THREE.PerspectiveCamera();
PerspectiveCamera
، يمكنك أيضًا ضبط السمات التي تشكّل نقطة المشاهدة، بما في ذلك الطائرات القريبة والبعيدة ونسبة العرض إلى الارتفاع ومجال الرؤية (الرنين). تشكّل هذه السمات إجمالاً ما يُعرف باسم ال إنجاز، وهو مفهوم مهم يجب استيعابه عند العمل بتقنية ثلاثية الأبعاد، ولكن خارج نطاق هذا الدرس التطبيقي حول الترميز. يكفي ضبطPerspectiveCamera
التلقائي. - أضِف مصادر إضاءة إلى المشهد.
بشكل تلقائي، ستظهر العناصر المعروضة في مشهد Three.js باللون الأسود، بغض النظر عن الزخارف التي تم تطبيقها عليها. وذلك لأنّ مشهد Three.js يحاكي كيفية عمل العناصر في العالم الحقيقي، حيث يعتمد مستوى رؤية اللون على الضوء الذي ينعكس على العنصر. باختصار، لا تكون هناك ألوان فاتحة.
يوفر Three.js مجموعة متنوعة من أنواع الإضاءة المختلفة التي ستستخدمها: AmbientLight
: لتوفير مصدر إضاءة منتشر في جميع العناصر في الصورة من جميع الزوايا بالتساوي. سيوفّر هذا الإجراء مقدارًا أساسيًا من الإضاءة لضمان ظهور الزخارف على كل العناصر.DirectionalLight
: لتوفير ضوء ينشأ من اتجاه في المشهد. وعلى عكس كيفية عمل المصباح ذي الموضع الصحيح في العالم الحقيقي، تكون شعاعات الضوء التي تنبعث منDirectionalLight
متوازية ولا تنتشر وتنتشر بعد بُعدها عن مصدر الضوء.
يمكنك ضبط لون كل كثافة وكثافتها لإنشاء تأثيرات إضاءة مجمّعة. على سبيل المثال، في الرمز أدناه، يقدّم الضوء المحيط ضوء أبيض ناعم للمشهد بأكمله، بينما يقدّم المصباح الاتجاهي ضوءًا ثانويًا يُصدِم أجسامًا بزاوية منخفضة. في حالة ضوء الاتجاه، يتم ضبط الزاوية باستخدامposition.set(x, y ,z)
، حيث ترتبط كل قيمة بالمحور ذي الصلة. على سبيل المثال، على سبيل المثال، ستضعposition.set(0,1,0)
الضوء فوق المشهد مباشرةً على المحور الصادي الذي يشير مباشرةً إلى الأسفل.
لإضافة مصادر الضوء إلى المشهد، يمكنك إلحاق ما يلي بخطافonAdd
:const ambientLight = new THREE.AmbientLight( 0xffffff, 0.75 ); scene.add(ambientLight); const directionalLight = new THREE.DirectionalLight(0xffffff, 0.25); directionalLight.position.set(0.5, -1, 0.5); scene.add(directionalLight);
من المفترض أن يبدو الخطاف في onAdd
الآن على النحو التالي:
webGLOverlayView.onAdd = () => {
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera();
const ambientLight = new THREE.AmbientLight( 0xffffff, 0.75 );
scene.add(ambientLight);
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.25);
directionalLight.position.set(0.5, -1, 0.5);
scene.add(directionalLight);
}
تم إعداد المشهد الآن وأصبح جاهزًا للعرض. بعد ذلك، سيكون عليك ضبط عارض WebGL وعرض المشهد.
6- عرض المشهد
حان الوقت لعرض المشهد. حتى الآن، يتم إعداد كل ما أنشأته باستخدام Three.js في الترميز، إلا أنه غير موجود في الأساس لأنه لم يتم عرضه بعد في سياق عرض WebGL. يعرض WebGL محتوى ثنائي الأبعاد وثلاثي الأبعاد في المتصفح باستخدام واجهة برمجة تطبيقات اللوحة. إذا كنت قد استخدمت واجهة برمجة تطبيقات"لوحة الرسم"من قبل، ربما تكون معتادًا على context
من لوحة رسم HTML، حيث يتم عرض كل شيء. ما لا تعرفه هو أن هذه هي واجهة تعرض سياق عرض رسومات OpenGL عبر واجهة برمجة تطبيقات WebGLRenderingContext
في المتصفّح.
لتسهيل التعامل مع عارض WebGL، يوفر Three.js WebGLRenderer
، وهو برنامج تضمين يسهِّل نسبيًا إعداد سياق عرض WebGL بحيث يمكن لـ Three.js عرض مشاهد في المتصفح. ولكن في حالة الخريطة، لا يكفي عرض مشهد Three.js في المتصفح إلى جانب الخريطة. يجب أن يُعرض Three.js في سياق العرض نفسه الموجود على الخريطة، بحيث يتم عرض كل من الخريطة وأي كائنات من مشهد Three.js في نفس العالم العالمي. ويتيح ذلك للعارض التعامل مع التفاعلات بين العناصر على الخريطة والكائنات في المشهد، مثل التراكم الذي يمثل تراكمًا في الخلفية أو تصغيرًا.
يبدو هذا معقدًا، أليس كذلك؟ لحسن الحظ، يأتي فريق Three.js للإنقاذ مرة أخرى.
- إعداد عارض WebGL.
عند إنشاء مثيل جديد منWebGLRenderer
.js الثلاثة، يمكنك توفير سياق عرض WebGL محدد تريد عرض المشهد عليه. هل تتذكر الوسيطةgl
التي يتم تمريرها إلى هوكonContextRestored
؟ عنصرgl
هو سياق عرض WebGL على الخريطة. ما عليك سوى توفير السياق واللوحة وسماتها إلى مثيلWebGLRenderer
، وكلها متوفّرة من خلال الكائنgl
. وفي هذا الرمز، يتم أيضًا ضبط خاصيةautoClear
الخاصة بالعارض علىfalse
بحيث لا يمحو العارض أي نتائج في كل إطار.
لإعداد عارض، يُرجى إلحاق ما يلي بخطافonContextRestored
:renderer = new THREE.WebGLRenderer({ canvas: gl.canvas, context: gl, ...gl.getContextAttributes(), }); renderer.autoClear = false;
- عرض المشهد
بعد إعداد العارض، اطلب منrequestRedraw
على المثيلWebGLOverlayView
إبلاغك بإعادة رسم الإطار عند عرض الإطار التالي، ثم استدعاءrender
على العارض وتمريره مشهد Three.js والكاميرا للعرض. وأخيرًا، عليك محو حالة سياق عرض WebGL. تُعد هذه خطوة مهمة لتجنب تعارض حالة GL، نظرًا لأن استخدام عرض تراكب WebGL يعتمد على حالة GL المشتركة. وإذا لم تتم إعادة ضبط الحالة في نهاية كل طلب سحب، قد تؤدي حالات GL للحالة إلى تعذّر العارض.
ولإجراء ذلك، أضِف ما يلي إلى خطّافonDraw
حتى يتم تنفيذ كل إطار:webGLOverlayView.requestRedraw(); renderer.render(scene, camera); renderer.resetState();
من المفترض أن تبدو الخطوط onContextRestored
وonDraw
الآن على النحو التالي:
webGLOverlayView.onContextRestored = ({gl}) => {
renderer = new THREE.WebGLRenderer({
canvas: gl.canvas,
context: gl,
...gl.getContextAttributes(),
});
renderer.autoClear = false;
}
webGLOverlayView.onDraw = ({gl, transformer}) => {
webGLOverlayView.requestRedraw();
renderer.render(scene, camera);
renderer.resetState();
}
7- عرض نموذج ثلاثي الأبعاد على الخريطة
حسنًا، لديك كل القطع في مكانها الصحيح. لقد أعددت عرض تراكب WebGL وأنشأت مشهد Three.js، ولكن هناك مشكلة واحدة: لا يوجد شيء فيه. والآن، حان وقت عرض كائن ثلاثي الأبعاد في المشهد. ولإجراء ذلك، ستستخدِم "أداة تحميل GLTF" التي استوردتها سابقًا.
تتوفّر النماذج الثلاثية الأبعاد بتنسيقات مختلفة، لكن تنسيق gLTF هو التنسيق المفضّل لملف Three.js بسبب حجمه وحجم وقت التشغيل. في هذا الدرس التطبيقي حول الترميز، يتوفّر لك نموذج ليتم عرضه في المشهد في /src/pin.gltf
.
- إنشاء مثيل عامل تحميل النموذج
إضافة ما يلي إلىonAdd
:loader = new GLTFLoader();
- حمِّل نموذجًا ثلاثي الأبعاد.
أدوات تحميل النماذج غير متزامنة وتنفِّذ استدعاءً بعد تحميل النموذج بالكامل. لتحميلpin.gltf
، أضِف ما يلي إلىonAdd
:const source = "pin.gltf"; loader.load( source, gltf => {} );
- أضِف النموذج إلى المشهد.
يمكنك الآن إضافة النموذج إلى المشهد من خلال إلحاق ما يلي باستدعاءloader
. لاحظ أنه تتم إضافةgltf.scene
، وليسgltf
:scene.add(gltf.scene);
- اضبط مصفوفة عرض الكاميرا.
وآخر ما تحتاج إليه لعرض النموذج بشكل سليم على الخريطة هو ضبط مصفوفة العرض للكاميرا في مشهد Three.js. يتم تحديد مصفوفة العرض على أنها مصفوفة Three.jsMatrix4
، والتي تحدد نقطة في ثلاث أبعاد بالإضافة إلى عمليات تحويل، مثل التدوير والقص والمقياس وغير ذلك.
في حالةWebGLOverlayView
، يتم استخدام مصفوفة العرض لإعلام العارض بمكان عرض مشهد Three.js وطريقة ارتباطه بالخريطة الأساسية. ولكن هناك مشكلة. يتم تحديد المواقع على الخريطة كأزواج إحداثيات خطوط العرض وخطوط الطول، بينما المواقع في مشهد Three.js هي إحداثياتVector3
. كما قد توقعت، لا يُعد حساب التحويل بين النظامين عملية بسيطة. لحل هذه المشكلة، يمرِّرWebGLOverlayView
كائنcoordinateTransformer
إلى خطاف دورة الحياةOnDraw
الذي يحتوي على دالة تُسمىfromLatLngAltitude
. يستخدمfromLatLngAltitude
كائنLatLngAltitude
أوLatLngAltitudeLiteral
، وبشكل اختياري، مجموعة من الوسيطات التي تحدد تحويلاً للمشهد، ثم تغطيها إلى مصفوفة إسقاط العرض (MVP) لك. ما عليك سوى تحديد المكان الذي تريد عرض مشهد Three.js عليه على الخريطة، بالإضافة إلى الطريقة التي تريد تحويله، وWebGLOverlayView
ستتكفل بالباقي. ويمكنك بعد ذلك تحويل مصفوفة MVP إلى مصفوفةMatrix4
Three.js وضبط مصفوفة عرض الكاميرا عليها.
في الرمز الوارد في ما يلي، تُطلب الوسيطة الثانية طريقة عرض WebGL المركّبة لضبط ارتفاع مشهد Three.js على ارتفاع 120 متر فوق سطح الأرض، الأمر الذي سيجعل النموذج يطفو.
لضبط مصفوفة عرض الكاميرا، يمكنك إلحاق ما يلي بخطافonDraw
:const latLngAltitudeLiteral = { lat: mapOptions.center.lat, lng: mapOptions.center.lng, altitude: 120 } const matrix = transformer.fromLatLngAltitude(latLngAltitudeLiteral); camera.projectionMatrix = new THREE.Matrix4().fromArray(matrix);
- تحويل النموذج.
ستلاحظ أن الدبوس لا يجلس بشكل عمودي على الخريطة. في الرسومات الثلاثية الأبعاد، إضافةً إلى الفضاء العالمي الذي يحتوي على محاور س وص وز
في حالة هذا النموذج، لم يتم إنشاؤه باستخدام ما نعتبره عادةً "أعلى" و#39، ودبابيس مواجهة للمحور "ص"، لذا تحتاج إلى تحويل الكائن إلى الاتجاه الملائم للمساحة الفضائية من خلال طلبrotation.set
عليه. لاحظ أنه في Three.js، يتم تحديد التدوير بوحدات الراديان وليس بالدرجات. يكون من السهل عمومًا التفكير بالدرجات، لذا يجب إجراء الإحالة الناجحة المناسبة باستخدام الصيغةdegrees * Math.PI/180
.
بالإضافة إلى ذلك، فإن النموذج صغير بعض الشيء، وبالتالي يمكنك أيضًا تغيير حجمه بشكل متساوٍ على جميع المحاور عن طريق الاتصال بـscale.set(x, y ,z)
.
لتدوير النموذج وتغيير حجمه، أضِف ما يلي في استدعاءloader
للسمةonAdd
قبلscene.add(gltf.scene)
، ما يضيف قيمة gLTF إلى المشهد:gltf.scene.scale.set(25,25,25); gltf.scene.rotation.x = 180 * Math.PI/180;
الآن، يستقر الدبوس بشكل عمودي على الخريطة.
من المفترض أن تبدو الخطوط onAdd
وonDraw
الآن على النحو التالي:
webGLOverlayView.onAdd = () => {
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera();
const ambientLight = new THREE.AmbientLight( 0xffffff, 0.75 ); // soft white light
scene.add( ambientLight );
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.25);
directionalLight.position.set(0.5, -1, 0.5);
scene.add(directionalLight);
loader = new GLTFLoader();
const source = 'pin.gltf';
loader.load(
source,
gltf => {
gltf.scene.scale.set(25,25,25);
gltf.scene.rotation.x = 180 * Math.PI/180;
scene.add(gltf.scene);
}
);
}
webGLOverlayView.onDraw = ({gl, transformer}) => {
const latLngAltitudeLiteral = {
lat: mapOptions.center.lat,
lng: mapOptions.center.lng,
altitude: 100
}
const matrix = transformer.fromLatLngAltitude(latLngAltitudeLiteral);
camera.projectionMatrix = new THREE.Matrix4().fromArray(matrix);
webGLOverlayView.requestRedraw();
renderer.render(scene, camera);
renderer.resetState();
}
نتعرّف في ما يلي على الصور المتحركة للكاميرا.
8- إضافة تأثيرات حركية إلى الكاميرا
الآن وبعد أن عرضت نموذجًا على الخريطة ويمكنك نقل كل شيء ثلاثي الأبعاد، فإن الخطوة التالية التي من المحتمل أن تريد تنفيذها هي التحكم في تلك الحركة آليًا. تتيح لك وظيفة moveCamera
ضبط خصائص المركز والتكبير/التصغير والإمالة والعنوان في الوقت نفسه، مما يمنحك التحكم الدقيق في تجربة المستخدم. بالإضافة إلى ذلك، يمكن استدعاء moveCamera
في حلقة صور متحركة لإنشاء انتقال سلس بين الإطارات عند 60 لقطة في الثانية تقريبًا.
- انتظِر حتى يتم تحميل النموذج.
لإنشاء تجربة سلسة للمستخدم، ستكون بحاجة إلى الانتظار لبدء تحريك الكاميرا حتى يتم تحميل نموذج gLTF. للقيام بذلك، أضِف معالج أحداثonLoad
للقائم بالتحميل إلى الخطّافonContextRestored
:loader.manager.onLoad = () => {}
- أنشئ حلقة رسوم متحركة.
هناك أكثر من طريقة واحدة لإنشاء حلقة صور متحركة، مثل استخدامsetInterval
أوrequestAnimationFrame
. في هذه الحالة، ستستخدم الوظيفةsetAnimationLoop
لعارض Three.js، والتي استدعاء تلقائيًا أي رمز تشير إليه في معاودة الاتصال في كل مرة يعرض فيها Three.js إطارًا جديدًا. لإنشاء حلقة الصور المتحركة، أضِف ما يلي إلى معالج أحداثonLoad
في الخطوة السابقة:renderer.setAnimationLoop(() => {});
- اضبط موضع الكاميرا في حلقة الصور المتحركة.
بعد ذلك، اتصل بالرقمmoveCamera
لتعديل الخريطة. في هذا المثال، يتم استخدام الخصائص من الكائنmapOptions
الذي تم استخدامه لتحميل الخريطة لتحديد موضع الكاميرا:map.moveCamera({ "tilt": mapOptions.tilt, "heading": mapOptions.heading, "zoom": mapOptions.zoom });
- عدِّل الكاميرا لكل إطار.
الخطوة الأخيرة عليك تعديل العنصرmapOptions
في نهاية كل إطار لضبط موضع الكاميرا للإطار التالي. في هذا الرمز، يتم استخدام عبارةif
لزيادة الإمالة حتى تصل إلى الحد الأقصى لقيمة الإمالة 67.5، ثم يتم تغيير العنوان قليلاً لكل إطار حتى تكمل الكاميرا دوران كامل بزاوية 360 درجة. بعد اكتمال الصورة المتحركة المطلوبة، يتم تمريرnull
إلىsetAnimationLoop
لإلغاء الصورة المتحركة حتى لا يتم تشغيلها إلى الأبد.if (mapOptions.tilt < 67.5) { mapOptions.tilt += 0.5 } else if (mapOptions.heading <= 360) { mapOptions.heading += 0.2; } else { renderer.setAnimationLoop(null) }
من المفترض أن يبدو الخطاف في onContextRestored
الآن على النحو التالي:
webGLOverlayView.onContextRestored = ({gl}) => {
renderer = new THREE.WebGLRenderer({
canvas: gl.canvas,
context: gl,
...gl.getContextAttributes(),
});
renderer.autoClear = false;
loader.manager.onLoad = () => {
renderer.setAnimationLoop(() => {
map.moveCamera({
"tilt": mapOptions.tilt,
"heading": mapOptions.heading,
"zoom": mapOptions.zoom
});
if (mapOptions.tilt < 67.5) {
mapOptions.tilt += 0.5
} else if (mapOptions.heading <= 360) {
mapOptions.heading += 0.2;
} else {
renderer.setAnimationLoop(null)
}
});
}
}
9- تهانينا
إذا تم تطبيق كل شيء وفقًا للخطة، يجب أن يكون لديك الآن خريطة تحتوي على دبوس كبير ثلاثي الأبعاد يبدو على النحو التالي:
ما تعلّمته
لقد تعلمت في هذا الدرس التطبيقي مجموعة من العناصر، وإليك أبرزها:
- تنفيذ ميزة
WebGLOverlayView
وحلقاتها الحيوية. - دمج Three.js في الخريطة.
- أساسيات إنشاء مشهد Three.js، بما في ذلك الكاميرات والإضاءة.
- تحميل النماذج الثلاثية الأبعاد ومعالجتها باستخدام Three.js.
- التحكم في الكاميرا وتحريكها باستخدام الخريطة باستخدام
moveCamera
.
ما الخطوات التالية؟
موضوع WebGL ورسومات الكمبيوتر بشكل عام موضوع معقد، وبالتالي يظل هناك العديد من الدروس الواجب تعلُّمها. في ما يلي بعض المراجع لمساعدتك في عملية الترقية:
- وثائق عرض تراكب WebGL
- بدء استخدام WebGL.
- وثائق ثلاثة.js
- يُرجى مساعدتنا في إنشاء المحتوى الذي قد تجده مفيدًا أكثر من خلال الإجابة عن السؤال التالي: «codelabs/maps-platform/shared/_next-lab-survey.lab.md}{ هل هذا هو الدرس التطبيقي حول الترميز الذي لا تريد إدراجه أعلاه؟ طلب حلول للمشكلة الجديدة هنا