我正在尝试让我的3D对象在我的Mapbox创建的场景中移动。我使用一个自定义图层通过Three.js在地图上创建我的对象,如以下代码所示:
var map = action.map;
var orign = {
lon: -8.34,
lat: 41.21
}
var camera, scene;
var fromLL = function (lon, lat) {
var extent = 20037508.34;
var x = lon * extent / 180;
var y = Math.log(Math.tan((90 + lat) * Math.PI / 360)) / (Math.PI / 180);
y = y * extent / 180;
return [(x + extent) / (2 * extent), 1 - ((y + extent) / (2 * extent))];
}
var translate = fromLL(orign.lon, orign.lat);
const transform = {
translateX: translate[0],
translateY: translate[1],
translateZ: 0,
rotateX: Math.PI / 2,
rotateY: 0,
rotateZ: 0,
scale: 5.41843220338983e-6
}
// configuration of the custom layer for a 3D model per the CustomLayerInterface
var customLayer = {
id: '3d-model' + uuid(),
type: 'custom',
renderingMode: '3d',
onAdd: function (map, gl) {
this.camera = new THREE.Camera();
this.scene = new THREE.Scene();
// create two three.js lights to illuminate the model
var directionalLight = new THREE.DirectionalLight(0xffffff);
directionalLight.position.set(0, -70, 100).normalize();
this.scene.add(directionalLight);
var directionalLight2 = new THREE.DirectionalLight(0xffffff);
directionalLight2.position.set(0, 70, 100).normalize();
this.scene.add(directionalLight2);
// use the three.js GLTF loader to add the 3D model to the three.js scene
var loader = new GLTFLoader();
const bus = 'https://threejsfundamentals.org/threejs/resources/models/animals/Horse.gltf';
loader.load(
bus,
(gltf) => {
this.scene.add(gltf.scene);
},
(xhr) => {
console.log(`${(xhr.loaded / xhr.total * 100)}% loaded`);
},
(error) => {
// called when loading has errors
console.error('An error happened', error);
}
);
this.map = map;
// use the Mapbox GL JS map canvas for three.js
this.renderer = new THREE.WebGLRenderer({
canvas: map.getCanvas(),
context: gl,
antialias: true
});
this.renderer.autoClear = false;
},
render: function (gl, matrix) {
const rotationX = new THREE.Matrix4().makeRotationAxis(new THREE.Vector3(1, 0, 0), transform.rotateX);
const rotationY = new THREE.Matrix4().makeRotationAxis(new THREE.Vector3(0, 1, 0), transform.rotateY);
const rotationZ = new THREE.Matrix4().makeRotationAxis(new THREE.Vector3(0, 0, 1), transform.rotateZ);
const m = new THREE.Matrix4().fromArray(matrix);
const l = new THREE.Matrix4().makeTranslation(transform.translateX, transform.translateY, transform.translateZ)
.scale(new THREE.Vector3(transform.scale, -transform.scale, transform.scale))
.multiply(rotationX)
.multiply(rotationY)
.multiply(rotationZ);
this.camera.projectionMatrix.elements = matrix;
this.camera.projectionMatrix = m.multiply(l);
this.renderer.state.reset();
this.renderer.render(this.scene, this.camera);
this.map.triggerRepaint();
}
}在将对象放入场景后,我要采取的下一步是使用Mapbox提供的方法控制相机。我的疑问是如何让"setInterval“函数通过"WASD”键更改我之前渲染的对象的位置值,而不仅仅是地图上的相机。下面是我正在尝试调整的代码,以适应我的对象的移动:
map.on('load', function () {
map.addLayer(customLayer);
var keys = {};
window.onkeyup = function (e) { keys[e.keyCode] = false; }
window.onkeydown = function (e) { keys[e.keyCode] = true; }
var heading = 180;
setInterval(function () {
var speed = 0;
if (keys[68]) {
heading += 2;
}
if (keys[65]) {
heading -= 2;
}
if (keys[87]) {
speed = 0.0002;
}
if (keys[83]) {
speed = -0.0002;
}
var rad = heading * 0.0174532925;
orign.lat += Math.cos(rad) * speed;
orign.lon += Math.sin(rad) * speed;
map.setBearing(heading);
map.setCenter([orign.lon, orign.lat]);
}, 1000 / 60);
});到目前为止,我所拥有的是:3D Object in map
发布于 2021-02-02 19:02:52
如果你还对这个感兴趣..。这是the example I have built based on your request of a WASD game-like demo in Mapbox。在这个示例中,我使用了threebox,它简化了与three.js和mapbox的所有交互,避免了您处理相机、矩阵、透视图和其他更多内容。
我还在你的问题中添加了一些额外的功能,比如惯性,加速度参数和一个填充挤压层,当你用卡车与建筑物相撞时,它会将建筑物涂成红色。

相关代码如下:
mapboxgl.accessToken = "PASTE YOUR TOKEN HERE";
let minZoom = 12;
let mapConfig = {
map: {
center: [-122.4301905, 37.7298202],
zoom: 20,
pitch: 60,
bearing: 38
},
truck: {
origin: [-122.4301905, 37.7298202, 0],
type: 'mtl',
model: 'https://unpkg.com/threebox-plugin/examples/models/Truck',
rotation: {
x: 90,
y: 0,
z: 0
},
scale: 3,
startRotation: {
x: 0,
y: 0,
z: -38
},
date: new Date(2020, 6, 19, 23)
},
names: {
compositeSource: "composite",
compositeSourceLayer: "building",
compositeLayer: "3d-buildings"
}
}
let map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/mapbox/satellite-streets-v11',
zoom: mapConfig.map.zoom,
center: mapConfig.map.center,
pitch: mapConfig.map.pitch,
bearing: mapConfig.map.bearing,
antialias: true // create the gl context with MSAA antialiasing, so custom layers are antialiased
});
window.tb = new Threebox(
map,
map.getCanvas().getContext('webgl'), {
realSunlight: true,
enableSelectingObjects: true,
enableDraggingObjects: true,
enableRotatingObjects: true,
enableTooltips: true
}
);
tb.setSunlight(new Date(2020, 6, 19, 23), map.getCenter());
// parameters to ensure the model is georeferenced correctly on the map
let truck;
function createCustomLayer(layerName) {
let model;
//create the layer
let customLayer3D = {
id: layerName,
type: 'custom',
renderingMode: '3d',
onAdd: function(map, gl) {
let options = {
type: mapConfig.truck.type, //model type
obj: mapConfig.truck.model + '.obj', //model .obj url
mtl: mapConfig.truck.model + '.mtl', //model .mtl url
units: 'meters', // in meters
scale: mapConfig.truck.scale, //x3 times is real size for this model
rotation: mapConfig.truck.rotation, //default rotation
anchor: 'top'
}
tb.loadObj(options, function(model) {
truck = model.setCoords(mapConfig.truck.origin);
truck.setRotation(mapConfig.truck.startRotation); //turn it to the initial street way
truck.addTooltip("Drive with WASD keys", true, truck.anchor, true, 2);
truck.castShadow = true;
truck.selected = true;
truck.addEventListener('ObjectChanged', onObjectChanged, false);
tb.add(truck);
init();
});
},
render: function(gl, matrix) {
tb.update();
}
};
return customLayer3D;
};
function easing(t) {
return t * (2 - t);
}
let velocity = 0.0,
speed = 0.0,
ds = 0.01;
let keys;
map.on('style.load', function() {
let l = mapConfig.names.compositeLayer;
if (api.buildings) {
if (!map.getLayer(l)) {
map.addLayer(createCompositeLayer(l));
}
}
map.addLayer(createCustomLayer('3d-model'), 'waterway-label');
map.getCanvas().focus();
});
function createCompositeLayer(layerId) {
let layer = {
'id': layerId,
'source': mapConfig.names.compositeSource,
'source-layer': mapConfig.names.compositeSourceLayer,
'filter': ['==', 'extrude', 'true'],
'type': 'fill-extrusion',
'minzoom': minZoom,
'paint': {
'fill-extrusion-color': [
'case',
['boolean', ['feature-state', 'select'], false],
"red",
['boolean', ['feature-state', 'hover'], false],
"lightblue",
'#aaa'
],
// use an 'interpolate' expression to add a smooth transition effect to the
// buildings as the user zooms in
'fill-extrusion-height': [
'interpolate',
['linear'],
['zoom'],
minZoom,
0,
minZoom + 0.05,
['get', 'height']
],
'fill-extrusion-base': [
'interpolate',
['linear'],
['zoom'],
minZoom,
0,
minZoom + 0.05,
['get', 'min_height']
],
'fill-extrusion-opacity': 0.9
}
};
return layer;
}
let api = {
buildings: true,
acceleration: 5,
inertia: 3
};
function init() {
keys = {
a: false,
s: false,
d: false,
w: false
};
document.body.addEventListener('keydown', function(e) {
const key = e.code.replace('Key', '').toLowerCase();
if (keys[key] !== undefined)
keys[key] = true;
});
document.body.addEventListener('keyup', function(e) {
const key = e.code.replace('Key', '').toLowerCase();
if (keys[key] !== undefined)
keys[key] = false;
});
animate();
}
function animate() {
requestAnimationFrame(animate);
speed = 0.0;
if (!(keys.w || keys.s)) {
if (velocity > 0) {
speed = -api.inertia * ds
} else if (velocity < 0) {
speed = api.inertia * ds
}
if (velocity > -0.0008 && velocity < 0.0008) {
speed = velocity = 0.0;
return;
}
}
if (keys.w)
speed = api.acceleration * ds;
else if (keys.s)
speed = -api.acceleration * ds;
velocity += (speed - velocity) * api.acceleration * ds;
if (speed == 0.0) {
velocity = 0;
return;
}
truck.set({
worldTranslate: new THREE.Vector3(0, -velocity, 0)
});
let options = {
center: truck.coordinates,
bearing: map.getBearing(),
easing: easing
};
function toDeg(rad) {
return rad / Math.PI * 180;
}
function toRad(deg) {
return deg * Math.PI / 180;
}
let deg = 1;
let rad = toRad(deg);
let zAxis = new THREE.Vector3(0, 0, 1);
if (keys.a || keys.d) {
rad *= (keys.d ? -1 : 1);
truck.set({
quaternion: [zAxis, truck.rotation.z + rad]
});
options.bearing = -toDeg(truck.rotation.z);
}
map.jumpTo(options);
tb.map.update = true;
}
function onObjectChanged(e) {
let model = e.detail.object; //here's the object already modified
if (api.buildings) {
let c = model.coordinates;
let point = map.project(c);
let features = map.queryRenderedFeatures(point, {
layers: [mapConfig.names.compositeLayer]
});
if (features.length > 0) {
light(features[0]); // crash!
}
}
}
function light(feature) {
fHover = feature;
map.setFeatureState({
source: fHover.source,
sourceLayer: fHover.sourceLayer,
id: fHover.id
}, {
select: true
});
}https://stackoverflow.com/questions/65845977
复制相似问题