בעזרת שכבת על מבוססת-WebGL אפשר להוסיף תוכן למפות באמצעות WebGL ישירות, או באמצעות ספריות גרפיקה פופולריות כמו Three.js. שכבת על מבוססת-WebGL מספקת גישה ישירה לאותו הקשר של עיבוד WebGL שבו משתמשת Google Maps Platform כדי לרנדר את מפת הבסיס הווקטורית. השימוש בהקשר משותף של רינדור מספק יתרונות כמו הסתרת עומק באמצעות גיאומטריה של בניין תלת-ממדי, והיכולת לסנכרן תוכן דו-ממדי ותלת-ממדי עם רינדור של מפת בסיס. אפשר גם לקשור אובייקטים שמעובדים באמצעות שכבת על מבוססת-WebGL לקואורדינטות של קו רוחב וקו אורך, כך שהם יזוזו כשגוררים, מגדילים, מקטינים, מזיזים או משנים את זווית התצוגה של המפה.
דרישות
כדי להשתמש בשכבת על מבוססת-WebGL, צריך לטעון את המפה באמצעות מזהה מפה עם מפה וקטורית מופעלת. מומלץ מאוד להפעיל את ההטיה והסיבוב כשיוצרים את מזהה המפה, כדי לאפשר שליטה מלאה במצלמה בתלת-ממד. פרטים נוספים מופיעים במאמר הסקירה הכללית.
הוספת שכבת על מבוססת-WebGL
כדי להוסיף את שכבת העל למפה, מטמיעים את google.maps.WebGLOverlayView ואז מעבירים את מופע המפה באמצעות setMap:
// Create a map instance.
const map = new google.maps.Map(mapDiv, mapOptions);
// Create a WebGL Overlay View instance.
const webglOverlayView = new google.maps.WebGLOverlayView();
// Add the overlay to the map.
webglOverlayView.setMap(map);
קטעי הוק (hooks) של מחזור החיים
התכונה 'שכבת על מבוססת-WebGL' מספקת קבוצה של ווים שמופעלים בזמנים שונים במחזור החיים של הקשר העיבוד של WebGL במפת הבסיס הווקטורית. ב-lifecycle hooks האלה מגדירים, מציירים ומסירים כל מה שרוצים שיוצג בשכבת-העל.
- הפונקציה
onAdd()מופעלת כשהשכבה השקופה נוצרת. אפשר להשתמש בו כדי לאחזר או ליצור מבני נתונים ביניים לפני שהשכבה מוצגת, שלא דורשים גישה מיידית להקשר של עיבוד WebGL. - הקריאה ל-
onContextRestored({gl})מתבצעת אחרי שהקשר של העיבוד זמין. אפשר להשתמש בו כדי לאתחל או לקשור כל מצב WebGL, כמו shaders, אובייקטים של GL buffer וכו'. הפונקציהonContextRestored()מקבלת מופע שלWebGLStateOptionsשיש לו שדה אחד:-
glהוא שם שלWebGLRenderingContextשמשמש במפת הבסיס.
-
-
onDraw({gl, transformer})מעבד את הסצנה במפה הבסיסית. הפרמטרים שלonDraw()הם אובייקטWebGLDrawOptions, שיש לו שני שדות:-
glהוא שם שלWebGLRenderingContextשמשמש במפת הבסיס. -
transformerמספק פונקציות עזר להמרה מקואורדינטות של מפה למטריצת הקרנה של תצוגת מודל, שאפשר להשתמש בה כדי לתרגם קואורדינטות של מפה למרחב עולמי, למרחב מצלמה ולמרחב מסך.
-
-
onContextLost()נקראת כשהקשר העיבוד אבד מסיבה כלשהי, וזה המקום שבו צריך לנקות את מצב ה-GL הקיים, כי הוא כבר לא נחוץ. -
onStateUpdate({gl})מעדכן את מצב ה-GL מחוץ ללולאת הרינדור, והוא מופעל כשקוראים ל-requestStateUpdate. היא מקבלת מופע שלWebGLStateOptions, שיש לו שדה אחד:-
glהוא שם שלWebGLRenderingContextשמשמש במפת הבסיס.
-
- הפונקציה
onRemove()מופעלת כשהשכבה מוסרת מהמפה באמצעותWebGLOverlayView.setMap(null), ובה צריך להסיר את כל האובייקטים הזמניים.
לדוגמה, ההטמעה הבסיסית של כל ה-lifecycle hooks היא כזו:
const webglOverlayView = new google.maps.WebGLOverlayView();
webglOverlayView.onAdd = () => {
// Do setup that does not require access to rendering context.
}
webglOverlayView.onContextRestored = ({gl}) => {
// Do setup that requires access to rendering context before onDraw call.
}
webglOverlayView.onStateUpdate = ({gl}) => {
// Do GL state setup or updates outside of the render loop.
}
webglOverlayView.onDraw = ({gl, transformer}) => {
// Render objects.
}
webglOverlayView.onContextLost = () => {
// Clean up pre-existing GL state.
}
webglOverlayView.onRemove = () => {
// Remove all intermediate objects.
}
webglOverlayView.setMap(map);
איפוס מצב GL
שכבת על מבוססת-WebGL חושפת את הקשר של רינדור WebGL של המפה הבסיסית. לכן, חשוב מאוד לאפס את מצב ה-GL למצב המקורי שלו כשמסיימים לעבד אובייקטים. אם לא תאפסו את מצב ה-GL, סביר להניח שיהיו התנגשויות במצב ה-GL, שיגרמו לכך שהרינדור של המפה ושל כל האובייקטים שתציינו ייכשל.
בדרך כלל, איפוס מצב ה-GL מתבצע ב-hook onDraw(). לדוגמה,
Three.js מספקת פונקציית עזר שמנקה את כל השינויים במצב GL:
webglOverlayView.onDraw = ({gl, transformer}) => {
// Specify an object to render.
renderer.render(scene, camera);
renderer.resetState();
}
אם המפה או האובייקטים לא מוצגים, סביר מאוד להניח שמצב ה-GL לא אופס.
טרנספורמציות של קואורדינטות
המיקום של אובייקט במפת הווקטור נקבע על ידי צירוף של קואורדינטות של קו רוחב וקו אורך, וגם גובה. לעומת זאת, גרפיקה תלת-ממדית מוגדרת במרחב העולמי, במרחב המצלמה או במרחב המסך.
כדי להקל על המרת קואורדינטות של מפה למרחבים האלה שנמצאים בשימוש נפוץ יותר, שכבת העל מבוססת-WebGL מספקת את פונקציית העזר coordinateTransformer.fromLatLngAltitude(latLngAltitude, rotationArr,
scalarArr) ב-hook onDraw() שמקבלת את הפרמטרים הבאים ומחזירה Float64Array:
-
latLngAltitude: קואורדינטות של קו רוחב, קו אורך וגובה, בפורמטLatLngAltitudeאוLatLngAltitudeLiteral. -
rotationArr:Float32Arrayשל זוויות סיבוב של אוילר שצוינו במעלות. -
scalarArr:Float32Arrayשל סקלרים להחלה על הציר הקרדינלי.
לדוגמה, הקוד הבא משתמש ב-fromLatLngAltitude() כדי ליצור מטריצת הקרנה של מצלמה ב-Three.js:
const camera = new THREE.PerspectiveCamera();
const matrix = coordinateTransformer.fromLatLngAltitude({
lat: mapOptions.center.lat,
lng: mapOptions.center.lng,
altitude: 120,
});
camera.projectionMatrix = new THREE.Matrix4().fromArray(matrix);
דוגמה
זוהי דוגמה פשוטה לשימוש ב-Three.js, ספריית WebGL פופולרית בקוד פתוח, כדי להציב אובייקט תלת-ממדי במפה. כדי לקבל הדרכה מפורטת על השימוש ב-שכבת על מבוססת-WebGL כדי ליצור את הדוגמה שמוצגת בראש הדף הזה, אפשר לנסות את ה-Codelab בנושא יצירת חוויות מפה מואצות באמצעות WebGL.
const webglOverlayView = new google.maps.WebGLOverlayView();
let scene, renderer, camera, loader;
webglOverlayView.onAdd = () => {
// Set up the Three.js scene.
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera();
const ambientLight = new THREE.AmbientLight( 0xffffff, 0.75 ); // Soft white light.
scene.add(ambientLight);
// Load the 3D model with GLTF Loader from Three.js.
loader = new GLTFLoader();
loader.load("pin.gltf");
}
webglOverlayView.onContextRestored = ({gl}) => {
// Create the Three.js renderer, using the
// maps's WebGL rendering context.
renderer = new THREE.WebGLRenderer({
canvas: gl.canvas,
context: gl,
...gl.getContextAttributes(),
});
renderer.autoClear = false;
}
webglOverlayView.onDraw = ({gl, transformer}) => {
// Update camera matrix to ensure the model is georeferenced correctly on the map.
const matrix = transformer.fromLatLngAltitude({
lat: mapOptions.center.lat,
lng: mapOptions.center.lng,
altitude: 120,
});
camera.projectionMatrix = new THREE.Matrix4().fromArray(matrix);
// Request a redraw and render the scene.
webglOverlayView.requestRedraw();
renderer.render(scene, camera);
// Always reset the GL state.
renderer.resetState();
}
// Add the overlay to the map.
webglOverlayView.setMap(map);