|
首先得理解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.com let 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 CustomLayerInterface var 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 scene var 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.js renderer = 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 animation map.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模型的点击事件还没研究出来,希望大家给点建议或者意见,好让本人开开眼界。 |