漫游和巡检
parent
204a47bde4
commit
245208584c
Binary file not shown.
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 3.2 KiB |
Binary file not shown.
Before Width: | Height: | Size: 31 MiB After Width: | Height: | Size: 43 MiB |
File diff suppressed because one or more lines are too long
|
@ -15,6 +15,9 @@
|
|||
<div class="button" @click="roam()">
|
||||
漫游
|
||||
</div>
|
||||
<div class="button" @click="check()">
|
||||
巡检
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -47,8 +50,8 @@ onMounted(() => {
|
|||
});
|
||||
// document.addEventListener("mousemove", onMouseMove);
|
||||
});
|
||||
let scene, renderer, camera, controls, clickedObject, pointsArr = true;
|
||||
let biggerSphereMesh = null;
|
||||
let scene, renderer, camera, controls, clickedObject, model;
|
||||
|
||||
// 克隆颜色和模型
|
||||
let objArr = [];
|
||||
let objM = [];
|
||||
|
@ -57,8 +60,10 @@ let warnSets = [];
|
|||
// 设置漫游索引
|
||||
let currentIndex = 0;
|
||||
let romeObj = []
|
||||
// 设置巡检
|
||||
let checkArr = [];
|
||||
let checkindex = 0;
|
||||
|
||||
let i = 1;
|
||||
let mouse = new THREE.Vector2();
|
||||
let labelRenderer = new CSS2DRenderer(); //新建CSS2DRenderer
|
||||
const data = reactive({
|
||||
|
@ -120,7 +125,7 @@ const init = () => {
|
|||
scene.background = new THREE.Color(bimStore().activateMenu.background);
|
||||
// 相机
|
||||
camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 0.1, 1000);
|
||||
camera.position.set(-83.68342627048388, 83.03295496739706, -11.88944568919905);
|
||||
camera.position.set(-65.82410159732751, 111.17437832684305, -45.026345528621334);
|
||||
camera.lookAt(scene.position);
|
||||
//渲染器
|
||||
renderer = new THREE.WebGLRenderer({ antialias: true });
|
||||
|
@ -140,8 +145,8 @@ const loadSence = () => {
|
|||
const dracoLoader = new DRACOLoader();
|
||||
dracoLoader.setDecoderPath('/draco/gltf/')//设置解压库文件路径
|
||||
gltfLoader.setDRACOLoader(dracoLoader)
|
||||
gltfLoader.load('/jzc/scene3.gltf', (gltf) => {
|
||||
var model = gltf.scene;
|
||||
gltfLoader.load('/jzc/jz.gltf', (gltf) => {
|
||||
model = gltf.scene;
|
||||
// 克隆初始的材料和模型
|
||||
model.traverse(e => {
|
||||
objArr.push(e);
|
||||
|
@ -161,9 +166,35 @@ const loadSence = () => {
|
|||
})
|
||||
// 漫游结束
|
||||
|
||||
// 获取巡检设备
|
||||
const checkname = [{
|
||||
name: 'start',
|
||||
isPass: true
|
||||
}, {
|
||||
name: 'middle1',
|
||||
isPass: true
|
||||
}, {
|
||||
name: 'middle2',
|
||||
isPass: false
|
||||
}, {
|
||||
name: 'end',
|
||||
isPass: true
|
||||
}]
|
||||
checkname.forEach((item, index) => {
|
||||
var targetO = model.getObjectByName(item.name);
|
||||
if (targetO) {
|
||||
targetO.isPass = item.isPass;
|
||||
checkArr.push(
|
||||
targetO
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
scene.add(model);
|
||||
// 将预警设备染色
|
||||
warn();
|
||||
// 更换墙体纹理
|
||||
changeMap();
|
||||
});
|
||||
};
|
||||
const renderScene = () => {
|
||||
|
@ -172,7 +203,7 @@ const renderScene = () => {
|
|||
const cameraX = cameraPosition.x;
|
||||
const cameraY = cameraPosition.y;
|
||||
const cameraZ = cameraPosition.z;
|
||||
console.log('坐标', cameraX, cameraY, cameraZ);
|
||||
// console.log('坐标', cameraX, cameraY, cameraZ);
|
||||
TWEEN.update();
|
||||
controls.update();
|
||||
renderer.render(scene, camera);
|
||||
|
@ -199,6 +230,16 @@ const enableGroup = [
|
|||
'yuanliao_room',
|
||||
'tanghua_room',
|
||||
'touliao_room',
|
||||
'guan1',
|
||||
'guan2',
|
||||
'guan3',
|
||||
'guan4',
|
||||
'guan5',
|
||||
'guan6',
|
||||
'guan7',
|
||||
'guan8',
|
||||
'guan9',
|
||||
'guan10'
|
||||
]
|
||||
const isSelent = (obj) => {
|
||||
var o = obj
|
||||
|
@ -206,7 +247,7 @@ const isSelent = (obj) => {
|
|||
if (o.name != "jzgltf" && enableGroup.indexOf(o.name) != -1) {
|
||||
return o;
|
||||
} else {
|
||||
if (o.parent.name == "jzgltf") {
|
||||
if (o.parent && o.parent.name == "jzgltf") {
|
||||
return null;
|
||||
} else {
|
||||
o = o.parent;
|
||||
|
@ -247,13 +288,13 @@ const onMouseDownRight = (event) => {
|
|||
mouse.y = -((event.clientY - marginTop) / window.innerHeight) * 2 + 1;
|
||||
raycaster.setFromCamera(mouse, camera);
|
||||
const intersects = raycaster.intersectObjects(scene.children, true);
|
||||
console.log(123, event);
|
||||
// console.log(123, event);
|
||||
|
||||
if (intersects.length > 0) {
|
||||
const clickedObject = intersects[0].object;
|
||||
console.log('这是我选中的模型', clickedObject);
|
||||
selectedObject = isSelent(clickedObject);
|
||||
addLabel(selectedObject, true);
|
||||
addLabel(selectedObject, 'details');
|
||||
}
|
||||
}
|
||||
// 鼠标点击效果
|
||||
|
@ -273,7 +314,7 @@ const onMouseDown = (event) => {
|
|||
// 高亮所在区域
|
||||
boxLight(selectedObject);
|
||||
// 染色点击的模型
|
||||
|
||||
console.log(1,clickedObject);
|
||||
if (bimStore().activateIndex == '0') {
|
||||
// 联动左侧菜单
|
||||
Bus.emit('handleTreeClick', clickedObject);
|
||||
|
@ -323,7 +364,7 @@ const cleanColor = () => {
|
|||
}
|
||||
// 预警
|
||||
const warn = () => {
|
||||
['guan1', 'guan2', 'guan3', 'guan4'].forEach(item => {
|
||||
['guan1', 'guan2', 'guan3', 'guan4', 'guan5', 'guan6', 'guan7', 'guan8', 'guan9', 'guan10'].forEach(item => {
|
||||
warnSets.push(scene.getObjectByName(item));
|
||||
})
|
||||
|
||||
|
@ -374,15 +415,17 @@ const centerSelectedGroup = (obj) => {
|
|||
// 漫游
|
||||
const roam = () => {
|
||||
if (currentIndex < romeObj.length) {
|
||||
console.log('----', currentIndex);
|
||||
console.log('----', romeObj.length);
|
||||
console.log('照相机坐标', camera.position);
|
||||
console.log('物体坐标', romeObj[currentIndex].getWorldPosition(new THREE.Vector3()));
|
||||
|
||||
|
||||
var nextPosition = romeObj[currentIndex].getWorldPosition(new THREE.Vector3());
|
||||
// 在动画完成后触发下一个漫游
|
||||
gsap.to(camera.position, {
|
||||
x: nextPosition.x,
|
||||
y: nextPosition.y + 1.2,
|
||||
y: nextPosition.y + 2.2,
|
||||
z: nextPosition.z,
|
||||
duration: 4,
|
||||
duration: 10,
|
||||
ease: 'power1.inOut',
|
||||
onComplete: () => {
|
||||
roam()
|
||||
|
@ -397,9 +440,9 @@ const roam = () => {
|
|||
}
|
||||
gsap.to(controls.target, {
|
||||
x: lookObj.x,
|
||||
y: lookObj.y + 1.2,
|
||||
y: lookObj.y + 2.2,
|
||||
z: lookObj.z,
|
||||
duration: 4,
|
||||
duration: 10,
|
||||
|
||||
ease: "power1.inOut",
|
||||
onComplete: () => { },
|
||||
|
@ -440,20 +483,18 @@ const nearCamera = (floor) => {
|
|||
//标签
|
||||
const setLabel = () => {
|
||||
if (isAddLabel.value) {
|
||||
let obj = scene.getObjectByName('set2');
|
||||
addLabel(obj, false);
|
||||
let obj = scene.getObjectByName('guan2');
|
||||
addLabel(obj, 'title');
|
||||
} else {
|
||||
removeLabel();
|
||||
}
|
||||
isAddLabel.value = !isAddLabel.value;
|
||||
}
|
||||
// 添加标签
|
||||
const addLabel = (obj, isShowDetail) => {
|
||||
const addLabel = (obj, t) => {
|
||||
removeLabel();
|
||||
// console.log(123, obj);
|
||||
centerSelectedGroup(obj);
|
||||
let text = "设备二";
|
||||
pointLabel = createLableObj(text, isShowDetail);
|
||||
pointLabel = createLableObj(obj.name, t);
|
||||
obj.add(pointLabel);
|
||||
labelRenderer.setSize(window.innerWidth, window.innerHeight);
|
||||
labelRenderer.domElement.style.position = "absolute";
|
||||
|
@ -463,19 +504,25 @@ const addLabel = (obj, isShowDetail) => {
|
|||
// 将呈现器的输出添加到HTML元素
|
||||
document.getElementById("dom").appendChild(renderer.domElement);
|
||||
};
|
||||
const createLableObj = (text, isShowDetail) => {
|
||||
const createLableObj = (text, t) => {
|
||||
let laberDiv = document.createElement("div"); //创建div容器
|
||||
if (!isShowDetail) {
|
||||
// 只显示标签
|
||||
if (t === 'title') {
|
||||
laberDiv.className = "laber_name";
|
||||
laberDiv.innerHTML = `<div class="arrow_outer"></div><span>设备名称:${text}</span><span>状态:启用</span><span>压力:50 Pa</span>`
|
||||
} else {
|
||||
laberDiv.innerHTML = `<div class="arrow_outer"><span>设备名称:${text}</span><span>状态:启用</span><span>压力:50 Pa</span></div>`
|
||||
//只显示详情
|
||||
} else if (t === 'details') {
|
||||
laberDiv.style.pointerEvents = 'auto';// 必须加
|
||||
laberDiv.className = "laber_name1";
|
||||
laberDiv.className = "laber_details";
|
||||
laberDiv.innerHTML = `<div class="detail-btn">详情</div>`;
|
||||
laberDiv.addEventListener('click', function (event) {
|
||||
emit('handleRightClick', selectedObject);
|
||||
console.log(labelRenderer.domElement);
|
||||
})
|
||||
// 巡检逻辑
|
||||
} else {
|
||||
laberDiv.className = "laber_state";
|
||||
laberDiv.innerHTML = `<div class="arrow_state"><span>设备名称:${text}</span><span>是否通过:${t ? '通过' : '停下,巡检没通过'}</span></div>`
|
||||
}
|
||||
let pointLabel = new CSS2DObject(laberDiv);
|
||||
return pointLabel;
|
||||
|
@ -525,7 +572,72 @@ const xfadd = (obj, state) => {
|
|||
sprite.position.y = 10; //标签底部箭头和空对象标注点重合
|
||||
obj.add(sprite); //tag会标注在空对象obj对应的位置
|
||||
}
|
||||
// 更换纹理贴图方法
|
||||
const changeMap = (img) => {
|
||||
// 获取墙体
|
||||
model.traverse(e => {
|
||||
if (['wallnew1', 'wallnew2', 'wallnew3', 'wallnew4'].indexOf(e.name) != -1) {
|
||||
console.log(e)
|
||||
e.material = new THREE.MeshBasicMaterial({
|
||||
transparent: true,
|
||||
opacity: 0.5,
|
||||
color: new THREE.Color('rgb( 3,95,180)')
|
||||
});
|
||||
} else if (['wall1988_01', 'wall1988_02', 'wall1988_03'].indexOf(e.name) != -1) {
|
||||
e.material = new THREE.MeshBasicMaterial({
|
||||
transparent: true,
|
||||
opacity: 0.5,
|
||||
color: new THREE.Color('rgb( 180,95,4 )')
|
||||
});
|
||||
} else if (['wall2010_01', 'wall2010_02'].indexOf(e.name) != -1) {
|
||||
e.material = new THREE.MeshBasicMaterial({
|
||||
transparent: true,
|
||||
opacity: 0.5,
|
||||
color: new THREE.Color('rgb(4,180,134)')
|
||||
});
|
||||
}
|
||||
})
|
||||
}
|
||||
// 巡检
|
||||
const check = () => {
|
||||
if (currentIndex < romeObj.length) {
|
||||
var checkPosition = checkArr[checkindex].getWorldPosition(new THREE.Vector3());
|
||||
gsap.to(camera.position, {
|
||||
x: checkPosition.x,
|
||||
y: checkPosition.y + 5.2,
|
||||
z: checkPosition.z,
|
||||
duration: 10,
|
||||
ease: 'power1.inOut',
|
||||
onComplete: () => {
|
||||
// 显示标签,已经检查通过
|
||||
addLabel(checkArr[checkindex], checkArr[checkindex].isPass);
|
||||
// 如果巡检通过,巡检下一个设备
|
||||
if (checkArr[checkindex].isPass) {
|
||||
setTimeout(() => {
|
||||
check()
|
||||
}, 2000)
|
||||
}
|
||||
}
|
||||
});
|
||||
let nextObj;
|
||||
if (checkindex == checkArr.length - 1) {
|
||||
nextObj = checkArr[0].getWorldPosition(new THREE.Vector3())
|
||||
} else if (checkindex < checkArr.length) {
|
||||
nextObj = checkArr[checkindex + 1].getWorldPosition(new THREE.Vector3())
|
||||
}
|
||||
gsap.to(controls.target, {
|
||||
x: nextObj.x,
|
||||
y: nextObj.y + 5.2,
|
||||
z: nextObj.z,
|
||||
duration: 10,
|
||||
|
||||
ease: "power1.inOut",
|
||||
onComplete: () => { },
|
||||
});
|
||||
checkindex++;
|
||||
console.log('nextObj', checkindex)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang='scss'>
|
||||
#gltf {
|
||||
|
@ -585,4 +697,13 @@ const xfadd = (obj, state) => {
|
|||
justify-content: center;
|
||||
z-index: 999;
|
||||
}
|
||||
|
||||
.arrow_state {
|
||||
display: inline-block;
|
||||
width: 200px;
|
||||
height: 100px;
|
||||
background: red;
|
||||
color: #fff;
|
||||
padding: 15px;
|
||||
}
|
||||
</style>
|
|
@ -1,752 +0,0 @@
|
|||
<template>
|
||||
<div class="scene">
|
||||
<div id="jindu-text-con">
|
||||
正在加载模型请稍等:<span id="jindu-text"></span>
|
||||
<div class="jindu-con">
|
||||
<div id="jindu"></div>
|
||||
</div>
|
||||
</div>
|
||||
<video id="videoContainer" style="position:absolute;top:0px;left:0px;z-index:100;visibility: hidden"></video>
|
||||
<div class="scene" id="viewer-container"></div>
|
||||
<div class="panel">
|
||||
<div class="main">
|
||||
<li class="tools-li" @click="resetScene">
|
||||
<p class="tools-name">场景重置</p>
|
||||
</li>
|
||||
<li class="tools-li" @click="autoRotateClick">
|
||||
<p class="tools-name">{{ !autoRotate ? '自动旋转' : '停止选择' }}</p>
|
||||
</li>
|
||||
<li class="tools-li" @click="billboardView">
|
||||
<p class="tools-name">视频视角</p>
|
||||
</li>
|
||||
<li class="tools-li" @click="driverView">
|
||||
<p class="tools-name">司机视角</p>
|
||||
</li>
|
||||
<li class="tools-li" @click="roam">
|
||||
<p class="tools-name">漫游</p>
|
||||
</li>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import modules from "./modules/index.js";
|
||||
import * as THREE from "three";
|
||||
import gsap from "gsap";
|
||||
|
||||
let viewer = null
|
||||
let office = null
|
||||
let oldOffice = {}
|
||||
let gltf75 = {}
|
||||
let tree_animate = null
|
||||
let cityv1 = null
|
||||
let modelSelectName = null
|
||||
let modelMoveName = null
|
||||
let isModelSelectName = false
|
||||
let che, cheLable
|
||||
let romeObj = []
|
||||
// 设置漫游索引
|
||||
let currentIndex = 0;
|
||||
// const gui = new dat.GUI();
|
||||
export default {
|
||||
name: "Three",
|
||||
data() {
|
||||
return {
|
||||
autoRotate: false,
|
||||
isDriver: false,
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
|
||||
//判断是否网址
|
||||
|
||||
this.init();
|
||||
},
|
||||
destroyed() {
|
||||
console.log(1111333)
|
||||
},
|
||||
methods: {
|
||||
roam() {
|
||||
if (currentIndex < romeObj.length) {
|
||||
var nextPosition = romeObj[currentIndex].getWorldPosition(new THREE.Vector3());
|
||||
// 在动画完成后触发下一个漫游
|
||||
gsap.to(viewer.camera.position, {
|
||||
x: nextPosition.x,
|
||||
y: nextPosition.y + 1.2,
|
||||
z: nextPosition.z,
|
||||
duration: 4,
|
||||
ease: 'power1.inOut',
|
||||
onComplete: () => {
|
||||
this.roam()
|
||||
} // 回调函数,在动画完成后触发下一个漫游
|
||||
});
|
||||
let lookObj
|
||||
if (currentIndex == romeObj.length) {
|
||||
lookObj = romeObj[0].getWorldPosition(new THREE.Vector3())
|
||||
} else if(currentIndex < romeObj.length) {
|
||||
lookObj = romeObj[currentIndex + 1].getWorldPosition(new THREE.Vector3())
|
||||
}
|
||||
|
||||
gsap.to(viewer.controls.target, {
|
||||
x: lookObj.x,
|
||||
y: lookObj.y + 1.2,
|
||||
z: lookObj.z,
|
||||
duration: 4,
|
||||
|
||||
ease: "power1.inOut",
|
||||
onComplete: () => {},
|
||||
});
|
||||
currentIndex++;
|
||||
console.log('lookObj', currentIndex)
|
||||
}
|
||||
|
||||
},
|
||||
//司机视角
|
||||
driverView() {
|
||||
this.isDriver = !this.isDriver
|
||||
},
|
||||
//切换广告牌视角
|
||||
billboardView() {
|
||||
this.isDriver = false
|
||||
gsap.to(viewer.camera.position, {
|
||||
x: 4,
|
||||
y: 20,
|
||||
z: 5,
|
||||
duration: 2,
|
||||
ease: "power1.inOut",
|
||||
onComplete: () => {},
|
||||
});
|
||||
gsap.to(viewer.controls.target, {
|
||||
x: 4,
|
||||
y: 20,
|
||||
z: -15,
|
||||
duration: 2,
|
||||
ease: "power1.inOut",
|
||||
onComplete: () => {},
|
||||
});
|
||||
},
|
||||
autoRotateClick() {
|
||||
viewer.controls.autoRotate = !viewer.controls.autoRotate
|
||||
this.autoRotate = viewer.controls.autoRotate
|
||||
},
|
||||
resetScene() {
|
||||
gsap.to(viewer.camera.position, {
|
||||
x: -156,
|
||||
y: 100,
|
||||
z: 0,
|
||||
duration: 2,
|
||||
onStart: () => {
|
||||
|
||||
},
|
||||
ease: "Bounce.inOut",
|
||||
});
|
||||
gsap.to(viewer.controls.target, {
|
||||
x: 0,
|
||||
y: 0,
|
||||
z: 0,
|
||||
duration: 2,
|
||||
|
||||
ease: "power1.inOut",
|
||||
onComplete: () => {},
|
||||
});
|
||||
gsap.to(viewer.scene.children.find(o => o.name == '人').rotation, {
|
||||
y: 0,
|
||||
duration: 2,
|
||||
ease: "power1.inOut",
|
||||
});
|
||||
this.isDriver = false
|
||||
cheLable.visible = true
|
||||
viewer.scene.children[viewer.scene.children.findIndex(o => o.name == '快递车')].visible = true
|
||||
viewer.scene.children[viewer.scene.children.findIndex(o => o.name == '树')].visible = true
|
||||
viewer.scene.children[viewer.scene.children.findIndex(o => o.name == 'cityv1')].visible = true
|
||||
viewer.scene.children[viewer.scene.children.findIndex(o => o.name == '实验楼')] = gltf75.clone()
|
||||
viewer.scene.children[viewer.scene.children.findIndex(o => o.name == '办公大厅')] = office.object = oldOffice
|
||||
.clone()
|
||||
modelSelectName = null
|
||||
modelMoveName = null
|
||||
isModelSelectName = false
|
||||
},
|
||||
init() {
|
||||
let that = this
|
||||
let jindu_text_con = document.getElementById('jindu-text-con');
|
||||
let jindu_text = document.getElementById('jindu-text');
|
||||
let jindu = document.getElementById('jindu');
|
||||
|
||||
viewer = new modules.Viewer('viewer-container') //初始化场景
|
||||
// viewer.addAxis()
|
||||
let labels = new modules.Labels(viewer) //初始化场景
|
||||
let skyBoxs = new modules.SkyBoxs(viewer) //添加天空盒和雾化效果
|
||||
// let EffectComposer = new modules.EffectComposer(viewer)//添加天空盒和雾化效果
|
||||
skyBoxs.addSkybox(2)
|
||||
viewer.camera.position.set(-156, 100, 0) //设置相机位置
|
||||
//限制controls的上下角度范围
|
||||
viewer.controls.maxPolarAngle = Math.PI / 2.1;
|
||||
let lights = new modules.Lights(viewer)
|
||||
let ambientLight = lights.addAmbientLight()
|
||||
ambientLight.setOption({
|
||||
color: 0xffffff,
|
||||
intensity: 1
|
||||
})
|
||||
lights.addDirectionalLight([100, 100, -10], {
|
||||
color: 'rgb(253,253,253)',
|
||||
intensity: 3,
|
||||
castShadow: true,
|
||||
})
|
||||
let modeloader = new modules.ModelLoder(viewer)
|
||||
//添加视频纹理
|
||||
let video = document.getElementById('videoContainer');
|
||||
video.src = "bi.mp4"; // 设置视频地址
|
||||
video.autoplay = "autoplay"; //要设置播放
|
||||
video.loop = "loop"; //要设置循环播放
|
||||
video.muted = "muted"; //要设置静音
|
||||
let texture = new THREE.VideoTexture(video)
|
||||
|
||||
//停车场栅栏
|
||||
let Mesh26
|
||||
let isopen = false
|
||||
let tiemen = {}
|
||||
modeloader.loadModelToScene('scene1.glb', _model => {
|
||||
_model.object.name = 'cityv1'
|
||||
_model.openCastShadow()
|
||||
_model.openReceiveShadow()
|
||||
// let center = _model.getCenter(new THREE.Vector3())
|
||||
// viewer.camera.lookAt(center)
|
||||
const objname = ['start', 'middle1001', 'middle2', 'end']
|
||||
|
||||
objname.forEach((item, index) => {
|
||||
var targetModel = _model.object.getObjectByName(item);
|
||||
if (targetModel) romeObj.push(
|
||||
targetModel
|
||||
)
|
||||
console.log('targetModel', targetModel)
|
||||
})
|
||||
_model.object.children.forEach((item, index) => {
|
||||
console.log('item.name', item.name)
|
||||
if (item.name === 'Mesh26') {
|
||||
//平移
|
||||
Mesh26 = item
|
||||
gsap.to(item.scale, {
|
||||
x: item.scale.x / 8,
|
||||
duration: 5,
|
||||
ease: "power1.inOut",
|
||||
onComplete: () => {
|
||||
makeCurve()
|
||||
isopen = true
|
||||
}
|
||||
});
|
||||
}
|
||||
})
|
||||
tiemen = tiemen = {
|
||||
fun: moveOnCurve,
|
||||
content: che
|
||||
}
|
||||
viewer.addAnimate(tiemen)
|
||||
cityv1 = _model.object.clone()
|
||||
}, (progress) => {
|
||||
progress = Math.floor(progress * 100)
|
||||
jindu_text.innerText = progress + '%';
|
||||
jindu.style.width = progress + '%'
|
||||
if (progress === 100) {
|
||||
jindu_text_con.style.display = 'none'
|
||||
}
|
||||
}, (error) => {
|
||||
console.log(error)
|
||||
})
|
||||
|
||||
/* modeloader.loadModelToScene('zuo.glb', _model => {
|
||||
office = _model
|
||||
office.openCastShadow()
|
||||
office.openReceiveShadow()
|
||||
//旋转360度
|
||||
office.object.rotation.y = Math.PI
|
||||
office.object.position.set(16, 0, -5)
|
||||
office.object.scale.set(0.2, 0.2, 0.2)
|
||||
office.object.name = '办公大厅'
|
||||
office.object.children.forEach(item => {
|
||||
item.name = item.name.replace('zuo', '')
|
||||
if (item.name == 'ding') {
|
||||
item.name = 6
|
||||
}
|
||||
item.name--
|
||||
})
|
||||
office.object.children.sort((a, b) => a.name - b.name).forEach(v => {
|
||||
v.name = 'zuo' + v.name
|
||||
})
|
||||
office.forEach(child => {
|
||||
if (child.isMesh) {
|
||||
child.frustumCulled = false
|
||||
child.material.emissive = child.material.color;
|
||||
child.material.emissiveMap = child.material.map;
|
||||
child.material.emissiveIntensity = 1.2
|
||||
child.material.envmap = viewer.scene.background
|
||||
}
|
||||
})
|
||||
oldOffice = office.object.clone()
|
||||
let box = office.getBox()
|
||||
labels.addCss2dLabel({
|
||||
x: box.max.x / 2,
|
||||
y: box.max.y,
|
||||
z: box.max.z
|
||||
}, `<span class="label">${_model.object.name}</span>`)
|
||||
gsap.to(labels.label.position, {
|
||||
y: box.max.y + 2,
|
||||
repeat: -1,
|
||||
yoyo: true,
|
||||
duration: 2,
|
||||
ease: "Bounce.inOut",
|
||||
});
|
||||
})
|
||||
|
||||
modeloader.loadModelToScene('75.gltf', _model => {
|
||||
_model.openCastShadow()
|
||||
_model.openReceiveShadow()
|
||||
_model.object.rotateY(Math.PI / 2)
|
||||
_model.object.position.set(-17, 0, 5)
|
||||
_model.object.scale.set(0.7, 0.7, 0.7)
|
||||
_model.object.name = '实验楼'
|
||||
gltf75 = _model.object.clone()
|
||||
let box = _model.getBox()
|
||||
labels.addCss2dLabel({
|
||||
x: box.max.x,
|
||||
y: box.max.y,
|
||||
z: box.max.z
|
||||
}, `<span class="label">${_model.object.name}</span>`)
|
||||
gsap.to(labels.label.position, {
|
||||
y: box.max.y + 2,
|
||||
repeat: -1,
|
||||
yoyo: true,
|
||||
duration: 2,
|
||||
ease: "Bounce.inOut",
|
||||
});
|
||||
})
|
||||
|
||||
modeloader.loadModelToScene('billboard_-_lowpoly.glb', _model => {
|
||||
_model.openCastShadow()
|
||||
_model.object.position.set(4, -20, -35)
|
||||
_model.object.rotateY(-Math.PI / 2)
|
||||
_model.object.scale.set(2.7, 2.7, 2.7)
|
||||
_model.object.name = '广告牌'
|
||||
let Object_6 = _model.object.getObjectByName('Object_6')
|
||||
Object_6.material = new THREE.MeshBasicMaterial({
|
||||
map: texture, // 设置纹理贴图
|
||||
side: THREE.DoubleSide,
|
||||
transparent: true,
|
||||
}); //材质对象Material
|
||||
let box = _model.getBox()
|
||||
modeloader.loadModelToScene('drone/wrj.glb', res => {
|
||||
res.openCastShadow()
|
||||
res.object.position.set(16, 12, 5)
|
||||
res.object.scale.set(0.3, 0.3, 0.3)
|
||||
res.object.name = '无人机'
|
||||
res.startAnima(0)
|
||||
gsap.to(res.object.position, {
|
||||
x: _model.object.position.x,
|
||||
y: box.max.y,
|
||||
z: _model.object.position.z,
|
||||
repeat: -1,
|
||||
yoyo: true,
|
||||
duration: 13,
|
||||
ease: "Expo.inOut",
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
modeloader.loadModelToScene('car13.gltf', _model => {
|
||||
che = _model
|
||||
_model.openCastShadow()
|
||||
_model.openReceiveShadow()
|
||||
_model.object.position.set(11.5, 0, 18)
|
||||
_model.object.scale.set(1, 1, 1)
|
||||
_model.object.name = '快递车'
|
||||
let boxx = _model.getBox()
|
||||
// let center = boxx.getCenter(new THREE.Vector3())
|
||||
// // //相机跟随
|
||||
// viewer.camera.position.set(center.x, center.y, center.z)
|
||||
// viewer.camera.lookAt(center)
|
||||
cheLable = labels.addCss2dLabel({
|
||||
x: boxx.max.x,
|
||||
y: boxx.max.y + 2,
|
||||
z: boxx.max.z
|
||||
}, `<span class="label">${_model.object.name}</span>`)
|
||||
})
|
||||
|
||||
modeloader.loadModelToScene('ren.glb', _model => {
|
||||
_model.openCastShadow()
|
||||
_model.object.position.set(13, 0, 15)
|
||||
_model.object.name = '人'
|
||||
_model.startAnima(1)
|
||||
_model.cloneModel([25, 0, 29]).startAnima()
|
||||
})
|
||||
|
||||
modeloader.loadModelToScene('tree_animate/scene.gltf', _model => {
|
||||
_model.openCastShadow()
|
||||
_model.object.position.set(8, 0, 26)
|
||||
_model.object.scale.set(0.08, 0.08, 0.08)
|
||||
_model.object.name = '树'
|
||||
_model.startAnima()
|
||||
tree_animate = _model.object.clone()
|
||||
}) */
|
||||
|
||||
let curve = null;
|
||||
|
||||
function makeCurve() {
|
||||
//Create a closed wavey loop
|
||||
curve = new THREE.CatmullRomCurve3([
|
||||
new THREE.Vector3(11.5, 0, 18),
|
||||
new THREE.Vector3(11.5, 0, 34),
|
||||
new THREE.Vector3(35, 0, 34),
|
||||
new THREE.Vector3(35, 0, 31),
|
||||
new THREE.Vector3(11.5, 0, 31),
|
||||
]);
|
||||
curve.curveType = "catmullrom";
|
||||
curve.closed = true; //设置是否闭环
|
||||
curve.tension = 0; //设置线的张力,0为无弧度折线
|
||||
|
||||
// 为曲线添加材质在场景中显示出来,不显示也不会影响运动轨迹,相当于一个Helper
|
||||
const points = curve.getPoints(0.1);
|
||||
const geometry = new THREE.BufferGeometry().setFromPoints(points);
|
||||
const material = new THREE.LineBasicMaterial({
|
||||
color: 0xff0000,
|
||||
});
|
||||
|
||||
// Create the final object to add to the scene
|
||||
const curveObject = new THREE.Line(geometry, material);
|
||||
curveObject.position.y = -1;
|
||||
viewer.scene.add(curveObject)
|
||||
}
|
||||
|
||||
|
||||
let progress = 0; // 物体运动时在运动路径的初始位置,范围0~1
|
||||
const velocity = 0.001; // 影响运动速率的一个值,范围0~1,需要和渲染频率结合计算才能得到真正的速率
|
||||
// 物体沿线移动方法
|
||||
function moveOnCurve(_model) {
|
||||
if (curve == null || che == null) {} else {
|
||||
if (progress <= 1 - velocity) {
|
||||
let che = _model.object
|
||||
let boxx = _model.getBox()
|
||||
cheLable.position.set(boxx.max.x, boxx.max.y + 2, boxx.max.z)
|
||||
if (che.position.z.toFixed(2) >= 28.00 && che.position.z.toFixed(2) <= 28.10) {
|
||||
if (isopen) {
|
||||
gsap.to(Mesh26.scale, {
|
||||
x: Mesh26.scale.x * 8,
|
||||
duration: 5,
|
||||
ease: "power1.inOut",
|
||||
onComplete: () => {
|
||||
isopen = false
|
||||
},
|
||||
});
|
||||
} else {
|
||||
gsap.to(Mesh26.scale, {
|
||||
x: Mesh26.scale.x / 8,
|
||||
duration: 5,
|
||||
ease: "power1.inOut",
|
||||
onComplete: () => {
|
||||
isopen = true
|
||||
viewer.addAnimate(tiemen)
|
||||
},
|
||||
onStart: () => {
|
||||
viewer.removeAnimate(tiemen)
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
const point = curve.getPointAt(progress); //获取样条曲线指定点坐标
|
||||
const pointBox = curve.getPointAt(progress + velocity); //获取样条曲线指定点坐标
|
||||
|
||||
if (point && pointBox) {
|
||||
che.position.set(point.x, point.y, point.z);
|
||||
che.lookAt(pointBox.x, pointBox.y, pointBox
|
||||
.z); //因为这个模型加载进来默认面部是正对Z轴负方向的,所以直接lookAt会导致出现倒着跑的现象,这里用重新设置朝向的方法来解决。
|
||||
let center = _model.getBox().getCenter(new THREE.Vector3())
|
||||
// viewer.camera.position.copy(pointBox)
|
||||
// viewer.camera.lookAt(point)
|
||||
// viewer.controls.target.set(pointBox.x, center.y, pointBox.z+10)
|
||||
if (that.isDriver) {
|
||||
viewer.camera.position.set(point.x, point.y + 2, point.z)
|
||||
viewer.camera.lookAt(pointBox.x, pointBox.y + 2, pointBox.z)
|
||||
viewer.controls.position0.set(point.x, point.y + 2, point.z) //非必要,场景有控件时才加上
|
||||
viewer.controls.target.set(pointBox.x, pointBox.y + 2, pointBox.z) //非必要,场景有控件时才加上
|
||||
}
|
||||
let targetPos = pointBox //目标位置点
|
||||
let offsetAngle = 22 //目标移动时的朝向偏移
|
||||
|
||||
// //以下代码在多段路径时可重复执行
|
||||
let mtx = new THREE.Matrix4() //创建一个4维矩阵
|
||||
// .lookAt ( eye : Vector3, target : Vector3, up : Vector3 ) : this,构造一个旋转矩阵,从eye 指向 target,由向量 up 定向。
|
||||
mtx.lookAt(che.position, targetPos, che.up) //设置朝向
|
||||
mtx.multiply(new THREE.Matrix4().makeRotationFromEuler(new THREE.Euler(0, offsetAngle, 0)))
|
||||
let toRot = new THREE.Quaternion().setFromRotationMatrix(mtx) //计算出需要进行旋转的四元数值
|
||||
che.quaternion.slerp(toRot, 0.2)
|
||||
}
|
||||
progress += velocity;
|
||||
} else {
|
||||
progress = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let modelSelect = ['zuo0', 'zuo1', 'zuo2', 'zuo3', 'zuo4', 'zuo5']
|
||||
viewer.startSelectEvent('mousemove', false, (model) => {
|
||||
if (model.parent && model.parent.parent && model.parent.parent.name == '办公大厅') {
|
||||
modelSelect.forEach((item) => {
|
||||
if (item == model.parent.name) {
|
||||
modelMoveName = item
|
||||
if (modelSelectName == modelMoveName) return
|
||||
office.object.getObjectByName(item).traverse(function(child) {
|
||||
if (child.isMesh) {
|
||||
child.material = new THREE.MeshPhongMaterial({
|
||||
color: 'yellow',
|
||||
transparent: true,
|
||||
opacity: 0.8,
|
||||
emissive: child.material.color,
|
||||
emissiveMap: child.material.map,
|
||||
emissiveIntensity: 3
|
||||
})
|
||||
}
|
||||
})
|
||||
} else {
|
||||
if (!isModelSelectName) {
|
||||
let oldmodel = oldOffice.getObjectByName(item)
|
||||
office.object.getObjectByName(item).traverse(function(child) {
|
||||
if (child.isMesh) {
|
||||
child.material = oldmodel.getObjectByName(child.name)
|
||||
.material
|
||||
}
|
||||
})
|
||||
} else {
|
||||
office.object.getObjectByName(item).traverse(function(child) {
|
||||
if (child.isMesh && child.parent.name != modelSelectName) {
|
||||
child.material = new THREE.MeshPhongMaterial({
|
||||
color: new THREE.Color('#123ca8'),
|
||||
transparent: true,
|
||||
opacity: 0.5,
|
||||
emissiveMap: child.material.map,
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
let sceneList = ['实验楼']
|
||||
viewer.renderer.domElement.addEventListener('click', (e) => {
|
||||
const raycaster = new THREE.Raycaster()
|
||||
const mouse = new THREE.Vector2()
|
||||
mouse.x = (e.offsetX / viewer.renderer.domElement.clientWidth) * 2 - 1
|
||||
mouse.y = -(e.offsetY / viewer.renderer.domElement.clientHeight) * 2 + 1
|
||||
raycaster.setFromCamera(mouse, viewer.camera)
|
||||
const intersects = raycaster.intersectObject(viewer.scene, true)
|
||||
if (intersects.length > 0 && intersects[0] && modelMoveName) {
|
||||
let model = intersects[0].object.parent
|
||||
if (model.name.includes('zuo')) {
|
||||
if (!isModelSelectName) {
|
||||
cheLable.visible = false
|
||||
viewer.scene.children[viewer.scene.children.findIndex(o => o.name == '快递车')]
|
||||
.visible = false
|
||||
viewer.scene.children[viewer.scene.children.findIndex(o => o.name == 'cityv1')]
|
||||
.visible = false
|
||||
viewer.scene.children[viewer.scene.children.findIndex(o => o.name == '树')]
|
||||
.visible = false
|
||||
sceneList.forEach(item => {
|
||||
viewer.scene.children.find(o => o.name == item).traverse((child) => {
|
||||
child.material = new THREE.MeshPhongMaterial({
|
||||
color: new THREE.Color('rgba(7,32,96,0.76)'),
|
||||
transparent: true,
|
||||
opacity: 0.1,
|
||||
wireframe: true,
|
||||
depthWrite: true, // 无法被选择,鼠标穿透
|
||||
})
|
||||
})
|
||||
})
|
||||
gsap.to(viewer.scene.children.find(o => o.name == '人').rotation, {
|
||||
y: Math.PI,
|
||||
duration: 2,
|
||||
ease: "power1.inOut",
|
||||
onComplete: () => {
|
||||
isModelSelectName = true
|
||||
},
|
||||
});
|
||||
}
|
||||
selectOffice(model)
|
||||
}
|
||||
if (!model.name.includes('zuo')) {
|
||||
if (!isModelSelectName) {
|
||||
let oldmodel = oldOffice.getObjectByName(modelMoveName)
|
||||
office.object.getObjectByName(modelMoveName).traverse(function(child) {
|
||||
if (child.isMesh) {
|
||||
child.material = oldmodel.getObjectByName(child.name).material
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const selectOffice = (model) => {
|
||||
modelSelectName = model.name
|
||||
let oldmodel = oldOffice.getObjectByName(modelSelectName)
|
||||
let modelSelectIndex = modelSelect.findIndex(v => v == modelSelectName)
|
||||
office.object.children.forEach((child, index) => {
|
||||
child.children.forEach((Mesh) => {
|
||||
if (child.name === modelSelectName) {
|
||||
child.children.forEach(Mesh => {
|
||||
Mesh.material = oldmodel.getObjectByName(Mesh.name)
|
||||
.material
|
||||
})
|
||||
} else {
|
||||
Mesh.material = new THREE.MeshPhongMaterial({
|
||||
color: new THREE.Color('#123ca8'),
|
||||
transparent: true,
|
||||
opacity: 0.5,
|
||||
emissiveMap: Mesh.material.map,
|
||||
})
|
||||
}
|
||||
})
|
||||
if (!model.userData.position && index > modelSelectIndex) {
|
||||
gsap.to(child.position, {
|
||||
y: !child.userData.position ? child.position.y + 25 : child.position.y,
|
||||
duration: 2,
|
||||
ease: "power1.inOut",
|
||||
onComplete: () => {
|
||||
child.userData.position = true
|
||||
},
|
||||
});
|
||||
}
|
||||
if (model.userData.position && index <= modelSelectIndex) {
|
||||
if (child.userData.position) {
|
||||
gsap.to(child.position, {
|
||||
y: oldOffice.getObjectByName(child.name).position.y,
|
||||
duration: 2,
|
||||
ease: "power1.inOut",
|
||||
onComplete: () => {
|
||||
child.userData.position = false
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
})
|
||||
gsap.to(viewer.controls.target, {
|
||||
x: 12,
|
||||
y: 0,
|
||||
z: -5,
|
||||
duration: 2,
|
||||
ease: "power1.inOut",
|
||||
onComplete: () => {},
|
||||
});
|
||||
gsap.to(viewer.camera.position, {
|
||||
x: 12,
|
||||
y: 18,
|
||||
z: 38,
|
||||
duration: 2,
|
||||
ease: "power1.inOut",
|
||||
onComplete: () => {},
|
||||
});
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
//定义全局颜色
|
||||
$color: #123ca8;
|
||||
|
||||
.scene {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
|
||||
.label {
|
||||
padding: 20px;
|
||||
background: $color;
|
||||
color: aliceblue;
|
||||
border-radius: 5px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.jindu-con {
|
||||
width: 300px;
|
||||
height: 10px;
|
||||
border-radius: 50px;
|
||||
background-color: white;
|
||||
margin-top: 10px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#jindu {
|
||||
height: inherit;
|
||||
background-color: #007bff;
|
||||
width: 0;
|
||||
}
|
||||
|
||||
#jindu-text-con {
|
||||
width: 300px;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
margin: 0 auto;
|
||||
top: 15%;
|
||||
text-align: center;
|
||||
background-color: rgba(255, 255, 255, .5);
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.panel {
|
||||
margin: 0 auto;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
bottom: 10px;
|
||||
position: absolute;
|
||||
opacity: 0.8;
|
||||
width: 100%;
|
||||
left: 0;
|
||||
right: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
.main {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
border-radius: 4px;
|
||||
opacity: 0.96;
|
||||
border: 1px solid #14171c;
|
||||
background: linear-gradient(0deg, #1e202a 0%, #0d1013 100%);
|
||||
box-shadow: 0px 2px 21px 0px rgba(33, 34, 39, 0.55);
|
||||
|
||||
li {
|
||||
padding: 5px 10px;
|
||||
box-sizing: border-box;
|
||||
list-style: none;
|
||||
cursor: pointer;
|
||||
border: 1px solid #313642;
|
||||
border-radius: 2px;
|
||||
float: left;
|
||||
margin: 5px;
|
||||
position: relative;
|
||||
width: 70px;
|
||||
|
||||
p {
|
||||
list-style: none;
|
||||
cursor: pointer;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
height: 20px;
|
||||
text-align: center;
|
||||
font-size: 12px;
|
||||
font-weight: 400;
|
||||
color: #fbfbfb;
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
Loading…
Reference in New Issue