תצוגת שכבת-על מבוססת-WebGL

לדוגמה

בעזרת שכבת על מבוססת-WebGL אפשר להוסיף תוכן למפות Google באמצעות 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);