mapbox gl 加载gltf模型

论坛 期权论坛 编程之家     
选择匿名的用户   2021-5-31 23:55   51   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.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模型的点击事件还没研究出来,希望大家给点建议或者意见,好让本人开开眼界。

分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:3875789
帖子:775174
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP