Unable to implement threejs on mapbox

Viewed 28

I'd like to implement transformcontrol threejs in mapbox. First I add cube to the scene and attach it to the control. In current mapbox I have some other layer, Icon, 3d building etc. The problem is I can't hover transformcontrol threejs correctly and can't move the cube. Seems this happened because layer of mapbox. enter image description here

export class ModelLayerAOA implements mapboxgl.CustomLayerInterface {
  modelOrigin: [number, number];

  modelAltitude: number;

  onLoad?: () => void;

  id: string;

  type: 'custom';

  renderingMode: '3d';

  modelTransform: {
    translateX: number;
    translateY: number;
    translateZ: number;
    rotateX: number;
    rotateY: number;
    rotateZ: number;
    scale: number;
  };

  color: number;

  map: mapboxgl.Map | undefined;

  camera: THREE.PerspectiveCamera | undefined;

  scene: THREE.Scene | undefined;

  renderer: THREE.WebGLRenderer | undefined;

  model: THREE.Group | undefined | THREE.Mesh;

  transformControl: TransformControls | undefined;

  constructor(options: SpriteOption) {
    this.modelOrigin = options.origin;
    this.modelAltitude = options.altitude;
    this.onLoad = options.onLoad;
    this.id = options.id;
    this.type = 'custom';
    this.renderingMode = '3d';
    this.color = options.color;
    const rotate = [Math.PI / 2, THREE.MathUtils.degToRad(options.rotateY), 0];
    const mercator = mapboxgl.MercatorCoordinate.fromLngLat(
      this.modelOrigin,
      this.modelAltitude,
    );
    const coord = new mapboxgl.MercatorCoordinate(
      mercator.x,
      mercator.y,
      mercator.z,
    );
    console.log(mercator);
    console.log(coord.toLngLat());

    const scale = mercator.meterInMercatorCoordinateUnits();

    this.modelTransform = {
      translateX: mercator.x,
      translateY: mercator.y,
      translateZ: mercator.z ?? 0,
      rotateX: rotate[0],
      rotateY: rotate[1],
      rotateZ: rotate[2],
      scale,
    };
  }

  async onAdd(map: mapboxgl.Map, gl: WebGLRenderingContext) {
    this.map = map;

    this.camera = new THREE.PerspectiveCamera(75);
    this.camera.position.z = 1;
    this.scene = new THREE.Scene();

    const ambientLight = new THREE.AmbientLight(0xffffff, 0.5);
    this.scene.add(ambientLight);

    const geometry = new THREE.BoxGeometry(1, 1, 1);
    const material = new THREE.MeshBasicMaterial({
      color: 0x00ff00,
      transparent: true,
      opacity: 0.3,
    });

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

    if (this.renderer?.domElement && this.camera) {
      this.transformControl = new TransformControls(
        this.camera,
        this.renderer?.domElement,
      );
      this.transformControl.size = 5;
      this.transformControl.addEventListener('change', this.updateRender);
    }

    const cube = new THREE.Mesh(geometry, material);

    let pos = new THREE.Vector3();
    cube.getWorldPosition(pos);

    this.model = cube;

    this.renderer.autoClear = false;
    this.addTransformControl();
  }

  addTransformControl = () => {
    if (this.transformControl && this.model) {
      this.transformControl?.attach(this.model);
      this.scene?.add(this.transformControl);
      this.scene?.add(this.model);
    }
  };

  onRemove(map: mapboxgl.Map) {
    map.removeLayer(this.id);
    if (this.model) {
      this.scene?.remove(this.model);
    }
    this.camera?.clear();
    this.scene?.clear();
  }

  render(gl: WebGLRenderingContext, matrix: number[]) {
    const modelTransform = this.modelTransform;
    const rotationX = new THREE.Matrix4().makeRotationAxis(
      new Vector3(1, 0, 0),
      modelTransform.rotateX,
    );
    const rotationY = new THREE.Matrix4().makeRotationAxis(
      new Vector3(0, 1, 0),
      modelTransform.rotateY,
    );
    const rotationZ = new THREE.Matrix4().makeRotationAxis(
      new Vector3(0, 0, 1),
      modelTransform.rotateZ,
    );

    const m = new THREE.Matrix4().fromArray(matrix);
    const l = new THREE.Matrix4()
      .makeTranslation(
        modelTransform.translateX,
        modelTransform.translateY,
        modelTransform.translateZ,
      )
      .scale(
        new Vector3(
          modelTransform.scale,
          -modelTransform.scale,
          modelTransform.scale,
        ),
      )
      .multiply(rotationX)
      .multiply(rotationY)
      .multiply(rotationZ);

    if (this.camera && this.scene && this.map) {
      this.camera.projectionMatrix.elements = matrix;
      this.camera.projectionMatrix = m.multiply(l);
      this.renderer?.resetState();
      this.updateRender();
      this.map.triggerRepaint();
    }
  }

  updateRender = () => {
    if (this.scene && this.camera) {
      this.renderer?.render(this.scene, this.camera);
    }
  };
}
0 Answers
Related