-
Notifications
You must be signed in to change notification settings - Fork 301
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
Demo/Example for using with Mapbox GL JS #295
Comments
Hello! There is not - if you'd like to add an example demonstrating how to use the 3d tiles renderer to mapbox please feel free to make a PR! I'm happy to provide any pointers. |
Here is an example to add a cesium asset to mapbox. sample code<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Add a 3D model</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>
<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/[email protected]/build/three.module.js",
"three/examples/": "https://unpkg.com/[email protected]/examples/",
"3d-tiles-renderer": "https://unpkg.com/[email protected]/src/index.js"
}
}
</script>
<script type="module">
import { TilesRenderer, GLTFCesiumRTCExtension } from '3d-tiles-renderer';
import * as THREE from 'three';
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js'
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader.js'
const CESIUM_TOKEN = "your cesium token";
mapboxgl.accessToken = "your mapbox token";
const map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/mapbox/light-v11',
center: [114.18819431019777, 22.31391077950837],
zoom: 16.5,
pitch: 26.9,
bearing: 48.5,
antialias: true
});
map.on('style.load', async () => {
const customLayer = await createCesiumLayer(1393025, [114.1876210, 22.31245660], 70);
map.addLayer(customLayer, 'waterway-label');
});
async function createCesiumLayer(assetId, modelOrigin, modelAltitude) {
const response = await fetch(`https://api.cesium.com/v1/assets/${assetId}/endpoint?access_token=` + CESIUM_TOKEN);
const result = await response.json();
let tilesRenderer = new TilesRenderer(result.url);
tilesRenderer.fetchOptions.headers = { Authorization: `Bearer ${result.CESIUM_TOKEN}` };
tilesRenderer.fetchOptions.mode = 'cors';
const gltfLoader = new GLTFLoader(tilesRenderer.manager);
gltfLoader.register(() => new GLTFCesiumRTCExtension());
const dracoLoader = new DRACOLoader();
dracoLoader.setDecoderPath('https://unpkg.com/[email protected]/examples/jsm/libs/draco/gltf/');
gltfLoader.setDRACOLoader(dracoLoader);
tilesRenderer.manager.addHandler(/(\.gltf|\.glb)$/, gltfLoader);
const modelRotate = [Math.PI / 2, 0, 0];
const modelAsMercatorCoordinate = mapboxgl.MercatorCoordinate.fromLngLat(
modelOrigin,
modelAltitude
);
// transformation parameters to position, rotate and scale the 3D model onto the map
const modelTransform = {
translateX: modelAsMercatorCoordinate.x,
translateY: modelAsMercatorCoordinate.y,
translateZ: modelAsMercatorCoordinate.z,
rotateX: modelRotate[0],
rotateY: modelRotate[1],
rotateZ: modelRotate[2],
/* Since the 3D model is in real world meters, a scale transform needs to be
* applied since the CustomLayerInterface expects units in MercatorCoordinates.
*/
scale: modelAsMercatorCoordinate.meterInMercatorCoordinateUnits()
};
const rotationX = new THREE.Matrix4().makeRotationAxis(
new THREE.Vector3(1, 0, 0),
modelTransform.rotateX
);
const rotationY = new THREE.Matrix4().makeRotationAxis(
new THREE.Vector3(0, 1, 0),
modelTransform.rotateY
);
const rotationZ = new THREE.Matrix4().makeRotationAxis(
new THREE.Vector3(0, 0, 1),
modelTransform.rotateZ
);
const l = new THREE.Matrix4()
.makeTranslation(
modelTransform.translateX,
modelTransform.translateY,
modelTransform.translateZ
)
.scale(
new THREE.Vector3(
modelTransform.scale,
-modelTransform.scale,
modelTransform.scale
)
)
.multiply(rotationX)
.multiply(rotationY)
.multiply(rotationZ);
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;
}
return {
id: '3d-model',
type: 'custom',
renderingMode: '3d',
onAdd: function (map, gl) {
this.camera = new THREE.Camera();
this.scene = new THREE.Scene();
// light
const bgLight = new THREE.AmbientLight(0xffffff);
this.scene.add(bgLight);
const directionalLight = new THREE.DirectionalLight(0xbbbbbb);
directionalLight.position.set(20, -70, -100).normalize();
this.scene.add(directionalLight);
const directionalLight2 = new THREE.DirectionalLight(0xbbbbbb);
directionalLight2.position.set(-20, -70, 100).normalize();
this.scene.add(directionalLight2);
this.map = map;
this.renderer = new THREE.WebGLRenderer({
canvas: map.getCanvas(),
context: gl,
antialias: true
});
this.renderer.autoClear = false;
tilesRenderer.onLoadTileSet = (tileset) => {
const box = new THREE.Box3();
const sphere = new THREE.Sphere();
const matrix = new THREE.Matrix4();
let position;
let distanceToEllipsoidCenter;
if (tilesRenderer.getOrientedBounds(box, matrix)) {
position = new THREE.Vector3().setFromMatrixPosition(matrix);
distanceToEllipsoidCenter = position.length();
} else if (tilesRenderer.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);
tilesRenderer.group.quaternion.x = rotationToNorthPole.x;
tilesRenderer.group.quaternion.y = rotationToNorthPole.y;
tilesRenderer.group.quaternion.z = rotationToNorthPole.z;
tilesRenderer.group.quaternion.w = rotationToNorthPole.w;
tilesRenderer.group.position.y = -distanceToEllipsoidCenter;
}
tilesRenderer.setCamera(this.camera);
tilesRenderer.setResolutionFromRenderer(this.camera, this.renderer);
this.scene.add(tilesRenderer.group);
},
render: function (gl, matrix) {
const m = new THREE.Matrix4().fromArray(matrix);
this.camera.projectionMatrix = m.multiply(l);
this.renderer.resetState();
tilesRenderer.update();
this.renderer.render(this.scene, this.camera);
this.map.triggerRepaint();
}
};
}
</script>
</body>
</html> |
Please provide a JSFiddle or Code Sandbox demonstrating the issue so it's easier for me to check and understand what's happening. |
I think that example html file is able to run on any web server. |
Understood - where possible it's best to provide live examples with everything needed and unfortunately I don't have an API key. If you're able to reproduce the issue without mapbox (ie extract the camera matrix, tiles transform, etc passed into the tilesrenderer) I can take a look at the issue in a JSFiddle. Otherwise someone more familiar with MapBox will have to provide some info or when I have more availability I will have to dive into the mapbox project. |
@chunlampang Maybe the altitude of your model's central position is setting too low. |
Closing in favor of #426 |
Is your feature request related to a problem? Please describe.
Is there any sample code available for this project to work with mapbox gl js ?
Describe the solution you'd like
Just a sample code to see how it is possible to glue the camera from mapbox gl js to this project
Describe alternatives you've considered
Currently using deck.gl, which has many problems and bad computation of 3d tiles geometric error
The text was updated successfully, but these errors were encountered: