WebGL Overlay Google 地图:如何投射阴影?

WebGL Overlay Google map: How to cast Shadows?

如何使用 WebGL 叠加层 API 制作加载到地图中的 3d 对象,以便在地图图块和其他加载的对象上投射阴影?

在我看来,这还不受支持(或此功能已被删除),那么有什么解决方法吗?

首选 WebGL 框架:ThreeJs

我们在 google 地图上还没有此选项,因为我们从“webgloverlayview”获得的地图叠加层没有接收阴影选项。

我尝试在 google 地图上创建自己的平面并获得阴影 我的平面不透明度非常轻,如 0.3。我还在下面的彩色平面中添加了图像来解释。

++ 请看@yosan_melese回答一下 完美使用 ShadowMaterial

这里是示例代码

    import { Loader } from '@googlemaps/js-api-loader';
    import * as THREE from 'three';
    import {FBXLoader} from 'three/examples/jsm/loaders/FBXLoader.js';
    
    const apiOptions = {
      apiKey: 'A***********8',
      version: "beta",
      map_ids: [""]
    };
    let directionalLight = '';
    const mapOptions = {
      "tilt": 0,
      "heading": 0,
      "zoom": 18,
      "center": { lat: 33.57404, lng: 73.1637 },
      "mapId": "" ,
      "mapTypeId": 'roadmap'
    }
    /*
    roadmap: the default map that you usually see.
    satellite: satellite view of Google Maps and Google Earth, when available.
    hybrid: a mixture of roadmap and satellite view.
    terrain: a map based on terrain information, such as mountains and valleys.
    */
    async function initMap() {    
      const mapDiv = document.getElementById("map");
      const apiLoader = new Loader(apiOptions);
      await apiLoader.load();
      return new google.maps.Map(mapDiv, mapOptions);
    }
    
    let scene, renderer, camera, loader,loader1,controls;
    function initWebglOverlayView(map) {  
      
      const webglOverlayView = new google.maps.WebglOverlayView();
      
      webglOverlayView.onAdd = () => {   
        // set up the scene
        scene = new THREE.Scene();
        camera = new THREE.PerspectiveCamera();
    
        const ambientLight = new THREE.AmbientLight( 0xffffff, 0.75 ); // soft white light
        scene.add(ambientLight);
    
        directionalLight = new THREE.DirectionalLight(0xffffff, 1);
        directionalLight.position.x += (-90)
        directionalLight.position.y += 0
        directionalLight.position.z += 20
        directionalLight.castShadow = true
        const d = 100;
        directionalLight.shadow.camera.left = - d;
        directionalLight.shadow.camera.right = d;
        directionalLight.shadow.camera.top = d;
        directionalLight.shadow.camera.bottom = - d;
        scene.add(directionalLight);
        scene.add( new THREE.CameraHelper( directionalLight.shadow.camera ) );
    
    
        // FLOOR

/*
        const plane = new THREE.Mesh(new THREE.PlaneGeometry(2050, 2200, 300),
        new THREE.MeshPhongMaterial({ color: 0xF3F4F5, opacity: 0.3, transparent: true}));
        plane.rotation.x = 0;
        plane.rotation.y = 0;
        plane.rotation.z = 0;
        plane.castShadow = true
        plane.receiveShadow = true
        scene.add(plane);
 */

//after yosan_melese answer i am using ShadowMaterial 

const geometry = new THREE.PlaneGeometry( 2000, 2000 );
geometry.rotateX( - Math.PI / 2 );

const material = new THREE.ShadowMaterial();
material.opacity = 0.5;

const plane = new THREE.Mesh( geometry, material );
plane.rotation.x = 2;
plane.position.x = 0;
plane.position.y = 0;
plane.position.z = 0;
plane.receiveShadow = true;
scene.add( plane );   
    
        loader = new FBXLoader();
        loader.load( 'model/name_model.fbx', function ( object ) {
          object.scale.set( 1, 1, 1 );
          object.rotation.x = 1.480;
          object.rotation.y = 0.950;
          object.rotation.z = 0.070;
          object.castShadow = true;
          object.receiveShadow = true;
          object.name = "name_model"; 
          object.traverse( function ( child ) {
            if(child.isMesh ) {
              child.castShadow = true;
              child.receiveShadow = true;
            }
          });
          scene.add( object );
        });
      
      }
      
      webglOverlayView.onContextRestored = (gl) => {        
        // create the three.js renderer, using the
        // maps's WebGL rendering context.
        renderer = new THREE.WebGLRenderer({
          canvas: gl.canvas,
          context: gl,
          ...gl.getContextAttributes(),
        });
        renderer.autoClear = false;
        renderer.shadowMap.enabled = true;
        renderer.shadowMap.type = THREE.PCFSoftShadowMap;
        renderer.receiveShadow = true;
        renderer.castShadow = true;
        
      }
    
      webglOverlayView.onDraw = (gl, coordinateTransformer) => {
        // update camera matrix to ensure the model is georeferenced correctly on the map     
        const matrix = coordinateTransformer.fromLatLngAltitude(mapOptions.center, 10);
        camera.projectionMatrix = new THREE.Matrix4().fromArray(matrix);
        webglOverlayView.requestRedraw();
        renderer.render(scene, camera);
        // always reset the GL state
        renderer.resetState();
    
      }
      webglOverlayView.setMap(map);
    
    }
    
    (async () => {        
      const map = await initMap();
      initWebglOverlayView(map);    
    })();

在@yosan_melese代码之后

threeJS 的解决方法是在地面上放置一个薄盒子(它不适用于 planeGeometry),该盒子完全透明但会接收阴影。这可以通过 shadowMaterial

来实现

注意:这只会显示添加到 webgloverlay 的网格的阴影,而不是地图上建筑物的阴影