WebGL yer paylaşımlı görünümü ile 3D harita deneyimleri oluşturma

1. Başlamadan önce

Bu codelab'de, Maps JavaScript API'nin WebGL destekli özelliklerini kullanarak vektör haritayı üç boyutlu olarak nasıl kontrol edeceğinizi ve oluşturacağınızı öğreneceksiniz.

Final 3D Pin

Ön koşullar

Bu codelab'de JavaScript ve Maps JavaScript API hakkında orta düzeyde bilgi sahibi olduğunuz varsayılır. Maps JS API'yi kullanmanın temellerini öğrenmek için Web sitenize harita ekleme (JavaScript) codelab'ini deneyin.

Neler öğreneceksiniz?

  • JavaScript için vektör haritası etkinleştirilmişken harita kimliği oluşturma.
  • Programatik eğme ve döndürme ile haritayı kontrol etme.
  • WebGLOverlayView ve Three.js ile haritada 3D nesneleri oluşturma.
  • moveCamera ile kamera hareketlerine animasyon ekleme.

İhtiyacınız olanlar

  • Faturalandırmanın etkinleştirildiği bir Google Cloud Platform hesabı
  • Maps JavaScript API'nin etkin olduğu bir Google Haritalar Platformu API anahtarı
  • JavaScript, HTML ve CSS hakkında orta düzeyde bilgi
  • Seçtiğiniz bir metin düzenleyici veya IDE
  • Node.js

2. Hazırlanın

Aşağıdaki etkinleştirme adımı için Maps JavaScript API'yi etkinleştirmeniz gerekir.

Google Haritalar Platformu'nu ayarlama

Henüz bir Google Cloud Platform hesabınız ve faturalandırmanın etkinleştirildiği bir projeniz yoksa lütfen faturalandırma hesabı ve proje oluşturmak için Google Haritalar Platformu'nu Kullanmaya Başlama kılavuzuna bakın.

  1. Cloud Console'da proje açılır menüsünü tıklayın ve bu codelab için kullanmak istediğiniz projeyi seçin.

  1. Bu codelab için gereken Google Haritalar Platformu API'lerini ve SDK'larını Google Cloud Marketplace'te etkinleştirin. Bunun için bu videodaki veya bu dokümandaki adımları uygulayın.
  2. Cloud Console'un Kimlik Bilgileri sayfasında bir API anahtarı oluşturun. Bu videodaki veya bu dokümandaki adımları uygulayabilirsiniz. Google Haritalar Platformu'na yapılan tüm istekler için API anahtarı gerekir.

Node.js kurulumu

Henüz yüklemediyseniz Node.js çalışma zamanını bilgisayarınıza indirmek ve yüklemek için https://nodejs.org/ adresine gidin.

Node.js, bu codelab'in bağımlılıklarını yüklemek için ihtiyacınız olan npm paket yöneticisiyle birlikte gelir.

Proje başlangıç şablonunu indirme

Bu codelab'e başlamadan önce başlangıç projesi şablonunu ve tam çözüm kodunu indirmek için aşağıdakileri yapın:

  1. https://github.com/googlecodelabs/maps-platform-101-webgl/ adresinden bu codelab'in GitHub deposunu indirin veya çatallayın. Başlangıç projesi, /starter dizininde bulunur ve codelab'i tamamlamak için ihtiyacınız olan temel dosya yapısını içerir. Çalışmak için ihtiyaç duyduğunuz her şey /starter/src dizininde bulunur.
  2. Başlangıç projesini indirdikten sonra npm install dizininde /starter komutunu çalıştırın. Bu komut, package.json içinde listelenen tüm gerekli bağımlılıkları yükler.
  3. Bağımlılıklarınız yüklendikten sonra dizinde npm start komutunu çalıştırın.

Başlangıç projesi, yerel olarak yazdığınız kodu derleyip çalıştıran webpack-dev-server'ı kullanabilmeniz için ayarlanmıştır. webpack-dev-server, kodda değişiklik yaptığınız her seferde uygulamanızı tarayıcıda otomatik olarak yeniden yükler.

Çalışan çözüm kodunun tamamını görmek isterseniz yukarıdaki kurulum adımlarını /solution dizininde tamamlayabilirsiniz.

