1. Antes de começar
Este codelab ensina a usar os recursos da API Maps JavaScript com a tecnologia WebGL para renderizar e controlar o mapa vetorial em três dimensões.

Pré-requisitos
Este codelab pressupõe que você tem conhecimento intermediário de JavaScript e da API Maps JavaScript. Para aprender os conceitos básicos da API Maps JS, consulte o codelab Adicionar um mapa ao seu site (JavaScript).
O que você aprenderá
- Gerar um ID do mapa com o mapa vetorial para JavaScript ativado
- Controlar o mapa com inclinação e rotação programáticas
- Renderizar objetos 3D no mapa com WebGLOverlayViewe three.js (em inglês)
- Animar movimentos de câmera com moveCamera
Recursos necessários
- Uma conta do Google Cloud Platform com o faturamento ativado
- Uma chave de API da Plataforma Google Maps com a API Maps JavaScript ativada
- Conhecimento intermediário de JavaScript, HTML e CSS
- Um editor de texto ou ambiente de desenvolvimento integrado de sua escolha
- Node.js (link em inglês)
2. Começar a configuração
Para a etapa abaixo, é necessário ativar a API Maps JavaScript.
Configurar a Plataforma Google Maps
Caso você ainda não tenha uma conta do Google Cloud Platform e um projeto com faturamento ativado, veja como criá-los no guia da Plataforma Google Maps.
- No Console do Cloud, clique no menu suspenso do projeto e selecione o projeto que você quer usar neste codelab.

- Ative as APIs e os SDKs da Plataforma Google Maps necessários para este codelab no Google Cloud Marketplace. Para fazer isso, siga as etapas descritas neste vídeo ou nesta documentação.
- Gere uma chave de API na página Credenciais do Console do Cloud. Siga as etapas indicadas neste vídeo ou nesta documentação. Todas as solicitações feitas à Plataforma Google Maps exigem uma chave de API.
Configuração do Node.js
Acesse https://nodejs.org/ (em inglês), faça o download do ambiente de execução do Node.js e instale no computador, caso ainda não tenha feito isso.
O Node.js vem com o gerenciador de pacotes npm, que é necessário para instalar as dependências deste codelab.
Fazer o download do modelo inicial do projeto
Antes de iniciar este codelab, siga as instruções abaixo para fazer o download do modelo inicial do projeto e do código completo da solução.
- Faça o download ou crie uma bifurcação do repositório GitHub deste codelab em https://github.com/googlecodelabs/maps-platform-101-webgl/ (em inglês). O projeto inicial está localizado no diretório /startere inclui a estrutura de arquivos básica necessária para concluir o codelab. Tudo o que você precisa para trabalhar está no diretório/starter/src.
- Depois de fazer o download do projeto inicial, execute npm installno diretório/starter. Isso instala todas as dependências necessárias listadas empackage.json.
- Depois de instalar as dependências, execute npm startno diretório.
O projeto inicial foi configurado para que você possa usar o webpack-dev-server, que compila e executa o código escrito localmente. O webpack-dev-server também recarrega automaticamente o app no navegador sempre que você faz alterações no código.
Se você quiser ver o código completo da solução em execução, conclua as etapas de configuração acima no diretório /solution.
Adicionar sua chave de API
O app inicial inclui todo o código necessário para carregar o mapa com o JS API Loader (em inglês). Assim, basta informar a chave de API e o ID do mapa. O JS API Loader é uma biblioteca simples que abstrai o método tradicional de carregamento da API Maps JS in-line no modelo HTML com uma tag script. Assim, você pode processar tudo no código JavaScript.
Para adicionar a chave de API, faça o seguinte no projeto inicial:
- Abra app.js.
- No objeto apiOptions, defina sua chave de API como o valor deapiOptions.apiKey.
3. Gerar e usar um ID do mapa
Para usar os recursos baseados em WebGL da API Maps JavaScript, você precisa de um ID do mapa com o mapa vetorial ativado.
Como gerar um ID do mapa

- No Console do Google Cloud, acesse "Plataforma Google Maps" > "Gerenciamento de mapas".
- Clique em "CREATE MAP ID".
- No campo "Nome", insira um nome para este ID do mapa.
- Na lista suspensa "Tipo de mapa", selecione "JavaScript". As "Opções de JavaScript" serão exibidas.
- Selecione a opção "Vetor" e as caixas de seleção "Inclinação" e "Rotação".
- Opcional: no campo "Descrição", insira uma descrição para a chave de API.
- Clique no botão "Salvar". A página "Detalhes do ID do mapa" é exibida.  
- Copie o ID do mapa. Você precisará dele para carregar o mapa na próxima etapa.
Como usar um ID do mapa
Para carregar o mapa vetorial, é necessário inserir um ID do mapa como uma propriedade nas opções ao instanciar o mapa. Você também pode inserir o mesmo ID do mapa ao carregar a API Maps JavaScript.
Para carregar o mapa com seu ID, faça o seguinte:
- Defina seu ID do mapa como o valor de mapOptions.mapId.
 Inserir o ID ao instanciar o mapa informa à Plataforma Google Maps quais dos seus mapas devem ser carregados em uma determinada instância. Você pode reutilizar o mesmo ID do mapa em vários apps ou várias visualizações no mesmo app.const mapOptions = { "tilt": 0, "heading": 0, "zoom": 18, "center": { lat: 35.6594945, lng: 139.6999859 }, "mapId": "YOUR_MAP_ID" };
Verifique o app em execução no seu navegador. O mapa vetorial com inclinação e rotação ativados deve carregar sem problemas. Para verificar se a inclinação e a rotação estão ativadas, mantenha a tecla Shift pressionada e arraste com o mouse ou use as setas do teclado.
Se o mapa não carregar, verifique se você inseriu uma chave de API válida em apiOptions. Se o mapa não inclinar ou rotacionar, verifique se você inseriu um ID do mapa com inclinação e rotação ativadas em apiOptions e mapOptions.

Seu arquivo app.js ficou assim:
    import { Loader } from '@googlemaps/js-api-loader';
    const apiOptions = {
      "apiKey": 'YOUR_API_KEY',
      "version": "beta"
    };
    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. Implementar WebGLOverlayView
O WebGLOverlayView oferece acesso direto ao mesmo contexto de renderização WebGL usado para renderizar o mapa básico vetorial. Isso significa que você pode renderizar objetos 2D e 3D diretamente no mapa usando WebGL, bem como bibliotecas de gráficos baseadas em WebGL.
O WebGLOverlayView expõe cinco hooks que você pode usar no ciclo de vida do contexto de renderização WebGL do mapa. Veja uma breve descrição de cada hook e como eles podem ser usados:
- onAdd(): chamado quando a sobreposição é adicionada a um mapa. Para isso, chame- setMapem uma instância- WebGLOverlayView. É aqui que você deve fazer qualquer trabalho em WebGL que não exija acesso direto ao contexto WebGL.
- onContextRestored(): chamado quando o contexto WebGL fica disponível, mas antes da renderização de qualquer elemento. É aqui que você precisa inicializar objetos, vincular o estado por binding e fazer qualquer outra coisa que precise de acesso ao contexto WebGL, mas que possa ser realizada fora da chamada- onDraw(). Isso permite que você configure tudo o que precisa sem sobrecarregar a renderização do mapa, que já usa muita GPU.
- onDraw(): chamado uma vez por frame quando o WebGL começa a renderizar o mapa e o que mais você tiver solicitado. Faça o mínimo de alterações possível no- onDraw()para evitar problemas de desempenho na renderização do mapa.
- onContextLost(): chamado quando o contexto de renderização WebGL é perdido por qualquer motivo.
- onRemove(): chamado quando a sobreposição é removida do mapa. Para isso, chame- setMap(null)em uma instância- WebGLOverlayView.
Nesta etapa, você criará uma instância de WebGLOverlayView e implementará três hooks de ciclo de vida: onAdd, onContextRestored e onDraw. Para manter tudo limpo e fácil de acompanhar, todo o código da sobreposição será processado na função initWebGLOverlayView() fornecida no modelo inicial deste codelab.
- Crie uma instância WebGLOverlayView().
 A sobreposição é fornecida pela API Maps JS nogoogle.maps.WebGLOverlayView. Para começar, crie uma instância anexando o código a seguir ainitWebGLOverlayView():const webGLOverlayView = new google.maps.WebGLOverlayView();
- Implemente hooks de ciclo de vida. 
 Para implementar os hooks de ciclo de vida, anexe o seguinte ainitWebGLOverlayView():webGLOverlayView.onAdd = () => {}; webGLOverlayView.onContextRestored = ({gl}) => {}; webGLOverlayView.onDraw = ({gl, coordinateTransformer}) => {};
- Adicione a instância de sobreposição ao mapa. 
 Agora, chamesetMap()na instância de sobreposição e transmita o mapa anexando o seguinte ainitWebGLOverlayView():webGLOverlayView.setMap(map)
- Chame initWebGLOverlayView.
 A última etapa é executarinitWebGLOverlayView()adicionando o seguinte à função invocada imediatamente na parte de baixo doapp.js:initWebGLOverlayView(map);
O initWebGLOverlayView e a função imediatamente invocada vão ficar assim:
    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);
    })();
Isso é tudo o que você precisa para implementar o WebGLOverlayView. Agora você vai configurar todo o necessário para renderizar um objeto 3D no mapa usando o three.js.
5. Configurar uma cena three.js
Usar o WebGL pode ser muito complicado, porque exige que você defina todos os aspectos de cada objeto manualmente. Para facilitar muito as coisas, para este codelab, você usará o three.js, uma biblioteca de gráficos bastante utilizada que insere uma camada de abstração simplificada por cima do WebGL. O three.js vem com uma ampla variedade de funções de conveniência que fazem de tudo, desde a criação de um renderizador WebGL até o desenho de formas comuns de objetos 2D e 3D, o controle de câmeras, transformações de objeto e muito mais.
Existem três tipos básicos de objeto no three.js necessários para exibir qualquer coisa:
- Cena: um "contêiner" em que todos os objetos, fontes de luz, texturas etc. são renderizados e exibidos.
- Câmera: representa o ponto de vista da cena. Vários tipos de câmera estão disponíveis, e uma ou mais câmeras podem ser adicionadas a uma única cena.
- Renderizador: faz o processamento e a exibição de todos os objetos na cena. No three.js, WebGLRendereré o renderizador mais usado, mas alguns outros estão disponíveis como contingência caso o cliente não seja compatível com o WebGL.
Nesta etapa, você carregará todas as dependências necessárias para o three.js e criará uma cena básica.
- Carregue o three.js. 
 Você precisará de duas dependências para este codelab: a biblioteca three.js e o glTF Loader, uma classe que permite carregar objetos 3D no Formato de transferência GL, ou glTF (em inglês). O three.js oferece carregadores especializados para muitos formatos de objetos 3D diferentes, mas o uso do glTF é recomendado.
 No código abaixo, toda a biblioteca three.js é importada. Em um app de produção, é recomendável importar apenas as classes necessárias, mas, para este codelab, importe toda a biblioteca para simplificar. Observe também que o glTF Loader não está incluído na biblioteca padrão e precisa ser importado de um caminho separado na dependência. Esse é o caminho em que você pode acessar todos os carregadores fornecidos pelo three.js.
 Para importar o three.js e o glTF Loader, adicione o seguinte no início deapp.js:import * as THREE from 'three'; import {GLTFLoader} from 'three/examples/jsm/loaders/GLTFLoader.js';
- Crie uma cena three.js. 
 Para criar uma cena, instancie a classeScenedo three.js anexando o seguinte ao hookonAdd:scene = new THREE.Scene();
- Adicione uma câmera à cena. 
 Como mencionado anteriormente, a câmera representa a perspectiva da visualização da cena e determina como o three.js faz a renderização visual de objetos em uma cena. Sem uma câmera, a cena não é "vista", o que significa que os objetos não serão exibidos porque não serão renderizados.
 O three.js oferece várias câmeras diferentes que afetam o modo como o renderizador trata os objetos em relação a aspectos como perspectiva e profundidade. Na cena, você usará aPerspectiveCamera, o tipo de câmera mais usado no three.js, projetado para emular a forma como o olho humano perceberia a cena. Isso significa que os objetos mais distantes da câmera serão menores do que os que estão mais próximos, a cena terá um ponto de fuga, entre outros.
 Para adicionar uma câmera de perspectiva à cena, anexe o seguinte ao hookonAdd:
 Com acamera = new THREE.PerspectiveCamera();PerspectiveCamera, também é possível configurar os atributos que compõem o ponto de vista, incluindo as áreas próximas e distantes, a proporção e o campo de visão (FOV, na sigla em inglês). Coletivamente, esses atributos compõem o que é conhecido como frustum de visualização (link em inglês), um conceito que é importante compreender quando se trabalha em 3D, mas que não faz parte do escopo deste codelab. A configuração padrão dePerspectiveCamerajá é suficiente.
- Adicione fontes de luz à cena. 
 Por padrão, os objetos renderizados em uma cena three.js aparecerão pretos, independentemente das texturas aplicadas. Isso ocorre porque uma cena three.js imita como os objetos agem no mundo real, onde a visibilidade da cor depende da luz refletida por um objeto. Em resumo: sem luz, sem cor.
 O three.js oferece vários tipos diferentes de luz. Você usará dois:
- AmbientLight: aplica uma fonte de luz difusa que ilumina de maneira uniforme todos os objetos na cena, de todos os ângulos. Isso dará à cena uma quantidade de luz referencial para garantir que as texturas em todos os objetos fiquem visíveis.
- DirectionalLight: aplica uma luz vinda de uma direção específica na cena. Ao contrário de como uma luz posicionada funcionaria no mundo real, os raios de luz emitidos por- DirectionalLightsão todos paralelos e não se espalham nem difundem conforme se afastam da fonte de luz.
 Você pode configurar a cor e a intensidade de cada luz para agregar efeitos de iluminação. Por exemplo, no código abaixo, a luz ambiente emite uma tonalidade branca suave para toda a cena, enquanto a luz direcional é secundária e atinge objetos em um ângulo para baixo. No caso da luz direcional, o ângulo é definido usando- position.set(x, y ,z), em que cada valor é relativo ao respectivo eixo. Por exemplo,- position.set(0,1,0)colocaria a luz diretamente acima da cena no eixo y apontando para baixo.
 Para adicionar fontes de luz à cena, anexe o seguinte ao hook- 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);
Seu hook onAdd ficou assim:
    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);
    }
Sua cena está configurada e pronta para renderização. Em seguida, você vai configurar o renderizador WebGL e renderizar a cena.
6. Renderizar a cena
É hora de renderizar a cena. Até agora, tudo que você criou com o three.js está inicializado no código, mas essencialmente não existe porque ainda não foi renderizado no contexto de renderização WebGL. O WebGL renderiza o conteúdo 2D e 3D no navegador usando a API Canvas. Se você já usou a API Canvas, provavelmente conhece o context de uma tela HTML, que é onde tudo é renderizado. O que talvez você não saiba é que essa é uma interface que expõe o contexto de renderização dos gráficos OpenGL por meio da API WebGLRenderingContext no navegador.
Para facilitar o gerenciamento do renderizador do WebGL, o three.js oferece o WebGLRenderer (em inglês), um wrapper que facilita a configuração do contexto de renderização WebGL para que o three.js possa renderizar cenas no navegador. No entanto, no caso do mapa, não basta renderizar a cena three.js no navegador ao lado do mapa. O three.js precisa ser renderizado exatamente no mesmo contexto de renderização do mapa, de modo que o mapa e todos os objetos da cena three.js sejam renderizados no mesmo espaço mundial. Isso possibilita que o renderizador processe as interações entre os objetos no mapa e na cena, como a oclusão, que é uma maneira sofisticada de dizer que um objeto ocultará elementos atrás dele.
Parece complicado, não parece? Felizmente, o three.js vem de novo ao resgate.
- Configure o renderizador WebGL. 
 Quando cria uma nova instância doWebGLRendererdo three.js, você pode dar a ela o contexto de renderização WebGL específico em que você quer renderizar a cena. Lembra do argumentoglque é transmitido para o hookonContextRestored? Esse objetoglé o contexto de renderização WebGL do mapa. Tudo o que você precisa fazer é inserir o contexto, a tela e os atributos na instânciaWebGLRenderer, todos disponíveis pelo objetogl. Nesse código, a propriedadeautoCleardo renderizador também é definida comofalsepara que ele não apague a saída a cada frame.
 Para configurar o renderizador, anexe o seguinte ao hookonContextRestored:renderer = new THREE.WebGLRenderer({ canvas: gl.canvas, context: gl, ...gl.getContextAttributes(), }); renderer.autoClear = false;
- Renderize a cena. 
 Depois de configurar o renderizador, chamerequestRedrawna instânciaWebGLOverlayViewpara informar à sobreposição que é necessário redesenhar quando o próximo frame for renderizado. Em seguida, chamerenderno renderizador. e transmita a cena e a câmera do three.js para renderizar. Por fim, limpe o estado do contexto de renderização WebGL. Essa é uma etapa importante para evitar conflitos de estado GL, já que o uso da visualização de sobreposição do WebGL depende do estado GL compartilhado. Se o estado não for redefinido ao final de cada chamada de desenho, os conflitos de estado GL poderão causar uma falha no renderizador.
 Para fazer isso, anexe o seguinte ao hookonDrawpara que ele seja executado em cada frame:webGLOverlayView.requestRedraw(); renderer.render(scene, camera); renderer.resetState();
Os hooks onContextRestored e onDraw ficarão assim:
    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. Renderizar um modelo 3D no mapa
Você já colocou todas as peças no lugar. Você configurou a visualização de sobreposição do WebGL e criou uma cena three.js, mas há um problema: não há nada nela. Agora é hora de renderizar um objeto 3D na cena. Para isso, vamos usar o glTF Loader que você importou em uma etapa anterior. 
 Os modelos 3D têm vários formatos diferentes. No entanto, para o three.js, o formato glTF é o preferido devido ao tamanho e ao desempenho do ambiente de execução. Neste codelab, um modelo para você renderizar na cena já está disponível em /src/pin.gltf.
- Crie uma instância de carregador de modelo. 
 Anexe o seguinte aonAdd:loader = new GLTFLoader();
- Carregue um modelo 3D. 
 Os carregadores de modelo são assíncronos e executam um callback quando o modelo é totalmente carregado. Para carregarpin.gltf, anexe o seguinte aonAdd:const source = "pin.gltf"; loader.load( source, gltf => {} );
- Adicione o modelo à cena. 
 Agora, é possível adicionar o modelo à cena anexando o seguinte ao callbackloader. Observe que o que está sendo adicionado égltf.scene, e nãogltf:scene.add(gltf.scene);
- Configure a matriz de projeção da câmera. 
 A última coisa que você precisa para renderizar corretamente o modelo no mapa é definir a matriz de projeção da câmera na cena three.js. A matriz de projeção é especificada como uma matrizMatrix4do three.js, que define um ponto em um espaço tridimensional com transformações, como rotações, distorção, escala e muito mais.
 No caso doWebGLOverlayView, a matriz de projeção é usada para informar ao renderizador onde e como renderizar a cena three.js em relação ao mapa básico. Mas há um problema. Os locais no mapa são especificados como pares de coordenadas de latitude e longitude, enquanto os locais na cena three.js são coordenadasVector3. Como você pode ter imaginado, o cálculo da conversão entre os dois sistemas não é simples. Para resolver isso, oWebGLOverlayViewtransmite um objetocoordinateTransformerpara o hook de ciclo de vidaOnDrawque contém uma função chamadafromLatLngAltitude. OfromLatLngAltitudeusa um objetoLatLngAltitudeouLatLngAltitudeLiterale, opcionalmente, um conjunto de argumentos que definem uma transformação para a cena e a convertem em uma matriz de projeção de visualização do modelo (MVP, na sigla em inglês) para você. Tudo o que você precisa fazer é especificar no mapa onde quer que a cena three.js seja renderizada, além de como quer que ela seja transformada, e oWebGLOverlayViewfará o resto. Depois, é possível converter a matriz de MVP em uma matrizMatrix4do three.js e definir a matriz de projeção da câmera nela.
 No código abaixo, o segundo argumento diz à visualização de sobreposição do WebGL para definir a altitude da cena three.js em 120 metros acima do solo, o que fará com que o modelo pareça flutuar.
 Para definir a matriz de projeção da câmera, anexe o seguinte ao hookonDraw:const latLngAltitudeLiteral = { lat: mapOptions.center.lat, lng: mapOptions.center.lng, altitude: 120 } const matrix = transformer.fromLatLngAltitude(latLngAltitudeLiteral); camera.projectionMatrix = new THREE.Matrix4().fromArray(matrix);
- Transforme o modelo. 
 Você vai perceber que o alfinete não está perpendicular ao mapa. Nos gráficos 3D, além do espaço mundial ter os próprios eixos x, y e z que determinam a orientação, cada objeto também tem o próprio espaço, com um conjunto independente de eixos.
 No caso desse modelo, ele não foi criado com o que normalmente consideramos a "parte superior" do alfinete voltada para cima no eixo y. Portanto, é necessário transformar o objeto para orientá-lo na direção desejada relativa ao espaço mundial, chamandorotation.setnele. No three.js, a rotação é especificada em radianos, não em graus. Geralmente, é mais fácil pensar em graus. Por isso, a conversão apropriada precisa ser feita usando a fórmuladegrees * Math.PI/180.
 Além disso, o modelo é pequeno, então você também irá escalonar de maneira uniforme em todos os eixos dele chamandoscale.set(x, y ,z).
 Para girar e dimensionar o modelo, adicione o seguinte no callbackloaderdeonAddantes descene.add(gltf.scene), que adiciona o glTF à cena:gltf.scene.scale.set(25,25,25); gltf.scene.rotation.x = 180 * Math.PI/180;
Agora o alfinete está na posição vertical em relação ao mapa.

Os hooks onAdd e onDraw ficarão assim:
    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();
    }
A seguir, veremos as animações da câmera.
8. Animar a câmera
Agora que você renderizou um modelo no mapa e consegue mover tudo nas três dimensões, o próximo passo será controlar esse movimento de forma programática. A função moveCamera permite definir as propriedades de centro, zoom, inclinação e direção do mapa simultaneamente, dando a você um controle preciso da experiência do usuário. Além disso, o moveCamera pode ser chamado em um loop de animação para criar transições fluidas a quase 60 frames por segundo.
- Aguarde o carregamento do modelo. 
 Para criar uma experiência perfeita para o usuário, aguarde para começar a mover a câmera até que o modelo glTF seja carregado. Para fazer isso, anexe o manipulador de eventosonLoaddo carregador ao hookonContextRestored:loader.manager.onLoad = () => {}
- Crie um loop de animação. 
 Há mais de uma maneira de criar um loop de animação, como usarsetIntervalourequestAnimationFrame. Neste caso, você usará a funçãosetAnimationLoopdo renderizador three.js, que chamará automaticamente qualquer código declarado no callback sempre que o three.js renderizar um novo frame. Para criar o loop de animação, adicione o seguinte ao manipulador de eventosonLoadda etapa anterior:renderer.setAnimationLoop(() => {});
- Defina a posição da câmera no loop de animação. 
 Em seguida, chamemoveCamerapara atualizar o mapa. Aqui, as propriedades do objetomapOptions, usado para carregar o mapa, irão definir a posição da câmera:map.moveCamera({ "tilt": mapOptions.tilt, "heading": mapOptions.heading, "zoom": mapOptions.zoom });
- Atualize a câmera a cada frame. 
 Última etapa! Atualize o objetomapOptionsno final de cada frame para definir a posição da câmera para o próximo frame. Neste código, uma instruçãoifé usada para aumentar a inclinação até que o valor máximo de 67,5 seja atingido. A direção é alterada um pouco a cada frame até a câmera concluir a rotação de 360 graus. Quando a animação desejada for concluída,nullserá transmitido parasetAnimationLoopa fim de cancelar a animação para que ela não seja exibida para sempre.if (mapOptions.tilt < 67.5) { mapOptions.tilt += 0.5 } else if (mapOptions.heading <= 360) { mapOptions.heading += 0.2; } else { renderer.setAnimationLoop(null) }
Seu hook onContextRestored ficou assim:
    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. Parabéns!
Se tudo correu de acordo com o plano, você terá um mapa com um grande alfinete 3D que tem esta aparência:

O que você aprendeu
Neste codelab, você aprendeu várias coisas. Veja os destaques:
- Implementar WebGLOverlayViewe seus hooks de ciclo de vida
- Integrar o three.js ao mapa
- Criar uma cena básica do three.js, incluindo câmeras e iluminação
- Carregar e manipular modelos 3D usando o three.js
- Controlar e animar a câmera para o mapa usando moveCamera
Qual é a próxima etapa?
O WebGL e os gráficos de computador em geral são assuntos complexos, por isso sempre há muito a aprender. Para começar, veja abaixo alguns recursos importantes:
- Documentação da visualização de sobreposição do WebGL
- Primeiros passos com o WebGL
- Documentação do three.js (em inglês)
- Ajude a criar o conteúdo mais relevante para você respondendo à pergunta abaixo: «codelabs/maps-platform/shared/_next-lab-survey.lab.md» O codelab que você quer não está listado acima? Crie um novo "Issue" aqui para sugerir o codelab (link em inglês).