-
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
Add an example demonstrating how to use with MapboxGL #426
Comments
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: 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
); |
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 |
I've taken a look at the codepen and these settings strike me as odd:
this.cameraTransform = new THREE.Matrix4()
.makeTranslation(x, y, z)
.scale(new THREE.Vector3(scale, -scale, scale));
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. |
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. |
<!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/v3.8.0/mapbox-gl.css" rel="stylesheet">
<script src="https://api.mapbox.com/mapbox-gl-js/v3.8.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'
mapboxgl.accessToken =
"pk.eyJ1IjoieGlheGlhbmdmbmVnIiwiYSI6ImNscWYyNjU3azByd3gya3JxOTVrc2NkY3UifQ.362MspMnDi9ZGH-D6P1CtQ";
const CESIUM_TOKEN = "your cesium token";
const map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/mapbox/streets-v12',
center: [121, 31],
zoom: 3,
pitch: 12,
bearing: 0,
antialias: true
});
function radiansToDegrees(radians) {
return radians * (180 / Math.PI);
}
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;
}
function getOriginMatrix4(tilesRenderer, position,other) {
const cart = {};
tilesRenderer.ellipsoid.getPositionToCartographic(position, cart);
const lon = radiansToDegrees(cart.lon);
const lat = radiansToDegrees(cart.lat);
new mapboxgl.Marker().setLngLat([lon,lat]).addTo(map);
new mapboxgl.Marker().setLngLat([lon-0.007,lat+0.066]).addTo(map);
map.flyTo({
center:[lon,lat],
zoom:15
})
const modelRotate = other.rotate;
const height = other.height || cart.height;
const modelAsMercatorCoordinate = mapboxgl.MercatorCoordinate.fromLngLat([lon, lat], height);
const scale = modelAsMercatorCoordinate.meterInMercatorCoordinateUnits();
const rotationX = new THREE.Matrix4().makeRotationAxis(new THREE.Vector3(1, 0, 0), modelRotate[0]);
const rotationY = new THREE.Matrix4().makeRotationAxis(new THREE.Vector3(0, 1, 0), modelRotate[1]);
const rotationZ = new THREE.Matrix4().makeRotationAxis(new THREE.Vector3(0, 0, 1), modelRotate[2]);
return new THREE.Matrix4()
.makeTranslation(
modelAsMercatorCoordinate.x,
modelAsMercatorCoordinate.y,
modelAsMercatorCoordinate.z
)
.scale(new THREE.Vector3(scale, -scale, scale))
.multiply(rotationX)
.multiply(rotationY)
.multiply(rotationZ);
}
function initThree(map, gl) {
const camera = new THREE.Camera();
// const {width,height} = map._canvas
// const camera = new THREE.PerspectiveCamera(map.transform.fov, width / height, 0.001, 4000 );
const scene = new THREE.Scene();
// light
const bgLight = new THREE.AmbientLight(0xffffff);
scene.add(bgLight);
const directionalLight = new THREE.DirectionalLight(0xbbbbbb);
directionalLight.position.set(20, -70, -100).normalize();
scene.add(directionalLight);
const directionalLight2 = new THREE.DirectionalLight(0xbbbbbb);
directionalLight2.position.set(-20, -70, 100).normalize();
scene.add(directionalLight2);
const renderer = new THREE.WebGLRenderer({
canvas: map.getCanvas(),
context: gl,
antialias: true
});
renderer.autoClear = false;
return { camera, scene, renderer }
}
function addLayer(url,height) {
let tilesRenderer, camera, renderer, scene, originMatrix4 = new THREE.Matrix4();
map.addLayer({
id: '3d-model',
type: 'custom',
renderingMode: '3d',
onAdd: function (map, gl) {
const threeInfo = initThree(map, gl);
camera = threeInfo.camera;
scene = threeInfo.scene;
renderer = threeInfo.renderer;
tilesRenderer = new TilesRenderer(url);
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);
let isRootLoad = true;
tilesRenderer.onLoadTileSet = (tileset) => {
const box = new THREE.Box3();
const sphere = new THREE.Sphere();
const matrix = new THREE.Matrix4();
let position;
if (tilesRenderer.getOrientedBoundingBox(box, matrix)) {
position = new THREE.Vector3().setFromMatrixPosition(matrix);
} else if (tilesRenderer.getBoundingSphere(sphere)) {
position = sphere.center.clone();
}
const distanceToEllipsoidCenter = position.length();
if (isRootLoad) {
isRootLoad = false;
originMatrix4 = getOriginMatrix4(tilesRenderer, position,height);
}
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(camera);
tilesRenderer.setResolutionFromRenderer(camera, renderer);
scene.add(tilesRenderer.group);
},
render: function (gl, matrix) {
const m = new THREE.Matrix4().fromArray(matrix);
camera.projectionMatrix = m.multiply(originMatrix4)
renderer.resetState();
tilesRenderer.update();
renderer.render(scene, camera);
map.triggerRepaint();
}
});
}
map.on('style.load', async () => {
//TODO Question 1: The y-axis of rotate has different rotation angles at different latitudes and longitudes. The following two examples show
//TODO Question 2: When the position is far away from the center of the model, there will be position offset. In demo-1, I drew two marks, one is the center point of the model and the other is the farther position.
// demo-1
addLayer("http://data.mars3d.cn/3dtiles/jzw-shanghai/tileset.json",{
rotate: [Math.PI / 2, 342 / 360 * Math.PI, 0]
});
// demo-2
// addLayer("http://data.mars3d.cn/3dtiles/qx-dyt/tileset.json",{
// height:10,
// rotate: [Math.PI/2 ,348/360 *Math.PI, 0]
// });
});
</script>
</body>
</html>
|
I'm not all that familiar with MapBox so I can't say exactly what the issues might be but I looked through your code briefly. I can't say if all of the math is right (I recommend using three.js' math functions rather than manually assigning quaternion fields, for example) and I don't know anything about the MapboxGL coordinate system but here are some thoughts:
I assume you're referring to the 342 / 360 factor you're using in
Similar to question 1 - it seems there is something out of sync regarding the generated data set and the Mapbox globe surface. Or something in the math setup is incorrect. |
I have tried two canvases, and then the camera synchronization method (this reference is threebox), which is the same as above. I don't know how I should deal with it. I went to see the source code of mapbox, and the code for calculating the camera seems to be here https://github.com/mapbox/mapbox-gl-js/blob/main/src/geo/transform.ts#L2224 |
Without seeing how the axis gizmo is added there's not much that can be said about it's alignment. The image looks reasonable to me, though, assuming it represents the root of the tile set. The tiles are just oriented and positioned so the sit on the surface of the globe.
Unfortunately I don't know that much about Mapbox and I don't have the bandwidth to investigate this in detail so I will have to leave this up to someone else to investigate. There are a few places where differences can lead to these kind of visual inconsistencies, including the original data sets being loaded, which should be verified and understood to make sure everything is displaying correctly. The 342 / 360 factor in the rotation seems indicative of a misunderstanding or misalignment in the source data sets being loaded. But again I'm not familiar with Mapbox GL data or the data provided by Mars3D. |
Thank you very much for your help. I don't have the ability to solve this problem. |
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:
Code
The address of the code on GitHub
https://github.com/xiaxiangfeng/3DTilesRendererJS.Test/tree/main/docs
Live example
https://xiaxiangfeng.github.io/3DTilesRendererJS.Test/mapbox.three.camera.3dtiles.html
Expected behavior
Display normally during rotation
Screenshots
normal
bug
Disappears after rotating 180 degrees
Platform:
The text was updated successfully, but these errors were encountered: