1. قبل از شروع
این کد لبه به شما می آموزد که چگونه از ویژگی های مبتنی بر WebGL Maps JavaScript API برای کنترل و رندر کردن نقشه برداری در سه بعدی استفاده کنید.
پیش نیازها
این کد لبه فرض می کند که شما دانش متوسطی از جاوا اسکریپت و Maps JavaScript API دارید. برای یادگیری اصول اولیه استفاده از Maps JS API، نوار کد افزودن نقشه به وب سایت خود (جاوا اسکریپت) را امتحان کنید.
چیزی که یاد خواهید گرفت
- ایجاد شناسه نقشه با فعال بودن نقشه برداری برای جاوا اسکریپت.
- کنترل نقشه با شیب و چرخش برنامه ای.
- رندر کردن اشیاء سه بعدی روی نقشه با
WebGLOverlayView
و Three.js . - متحرک سازی حرکات دوربین با
moveCamera
.
آنچه شما نیاز دارید
- یک حساب Google Cloud Platform با فعال کردن صورتحساب
- یک کلید API پلتفرم Google Maps با فعال کردن API جاوا اسکریپت Maps
- دانش متوسط از جاوا اسکریپت، HTML و CSS
- یک ویرایشگر متن یا IDE به انتخاب شما
- Node.js
2. راه اندازی شوید
برای مرحله فعال سازی زیر، باید Maps JavaScript API را فعال کنید.
پلتفرم نقشه های گوگل را راه اندازی کنید
اگر قبلاً حساب Google Cloud Platform و پروژهای با صورتحساب فعال ندارید، لطفاً راهنمای شروع به کار با Google Maps Platform را برای ایجاد یک حساب صورتحساب و یک پروژه ببینید.
- در Cloud Console ، روی منوی کشویی پروژه کلیک کنید و پروژه ای را که می خواهید برای این کد لبه استفاده کنید انتخاب کنید.
- APIها و SDKهای پلتفرم Google Maps مورد نیاز برای این لبه کد را در Google Cloud Marketplace فعال کنید. برای انجام این کار، مراحل این ویدئو یا این مستند را دنبال کنید.
- یک کلید API در صفحه Credentials در Cloud Console ایجاد کنید. می توانید مراحل این ویدئو یا این مستند را دنبال کنید. همه درخواستها به پلتفرم نقشههای Google به یک کلید API نیاز دارند.
راه اندازی 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 استفاده کنید که کدی را که شما به صورت محلی می نویسید را کامپایل و اجرا می کند. webpack-dev-server همچنین هر زمان که کد را تغییر دهید به طور خودکار برنامه شما را در مرورگر بارگیری می کند.
اگر میخواهید کد راهحل کامل را در حال اجرا ببینید، میتوانید مراحل راهاندازی بالا را در پوشه /solution
کامل کنید.
کلید API خود را اضافه کنید
برنامه شروع کننده شامل تمام کدهای مورد نیاز برای بارگیری نقشه با JS API Loader است، به طوری که تنها کاری که باید انجام دهید این است که کلید API و شناسه نقشه خود را ارائه دهید. JS API Loader یک کتابخانه ساده است که روش سنتی بارگیری Maps JS API به صورت درون خطی در قالب HTML را با یک تگ script
خلاصه می کند و به شما امکان می دهد همه چیز را در کد جاوا اسکریپت مدیریت کنید.
برای افزودن کلید API خود، در پروژه شروع به صورت زیر عمل کنید:
-
app.js
باز کنید. - در شیء
apiOptions
، کلید API خود را به عنوان مقدارapiOptions.apiKey
کنید.
3. یک Map ID ایجاد و استفاده کنید
برای استفاده از ویژگی های مبتنی بر WebGL Maps JavaScript API، به شناسه نقشه با فعال بودن نقشه برداری نیاز دارید.
ایجاد شناسه نقشه
- در کنسول Google Cloud، به 'Google Maps Platform' > 'Map Management' بروید.
- روی «ایجاد شناسه نقشه جدید» کلیک کنید.
- در قسمت «نام نقشه»، یک نام برای شناسه نقشه خود وارد کنید.
- در منوی کشویی «نوع نقشه»، «جاوا اسکریپت» را انتخاب کنید. 'گزینه های جاوا اسکریپت' ظاهر می شود.
- در زیر «گزینههای جاوا اسکریپت»، دکمه رادیویی «وکتور»، کادر «تیلت» و کادر «چرخش» را انتخاب کنید.
- اختیاری در قسمت «توضیحات»، توضیحاتی را برای کلید API خود وارد کنید.
- روی دکمه «بعدی» کلیک کنید. صفحه "جزئیات شناسه نقشه" ظاهر می شود.
- شناسه نقشه را کپی کنید. از این در مرحله بعد برای بارگیری نقشه استفاده خواهید کرد.
با استفاده از شناسه نقشه
برای بارگذاری نقشه برداری، باید یک شناسه نقشه را به عنوان ویژگی در گزینه ها هنگام نمونه سازی نقشه ارائه دهید. در صورت تمایل، هنگام بارگیری Maps JavaScript API، میتوانید همان Map ID را نیز ارائه دهید.
برای بارگذاری نقشه با شناسه نقشه، موارد زیر را انجام دهید:
- شناسه نقشه خود را به عنوان مقدار
mapOptions.mapId
تنظیم کنید.
ارائه شناسه نقشه هنگام نمونهبرداری از نقشه، به پلتفرم نقشههای Google میگوید کدام یک از نقشههای شما برای یک نمونه خاص بارگیری شود. میتوانید از همان Map ID در چندین برنامه یا چندین نما در یک برنامه دوباره استفاده کنید.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 را می دهد که برای ارائه نقشه پایه برداری استفاده می شود. این بدان معناست که میتوانید با استفاده از WebGL و همچنین کتابخانههای گرافیکی مبتنی بر WebGL، اشیاء دو بعدی و سه بعدی را مستقیماً روی نقشه رندر کنید.
WebGLOverlayView
پنج قلاب را در چرخه حیات بافت رندر WebGL نقشه نشان می دهد که می توانید از آنها استفاده کنید. در اینجا یک توضیح سریع از هر قلاب و اینکه برای چه کاری باید آنها را انجام دهید آورده شده است:
-
onAdd()
: زمانی که با فراخوانیsetMap
در یک نمونهWebGLOverlayView
، همپوشانی به نقشه اضافه می شود، فراخوانی می شود. اینجاست که شما باید هر کار مرتبط با WebGL را که نیازی به دسترسی مستقیم به زمینه WebGL ندارد، انجام دهید. -
onContextRestored()
: زمانی فراخوانی می شود که زمینه WebGL در دسترس باشد اما قبل از اینکه هر چیزی رندر شود. اینجاست که باید اشیاء را مقداردهی اولیه کنید، وضعیت bind را انجام دهید و هر کار دیگری که نیاز به دسترسی به زمینه WebGL دارد اما خارج ازonDraw()
انجام می شود، انجام دهید. این به شما این امکان را میدهد تا هر چیزی را که نیاز دارید بدون اضافه کردن سربار اضافی به رندر واقعی نقشه، که در حال حاضر به GPU فشرده است، تنظیم کنید. -
onDraw()
: هنگامی که WebGL شروع به رندر کردن نقشه و هر چیز دیگری که درخواست کرده اید، یک بار در هر فریم فراخوانی می شود. شما باید تا حد امکان درonDraw()
کمتر کار کنید تا از ایجاد مشکل در عملکرد در رندر نقشه جلوگیری کنید. -
onContextLost()
: زمانی فراخوانی می شود که زمینه رندر WebGL به هر دلیلی از بین برود. -
onRemove()
: زمانی فراخوانی می شود که همپوشانی با فراخوانیsetMap(null)
در یک نمونهWebGLOverlayView
از روی نقشه حذف شود.
در این مرحله، یک نمونه از WebGLOverlayView
ایجاد میکنید و سه مورد از قلابهای چرخه حیات آن را پیادهسازی میکنید: onAdd
، onContextRestored
، و onDraw
. برای تمیز نگه داشتن چیزها و پیگیری آسان تر، تمام کدهای همپوشانی در تابع initWebGLOverlayView()
ارائه شده در قالب شروع برای این کد لبه استفاده می شود.
- یک
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()
را در نمونه overlay فراخوانی کنید و با اضافه کردن موارد زیر به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. یک صحنه three.js تنظیم کنید
استفاده از WebGL میتواند بسیار پیچیده باشد، زیرا به شما نیاز دارد که تمام جنبههای هر شی را به صورت دستی و سپس برخی از آنها را تعریف کنید. برای آسانتر کردن کارها، برای این نرمافزار از Three.js، یک کتابخانه گرافیکی محبوب استفاده میکنید که یک لایه انتزاعی ساده در بالای WebGL ارائه میکند. Three.js با طیف گسترده ای از توابع راحت ارائه می شود که همه کارها را از ایجاد یک رندر WebGL گرفته تا ترسیم اشکال شیء دو بعدی و سه بعدی تا کنترل دوربین ها، تبدیل اشیا و موارد دیگر انجام می دهد.
سه نوع شی اصلی در Three.js وجود دارد که برای نمایش هر چیزی لازم است:
- صحنه: «کانتینری» که در آن همه اشیا، منابع نور، بافت ها و غیره رندر و نمایش داده می شوند.
- دوربین: دوربینی که نمای صحنه را نشان می دهد. چندین نوع دوربین موجود است و ممکن است یک یا چند دوربین به یک صحنه اضافه شود.
- Renderer: یک رندر که پردازش و نمایش تمام اشیاء در صحنه را انجام می دهد. در Three.js،
WebGLRenderer
متداولترین مورد استفاده است، اما در صورتی که کلاینت از WebGL پشتیبانی نمیکند، چند مورد دیگر به عنوان جایگزین در دسترس هستند.
در این مرحله، تمام وابستگیهای مورد نیاز برای Three.js را بارگیری میکنید و یک صحنه اصلی را تنظیم میکنید.
- سه.js را بارگیری کنید
برای این کد لبه به دو وابستگی نیاز دارید: کتابخانه Three.js و GLTF Loader، کلاسی که به شما امکان می دهد اشیاء سه بعدی را در قالب GL Trasmission (gLTF) بارگذاری کنید. Three.js بارگذارهای تخصصی را برای بسیاری از فرمت های شی سه بعدی مختلف ارائه می دهد، اما استفاده از gLTF توصیه می شود.
در کد زیر، کل کتابخانه Three.js وارد شده است. در یک برنامه تولیدی احتمالاً می خواهید فقط کلاس های مورد نیاز خود را وارد کنید، اما برای این کد لبه، کل کتابخانه را وارد کنید تا همه چیز ساده باشد. همچنین توجه داشته باشید که GLTF Loader در کتابخانه پیشفرض گنجانده نشده است، و باید از یک مسیر جداگانه در وابستگی وارد شود - این مسیری است که در آن میتوانید به همه لودرهای ارائهشده توسط Three.js دسترسی داشته باشید.
برای وارد کردن Three.js و GLTF Loader، موارد زیر را به بالایapp.js
کنید:import * as THREE from 'three'; import {GLTFLoader} from 'three/examples/jsm/loaders/GLTFLoader.js';
- یک صحنه three.js ایجاد کنید.
برای ایجاد یک صحنه، کلاس Three.jsScene
را با اضافه کردن موارد زیر به قلابonAdd
نمونه سازی کنید:scene = new THREE.Scene();
- یک دوربین به صحنه اضافه کنید.
همانطور که قبلا ذکر شد، دوربین نمایانگر دید صحنه است و تعیین می کند که Three.js چگونه رندر بصری اشیاء را در یک صحنه انجام می دهد. بدون دوربین، صحنه عملاً "دیده" نمی شود، به این معنی که اشیا ظاهر نمی شوند زیرا رندر نمی شوند.
Three.js انواع دوربین های مختلف را ارائه می دهد که بر نحوه برخورد رندر با اشیاء با توجه به مواردی مانند پرسپکتیو و عمق تأثیر می گذارد. در این صحنه، ازPerspectiveCamera
، رایج ترین نوع دوربین در Three.js استفاده می کنید، که برای تقلید از نحوه درک چشم انسان از صحنه طراحی شده است. این بدان معناست که اشیاء دورتر از دوربین کوچکتر از اجسام نزدیکتر به نظر می رسند، صحنه یک نقطه ناپدید خواهد داشت و موارد دیگر.
برای افزودن یک دوربین پرسپکتیو به صحنه، موارد زیر را به قلابonAdd
اضافه کنید:
باcamera = new THREE.PerspectiveCamera();
PerspectiveCamera
، همچنین میتوانید ویژگیهایی را که دیدگاه را تشکیل میدهند، از جمله سطوح نزدیک و دور، نسبت تصویر، و میدان را پیکربندی کنید. بینایی (fov). در مجموع، این ویژگیها چیزی را تشکیل میدهند که به عنوان frustum مشاهده شناخته میشود، مفهومی مهم که هنگام کار در سه بعدی باید درک کرد، اما خارج از محدوده این نرمافزار است. پیکربندی پیش فرض دوربینPerspectiveCamera
به خوبی کافی است. - منابع نور را به صحنه اضافه کنید.
بهطور پیشفرض، اشیایی که در صحنه Three.js ارائه میشوند، بدون توجه به بافتهایی که روی آنها اعمال میشوند، سیاه به نظر میرسند. این به این دلیل است که یک صحنه Three.js نحوه عملکرد اجسام در دنیای واقعی را تقلید می کند، جایی که دید رنگ به بازتاب نور از یک شی بستگی دارد. به طور خلاصه، بدون نور، بدون رنگ.
Three.js انواع مختلفی از چراغ ها را ارائه می دهد که شما از دو مورد از آنها استفاده خواهید کرد: -
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. صحنه را رندر کنید
زمان رندر صحنه شماست تا این مرحله، هر چیزی که با Three.js ایجاد کردهاید در کد مقداردهی اولیه میشود، اما اساساً وجود ندارد زیرا هنوز در زمینه رندر WebGL رندر نشده است. WebGL محتوای دو بعدی و سه بعدی را در مرورگر با استفاده از Canvas API ارائه می کند. اگر قبلا از Canvas API استفاده کرده اید، احتمالاً با context
یک بوم HTML آشنا هستید، جایی که همه چیز در آن رندر می شود. چیزی که ممکن است ندانید این است که این رابطی است که زمینه رندر گرافیکی OpenGL را از طریق WebGLRenderingContext
API در مرورگر نشان می دهد.
برای آسانتر کردن کار با رندر WebGL، Three.js WebGLRenderer
را ارائه میکند، پوششی که پیکربندی زمینه رندر WebGL را نسبتاً آسان میکند تا Three.js بتواند صحنهها را در مرورگر رندر کند. با این حال، در مورد نقشه، رندر کردن صحنه Three.js در مرورگر در کنار نقشه کافی نیست. Three.js باید دقیقاً در زمینه رندرینگ مشابه نقشه رندر شود، به طوری که هم نقشه و هم هر شیء از صحنه Three.js در یک فضای جهانی رندر شوند. این امکان را برای رندر فراهم می کند تا تعاملات بین اشیاء روی نقشه و اشیاء موجود در صحنه را مدیریت کند، مانند انسداد، که روشی فانتزی برای گفتن اینکه یک شی اشیاء را در پشت خود از دید پنهان می کند، است.
خیلی پیچیده به نظر می رسد، درست است؟ خوشبختانه Three.js دوباره به کمک می آید.
- رندر WebGL را راه اندازی کنید.
وقتی یک نمونه جدید از Three.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
فراخوانی کنید و صحنه و دوربین Three.js را برای رندر به آن ارسال کنید. در نهایت، وضعیت زمینه رندر WebGL را پاک کنید. این یک گام مهم برای جلوگیری از تداخل وضعیت GL است، زیرا استفاده از WebGL Overlay View به حالت 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 Overlay View را راه اندازی کرده اید و یک صحنه Three.js ایجاد کرده اید، اما یک مشکل وجود دارد: چیزی در آن وجود ندارد. بنابراین، در مرحله بعد، زمان رندر کردن یک شی سه بعدی در صحنه است. برای انجام این کار، از GLTF Loader که قبلا وارد کرده اید استفاده می کنید.
مدلهای سهبعدی در فرمتهای مختلفی ارائه میشوند، اما برای Three.js، فرمت gLTF به دلیل اندازه و عملکرد زمان اجرا، قالب ترجیحی است. در این کد لبه، مدلی برای رندر در صحنه از قبل برای شما در /src/pin.gltf
ارائه شده است.
- یک نمونه لودر مدل ایجاد کنید.
موارد زیر را بهonAdd
اضافه کنید:loader = new GLTFLoader();
- یک مدل سه بعدی را بارگذاری کنید.
لودرهای مدل ناهمزمان هستند و پس از بارگیری کامل مدل، یک تماس برگشتی را اجرا می کنند. برای بارگیریpin.gltf
، موارد زیر را بهonAdd
اضافه کنید:const source = "pin.gltf"; loader.load( source, gltf => {} );
- مدل را به صحنه اضافه کنید.
اکنون می توانید با اضافه کردن موارد زیر به callbackloader
، مدل را به صحنه اضافه کنید. توجه داشته باشید کهgltf.scene
در حال اضافه شدن است، نهgltf
:scene.add(gltf.scene);
- ماتریس طرح ریزی دوربین را پیکربندی کنید.
آخرین چیزی که برای رندر کردن مدل به درستی روی نقشه نیاز دارید، تنظیم ماتریس پروجکشن دوربین در صحنه Three.js است. ماتریس طرح ریزی به عنوان یک آرایه Three.jsMatrix4
مشخص می شود که یک نقطه را در فضای سه بعدی همراه با تبدیل هایی مانند چرخش، برش، مقیاس و غیره تعریف می کند.
در موردWebGLOverlayView
، ماتریس طرح ریزی برای اینکه به رندرکننده بگوید کجا و چگونه صحنه Three.js را نسبت به نقشه پایه رندر کند استفاده می شود. اما یک مشکل وجود دارد مکان ها روی نقشه به عنوان جفت مختصات طول و عرض جغرافیایی مشخص می شوند، در حالی که مکان ها در صحنه Three.js مختصاتVector3
هستند. همانطور که ممکن است حدس بزنید، محاسبه تبدیل بین دو سیستم بی اهمیت نیست. برای حل این مشکل،WebGLOverlayView
یک شیءcoordinateTransformer
Transformer را به قلاب چرخه حیاتOnDraw
می کند که حاوی تابعی به نامfromLatLngAltitude
است.fromLatLngAltitude
یک شیLatLngAltitude
یاLatLngAltitudeLiteral
را می گیرد و به صورت اختیاری مجموعه ای از آرگومان ها را که تبدیلی را برای صحنه تعریف می کنند، می گیرد، سپس آنها را در یک ماتریس طرح نمای مدل (MVP) برای شما پنهان می کند. تنها کاری که باید انجام دهید این است که مشخص کنید در کجای نقشه می خواهید صحنه Three.js رندر شود و همچنین نحوه تبدیل آن را مشخص کنید وWebGLOverlayView
بقیه کارها را انجام می دهد. سپس می توانید ماتریس MVP را به یک آرایه Three.jsMatrix4
تبدیل کنید و ماتریس نمایش دوربین را روی آن تنظیم کنید.
در کد زیر، آرگومان دوم به WebGl Overlay View میگوید که ارتفاع صحنه 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);
- مدل را تبدیل کنید.
متوجه خواهید شد که پین عمود بر نقشه قرار ندارد. در گرافیک سه بعدی، علاوه بر اینکه فضای جهان دارای محورهای x، y و z خاص خود است که جهت گیری را تعیین می کند، هر جسم نیز فضای شی خاص خود را با مجموعه ای از محورهای مستقل دارد.
در مورد این مدل، با چیزی که ما معمولاً "بالای" پین را رو به محور y در نظر می گیریم، ایجاد نشده است، بنابراین باید شی را تغییر دهید تا آن را در جهت دلخواه نسبت به فضای جهان با استفاده از فراخوانیrotation.set
روی آن. توجه داشته باشید که در Three.js چرخش بر حسب رادیان مشخص شده است نه درجه. به طور کلی فکر کردن به درجه آسانتر است، بنابراین تبدیل مناسب باید با استفاده از فرمولdegrees * Math.PI/180
انجام شود.
علاوه بر این، مدل کمی کوچک است، بنابراین با فراخوانیscale.set(x, y ,z)
آن را در همه محورها به طور یکنواخت مقیاس خواهید کرد.
برای چرخاندن و مقیاسبندی مدل، موارد زیر را در callbackloader
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 یک فریم جدید را ارائه می دهد، به طور خودکار هر کدی را که در callback خود اعلام می کنید، فراخوانی می کند. برای ایجاد حلقه انیمیشن، موارد زیر را در مرحله قبل به کنترل کننده رویداد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. تبریک می گویم
اگر همه چیز طبق برنامه پیش رفت، اکنون باید نقشه ای با یک پین سه بعدی بزرگ داشته باشید که به شکل زیر است:
چیزی که یاد گرفتی
در این Codelab شما یک سری چیزها را یاد گرفتید. در اینجا نکات برجسته وجود دارد:
- پیاده سازی
WebGLOverlayView
و قلاب های چرخه حیات آن. - ادغام Three.js در نقشه
- اصول اولیه ایجاد یک صحنه Three.js، از جمله دوربین و نور.
- بارگذاری و دستکاری مدل های سه بعدی با استفاده از Three.js.
- کنترل و متحرک سازی دوربین برای نقشه با استفاده از
moveCamera
.
بعدش چی؟
WebGL، و گرافیک کامپیوتری به طور کلی، یک موضوع پیچیده است، بنابراین همیشه چیزهای زیادی برای یادگیری وجود دارد. در اینجا چند منبع برای شروع شما آورده شده است:
- نمای WebGL Overlay مستندات
- شروع با WebGL .
- اسناد Three.js
- با پاسخ دادن به سوال زیر، به ما کمک کنید محتوایی را ایجاد کنیم که برای شما مفیدتر باشد: «codelabs/maps-platform/shared/_next-lab-survey.lab.md» آیا نرم افزار کدی که می خواهید در بالا فهرست نشده است؟ آن را با یک شماره جدید در اینجا درخواست کنید .