3D models intersections

Use the MapTiler 3D JS module test whether a 3D model intersects another 3D model.

NPM module setup


npm install --save @maptiler/sdk @maptiler/3d three
import { Map, MapStyle, config } from '@maptiler/sdk';
import '@maptiler/sdk/dist/maptiler-sdk.css';
import { Layer3D, AltitudeReference } from '@maptiler/3d';

import * as THREE from 'three';
config.apiKey = 'YOUR_MAPTILER_API_KEY_HERE';

const center = [-11.40318, 21.12953];

const map = new Map({
  container: document.getElementById('map'),
  hash: true,
  style: MapStyle.SATELLITE,
  zoom: 12.63,
  center: center,
  pitch: 47,
  maxPitch: 85,
  terrainControl: true,
  terrain: true,
  maptilerLogo: true,
});

(async () => {
  await map.onReadyAsync();

  const layer3D = new Layer3D("item3d-intersections");
  map.addLayer(layer3D);

  // Adding a point light
  layer3D.addPointLight("light", {
    lngLat: [
      center[0],
      center[1],
    ],
    intensity: 10,
    decay: 0.1,
    color: "#ffffff",
    altitude: 6000,
  });

  // Adding a mesh. 
  const leftCubeMesh = new THREE.Mesh(new THREE.BoxGeometry(400, 400, 400), new THREE.MeshStandardMaterial({ color: "red", metalness: 0.25, roughness: 0.5 }));
  leftCubeMesh.name = "static-cube-1";
  const leftCubeItem3D = layer3D.addMesh("mesh1", leftCubeMesh, {
    altitudeReference: AltitudeReference.MEAN_SEA_LEVEL,
    lngLat: [
      center[0] - 0.02,
      center[1],
    ],
  });

  leftCubeItem3D.modify({
    heading: 45,
    altitude: 1000,
  });

  const movingItem3D = await layer3D.addMeshFromURL("duck", "https://docs-media.maptiler.com/docs/models/duck.glb", {
    lngLat: center,
    heading: 0,
    scale: 180,
    altitude: 950,
    altitudeReference: AltitudeReference.MEAN_SEA_LEVEL,
  });

  const sphereRightMesh = new THREE.Mesh(new THREE.SphereGeometry(250, 32, 32), new THREE.MeshStandardMaterial({ color: "red", roughness: 0.5 }));
  sphereRightMesh.name = "static-sphere";
  const sphereRightItem3D = layer3D.addMesh("sphere", sphereRightMesh, {
    lngLat: [
      center[0] + 0.02,
      center[1],
    ],
    altitude: 1000,
    altitudeReference: AltitudeReference.MEAN_SEA_LEVEL,
  });


  const itemLngLat = movingItem3D.lngLat;
  let progress = 0;

  addDebugCheckBox([leftCubeItem3D, movingItem3D, sphereRightItem3D]);

  function loop() {
    requestAnimationFrame(loop);
    progress += 0.0005;

    leftCubeItem3D.modify({
      heading: 45,
      altitude: 1000,
    });

    movingItem3D.modify({
      lngLat: [
        itemLngLat.lng + Math.sin(progress * Math.PI * 2) * 0.025,
        itemLngLat.lat,
      ],
      heading: progress * Math.PI * 100,
    });


    const mesh2IntersectsMesh1 = movingItem3D.intersects(leftCubeItem3D, "low");
    const mesh2IntersectsMesh3 = movingItem3D.intersects(sphereRightItem3D, "low");

    if (mesh2IntersectsMesh1) {
      recursivelySetMaterialColor(leftCubeMesh, "green");
    } else if (mesh2IntersectsMesh3) {
      recursivelySetMaterialColor(sphereRightMesh, "blue");
    } else {
      recursivelySetMaterialColor(leftCubeMesh, "red");
      recursivelySetMaterialColor(sphereRightMesh, "red");
    }
  }

  loop();

})()

function recursivelySetMaterialColor(mesh, color) {
  if (mesh instanceof THREE.Mesh) {
    mesh.material.userData.oldMap = mesh.material.map;
    mesh.material.map = null;
    mesh.material.color.set(color);
  } else if (mesh instanceof Group) {
    mesh.traverse((node) => {
      if (node instanceof THREE.Mesh) {
        console.log(node);
        node.material.userData.oldMap = node.material.map;
        node.material.map = null;
        node.material.color.set(color);
      }
    });
  }
}

function addDebugCheckBox(objects) {
  const checkbox = document.createElement("input");
  checkbox.type = "checkbox";
  const label = document.createElement("label");
  label.style.position = "absolute";
  label.style.top = "10px";
  label.style.left = "10px";
  label.style.zIndex = "1000";
  label.style.background = "rgba(255,255,255,0.7)";
  label.style.padding = "4px 8px";
  label.style.borderRadius = "3px";
  label.style.fontSize = "14px";
  label.appendChild(checkbox);
  label.appendChild(document.createTextNode(" Show debug bounds"));
  checkbox.addEventListener("change", () => {
    objects.forEach((object) => {
      object.debug = checkbox.checked;
    });
  });
  document.body.appendChild(label);
}

COLLADA duck One texture Credit: © 2006, Sony. SCEA Shared Source License, Version 1.0 

3D model set the pitch or tilt

3D model pitch

Examples

Rotate 3D models by setting the pitch tilt property.

Add events on 3D models

3D model events

Examples

Listen for mouse events on 3D models in maps.

3D model set the pitch and roll

3D model pitch and roll

Examples

Rotate 3D models using pitch and roll properties.

Display an animated 3D model

Animate a 3D model

Examples

Animate 3D models and display them on a map.

Was this helpful?