1. ข้อควรทราบก่อนที่จะเริ่มต้น
Codelab นี้จะสอนวิธีใช้ฟีเจอร์ที่ขับเคลื่อนโดย WebGL ของ Maps JavaScript API เพื่อควบคุมและแสดงผลบนแผนที่เวกเตอร์ใน 3 มิติ
สิ่งที่ต้องมีก่อน
Codelab นี้จะถือว่าคุณมีความรู้ระดับกลางเกี่ยวกับ JavaScript และ Maps JavaScript API หากต้องการเรียนรู้พื้นฐานในการใช้ Maps JS API ให้ลองเพิ่มการแมปลงในเว็บไซต์ (JavaScript) Codelab
สิ่งที่คุณจะได้เรียนรู้
- กําลังสร้างรหัสแผนที่ด้วยแผนที่เวกเตอร์สําหรับ JavaScript ที่เปิดใช้
- การควบคุมแผนที่ด้วยการเอียงและการหมุนแบบเป็นโปรแกรม
- การแสดงภาพวัตถุ 3 มิติบนแผนที่ด้วย
WebGLOverlayView
และ Three.js - การทําให้กล้องเคลื่อนไหวด้วย
moveCamera
สิ่งที่ต้องมี
- บัญชี Google Cloud Platform ที่เปิดใช้การเรียกเก็บเงิน
- คีย์ API ของ Google Maps Platform ที่เปิดใช้ Maps JavaScript API
- ความรู้ระดับกลางเกี่ยวกับ JavaScript, HTML และ CSS
- เครื่องมือแก้ไขข้อความหรือ IDE ที่ต้องการ
- Node.js
2. ตั้งค่า
สําหรับขั้นตอนการเปิดใช้งานด้านล่าง คุณจะต้องเปิดใช้ Maps JavaScript API
ตั้งค่า Google Maps Platform
หากยังไม่มีบัญชี Google Cloud Platform และโปรเจ็กต์ที่เปิดใช้การเรียกเก็บเงิน โปรดดูคู่มือการเริ่มต้นใช้งาน Google Maps Platform เพื่อสร้างบัญชีสําหรับการเรียกเก็บเงินและโปรเจ็กต์
- ใน Cloud Console ให้คลิกเมนูแบบเลื่อนลงของโปรเจ็กต์ แล้วเลือกโปรเจ็กต์ที่ต้องการใช้สําหรับ Codelab นี้
- เปิดใช้ Google Maps Platform API และ SDK ที่จําเป็นสําหรับ Codelab นี้ใน Google Cloud Marketplace โดยทําตามขั้นตอนในวิดีโอนี้หรือเอกสารนี้
- สร้างคีย์ API ในหน้าข้อมูลเข้าสู่ระบบของ Cloud Console คุณสามารถทําตามขั้นตอนในวิดีโอนี้หรือเอกสารนี้ คําขอทั้งหมดสําหรับ Google Maps Platform ต้องใช้คีย์ API
การตั้งค่า Node.js
หากยังไม่มี โปรดไปที่ https://nodejs.org/ เพื่อดาวน์โหลดและติดตั้งรันไทม์ของ Node.js ในคอมพิวเตอร์
Node.js มาพร้อมกับตัวจัดการแพ็กเกจ npm ซึ่งคุณต้องติดตั้งทรัพยากร Dependency สําหรับ Codelab นี้
ดาวน์โหลดเทมเพลตเริ่มต้นของโปรเจ็กต์
ก่อนเริ่มต้น Codelab นี้ ให้ดําเนินการต่อไปนี้เพื่อดาวน์โหลดเทมเพลตโปรเจ็กต์เริ่มต้น และโค้ดโซลูชันที่สมบูรณ์
- ดาวน์โหลดหรือแยกที่เก็บ GitHub สําหรับ Codelab นี้ที่ https://github.com/googlecodelabs/maps-platform-101-webgl/ โปรเจ็กต์เริ่มต้นจะอยู่ในไดเรกทอรี
/starter
และมีโครงสร้างไฟล์พื้นฐานที่จําเป็นในการกรอกข้อมูลใน Codelab ให้เสร็จสมบูรณ์ ข้อมูลทั้งหมดที่คุณจําเป็นต้องใช้จะอยู่ในไดเรกทอรี/starter/src
- เมื่อดาวน์โหลดโปรเจ็กต์เริ่มต้นแล้ว ให้เรียกใช้
npm install
ในไดเรกทอรี/starter
การดําเนินการนี้จะติดตั้งทรัพยากร Dependency ที่จําเป็นทั้งหมดซึ่งแสดงอยู่ในpackage.json
- เมื่อติดตั้งทรัพยากร Dependency แล้ว ให้เรียกใช้
npm start
ในไดเรกทอรี
ระบบได้ตั้งค่าโปรเจ็กต์เริ่มต้นให้คุณแล้วโดยใช้ webpack-dev-server ซึ่งจะคอมไพล์และเรียกใช้โค้ดที่คุณเขียนในเครื่อง และ webpack-dev-server จะโหลดซ้ําแอปของคุณในเบราว์เซอร์โดยอัตโนมัติทุกครั้งที่ทําการเปลี่ยนแปลงโค้ด
หากต้องการดูรหัสโซลูชันแบบเต็มที่ทํางานอยู่ ให้ทําตามขั้นตอนการตั้งค่าข้างต้นในไดเรกทอรี /solution
เพิ่มคีย์ API
แอปเริ่มต้นมีโค้ดทั้งหมดที่จําเป็นในการโหลดแผนที่ด้วย JS API Loader ดังนั้นสิ่งที่ต้องทําคือการระบุคีย์ API และรหัสแผนที่ ตัวโหลด API ของ JS เป็นไลบรารีง่ายๆ ที่แยกวิธีการโหลด API ของ Maps JS แบบอินไลน์ไว้ในเทมเพลต HTML ด้วยแท็ก script
ซึ่งช่วยให้คุณจัดการทุกอย่างในโค้ด JavaScript ได้
หากต้องการเพิ่มคีย์ API ให้ทําตามขั้นตอนต่อไปนี้ในโปรเจ็กต์เริ่มต้น
- เปิด
app.js
- ในออบเจ็กต์
apiOptions
ให้ตั้งค่าคีย์ API เป็นค่าของapiOptions.apiKey
3. สร้างและใช้รหัสแผนที่
หากต้องการใช้ฟีเจอร์ WebGL ของ Maps JavaScript API คุณต้องมีรหัสแผนที่ที่เปิดใช้การแมปเวกเตอร์
กําลังสร้างรหัสแผนที่
- ใน Google Cloud Console ให้ไปที่ "Google Maps Platform' > "Maps Management'
- คลิก "สร้างรหัสแผนที่ใหม่'
- ในช่อง "ชื่อแผนที่' ให้ป้อนชื่อรหัสแผนที่ของคุณ
- ในเมนูแบบเลื่อนลง "ประเภทแผนที่' เลือก "JavaScript' ตัวเลือก "JavaScript&&33; จะปรากฏขึ้น
- ในส่วน "ตัวเลือก JavaScript' ให้เลือกปุ่มตัวเลือก "เวกเตอร์' ช่องทําเครื่องหมาย "เอียง" และ "หมุน"
- Optional ในช่อง "คําอธิบาย'" ให้ป้อนคําอธิบายคีย์ API
- คลิกปุ่ม "Next' หน้า "รายละเอียดรหัสแผนที่' จะปรากฏขึ้น
- คัดลอกรหัสแผนที่ คุณจะใช้การทํางานนี้ในขั้นตอนต่อไปเพื่อโหลดแผนที่
การใช้รหัสแผนที่
หากต้องการโหลดแผนที่เวกเตอร์ คุณต้องระบุรหัสแผนที่เป็นพร็อพเพอร์ตี้ในตัวเลือกเมื่อคุณสร้างอินสแตนซ์แผนที่ หรือคุณจะระบุรหัสแผนที่เดียวกันเมื่อโหลด Maps JavaScript API ก็ได้
หากต้องการโหลดแผนที่ด้วยรหัสแผนที่ ให้ทําตามขั้นตอนต่อไปนี้
- ตั้งค่ารหัสแผนที่เป็นค่า
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 ค้างไว้ แล้วลากเมาส์หรือใช้ปุ่มลูกศรบนแป้นพิมพ์
หากโหลดแผนที่ไม่ได้ ให้ตรวจสอบว่าได้ระบุคีย์ API ที่ถูกต้องใน 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 เดียวกันกับที่ใช้แสดงผลแผนที่ฐานเวกเตอร์โดยตรง ซึ่งหมายความว่าคุณจะแสดงภาพวัตถุ 2 มิติและ 3 มิติบนแผนที่ได้โดยตรงโดยใช้ WebGL รวมถึงไลบรารีกราฟิกยอดนิยมบน WebGL
WebGLOverlayView
แสดงฮุก 5 ตัวเป็นวงจรของบริบทการแสดงผล WebGL ของแผนที่ที่คุณใช้ได้ นี่คือคําอธิบายโดยย่อของเว็บฮุคแต่ละแบบและเหตุผลที่ควรใช้
onAdd()
: เรียกใช้เมื่อเพิ่มการวางซ้อนลงในแผนที่โดยเรียกsetMap
ในอินสแตนซ์WebGLOverlayView
นี่คือที่ที่คุณควรทํางานที่เกี่ยวข้องกับ WebGL ซึ่งไม่จําเป็นต้องเข้าถึงบริบทของ WebGL โดยตรงonContextRestored()
: เรียกใช้เมื่อบริบท WebGL พร้อมใช้งานแต่ก่อนที่จะแสดงผล นี่คือส่วนที่คุณต้องการเริ่มต้นออบเจ็กต์ เชื่อมโยงสถานะ และดําเนินการอื่นๆ ที่จําเป็นต้องเข้าถึงบริบท WebGL แต่สามารถดําเนินการนอกการเรียกonDraw()
วิธีนี้ช่วยให้คุณตั้งค่าทุกอย่างที่จําเป็นได้โดยไม่ต้องเพิ่มโอเวอร์เฮดที่มากเกินไปลงในการแสดงผลจริงของแผนที่ ซึ่งเน้นการใช้ GPU อยู่แล้วonDraw()
: เรียกใช้ 1 ครั้งต่อเฟรมเมื่อ WebGL เริ่มแสดงผลแผนที่และทุกสิ่งที่คุณขอ คุณควรทํางานให้น้อยที่สุดในonDraw()
เพื่อหลีกเลี่ยงปัญหาด้านประสิทธิภาพในการแสดงภาพแผนที่onContextLost()
: เรียกใช้เมื่อบริบทการแสดงผล WebGL หายไปไม่ว่าด้วยเหตุผลใดก็ตามonRemove()
: เรียกใช้เมื่อมีการนําการวางซ้อนออกจากแผนที่โดยเรียกsetMap(null)
ในอินสแตนซ์WebGLOverlayView
ในขั้นตอนนี้ คุณจะสร้างอินสแตนซ์ของ WebGLOverlayView
และใช้งานตะขอแขวนวงจรชีวิต 3 แบบ ได้แก่ onAdd
, onContextRestored
และ onDraw
ระบบจะจัดการโค้ดทั้งหมดสําหรับโฆษณาซ้อนทับในฟังก์ชัน initWebGLOverlayView()
ที่ให้ไว้ในเทมเพลตเริ่มต้นสําหรับ Codelab นี้ เพื่อให้ทุกอย่างดูง่ายขึ้นและติดตามได้ง่าย
- สร้างอินสแตนซ์
WebGLOverlayView()
การวางซ้อนมาจาก Maps JS API ใน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
จากนั้นให้ตั้งค่าทุกอย่างที่จําเป็นเพื่อแสดงวัตถุ 3 มิติบนแผนที่โดยใช้ 3.js
5. ตั้งค่าโหมด 3.js
การใช้ WebGL อาจมีความซับซ้อนมาก เนื่องจากคุณต้องกําหนดทุกแง่มุมของออบเจ็กต์ด้วยตนเอง จากนั้นทําบางส่วน เพื่อทําให้การทํางานง่ายขึ้น สําหรับ Codelab นี้ คุณจะใช้ Three.js ซึ่งเป็นไลบรารีกราฟิกยอดนิยมที่มีเลเยอร์นามธรรมง่ายๆ อยู่ด้านบนของ WebGL Three.js มาพร้อมฟังก์ชันอํานวยความสะดวกมากมายและทําทุกอย่างได้ตั้งแต่การสร้างตัวแสดงผล WebGL ไปจนถึงการวาดรูปทรงวัตถุ 2 มิติและ 3 มิติทั่วไป ไปจนถึงการควบคุมกล้อง การเปลี่ยนรูป และอื่นๆ อีกมากมาย
ประเภทออบเจ็กต์พื้นฐานใน 3.js ที่ต้องใช้แสดงทุกสิ่งมี 3 ประเภท ดังนี้
- ฉาก: A "container" แสดงวัตถุ แหล่งที่มาของแสง พื้นผิว ฯลฯ ทั้งหมด
- กล้อง: กล้องถ่ายรูปที่แสดงถึงมุมมองของฉาก กล้องมีหลายประเภทและอาจเพิ่มกล้องได้อย่างน้อย 1 ตัวในฉากเดียว
- ตัวแสดงผล: ตัวแสดงผลที่จัดการการประมวลผลและแสดงออบเจ็กต์ทั้งหมดในโหมด ใน 3.js คุณจะใช้
WebGLRenderer
บ่อยที่สุด ส่วนเวอร์ชันอื่นๆ มีให้ใช้เป็นโฆษณาสํารองในกรณีที่ไคลเอ็นต์ไม่รองรับ WebGL
ในขั้นตอนนี้ คุณจะโหลดทรัพยากร Dependency ทั้งหมดที่จําเป็นสําหรับ 3.js และตั้งค่าฉากพื้นฐาน
- โหลด 3.js
คุณต้องใช้ทรัพยากร Dependency สําหรับ Codelab นี้ 2 รายการ ได้แก่ ไลบรารี Three.js และ LoadTF Loader ซึ่งเป็นคลาสที่ให้คุณโหลดออบเจ็กต์ 3 มิติในรูปแบบ GL Trasmission Format (gLTF) 3.js มีตัวโหลดพิเศษสําหรับรูปแบบวัตถุ 3 มิติมากมาย แต่แนะนําให้ใช้ gLTF
ในโค้ดด้านล่าง ระบบจะนําเข้าไลบรารี Three.js ทั้งหมด ในแอปเวอร์ชันที่ใช้งานจริง คุณอาจต้องการนําเข้าเฉพาะชั้นเรียนที่คุณต้องการ แต่สําหรับ Codelab นี้ ให้นําเข้าทั้งไลบรารีเพื่อทําให้สิ่งต่างๆ ง่ายขึ้น โปรดทราบว่า GLTF Loader ไม่รวมอยู่ในไลบรารีเริ่มต้น และต้องนําเข้าจากเส้นทางแยกต่างหากในการขึ้นต่อกัน นี่คือเส้นทางที่คุณเข้าถึงตัวโหลดทั้งหมดที่ 3.js เตรียมไว้ได้
หากต้องการนําเข้า 3.js และตัวโหลด GLTF ให้เพิ่มสิ่งต่อไปนี้ที่ด้านบนของapp.js
import * as THREE from 'three'; import {GLTFLoader} from 'three/examples/jsm/loaders/GLTFLoader.js';
- สร้างโหมด 3.js
ในการสร้างฉาก ให้เรียกใช้คลาส 3.jsScene
โดยต่อท้ายสิ่งต่อไปนี้ด้วยonAdd
Hood:scene = new THREE.Scene();
- เพิ่มกล้องไปยังฉาก
ดังที่ได้กล่าวไปก่อนหน้านี้ กล้องแสดงถึงมุมมองของฉากและจะกําหนดวิธีที่ 3.js จัดการการแสดงภาพของวัตถุในฉาก หากไม่มีกล้อง ฉากจะไม่แสดงอย่างมีประสิทธิภาพ 
 ทําให้เห็น & ออก ซึ่งหมายความว่าวัตถุจะไม่ปรากฏขึ้นเนื่องจากแสดงผลไม่ได้
Three.js มีกล้องหลายตัวที่ส่งผลต่อวิธีที่ตัวแสดงผลดําเนินการกับวัตถุต่างๆ เช่น มุมมองและความลึก ในฉากนี้ คุณจะใช้PerspectiveCamera
ซึ่งเป็นกล้องประเภทที่มีการใช้กันมากที่สุดใน 3.js ซึ่งออกแบบมาเพื่อจําลองลักษณะสายตาของมนุษย์ ซึ่งหมายความว่าวัตถุที่อยู่ไกลออกไปจากกล้องจะปรากฏน้อยกว่าวัตถุที่อยู่ใกล้ ฉากจะมีจุดหายไปและอื่นๆ
หากต้องการเพิ่มกล้องสําหรับมุมมองในฉาก ให้เพิ่มข้อมูลต่อไปนี้ลงในonAdd
เบ็ด:
ด้วยcamera = new THREE.PerspectiveCamera();
PerspectiveCamera
คุณยังสามารถกําหนดค่าแอตทริบิวต์ที่ประกอบขึ้นเป็นมุมมอง ได้แก่ ระยะใกล้และระยะห่าง อัตราส่วน แอตทริบิวต์เหล่านี้ทั้งหมดเรียกรวมกันว่าการดู frustum ซึ่งเป็นแนวคิดสําคัญที่คุณต้องเข้าใจเมื่อทํางานในแบบ 3 มิติ แต่อยู่นอกขอบเขตของ Codelab นี้ การกําหนดค่าPerspectiveCamera
เริ่มต้นก็น่าจะเพียงพอแล้ว - เพิ่มที่มาของแสงในฉาก
โดยค่าเริ่มต้น ออบเจ็กต์ที่แสดงผลในฉาก 3.js จะปรากฏเป็นสีดําโดยไม่คํานึงถึงพื้นผิวที่ใช้ เนื่องจากฉาก 3.js จะเลียนแบบการทํางานของวัตถุในโลกจริง ซึ่งการเปิดเผยสีจะขึ้นอยู่กับแสงสะท้อนออกจากวัตถุ สรุปคือ ไม่มีแสง ไม่มีสี
Three.js มีหลอดไฟประเภทต่างๆ ที่คุณจะใช้ 2 ประเภท ได้แก่ AmbientLight
: มีแหล่งกําเนิดแสงแบบกระจายที่ช่วยส่องสว่างวัตถุทั้งหมดให้เท่ากันทุกมุม ซึ่งจะทําให้ฉากมีปริมาณแสงพื้นฐานเพื่อให้มองเห็นพื้นผิวของวัตถุทั้งหมดDirectionalLight
: ให้แสงที่มาจากทิศทางในฉาก แสงที่แผ่จากDirectionalLight
จะขนานและแผ่กระจายออกไปเมื่ออยู่ไกลขึ้นจากแหล่งที่มาที่มีแสง ต่างจากแสงที่วางอยู่ตรงตําแหน่งในโลกจริง
คุณจะกําหนดค่าสีและความเข้มของไฟแต่ละดวงเพื่อสร้างเอฟเฟกต์แสงโดยรวมได้ ตัวอย่างเช่น ในโค้ดด้านล่าง ไฟแอมเบียนท์จะให้แสงสีขาวนวลแก่ทั้งฉาก ส่วนแสงแวดล้อมมีแสงรองที่ตกกระทบวัตถุในมุมล่าง ในกรณีของแสงทิศทาง มุมจะได้รับการตั้งค่าโดยใช้position.set(x, y ,z)
โดยที่แต่ละค่าจะสัมพันธ์กับแกนที่เกี่ยวข้อง เช่นposition.set(0,1,0)
จะจัดตําแหน่งแสงเหนือฉากบนแกน Y ให้ชี้ลงโดยตรง
หากต้องการเพิ่มแหล่งที่มาของแสงในฉาก ให้เพิ่มค่าต่อไปนี้ลงในตะขอของ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. แสดงผลฉาก
เวลาที่ใช้ในการแสดงผลฉาก จนถึงตอนนี้ ทุกอย่างที่คุณสร้างด้วย 3.js จะมีการเริ่มต้นเป็นโค้ด แต่ที่จริงแล้วไม่มีอยู่จริงเนื่องจากยังไม่ได้แสดงผลในบริบทการแสดงผล WebGL WebGL แสดงเนื้อหา 2 มิติและ 3 มิติในเบราว์เซอร์โดยใช้ canvas API หากคุณเคยใช้ Canvas API มาก่อน คุณอาจคุ้นเคยกับ context
ของผืนผ้าใบ HTML ซึ่งเป็นที่ที่แสดงทุกอย่าง สิ่งที่คุณอาจไม่รู้ว่าคืออินเทอร์เฟซที่จะแสดงบริบทการแสดงภาพกราฟิกของ OpenGL ผ่าน WebGLRenderingContext
API ในเบราว์เซอร์
3.js มี WebGLRenderer
, Wrapper ที่ช่วยให้กําหนดค่าบริบทการแสดงผล WebGL ได้ง่ายๆ เพื่อให้ 3.js สามารถแสดงผลฉากในเบราว์เซอร์ได้ เพื่อให้จัดการกับตัวแสดงผล WebGL ได้ง่ายขึ้น แต่ในกรณีที่เป็นแผนที่ จะไม่เพียงพอสําหรับการแสดงภาพ 3.js ในเบราว์เซอร์พร้อมกับแผนที่ 3.js จะต้องแสดงผลในบริบทการแสดงผลเดียวกันกับแผนที่ เพื่อให้ทั้งแผนที่และวัตถุจากฉาก 3.js แสดงในพื้นที่ของโลกเดียวกัน ซึ่งจะทําให้ตัวแสดงผลจัดการการโต้ตอบระหว่างวัตถุในแผนที่และวัตถุในฉากได้ เช่น การบัง ซึ่งสามารถอธิบายได้ชัดเจนว่าวัตถุจะซ่อนวัตถุด้านหลังวัตถุ
ฟังดูซับซ้อนใช่ไหม โชคดีที่ Three.js เข้ามาช่วยเหลืออีกครั้ง
- ตั้งค่าตัวแสดงผล WebGL
เมื่อสร้างอินสแตนซ์ใหม่ของ 3.jsWebGLRenderer
คุณอาจให้บริบทการแสดงผล 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
บนตัวแสดงผลและส่งฉาก 3.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. แสดงโมเดล 3 มิติในแผนที่
โอเค คุณมีข้อมูลทุกอย่างครบแล้ว คุณได้ตั้งค่ามุมมองการวางซ้อน WebGl และสร้างฉาก 3.js แล้ว แต่ปัญหาหนึ่งคือไม่มีสิ่งใดเลย จากนั้นก็ได้เวลาแสดงผลวัตถุ 3 มิติในฉาก ในการทําเช่นนี้ คุณต้องใช้ตัวโหลด GLTF ที่นําเข้าก่อนหน้านี้
โมเดล 3 มิติมีหลายรูปแบบ แต่สําหรับ 3.js รูปแบบ gLTF เป็นรูปแบบที่ต้องการเนื่องจากมีขนาดและประสิทธิภาพรันไทม์ Codelab นี้มีโมเดลสําหรับแสดงผลในฉากให้คุณแล้วใน /src/pin.gltf
- สร้างอินสแตนซ์ตัวโหลดโมเดล
ต่อท้ายonAdd
:loader = new GLTFLoader();
- โหลดโมเดล 3 มิติ
ตัวโหลดโมเดลเป็นแบบไม่พร้อมกันและเรียกใช้โค้ดเรียกกลับเมื่อโมเดลโหลดเสร็จสมบูรณ์แล้ว หากต้องการโหลดpin.gltf
โปรดเติมค่าต่อไปนี้ลงในonAdd
:const source = "pin.gltf"; loader.load( source, gltf => {} );
- เพิ่มโมเดลลงในฉาก
ตอนนี้คุณสามารถเพิ่มโมเดลลงในฉากได้โดยเพิ่มสิ่งต่อไปนี้ลงในโค้ดเรียกกลับloader
โปรดทราบว่ากําลังเพิ่มgltf.scene
ไม่ใช่gltf
:scene.add(gltf.scene);
- กําหนดค่าเมทริกซ์การฉายภาพของกล้อง
สิ่งสุดท้ายที่คุณต้องทําให้โมเดลแสดงผลอย่างถูกต้องบนแผนที่คือ กําหนดเมทริกซ์การฉายภาพของกล้องในฉาก 3.js เมทริกซ์การฉายภาพจะระบุเป็นอาร์เรย์ 3.jsMatrix4
ซึ่งจะกําหนดจุดในมิติข้อมูล 3 จุดร่วมกับการเปลี่ยนรูปแบบ เช่น การหมุน การบีบ การปรับขนาด และอื่นๆ
ในกรณีของWebGLOverlayView
ระบบจะใช้เมทริกซ์การฉายภาพเพื่อบอกโหมดแสดงผลและวิธีที่จะแสดงภาพฉาก 3.js ที่สัมพันธ์กับแผนที่ฐาน แล้วแต่จะเกิดปัญหา ตําแหน่งบนแผนที่จะระบุเป็นคู่พิกัดละติจูดและลองจิจูด ส่วนตําแหน่งในฉาก 3.js คือพิกัดVector3
คุณอาจจะพอคาดเดาได้แล้วว่า การคํานวณ Conversion ระหว่างระบบทั้งสองนั้นไม่ใช่เรื่องเล็กๆ น้อยๆ เพื่อแก้ปัญหานี้WebGLOverlayView
จะส่งออบเจ็กต์coordinateTransformer
ไปยังตะขอสําหรับวงจรของOnDraw
ที่มีฟังก์ชันชื่อfromLatLngAltitude
fromLatLngAltitude
จะใช้ออบเจ็กต์LatLngAltitude
หรือLatLngAltitudeLiteral
และอาจเลือกชุดอาร์กิวเมนต์ที่กําหนดการเปลี่ยนรูปแบบสําหรับฉาก จากนั้นจึงที่ครอบคลุมกับเมทริกซ์การฉายภาพมุมมอง (MVP) ให้คุณ สิ่งที่คุณต้องทําคือระบุตําแหน่งที่ต้องการให้แสดงฉาก 3.js บนแผนที่ รวมถึงตําแหน่งที่ต้องการเปลี่ยนรูปแบบ และWebGLOverlayView
จะจัดการส่วนที่เหลือให้ จากนั้นคุณอาจแปลงเมทริกซ์ MVP เป็นอาร์เรย์ 3.jsMatrix4
และตั้งค่าเมทริกซ์ฉายภาพของกล้องได้
ในโค้ดด้านล่าง อาร์กิวเมนต์ที่ 2 จะบอกมุมมองวางซ้อนของ WebGl ให้ตั้งระดับความสูงของฉาก 3.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);
- เปลี่ยนรูปแบบ
คุณจะสังเกตเห็นว่าหมุดไม่ได้ตั้งฉากไว้บนแผนที่ ในกราฟิก 3 มิติ นอกจากพื้นที่โลกที่มีแกน x, y และ z ที่กําหนดการวางแนวแล้ว วัตถุแต่ละรายการยังมีพื้นที่วัตถุของตัวเองพร้อมชุดแกนอิสระ
ในกรณีของโมเดลนี้ โมเดลไม่ได้สร้างด้วยสิ่งที่เรามักมองว่าเป็น "top'" ของหมุดที่หันหน้าไปทางแกน Y คุณจึงต้องเปลี่ยนรูปแบบวัตถุให้เป็นไปตามทิศทางกับพื้นที่โลกโดยเรียกrotation.set
มา โปรดทราบว่าใน 3.js จะมีการระบุการหมุนเวียนเป็นเรเดียน ไม่ใช่องศา โดยทั่วไปแล้ว นักเรียนจะคิดในหน่วยองศาได้ง่ายขึ้น ดังนั้น Conversion ที่เหมาะสมจะต้องเกิดขึ้นโดยใช้สูตร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. ทําให้กล้องเคลื่อนไหว
เมื่อได้แสดงโมเดลในแผนที่และย้ายทุกอย่างได้ครบ 3 มิติแล้ว ขั้นตอนต่อไปที่คุณต้องทําก็คือการควบคุมการเคลื่อนไหวนั้นแบบเป็นโปรแกรม ฟังก์ชัน moveCamera
ให้คุณตั้งค่าคุณสมบัติตรงกลาง การซูม การเอียง และส่วนหัวของแผนที่พร้อมกัน คุณจึงควบคุมประสบการณ์ของผู้ใช้อย่างละเอียดได้ นอกจากนี้ ระบบยังเรียกใช้ moveCamera
แบบวนซ้ําในภาพเคลื่อนไหวเพื่อสร้างการเปลี่ยนแบบไหลระหว่างเฟรมที่อัตราเฟรมเกือบ 60 เฟรมต่อวินาทีได้
- รอให้โมเดลโหลด
หากต้องการสร้างประสบการณ์ของผู้ใช้ที่ราบรื่น คุณจะต้องรอเริ่มย้ายกล้องจนกว่าจะโหลดโมเดล gLTF แล้ว ในการทําเช่นนี้ ให้เพิ่มเครื่องจัดการเหตุการณ์onLoad
ของตัวโหลดต่อท้ายฮุกonContextRestored
:loader.manager.onLoad = () => {}
- สร้างภาพเคลื่อนไหวแบบวนซ้ํา
การสร้างภาพเคลื่อนไหวแบบวนซ้ํามีมากกว่า 1 วิธี เช่น การใช้setInterval
หรือrequestAnimationFrame
ในกรณีนี้ คุณจะใช้ฟังก์ชันsetAnimationLoop
ของเครื่องมือแสดงผล 3.js ซึ่งจะเรียกใช้โค้ดที่คุณประกาศในการเรียกกลับโดยอัตโนมัติทุกครั้งที่ 3.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. ยินดีด้วย
หากทุกอย่างเป็นไปตามแผน คุณควรมีแผนที่ที่มีหมุด 3 มิติขนาดใหญ่ซึ่งมีลักษณะดังนี้
สิ่งที่คุณได้เรียนรู้
ใน Codelab นี้ คุณได้เรียนรู้สิ่งต่างๆ มากมาย ต่อไปนี้เป็นไฮไลต์ต่างๆ
- การนํา
WebGLOverlayView
และตะขอสําหรับวงจรการใช้งานไปใช้ได้ - การผสานรวม 3.js เข้ากับแผนที่
- ข้อมูลเบื้องต้นเกี่ยวกับการสร้างฉากใน 3.js รวมถึงกล้องและการจัดแสง
- การโหลดและบิดเบือนโมเดล 3 มิติโดยใช้ Three.js
- การควบคุมและทําให้กล้องเคลื่อนไหวสําหรับแผนที่โดยใช้
moveCamera
มีอะไรอีกบ้าง
โดยทั่วไปแล้ว WebGL และกราฟิกคอมพิวเตอร์เป็นหัวข้อที่ซับซ้อน จึงมีสิ่งที่เรียนรู้อยู่มากมาย โปรดดูแหล่งข้อมูลต่อไปนี้เพื่อเริ่มอัปเกรด
- เอกสารประกอบเกี่ยวกับมุมมองการวางซ้อน WebGL
- การเริ่มต้นใช้งาน WebGL
- เอกสารประกอบเกี่ยวกับ 3.js
- ช่วยเราสร้างเนื้อหาที่คุณคิดว่ามีประโยชน์มากที่สุดโดยตอบคําถามด้านล่างนี้: «codelabs/maps-platform/shared/_next-lab-survey.lab.md » Codelab ที่คุณต้องการไม่อยู่ในรายการข้างต้นใช่ไหม ส่งคําขอเกี่ยวกับปัญหาใหม่ที่นี่