Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add an example demonstrating how to use with MapboxGL #426

Open
xiaxiangfeng opened this issue Dec 21, 2023 · 5 comments
Open

Add an example demonstrating how to use with MapboxGL #426

xiaxiangfeng opened this issue Dec 21, 2023 · 5 comments
Labels
enhancement New feature or request

Comments

@xiaxiangfeng
Copy link

xiaxiangfeng commented Dec 21, 2023

Describe the bug

After adding 3Dtiles to mapboxgl using 3DTilesRendererJS, the model disappears when the rotated map is greater than 180 degrees

To Reproduce

Steps to reproduce the behavior:

  1. Using mapboxgl to customize layers and add 3D tiles
  2. Use the right mouse button to rotate the map
  3. When the rotation is greater than 180 degrees, the model disappears

Code
The address of the code on GitHub

https://github.com/xiaxiangfeng/3DTilesRendererJS.Test/tree/main/docs

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>Display a map on a webpage</title>
    <meta
      name="viewport"
      content="initial-scale=1,maximum-scale=1,user-scalable=no"
    />
    <link
      href="https://api.mapbox.com/mapbox-gl-js/v2.13.0/mapbox-gl.css"
      rel="stylesheet"
    />
    <script src="https://api.mapbox.com/mapbox-gl-js/v2.13.0/mapbox-gl.js"></script>
    <script
      async
      src="https://unpkg.com/es-module-shims@1.3.6/dist/es-module-shims.js"
    ></script>
    <style>
      body {
        margin: 0;
        padding: 0;
      }

      #map {
        position: absolute;
        top: 0;
        bottom: 0;
        width: 100%;
      }
    </style>
  </head>

  <body>
    <div id="map"></div>
    <script type="importmap">
      {
        "imports": {
          "three": "https://unpkg.com/three@0.135.0/build/three.module.js",
          "three/examples/jsm/": "https://unpkg.com/three@0.140.0/examples/jsm/"
        }
      }
    </script>

    <script type="module">
      import * as THREE from "three";
      import { DebugTilesRenderer as TilesRenderer } from "./3DTilesRendererJS/index.js";

      window.THREE = THREE;

      var origin = [113.37796671195645, 22.994043025862794];

      mapboxgl.accessToken =
        "pk.eyJ1IjoieGlheGlhbmdmbmVnIiwiYSI6ImNscWYyNjU3azByd3gya3JxOTVrc2NkY3UifQ.362MspMnDi9ZGH-D6P1CtQ";
      const map = new mapboxgl.Map({
        container: "map",
        style: "mapbox://styles/mapbox/dark-v9",
        center: origin,
        zoom: 17.86614600777933,
        pitch: 70,
        bearing: -40,
      });

      const marker1 = new mapboxgl.Marker().setLngLat(origin).addTo(map);

      let centerM;

      function rotationBetweenDirections(dir1, dir2) {
        const rotation = new THREE.Quaternion();
        const a = new THREE.Vector3().crossVectors(dir1, dir2);
        rotation.x = a.x;
        rotation.y = a.y;
        rotation.z = a.z;
        rotation.w = 1 + dir1.clone().dot(dir2);
        rotation.normalize();

        return rotation;
      }

      map.on("load", () => {
        let renderer, scene, camera, world, tiles;
        const mixers = [];

        map.addLayer({
          id: "custom_layer",
          type: "custom",
          renderingMode: "3d",
          onAdd: function (map, mbxContext) {
            const center = map.getCenter();
            this.center = mapboxgl.MercatorCoordinate.fromLngLat(
              [center.lng, center.lat],
              0
            );
            centerM = this.center;

            const { x, y, z } = centerM;

            const scale = centerM.meterInMercatorCoordinateUnits();

            this.cameraTransform = new THREE.Matrix4()
              .makeTranslation(x, y, z)
              .scale(new THREE.Vector3(scale, -scale, scale));

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

            renderer.shadowMap.enabled = true;
            renderer.autoClear = false;

            scene = new THREE.Scene();
            camera = new THREE.PerspectiveCamera(
              28,
              window.innerWidth / window.innerHeight,
              0.000000000001,
              Infinity
            );

            const url = "./baowei21/tileset.json";

            tiles = new TilesRenderer(url);

            tiles.onLoadTileSet = (tileset) => {
              const box = new THREE.Box3();
              const sphere = new THREE.Sphere();
              const matrix = new THREE.Matrix4();

              let position;
              let distanceToEllipsoidCenter;

              if (tiles.getOrientedBounds(box, matrix)) {
                position = new THREE.Vector3().setFromMatrixPosition(matrix);
                distanceToEllipsoidCenter = position.length();
              } else if (tiles.getBoundingSphere(sphere)) {
                position = sphere.center.clone();
                distanceToEllipsoidCenter = position.length();
              }

              const surfaceDirection = position.normalize();
              const up = new THREE.Vector3(0, 1, 0);
              const rotationToNorthPole = rotationBetweenDirections(
                surfaceDirection,
                up
              );

              tiles.group.quaternion.x = rotationToNorthPole.x;
              tiles.group.quaternion.y = rotationToNorthPole.y;
              tiles.group.quaternion.z = rotationToNorthPole.z;
              tiles.group.quaternion.w = rotationToNorthPole.w;

              tiles.group.position.y = -distanceToEllipsoidCenter;
            };

            tiles.setCamera(camera);
            tiles.setResolutionFromRenderer(camera, renderer);

            world = new THREE.Group();

            world.add(tiles.group);
            scene.add(world);
          },

          render: function (gl, matrix) {
            const mercatorMatrix = new THREE.Matrix4().fromArray(matrix);
            camera.projectionMatrix = mercatorMatrix.multiply(
              this.cameraTransform
            );

            renderer.resetState();

            tiles.update();
            // Render the scene and repaint the map
            renderer.render(scene, camera);
            map.triggerRepaint();
          },
        });
      });
    </script>
  </body>
</html>

Live example
https://xiaxiangfeng.github.io/3DTilesRendererJS.Test/mapbox.three.camera.3dtiles.html

Expected behavior

Display normally during rotation

Screenshots
normal
image

bug
Disappears after rotating 180 degrees
image

Platform:

  • Device: [Desktop, Mobile, ...]
  • OS: [Windows, MacOS, Linux, Android, iOS, ...]
  • Browser: [Chrome, Firefox, Safari, Edge, ...]
  • Three.js version: [r135]
  • Library version: [new]
@xiaxiangfeng xiaxiangfeng added the bug Something isn't working label Dec 21, 2023
@gkjohnson gkjohnson added question Further information is requested and removed bug Something isn't working labels Dec 21, 2023
@gkjohnson
Copy link
Contributor

Without a live, editable example it's not possible to debug - but there must be sometihng wrong with your integration with Mapbox since the model works in the live example in this project:

image

That aside your initialized "near" and "far" values are not valid, though it's not clear if this would cause issues.

            camera = new THREE.PerspectiveCamera(
              28,
              window.innerWidth / window.innerHeight,
              0.000000000001,
              Infinity
            );

@xiaxiangfeng
Copy link
Author

https://github.com/xiaxiangfeng/3DTilesRendererJS.Test/tree/main/docs

I created this dome on the codepen. I guess it should be the same issue with mapboxgl syncing with threejs, but I don't know how to fix this, hope I can get your help

codepen

https://codepen.io/xiaxiangfeng/pen/KKEKmgq

@gkjohnson
Copy link
Contributor

gkjohnson commented Dec 23, 2023

I've taken a look at the codepen and these settings strike me as odd:

  • The camera scale is set to a negative scale on the X axis:
this.cameraTransform = new THREE.Matrix4()
  .makeTranslation(x, y, z)
  .scale(new THREE.Vector3(scale, -scale, scale));
  • And setting the three.js camera projection matrix to include a camera transformation (and whatever the passed in MapGL matrix is) does not look right all:
const mercatorMatrix = new THREE.Matrix4().fromArray(matrix);
camera.projectionMatrix = mercatorMatrix.multiply(this.cameraTransform);

I don't know how the render mapbox API works but please make sure the transformations and projection are set correctly on the threejs camera - these are required for the tiles renderer to function.

@xiaxiangfeng
Copy link
Author

I have resolved this issue and make a PR. Waiting for merge

@gkjohnson gkjohnson changed the title the model disappears when the rotated map is greater than 180 degrees Mapbox Integration: the model disappears when the rotated map is greater than 180 degrees Jan 9, 2024
@xiaxiangfeng
Copy link
Author

xiaxiangfeng commented Jan 10, 2024

I have resolved this issue and make a PR. Waiting for merge

Currently, there are still problems that have not been solved when using mapboxgl. The specific how to use it and the existing problems are in the PR at the address below. I hope someone can complete this PR or provide some help and suggestions in the future.

#435

@gkjohnson gkjohnson changed the title Mapbox Integration: the model disappears when the rotated map is greater than 180 degrees Add an example demonstrating how to use with MapboxGL Jan 11, 2024
@gkjohnson gkjohnson added enhancement New feature or request and removed question Further information is requested labels Jan 11, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants