Невозможно отбросить тень с THREE.js и Mapbox GL - PullRequest
0 голосов
/ 05 октября 2019

Я пытаюсь добавить сцену THREE.js в визуализацию Mapbox GL, следуя этому примеру . Я добавил сферу и плоскость земли и DirectionalLight. Теперь я пытаюсь заставить свет отбрасывать тень на землю. С добавлением DirectionalLightHelper и CameraHelper для теневой камеры, все выглядит довольно разумно:

A DirectionLight not casting a shadow

Я бы ожидал увидетьтень для сферы на плоскости.

Полный код здесь , но вот основные моменты:

class SpriteCustomLayer {
  type = 'custom';
  renderingMode = '3d';

  constructor(id) {
    this.id = id;
    this.gui = new dat.GUI();
    THREE.Object3D.DefaultUp.set(0, 0, 1);
  }

  async onAdd(map, gl) {
    this.camera = new THREE.Camera();

    const centerLngLat = map.getCenter();
    this.center = MercatorCoordinate.fromLngLat(centerLngLat, 0);
    const {x, y, z} = this.center;
    this.cameraTransform = new THREE.Matrix4()
      .makeTranslation(x, y, z)
      .scale(new THREE.Vector3(1, -1, 1));

    this.map = map;
    this.scene = this.makeScene();

    this.renderer = new THREE.WebGLRenderer({
      canvas: map.getCanvas(),
      context: gl,
      antialias: true,
    });
    this.renderer.shadowMap.enabled = true;

    this.renderer.autoClear = false;
  }

  makeScene() {
    const scene = new THREE.Scene();
    scene.add(new THREE.AmbientLight(0xffffff, 0.25));

    const s = this.center.meterInMercatorCoordinateUnits();

    const light = new THREE.DirectionalLight(0xffffff, 1);
    light.position.set(0.000002360847837325531, 0.000004566603480958114, 0.00000725142167844218);
    light.target.position.set(0, 0, 0);

    light.castShadow = true;
    light.shadow.mapSize.width = 1024;
    light.shadow.mapSize.height = 1024;

    light.shadow.camera.left = -0.000002383416166278454 * 2;
    light.shadow.camera.right = 0.000002383416166278454 * 2;
    light.shadow.camera.bottom = -0.000002383416166278454 * 2;
    light.shadow.camera.top = 0.000002383416166278454 * 2;
    light.shadow.camera.near = 0.0000012388642793465356;
    light.shadow.camera.far *= s;

    scene.add(light);
    this.light = light;

    {
      const planeSize = 500;
      const loader = new THREE.TextureLoader();
      const texture = loader.load('/checker.png');
      texture.wrapS = THREE.RepeatWrapping;
      texture.wrapT = THREE.RepeatWrapping;
      texture.magFilter = THREE.NearestFilter;
      const repeats = 10;
      texture.repeat.set(repeats, repeats);

      const planeGeo = new THREE.PlaneBufferGeometry(planeSize, planeSize);
      const planeMat = new THREE.MeshPhongMaterial({
        map: texture,
        side: THREE.DoubleSide,
      });

      const plane = new THREE.Mesh(planeGeo, planeMat);
      plane.scale.setScalar(s);
      plane.receiveShadow = true;
      scene.add(plane);
    }

    {
      const sphereRadius = 5e-7;
      const sphereGeo = new THREE.SphereBufferGeometry(sphereRadius, 32, 32);
      const sphereMat = new THREE.MeshPhongMaterial({color: '#CA8'});
      const mesh = new THREE.Mesh(sphereGeo, sphereMat);

      mesh.position.set(0, 0, 5e-6);
      mesh.castShadow = true;
      mesh.receiveShadow = false;
      sphereMat.side = THREE.DoubleSide;
      scene.add(mesh);
    }

    return scene;
  }

  render(gl, matrix) {
    this.camera.projectionMatrix = new THREE.Matrix4()
      .fromArray(matrix)
      .multiply(this.cameraTransform);
    this.renderer.state.reset();
    this.renderer.render(this.scene, this.camera);
    this.map.triggerRepaint();
  }
}

Mapbox GL JS использует систему координат, где всеМир находится в [0, 1], поэтому координаты довольно крошечные. Он также использует x / y для lat / lng и z для up, что отличается от обычных координат Three.js.

Как я могу получить тень для появления? Я использую Three.js r109 и Mapbox GL JS 1.4.0. Я пытался заменить PlaneBufferGeometry на тонкий BoxGeometry, но безрезультатно.

...