当前位置: 代码迷 >> 综合 >> mapbox gl 加载gltf模型
  详细解决方案

mapbox gl 加载gltf模型

热度:46   发布时间:2023-12-21 13:28:50.0

首先得理解gltf文件就是一个json文件,GLTF代表Graphics Language Transmission Format(图形语言传输格式),描述的是三维场景数据的组成和构造。

1.引入mapbox gl的sdk,另外也得引入

<script src="js/three.min.js"></script> <script src="js/GLTFLoader.js"></script>

这两个js插件,废话不多说,直接上代码:

<!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" /><script src="https://api.mapbox.com/mapbox-gl-js/v2.0.0/mapbox-gl.js"></script><link href="https://api.mapbox.com/mapbox-gl-js/v2.0.0/mapbox-gl.css" rel="stylesheet" /><style>body {margin: 0;padding: 0;}#map {position: absolute;top: 0;bottom: 0;width: 100%;}#start{position: absolute;z-index: 1;top:10px;left:10px;float: left;}#stop{position: absolute;z-index: 1;top:50px;left:10px;float: left;}</style></head><body><div id="domId" style="position: absolute;top:20px;left:20px;border: #0088FF;width:300px;height: 200px;"></div><script src="js/three.min.js"></script><script src="js/GLTFLoader.js"></script><div id="map"></div><button id="start">开启</button><button id="stop">暂停</button><script>// TO MAKE THE MAP APPEAR YOU MUST// ADD YOUR ACCESS TOKEN FROM// https://account.mapbox.comlet timer;let camera, scene, renderer;mapboxgl.accessToken = '你的秘钥';var map = (window.map = new mapboxgl.Map({container: 'map',style: 'mapbox://styles/mapbox/light-v10',zoom: 18,center: [148.9819193502973, -35.398500434944886],pitch: 60,antialias: true // create the gl context with MSAA antialiasing, so custom layers are antialiased}));var modelOrigin = [148.9819193502973, -35.398500434944886];var modelAltitude = 0;var modelRotate = [Math.PI / 2, 90, 0];//调整角度var modelOrigin2 = [148.98200184048164, -35.39849545391921];// var modelAsMercatorCoordinate2 = mapboxgl.MercatorCoordinate.fromLngLat(//     modelOrigin2,//     modelAltitude// );let customLayer2 = initCamera("two",modelOrigin2);// var ll = new mapboxgl.LngLat(-123.9749, 40.7736);// ll.lng; // = -123.9749// transformation parameters to position, rotate and scale the 3D model onto the map//添加图层map.on('style.load', function() {let customLayer = initCamera("one",modelOrigin);map.addLayer(customLayer);// map.addLayer(customLayer2);// map.removeLayer("3d-modeltwo")renderLine();//加载线initSeiintetval();map.getLayer('3d-modelone');});document.getElementById("stop").onclick = function(){clearInterval(timer);//清除定时器}document.getElementById("start").onclick = function(){initSeiintetval();//清除定时器}function  initSeiintetval(){let pointArr = [[148.9819193502973, -35.398500434944886],[148.98195162329682, -35.3985011334687],[148.98200184048164, -35.39849545391921]];let num = 0;timer = setInterval(function () {num++;if(num == pointArr.length){pointArr.reverse();num = 1;}if(map.getLayer("3d-modelone")){map.removeLayer("3d-modelone");let customLayer = initCamera("one",pointArr[num]);map.addLayer(customLayer);}}, 1000);}//初始化custom图层function initCamera(id, modelOrigin){var modelAsMercatorCoordinate = mapboxgl.MercatorCoordinate.fromLngLat(modelOrigin,modelAltitude);var modelTransform = {translateX: modelAsMercatorCoordinate.x,translateY: modelAsMercatorCoordinate.y,translateZ: modelAsMercatorCoordinate.z,rotateX: modelRotate[0],rotateY: modelRotate[1],rotateZ: modelRotate[2],scale: modelAsMercatorCoordinate.meterInMercatorCoordinateUnits()};var THREE = window.THREE;// configuration of the custom layer for a 3D model per the CustomLayerInterfacevar customLayer = {id: '3d-model'+id,type: 'custom',renderingMode: '3d',onAdd: function(map, gl) {camera = new THREE.Camera();scene = new THREE.Scene();var directionalLight = new THREE.DirectionalLight(0xffffff);directionalLight.position.set(0, -170, 100).normalize();scene.add(directionalLight);var directionalLight2 = new THREE.DirectionalLight(0xffffff);directionalLight2.position.set(0, 170, 100).normalize();scene.add(directionalLight2);// use the three.js GLTF loader to add the 3D model to the three.js scenevar loader = new THREE.GLTFLoader();loader.load('./testGtlf/test.gltf',function(gltf) {for (var c = 0; c < gltf.scene.children.length; c++) {gltf.scene.children[c]["newName"] = "newName_" + c;gltf.scene.children[c]["boolColor"] = false;gltf.scene.children[c]["objInfo"] = {"name":"zhangsan","age":30,"phone":"15634729129"};}scene.add(gltf.scene);}.bind(this));// map = map;// use the Mapbox GL JS map canvas for three.jsrenderer = new THREE.WebGLRenderer({canvas: map.getCanvas(),context: gl,antialias: true});renderer.autoClear = false;},render: function(gl, matrix) {var rotationX = new THREE.Matrix4().makeRotationAxis(new THREE.Vector3(1, 0, 0),modelTransform.rotateX);var rotationY = new THREE.Matrix4().makeRotationAxis(new THREE.Vector3(0, 1, 0),modelTransform.rotateY);var rotationZ = new THREE.Matrix4().makeRotationAxis(new THREE.Vector3(0, 0, 1),modelTransform.rotateZ);var m = new THREE.Matrix4().fromArray(matrix);var 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);camera.projectionMatrix = m.multiply(l);renderer.state.reset();renderer.render(scene, camera);map.triggerRepaint();}};return customLayer;}//渲染线function renderLine() {var geojson = {'type': 'FeatureCollection','features': [{'type': 'Feature','geometry': {'type': 'LineString','coordinates': [[148.9819193502973, -35.398500434944886],[148.98195162329682, -35.3985011334687],[148.98200184048164, -35.39849545391921]]}}]};map.addSource('line', {'type': 'geojson','data': geojson});// add the line which will be modified in the animationmap.addLayer({'id': 'line-animation','type': 'line','source': 'line','layout': {'line-cap': 'round','line-join': 'round'},'paint': {'line-color': '#ed6498','line-width': 5,'line-opacity': 0.8}});}/*设置拾取*/let raycaster = new THREE.Raycaster();let mouse = new THREE.Vector2();let SELECTED;function dbClick(event) {event.preventDefault();mouse.x = (event.clientX / window.innerWidth) * 2 - 1;mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;raycaster.setFromCamera(mouse, camera);let intersects = raycaster.intersectObjects(scene.children, true);//高亮if (intersects.length !== 0 && intersects[0].object instanceof THREE.Mesh) {if (SELECTED != intersects[0].object) {//选中当前位置if (SELECTED) SELECTED.material.color.setHex(SELECTED.currentHex);SELECTED = intersects[0].object;SELECTED.currentHex = SELECTED.material.color.getHex(); //记录当前选择的颜色//改变物体的颜色SELECTED.material.color.set(0x66ff00);//var objInfo = SELECTED.objInfo;document.getElementById("domId").innerHTML = "<p>"+objInfo["name"]+objInfo["age"]+"岁<br/>"+objInfo["phone"]+"</p>";} else {//其他if (SELECTED) SELECTED.material.color.set(SELECTED.currentHex); //恢复选择前的默认颜色SELECTED = null;}} else {if (SELECTED) SELECTED.material.color.set(SELECTED.currentHex); //恢复选择前的默认颜色SELECTED = null;}}/* 监听事件 */window.addEventListener('dblclick', dbClick, false);window.requestAnimationFrame(render)</script></body>
</html>

注意的点是在加载 

loader.load('./testGtlf/test.gltf',function(gltf) {scene.add(gltf.scene);}.bind(this));

这里的gltf的路径如果直接打开,那就会报错,这里需要用nginx或者hbuilder工具里自带的内核,或者把gltf文件放到服务器上部署也是可以,如果直接在本地打开则会报下面的错

这个错误按照上面的方法就可以解决。

另外需要注意的是加载gltf格式的时候,对应加载的gltf文件目录下还得有个同样名称的.bin后缀的文件。

不然会报错,错误如下:

最后gltf模型可以用3dmax制作。

注意:如果在vue项目里加载

loader.load("static/test/a.gltf",function(gltf){scene.add(gltf.scene);});

这里加载gltf的文件,该文件要放在public文件下下面才会避免加载失败的问题。目前在地图上加载gltf模型的点击事件还没研究出来,希望大家给点建议或者意见,好让本人开开眼界。