API anahtarınızı ekleme

Başlangıç uygulamasında, haritayı JS API Yükleyici ile yüklemek için gereken tüm kodlar bulunur. Bu nedenle, yalnızca API anahtarınızı ve harita kimliğinizi sağlamanız gerekir. JS API Yükleyici, Maps JS API'yi HTML şablonuna script etiketiyle satır içi olarak yüklemenin geleneksel yöntemini soyutlayan basit bir kitaplıktır. Bu kitaplık, her şeyi JavaScript kodunda işlemenize olanak tanır.

API anahtarınızı eklemek için başlangıç projesinde aşağıdakileri yapın:

  1. app.js adlı kişiyi aç.
  2. apiOptions nesnesinde, API anahtarınızı apiOptions.apiKey değeri olarak ayarlayın.

3. Harita kimliği oluşturma ve kullanma

Maps JavaScript API'nin WebGL tabanlı özelliklerini kullanmak için vektör haritanın etkinleştirildiği bir harita kimliğine ihtiyacınız vardır.

Harita kimliği oluşturma

Harita Kimliği Oluşturma

  1. Google Cloud Console'da "Google Haritalar Platformu" > "Harita Yönetimi"ne gidin.
  2. "YENİ HARİTA KİMLİĞİ OLUŞTUR"u tıklayın.
  3. "Harita adı" alanına Harita Kimliğiniz için bir ad girin.
  4. "Harita türü" açılır listesinde "JavaScript"i seçin. "JavaScript Seçenekleri" gösterilir.
  5. "JavaScript Seçenekleri" bölümünde "Vektör" radyo düğmesini, "Eğim" onay kutusunu ve "Döndürme" onay kutusunu seçin.
  6. İsteğe bağlı. "Açıklama" alanına API anahtarınız için bir açıklama girin.
  7. "Sonraki" düğmesini tıklayın. "Harita Kimliği Ayrıntıları" sayfası gösterilir.

    Harita Ayrıntıları sayfası
  8. Harita kimliğini kopyalayın. Haritayı yüklemek için bunu sonraki adımda kullanacaksınız.

Harita kimliği kullanma

Vektör haritayı yüklemek için Harita'yı oluştururken seçeneklerde bir özellik olarak harita kimliği sağlamanız gerekir. İsteğe bağlı olarak, Maps JavaScript API'yi yüklerken aynı harita kimliğini de sağlayabilirsiniz.

Haritayı harita kimliğinizle yüklemek için aşağıdakileri yapın:

  1. Harita kimliğinizi mapOptions.mapId değeri olarak ayarlayın.

    Haritayı oluştururken harita kimliğini sağlamak, Google Haritalar Platformu'na belirli bir örnek için hangi haritalarınızın yükleneceğini bildirir. Aynı harita kimliğini birden fazla uygulamada veya aynı uygulama içindeki birden fazla görünümde yeniden kullanabilirsiniz.
    const mapOptions = {
      "tilt": 0,
      "heading": 0,
      "zoom": 18,
      "center": { lat: 35.6594945, lng: 139.6999859 },
      "mapId": "YOUR_MAP_ID"
    };
    

Tarayıcınızda çalışan uygulamayı kontrol edin. Eğme ve döndürme özelliklerinin etkin olduğu vektör harita başarıyla yüklenmelidir. Eğme ve döndürmenin etkin olup olmadığını kontrol etmek için Shift tuşunu basılı tutun ve farenizle sürükleyin veya klavyenizdeki ok tuşlarını kullanın.

Harita yüklenmiyorsa apiOptions bölümünde geçerli bir API anahtarı sağladığınızı kontrol edin. Harita eğilip dönmüyorsa apiOptions ve mapOptions'da eğme ve döndürme özelliklerinin etkin olduğu bir harita kimliği sağladığınızı kontrol edin.

Eğik Harita

app.js dosyanız artık şu şekilde görünmelidir:

    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'u uygulama

WebGLOverlayView, vektör taban haritasını oluşturmak için kullanılan WebGL oluşturma bağlamına doğrudan erişmenizi sağlar. Bu sayede, WebGL'nin yanı sıra popüler WebGL tabanlı grafik kitaplıklarını kullanarak 2D ve 3D nesneleri doğrudan haritada oluşturabilirsiniz.

WebGLOverlayView, kullanabileceğiniz haritanın WebGL oluşturma bağlamının yaşam döngüsünde beş kanca gösterir. Her kancanın kısa bir açıklaması ve bunları hangi amaçla kullanmanız gerektiği aşağıda verilmiştir:

  • onAdd(): WebGLOverlayView örneğinde setMap çağrılarak yer paylaşımı haritaya eklendiğinde çağrılır. WebGL bağlamına doğrudan erişim gerektirmeyen WebGL ile ilgili tüm çalışmaları burada yapmanız gerekir.
  • onContextRestored(): WebGL bağlamı kullanılabilir hale geldiğinde ancak herhangi bir şey oluşturulmadan önce çağrılır. Nesneleri başlatmanız, durumu bağlamanız ve WebGL bağlamına erişilmesi gereken ancak onDraw() çağrısı dışında gerçekleştirilebilen diğer tüm işlemleri yapmanız gereken yer burasıdır. Bu sayede, halihazırda GPU yoğun olan haritanın gerçek oluşturulmasına gereksiz yük eklemeden ihtiyacınız olan her şeyi ayarlayabilirsiniz.
  • onDraw(): WebGL, haritayı ve istediğiniz diğer öğeleri oluşturmaya başladığında her kare için bir kez çağrılır. Haritanın oluşturulmasında performans sorununa neden olmamak için onDraw()'da mümkün olduğunca az işlem yapmalısınız.
  • onContextLost(): WebGL oluşturma bağlamı herhangi bir nedenle kaybolduğunda çağrılır.
  • onRemove(): Bir WebGLOverlayView örneğinde setMap(null) çağrılarak yer paylaşımı haritadan kaldırıldığında çağrılır.

Bu adımda, WebGLOverlayView örneği oluşturacak ve yaşam döngüsü kancalarından üçünü (onAdd, onContextRestored ve onDraw) uygulayacaksınız. Her şeyin düzenli ve kolay anlaşılır olması için yer paylaşımıyla ilgili tüm kodlar, bu codelab'in başlangıç şablonunda sağlanan initWebGLOverlayView() işlevinde ele alınır.

  1. WebGLOverlayView() örneği oluşturun.

    Yer paylaşımı, google.maps.WebGLOverlayView içindeki Maps JS API tarafından sağlanır. Başlamak için initWebGLOverlayView() öğesine aşağıdakileri ekleyerek bir örnek oluşturun:
    const webGLOverlayView = new google.maps.WebGLOverlayView();
    
  2. Yaşam döngüsü kancalarını uygulayın.

    Yaşam döngüsü kancalarını uygulamak için initWebGLOverlayView() öğesine aşağıdakileri ekleyin:
    webGLOverlayView.onAdd = () => {};
    webGLOverlayView.onContextRestored = ({gl}) => {};
    webGLOverlayView.onDraw = ({gl, transformer}) => {};
    
  3. Yer paylaşımı örneğini haritaya ekleyin.

    Şimdi, setMap() öğesini yer paylaşımı örneğinde çağırın ve initWebGLOverlayView() öğesine aşağıdakileri ekleyerek haritayı iletin:
    webGLOverlayView.setMap(map)
    
  4. initWebGLOverlayView Hizmetleri İçin Arayın.

    Son adım, app.js bölümünün en altındaki hemen çağrılan işleve aşağıdakileri ekleyerek initWebGLOverlayView() işlevini yürütmektir:
    initWebGLOverlayView(map);
    

initWebGLOverlayView ve hemen çağrılan işleviniz artık şu şekilde görünmelidir:

    async function initWebGLOverlayView (map) {
      let scene, renderer, camera, loader;
      const webGLOverlayView = new google.maps.WebGLOverlayView();

      webGLOverlayView.onAdd = () => {}
      webGLOverlayView.onContextRestored = ({gl}) => {}
      webGLOverlayView.onDraw = ({gl, transformer}) => {}
      webGLOverlayView.setMap(map);
    }

    (async () => {
      const map = await initMap();
      initWebGLOverlayView(map);
    })();

WebGLOverlayView'yı uygulamak için yapmanız gerekenler bu kadar. Ardından, Three.js kullanarak haritada 3D nesne oluşturmak için gereken her şeyi ayarlayacaksınız.

5. Three.js sahnesi oluşturma

WebGL'yi kullanmak çok karmaşık olabilir. Çünkü her nesnenin tüm yönlerini manuel olarak tanımlamanız gerekir. İşleri kolaylaştırmak için bu codelab'de, WebGL'nin üzerinde basitleştirilmiş bir soyutlama katmanı sağlayan popüler bir grafik kitaplığı olan Three.js'yi kullanacaksınız. Three.js, WebGL oluşturucu oluşturmaktan yaygın 2D ve 3D nesne şekillerini çizmeye, kameraları ve nesne dönüşümlerini kontrol etmeye kadar her şeyi yapan çok çeşitli kolaylık işlevleriyle birlikte gelir.

Three.js'de herhangi bir şeyin gösterilmesi için gereken üç temel nesne türü vardır:

  • Sahne: Tüm nesnelerin, ışık kaynaklarının, dokuların vb. oluşturulup görüntülendiği bir "kapsayıcı".
  • Kamera: Sahnenin bakış açısını temsil eden bir kamera. Birden fazla kamera türü mevcuttur ve tek bir sahneye bir veya daha fazla kamera eklenebilir.
  • Oluşturucu: Sahnedeki tüm nesnelerin işlenmesini ve görüntülenmesini sağlayan oluşturucu. Three.js'de en yaygın kullanılan WebGLRenderer olsa da istemci WebGL'yi desteklemediğinde yedek olarak kullanılabilecek birkaç başka oluşturucu da vardır.

Bu adımda, Three.js için gereken tüm bağımlılıkları yükleyip temel bir sahne oluşturacaksınız.

  1. three.js'yi yükleyin

    Bu codelab için iki bağımlılık gerekir: Three.js kitaplığı ve GL İletim Biçimi (gLTF)'ndeki 3D nesneleri yüklemenize olanak tanıyan bir sınıf olan GLTF Yükleyici. Three.js, birçok farklı 3D nesne biçimi için özel yükleyiciler sunar ancak gLTF kullanılması önerilir.

    Aşağıdaki kodda, Three.js kitaplığının tamamı içe aktarılır. Bir üretim uygulamasında muhtemelen yalnızca ihtiyacınız olan sınıfları içe aktarmak istersiniz ancak bu codelab'de işleri basit tutmak için kitaplığın tamamını içe aktarın. GLTF yükleyicinin varsayılan kitaplığa dahil olmadığını ve bağımlılıkta ayrı bir yoldan içe aktarılması gerektiğini de unutmayın. Bu yol, Three.js tarafından sağlanan tüm yükleyicilere erişebileceğiniz yoldur.

    Three.js ve GLTF yükleyiciyi içe aktarmak için app.js dosyasının en üstüne aşağıdakileri ekleyin:
    import * as THREE from 'three';
    import {GLTFLoader} from 'three/examples/jsm/loaders/GLTFLoader.js';
    
  2. three.js sahnesi oluşturun.

    Bir sahne oluşturmak için onAdd kancasına aşağıdakileri ekleyerek Three.js Scene sınıfını başlatın:
    scene = new THREE.Scene();
    
  3. Sahneye kamera ekleyin.

    Daha önce de belirtildiği gibi kamera, sahnenin görüntüleme perspektifini temsil eder ve Three.js'nin bir sahnedeki nesnelerin görsel olarak nasıl işleneceğini belirler. Kamera olmadan sahne etkin bir şekilde "görülmez". Bu nedenle, nesneler oluşturulmadıkları için görünmez.

    Three.js, oluşturucunun nesneleri perspektif ve derinlik gibi özellikler açısından nasıl ele aldığını etkileyen çeşitli kameralar sunar. Bu sahnede, insan gözünün sahneyi algılama şeklini taklit etmek için tasarlanmış ve Three.js'de en sık kullanılan kamera türü olan PerspectiveCamera öğesini kullanacaksınız. Bu durumda, kameradan daha uzakta olan nesneler daha yakında olan nesnelere göre daha küçük görünür, sahnenin bir kaybolma noktası olur ve daha birçok değişiklik gerçekleşir.

    Sahneye perspektif kamera eklemek için onAdd kancasına aşağıdakileri ekleyin:
    camera = new THREE.PerspectiveCamera();
    
    PerspectiveCamera ile yakın ve uzak düzlemler, en boy oranı ve görüş alanı (fov) dahil olmak üzere bakış açısını oluşturan özellikleri de yapılandırabilirsiniz. Bu özellikler toplu olarak görüntüleme frustum olarak bilinir. Bu, 3D ile çalışırken anlaşılması gereken önemli bir kavramdır ancak bu codelab'in kapsamı dışındadır. Varsayılan PerspectiveCamera yapılandırması yeterli olacaktır.
  4. Sahneye ışık kaynakları ekleyin.

    Varsayılan olarak, Three.js sahnesinde oluşturulan nesneler, üzerlerine uygulanan dokulardan bağımsız olarak siyah görünür. Bunun nedeni, Three.js sahnesinin nesnelerin gerçek dünyadaki davranışlarını taklit etmesidir. Gerçek dünyada, rengin görünürlüğü nesneden yansıyan ışığa bağlıdır. Kısacası, ışık yoksa renk de yoktur.

    Three.js, çeşitli farklı ışık türleri sunar. Bunlardan ikisini kullanacaksınız:

  5. AmbientLight: Sahnedeki tüm nesneleri her açıdan eşit şekilde aydınlatan dağınık bir ışık kaynağı sağlar. Bu, tüm nesnelerdeki dokuların görünür olmasını sağlamak için sahneye temel bir ışık miktarı verir.
  6. DirectionalLight: Sahnedeki bir yönden gelen ışığı sağlar. Konumlandırılmış bir ışığın gerçek dünyada çalışma şeklinden farklı olarak, DirectionalLight kaynağından çıkan ışınlar birbirine paraleldir ve ışık kaynağından uzaklaştıkça yayılmaz ve dağılmaz.

    Toplu aydınlatma efektleri oluşturmak için her ışığın rengini ve yoğunluğunu yapılandırabilirsiniz. Örneğin, aşağıdaki kodda ortam ışığı tüm sahne için yumuşak bir beyaz ışık sağlarken yönlü ışık, nesnelere aşağı doğru bir açıyla vuran ikincil bir ışık sağlar. Yönlü ışık durumunda açı, position.set(x, y ,z) kullanılarak ayarlanır. Burada her değer, ilgili eksene göre belirlenir. Örneğin, position.set(0,1,0) ışığı doğrudan aşağıyı gösteren y ekseninde sahnenin üzerine yerleştirir.

    Işık kaynaklarını sahneye eklemek için onAdd kancasına aşağıdakileri ekleyin:
    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 kancanız artık şu şekilde görünmelidir:

    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);
    }

Sahneniz artık ayarlandı ve oluşturulmaya hazır. Ardından, WebGL oluşturucuyu yapılandırıp sahneyi oluşturacaksınız.

6. Sahneyi oluşturma

Sahnenizi oluşturma zamanı. Bu noktaya kadar Three.js ile oluşturduğunuz her şey kodda başlatılır ancak henüz WebGL oluşturma bağlamında oluşturulmadığı için esasen mevcut değildir. WebGL, canvas API'sini kullanarak tarayıcıda 2D ve 3D içerikleri oluşturur. Daha önce Canvas API'yi kullandıysanız her şeyin oluşturulduğu bir HTML tuvalinin context ile ilgili bilgi sahibi olabilirsiniz. Ancak bu arayüzün, tarayıcıdaki WebGLRenderingContext API'si aracılığıyla OpenGL grafik oluşturma bağlamını kullanıma sunduğunu bilmiyor olabilirsiniz.

Three.js, WebGL oluşturucuyla çalışmayı kolaylaştırmak için WebGLRenderer adlı bir sarmalayıcı sağlar. Bu sarmalayıcı, WebGL oluşturma bağlamını Three.js'in sahneleri tarayıcıda oluşturabileceği şekilde yapılandırmayı nispeten kolaylaştırır. Ancak harita söz konusu olduğunda, Three.js sahnesini tarayıcıda haritanın yanında oluşturmak yeterli değildir. Three.js, hem haritanın hem de Three.js sahnesindeki tüm nesnelerin aynı dünya alanında oluşturulması için harita ile aynı oluşturma bağlamında oluşturulmalıdır. Bu sayede oluşturucu, haritadaki nesneler ile sahnedeki nesneler arasındaki etkileşimleri (ör. kapatma) işleyebilir. Kapatma, bir nesnenin arkasındaki nesneleri görünümden gizleyeceğini söylemenin süslü bir yoludur.

Karmaşık görünüyor, değil mi? Neyse ki Three.js yine yardıma koşuyor.

  1. WebGL oluşturucuyu ayarlayın.

    Three.js'nin yeni bir örneğini oluşturduğunuzda WebGLRenderer, sahnenizi oluşturmasını istediğiniz belirli WebGL oluşturma bağlamını sağlayabilirsiniz. onContextRestored kancasına iletilen gl bağımsız değişkenini hatırlıyor musunuz? Bu gl nesnesi, haritanın WebGL oluşturma bağlamıdır. Yapmanız gereken tek şey, WebGLRenderer örneğine bağlamı, tuvalini ve özelliklerini sağlamaktır. Bunların tümü gl nesnesi aracılığıyla kullanılabilir. Bu kodda, oluşturucunun autoClear özelliği de false olarak ayarlanır. Böylece oluşturucu, çıkışını her karede temizlemez.

    Oluşturucuyu yapılandırmak için onContextRestored kancasına aşağıdakileri ekleyin:
    renderer = new THREE.WebGLRenderer({
      canvas: gl.canvas,
      context: gl,
      ...gl.getContextAttributes(),
    });
    renderer.autoClear = false;
    
  2. Sahneyi oluşturun.

    Oluşturucu yapılandırıldıktan sonra, bir sonraki kare oluşturulduğunda kaplamanın yeniden çizilmesi gerektiğini bildirmek için WebGLOverlayView örneğinde requestRedraw işlevini çağırın. Ardından, oluşturucuda render işlevini çağırın ve oluşturulacak Three.js sahnesini ve kamerasını oluşturucuya iletin. Son olarak, WebGL oluşturma bağlamının durumunu temizleyin. WebGL Overlay View'un kullanımı ortak GL durumuna dayandığından, bu adım GL durumu çakışmalarını önlemek için önemlidir. Durum her çizim çağrısının sonunda sıfırlanmazsa GL durumu çakışmaları, oluşturucunun başarısız olmasına neden olabilir.

    Bunu yapmak için aşağıdaki kodu onDraw kancasına ekleyin. Böylece kod her karede yürütülür:
    webGLOverlayView.requestRedraw();
    renderer.render(scene, camera);
    renderer.resetState();
    

onContextRestored ve onDraw kancalarınız artık aşağıdaki gibi görünmelidir:

    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. Haritada 3D model oluşturma

Tamam, her şey hazır. WebGl Overlay View'u ayarladınız ve bir Three.js sahnesi oluşturdunuz ancak bir sorun var: Sahne boş. Şimdi sahnedeki bir 3D nesneyi oluşturma zamanı. Bunu yapmak için daha önce içe aktardığınız GLTF yükleyiciyi kullanacaksınız.

