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

לצפייה בדוגמה

בעזרת תצוגת שכבת-על WebGL תוכלו להוסיף תוכן למפות שלכם באמצעות WebGL באופן ישיר, או באמצעות ספריות גרפיות פופולריות כמו Three.js. תצוגת שכבת-על של WebGL מספקת גישה ישירה לאותו הקשר של עיבוד WebGL שמשמש את הפלטפורמה של מפות Google לעיבוד של המפה הבסיסית הווקטורית. השימוש בהקשר של עיבוד משותף מספק יתרונות כמו חסימת עומק עם גיאומטריה של בניינים בתלת ממד, והיכולת לסנכרן תוכן דו-ממדי או תלת-ממדי עם רינדור במפה הבסיסית. ניתן לקשר גם אובייקטים שעברו רינדור באמצעות תצוגת שכבת-העל של 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 של מפת הבסיס הווקטורית. קטעי ההוק (hooks) של מחזור החיים הם המקום שבו מגדירים, משרטטים ומפרקים כל דבר שרוצים לעבד בשכבת-העל.

  • הפונקציה onAdd() מופעלת כששכבת-העל נוצרת. אפשר להשתמש בו כדי לאחזר או ליצור מבני נתונים מסוג ביניים לפני יצירת שכבת-העל, שאינם מחייבים גישה מיידית להקשר העיבוד של WebGL.
  • קוראים לפונקציה onContextRestored({gl}) ברגע שההקשר של הרינדור זמין. אפשר להשתמש בו כדי לאתחל או לקשר כל מצב של WebGL, כמו תוכנות הצללה, אובייקטים של מאגר נתונים זמני של GL וכו'. הפונקציה 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), וזהו המקום שבו צריך להסיר את כל אובייקטי הביניים.

לדוגמה, הדוגמה הבאה היא הטמעה בסיסית של כל ההוקים (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 כדי ליצור את הדוגמה שמוצגת בחלק העליון של הדף הזה, אתם מוזמנים לנסות את יצירת קוד Lab לחוויית מפה מואצת ב-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);