3D modeller birçok farklı biçimde sunulur ancak Three.js için boyut ve çalışma zamanı performansı nedeniyle gLTF biçimi tercih edilir. Bu codelab'de, sahnede oluşturmanız için /src/pin.gltf içinde bir model sağlanmıştır.

  1. Model yükleyici örneği oluşturun.

    Aşağıdakileri onAdd listesine ekleyin:
    loader = new GLTFLoader();
    
  2. 3D model yükleyin.

    Model yükleyiciler eşzamansızdır ve model tamamen yüklendikten sonra geri çağırma işlevini yürütür. pin.gltf dosyasını yüklemek için onAdd dosyasına aşağıdakileri ekleyin:
    const source = "pin.gltf";
    loader.load(
      source,
      gltf => {}
    );
    
  3. Modeli sahneye ekleyin.

    Artık loader geri çağırma işlevine aşağıdakileri ekleyerek modeli sahneye ekleyebilirsiniz. gltf değil, gltf.scene eklenir:
    scene.add(gltf.scene);
    
  4. Kamera projeksiyon matrisini yapılandırın.

    Modelin haritada düzgün şekilde oluşturulması için yapmanız gereken son şey, Three.js sahnesinde kameranın projeksiyon matrisini ayarlamaktır. Projeksiyon matrisi, döndürme, kaydırma ve ölçek gibi dönüşümlerle birlikte üç boyutlu uzayda bir noktayı tanımlayan Three.js Matrix4 dizisi olarak belirtilir.

    WebGLOverlayView durumunda, projeksiyon matrisi, oluşturucuya Three.js sahnesinin temel haritaya göre nerede ve nasıl oluşturulacağını söylemek için kullanılır. Ancak bir sorun var. Haritadaki konumlar enlem ve boylam koordinat çiftleri olarak belirtilirken Three.js sahnesindeki konumlar Vector3 koordinatlarıdır. Tahmin edebileceğiniz gibi, iki sistem arasındaki dönüşümün hesaplanması kolay bir işlem değildir. Bu sorunu çözmek için WebGLOverlayView, fromLatLngAltitude adlı bir işlev içeren OnDraw yaşam döngüsü kancasına bir coordinateTransformer nesnesi iletir. fromLatLngAltitude, bir LatLngAltitude veya LatLngAltitudeLiteral nesnesi ve isteğe bağlı olarak sahne için bir dönüşüm tanımlayan bir dizi bağımsız değişken alır, ardından bunları sizin için bir model görünümü projeksiyonu (MVP) matrisine dönüştürür. Tek yapmanız gereken, Three.js sahnesinin haritada nerede oluşturulmasını istediğinizi ve nasıl dönüştürülmesini istediğinizi belirtmek. WebGLOverlayView gerisini halleder. Ardından MVP matrisini bir Three.js Matrix4 dizisine dönüştürebilir ve kamera projeksiyon matrisini buna ayarlayabilirsiniz.

    Aşağıdaki kodda, ikinci bağımsız değişken WebGL yer paylaşımı görünümüne Three.js sahnesinin yüksekliğini yerden 120 metre yukarıda ayarlamasını söyler. Bu da modelin havada süzülüyormuş gibi görünmesini sağlar.

    Kamera projeksiyon matrisini ayarlamak için onDraw kancasına aşağıdakileri ekleyin:
    const latLngAltitudeLiteral = {
        lat: mapOptions.center.lat,
        lng: mapOptions.center.lng,
        altitude: 120
    }
    const matrix = transformer.fromLatLngAltitude(latLngAltitudeLiteral);
    camera.projectionMatrix = new THREE.Matrix4().fromArray(matrix);
    
  5. Modeli dönüştürün.

    Raptiyenin haritaya dik olarak yerleştirilmediğini fark edeceksiniz. 3D grafiklerde, yönü belirleyen kendi x, y ve z eksenlerine sahip dünya uzayına ek olarak her nesnenin bağımsız bir eksen kümesiyle kendi nesne uzayı da vardır.

    Bu modelde, normalde pimin "üst" kısmı olarak kabul ettiğimiz kısım y eksenine bakacak şekilde oluşturulmadığı için rotation.set işlevini çağırarak nesneyi dünya alanına göre istediğiniz şekilde yönlendirecek şekilde dönüştürmeniz gerekir. Three.js'de dönüşün derece cinsinden değil, radyan cinsinden belirtildiğini unutmayın. Genellikle derece cinsinden düşünmek daha kolaydır. Bu nedenle, degrees * Math.PI/180 formülü kullanılarak uygun dönüştürme yapılmalıdır.

    Ayrıca model biraz küçük olduğundan scale.set(x, y ,z) işlevini çağırarak tüm eksenlerde eşit şekilde ölçeklendireceksiniz.

    Modeli döndürmek ve ölçeklendirmek için onAdd before scene.add(gltf.scene) öğesinin loader geri çağırma işlevine aşağıdakileri ekleyin. Bu işlev, gLTF'yi sahneye ekler:
    gltf.scene.scale.set(25,25,25);
    gltf.scene.rotation.x = 180 * Math.PI/180;
    

Artık raptiye, haritaya göre dik duruyor.

Dik Pimi

onAdd ve onDraw kancalarınız artık aşağıdaki gibi görünmelidir:

    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();
    }

Sırada kamera animasyonları var.

8. Kamerayı animasyonla hareketlendirme

Artık haritada bir model oluşturup her şeyi üç boyutlu olarak hareket ettirebildiğinize göre, bir sonraki adımda bu hareketi programatik olarak kontrol etmek isteyebilirsiniz. moveCamera işlevi, haritanın merkez, yakınlaştırma, eğme ve başlık özelliklerini aynı anda ayarlamanıza olanak tanıyarak kullanıcı deneyimi üzerinde ayrıntılı kontrol sağlar. Ayrıca, saniyede yaklaşık 60 kare hızında kareler arasında akıcı geçişler oluşturmak için moveCamera animasyon döngüsünde çağrılabilir.

  1. Modelin yüklenmesini bekleyin.

    Sorunsuz bir kullanıcı deneyimi oluşturmak için gLTF modeli yüklenene kadar kamerayı hareket ettirmeye başlamak üzere beklemek isteyebilirsiniz. Bunu yapmak için yükleyicinin onLoad etkinlik işleyicisini onContextRestored kancasına ekleyin:
    loader.manager.onLoad = () => {}
    
  2. Animasyon döngüsü oluşturma

    setInterval veya requestAnimationFrame gibi araçları kullanarak animasyon döngüsü oluşturmanın birden fazla yolu vardır. Bu durumda, Three.js yeni bir kare oluşturduğunda geri çağırmasında bildirdiğiniz tüm kodları otomatik olarak çağıran Three.js oluşturucusunun setAnimationLoop işlevini kullanırsınız. Animasyon döngüsü oluşturmak için önceki adımdaki onLoad etkinlik işleyicisine aşağıdakileri ekleyin:
    renderer.setAnimationLoop(() => {});
    
  3. Animasyon döngüsünde kamera konumunu ayarlayın.

    Ardından, haritayı güncellemek için moveCamera çağrısı yapın. Burada, haritayı yüklemek için kullanılan mapOptions nesnesindeki özellikler, kamera konumunu tanımlamak için kullanılır:
    map.moveCamera({
      "tilt": mapOptions.tilt,
      "heading": mapOptions.heading,
      "zoom": mapOptions.zoom
    });
    
  4. Kamerayı her karede güncelleyin.

    Son adım! Bir sonraki karenin kamera konumunu ayarlamak için her karenin sonunda mapOptions nesnesini güncelleyin. Bu kodda, eğim 67,5 olan maksimum eğim değerine ulaşana kadar eğimi artırmak için bir if ifadesi kullanılır.Ardından, kamera 360 derece tam dönüşünü tamamlayana kadar her karede başlık biraz değiştirilir. İstenen animasyon tamamlandığında, animasyonun sürekli olarak çalışmaması için null, setAnimationLoop'ye iletilir.
    if (mapOptions.tilt < 67.5) {
      mapOptions.tilt += 0.5
    } else if (mapOptions.heading <= 360) {
      mapOptions.heading += 0.2;
    } else {
      renderer.setAnimationLoop(null)
    }
    

onContextRestored kancanız artık şu şekilde görünmelidir:

    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. Tebrikler

Her şey plana göre ilerlediyse artık şu şekilde görünen büyük bir 3D raptiyeli haritanız olmalıdır:

Final 3D Pin

Öğrendikleriniz

Bu codelab'de birçok şey öğrendiniz. İşte öne çıkan noktalar:

  • WebGLOverlayView ve yaşam döngüsü kancalarını uygulama
  • Three.js'yi haritaya entegre etme.
  • Kameralar ve ışıklandırma dahil olmak üzere Three.js sahnesi oluşturmanın temelleri.
  • Three.js kullanarak 3D modelleri yükleme ve işleme.
  • moveCamera kullanarak harita için kamerayı kontrol etme ve animasyon oluşturma.

Sırada ne var?

WebGL ve genel olarak bilgisayar grafikleri karmaşık bir konu olduğundan her zaman öğrenilecek çok şey vardır. Başlamanıza yardımcı olacak birkaç kaynak: