You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
503 lines
13 KiB
Vue
503 lines
13 KiB
Vue
11 months ago
|
<template>
|
||
|
<div
|
||
|
v-loading="modelState"
|
||
|
style="width: 100%"
|
||
|
class="ModelLoading"
|
||
|
element-loading-text="模型正在加载中"
|
||
|
element-loading-spinner="el-icon-loading"
|
||
|
element-loading-background="rgba(0, 0, 0, 0)"
|
||
|
>
|
||
|
<div
|
||
|
v-show="!modelState"
|
||
|
id="modelContainers"
|
||
|
ref="modelContainers"
|
||
|
class="animate__animated animationTime2 animate__backInLeft"
|
||
|
/>
|
||
|
</div>
|
||
|
</template>
|
||
|
|
||
|
<script>
|
||
|
import * as THREE from 'three'
|
||
|
import C3S3D from '@/utils/c3s-3d-1.0.1-e'
|
||
|
import { TWEEN } from 'three/examples/jsm/libs/tween.module.min.js'
|
||
|
// 模型参数配置
|
||
|
import {
|
||
|
CAMERA_MOVE_DATA,
|
||
|
getTenToSixteenColor,
|
||
|
getPointData
|
||
|
} from '@/utils/modelData.js'
|
||
|
export default {
|
||
|
name: 'HelloWorld',
|
||
|
components: {},
|
||
|
props: {
|
||
|
modelType: {
|
||
|
type: String,
|
||
|
default: () => 'byq'
|
||
|
}
|
||
|
},
|
||
|
data() {
|
||
|
return {
|
||
|
loading: true,
|
||
|
loadingText: 100,
|
||
|
scale: 1,
|
||
|
publicPath: process.env.BASE_URL,
|
||
|
// 模型信息
|
||
|
modelState: false,
|
||
|
modelData: null,
|
||
|
rotateAct: null,
|
||
|
wrapper: null,
|
||
|
inforData: [],
|
||
|
byqMoveData: [
|
||
|
{
|
||
|
time: 500,
|
||
|
cx: 0,
|
||
|
cy: 0,
|
||
|
cz: 6000,
|
||
|
tx: 0,
|
||
|
ty: 0,
|
||
|
tz: 1200
|
||
|
}, // 一层
|
||
|
{
|
||
|
time: 1200,
|
||
|
cx: 0,
|
||
|
cy: 0,
|
||
|
cz: 1500,
|
||
|
tx: 0,
|
||
|
ty: 0,
|
||
|
tz: 0
|
||
|
}
|
||
|
],
|
||
|
gisMoveData: [
|
||
|
{
|
||
|
time: 500,
|
||
|
cx: 0,
|
||
|
cy: 0,
|
||
|
cz: 6000,
|
||
|
tx: 0,
|
||
|
ty: 800,
|
||
|
tz: 1000
|
||
|
}, // 一层
|
||
|
{
|
||
|
time: 1200,
|
||
|
cx: 0,
|
||
|
cy: 0,
|
||
|
cz: 1000,
|
||
|
tx: 0,
|
||
|
ty: 0,
|
||
|
tz: 0
|
||
|
}
|
||
|
],
|
||
|
geometry: null,
|
||
|
modelDataObj: null,
|
||
|
filePath: null,
|
||
|
modelSiteId: {}
|
||
|
}
|
||
|
},
|
||
|
watch: {
|
||
|
modelType: function(val) {
|
||
|
this.clearModel()
|
||
|
C3S3D.destory(this.ThreeObjs)
|
||
|
// this.modelCurrent(val);
|
||
|
// this.createdInit();
|
||
|
this.mountedGetData()
|
||
|
}
|
||
|
},
|
||
|
created() {
|
||
|
const modelParameter = JSON.parse(localStorage.getItem('getModelList'))
|
||
|
for (let index = 0; index < modelParameter.length; index++) {
|
||
|
const element = modelParameter[index]
|
||
|
if (element.modelType == '211') {
|
||
|
this.modelDataObj = JSON.parse(element.modelParams)
|
||
|
this.modelSiteId = element
|
||
|
this.filePath = element.filePath
|
||
|
break
|
||
|
}
|
||
|
}
|
||
|
},
|
||
|
mounted() {
|
||
|
this.mountedGetData()
|
||
|
},
|
||
|
beforeDestroy() {
|
||
|
C3S3D.destory(this.ThreeObjs)
|
||
|
},
|
||
|
methods: {
|
||
|
mountedGetData() {
|
||
|
this.$store.dispatch('getModelData').then(() => {
|
||
|
const type = this.modelType == 'byq' ? '111' : '211'
|
||
|
const modelParameter = JSON.parse(localStorage.getItem('getModelList'))
|
||
|
console.log('-5-95-5-5-5', modelParameter, type)
|
||
|
for (let index = 0; index < modelParameter.length; index++) {
|
||
|
const element = modelParameter[index]
|
||
|
if (element.modelType == type) {
|
||
|
this.modelDataObj = JSON.parse(element.modelParams)
|
||
|
this.filePath = element.filePath
|
||
|
break
|
||
|
}
|
||
|
}
|
||
|
console.log(!this.modelDataObj, 'wqeqweqewqe')
|
||
|
if (!this.modelDataObj) {
|
||
|
this.$bus.$emit('animateState', true)
|
||
|
return
|
||
|
}
|
||
|
this.$nextTick(() => {
|
||
|
this.createdInit()
|
||
|
})
|
||
|
})
|
||
|
},
|
||
|
createdInit() {
|
||
|
this.modelDataInit()
|
||
|
this.init()
|
||
|
},
|
||
|
modelDataInit() {
|
||
|
const data = this.modelDataObj
|
||
|
this.modelData = {
|
||
|
modelName: '111', // 模型名称
|
||
|
modelZoom: data.modelZoom, // 模型缩放
|
||
|
modelDraco: true, // 是否为Draco文件
|
||
|
modelRotateAct: data.modelRotateAct, // 是否开启自动旋转
|
||
|
modelPath: this.filePath, // 模型文件名称
|
||
|
modelaPosition: data.position, // 模型位置
|
||
|
cameraPosition: { x: 0, y: 0, z: 1000 }, // 场景相机位置
|
||
|
rotationVal: data.rotation,
|
||
|
Point: {
|
||
|
color: data.pointLight.color,
|
||
|
intensity: data.pointLight.intensity
|
||
|
},
|
||
|
Ambient: {
|
||
|
color: data.ambientLight.color,
|
||
|
intensity: data.ambientLight.intensity
|
||
|
},
|
||
|
pointIntensity: 0.3
|
||
|
}
|
||
|
},
|
||
|
// 初始化
|
||
|
init: function() {
|
||
|
const data = this.modelData
|
||
|
this.modelState = true
|
||
|
const lightList = [
|
||
|
// 环境光
|
||
|
{
|
||
|
type: 'Ambient',
|
||
|
color: getTenToSixteenColor(data.Ambient.color),
|
||
|
intensity: data.Ambient.intensity
|
||
|
}
|
||
|
]
|
||
|
// 环绕点光源
|
||
|
const pointData = getPointData(
|
||
|
data.Point.intensity,
|
||
|
getTenToSixteenColor(data.Point.color)
|
||
|
)
|
||
|
if (pointData) {
|
||
|
for (let index = 0; index < pointData.length; index++) {
|
||
|
const element = pointData[index]
|
||
|
lightList.push({
|
||
|
type: 'Point',
|
||
|
color: element.color,
|
||
|
intensity: element.intensity,
|
||
|
position: element.position
|
||
|
})
|
||
|
}
|
||
|
}
|
||
|
this.ThreeObjs = C3S3D.init({
|
||
|
container: this.$refs.modelContainers,
|
||
|
scene: {},
|
||
|
camera: {
|
||
|
far: 15000,
|
||
|
fov: 45,
|
||
|
position: [
|
||
|
data.cameraPosition.x,
|
||
|
data.cameraPosition.y,
|
||
|
data.cameraPosition.z
|
||
|
]
|
||
|
},
|
||
|
controls: {
|
||
|
noRotate: false,
|
||
|
autoRotate: true,
|
||
|
autoRotateSpeed: 2
|
||
|
},
|
||
|
renderer: {
|
||
|
alpha: 0
|
||
|
},
|
||
|
// css3dRenderer: {},
|
||
|
light: lightList,
|
||
|
update: (dt) => {
|
||
|
this.update(dt)
|
||
|
},
|
||
|
// 鼠标点击事件
|
||
|
clickCallback: (e) => {
|
||
|
// this.onMouseClick(e);
|
||
|
},
|
||
|
// 鼠标双击事件
|
||
|
dblclickCallback: () => {},
|
||
|
// 鼠标移动
|
||
|
mousemoveCallback: (e) => {
|
||
|
this.onMouseMove(e)
|
||
|
},
|
||
|
// 鼠标摁下
|
||
|
mousedownCallback: () => {}
|
||
|
})
|
||
|
|
||
|
this.loadGltf()
|
||
|
this.initOutline()
|
||
|
},
|
||
|
update() {
|
||
|
// C3S3D.update(this.ThreeObjs);
|
||
|
},
|
||
|
initOutline() {
|
||
|
C3S3D.initOutline({
|
||
|
ThreeObjs: this.ThreeObjs,
|
||
|
edgeStrength: 20,
|
||
|
edgeThickness: 10,
|
||
|
edgeGlow: 2,
|
||
|
pulsePeriod: 5,
|
||
|
visibleEdgeColor: 0x00ff00,
|
||
|
hiddenEdgeColor: 0x00ff00,
|
||
|
downSampleRatio: 1
|
||
|
})
|
||
|
},
|
||
|
// 清除模型
|
||
|
clearModel() {
|
||
|
// 清除局部的模型
|
||
|
if (this.ThreeObjs.scene !== null) {
|
||
|
// 必须要清空当前div下的canvas不然canvas会继续叠加
|
||
|
const domDiv = document.getElementById('modelContainers')
|
||
|
if (domDiv !== null) {
|
||
|
domDiv.removeChild(domDiv.firstChild)
|
||
|
}
|
||
|
// 确保3D相关对象已销毁
|
||
|
window.cancelAnimationFrame(stop) // 可以取消动画
|
||
|
this.ThreeObjs.scene = null
|
||
|
this.ThreeObjs.camera = null
|
||
|
this.ThreeObjs.renderer = null
|
||
|
this.ThreeObjs.orbitControls = null
|
||
|
}
|
||
|
},
|
||
|
|
||
|
loadGltf() {
|
||
|
const group = new THREE.Object3D()
|
||
|
this.ThreeObjs.scene.add(group)
|
||
|
C3S3D.loadGltf({
|
||
|
// url:
|
||
|
// process.env.VUE_APP_MODEL_API +
|
||
|
// this.modelData.modelPath.split('8022')[1],
|
||
|
url: this.modelData.modelPath,
|
||
|
parent: group,
|
||
|
scale: this.modelData.modelZoom * 1.5,
|
||
|
ThreeObjs: this.ThreeObjs,
|
||
|
position: this.modelData.modelaPosition,
|
||
|
rotation: {
|
||
|
x: C3S3D.toRadian(this.modelData.rotationVal.x),
|
||
|
y: C3S3D.toRadian(this.modelData.rotationVal.y),
|
||
|
z: C3S3D.toRadian(this.modelData.rotationVal.z)
|
||
|
},
|
||
|
draco: this.modelData.modelDraco,
|
||
|
onProgress: (percentage, val) => {
|
||
|
if (percentage >= 100) {
|
||
|
this.loading = false
|
||
|
}
|
||
|
},
|
||
|
onLoad: (geometry) => {
|
||
|
this.geometry = geometry
|
||
|
this.modelState = false
|
||
|
if (this.modelType == 'byq') {
|
||
|
this.startAutoPatrol(this.geometry, this.byqMoveData)
|
||
|
} else {
|
||
|
this.startAutoPatrol(this.geometry, this.gisMoveData)
|
||
|
}
|
||
|
}
|
||
|
})
|
||
|
},
|
||
|
onMouseClick(event) {
|
||
|
const selectObject = C3S3D.getIntersectsFirstMesh(
|
||
|
event,
|
||
|
this.ThreeObjs,
|
||
|
this.ThreeObjs.scene.children
|
||
|
)
|
||
|
if (selectObject) {
|
||
|
// 模型组件点亮
|
||
|
C3S3D.outlineLight(this.ThreeObjs, [selectObject])
|
||
|
// C3S3D.spreadLeftAndRight(this.geometry, 1, 100, 0, 1000);
|
||
|
} else {
|
||
|
C3S3D.outlineLight(this.ThreeObjs, [])
|
||
|
}
|
||
|
},
|
||
|
// 鼠标经过高亮部件
|
||
|
onMouseMove(event) {
|
||
|
const selectObject = C3S3D.getIntersectsFirstMesh(
|
||
|
event,
|
||
|
this.ThreeObjs,
|
||
|
this.ThreeObjs.scene.children
|
||
|
)
|
||
|
if (this.modelData.modelRotateAct) {
|
||
|
if (selectObject) {
|
||
|
this.ThreeObjs.orbitControls.autoRotate = false
|
||
|
} else {
|
||
|
this.ThreeObjs.orbitControls.autoRotate = true
|
||
|
}
|
||
|
}
|
||
|
},
|
||
|
startAutoPatrol(val, data) {
|
||
|
this.patrolPoints = data
|
||
|
this.patrolIndex = 0
|
||
|
this.doPatrol(this.patrolPoints[this.patrolIndex])
|
||
|
},
|
||
|
// 相机移动
|
||
|
doPatrol(point) {
|
||
|
const cameraPos = this.ThreeObjs.camera.position.clone()
|
||
|
const targetPos = this.ThreeObjs.orbitControls.target.clone()
|
||
|
this.patrolTween = C3S3D.createTween({
|
||
|
start: {
|
||
|
cx: cameraPos.x,
|
||
|
cy: cameraPos.y,
|
||
|
cz: cameraPos.z,
|
||
|
tx: targetPos.x,
|
||
|
ty: targetPos.y,
|
||
|
tz: targetPos.z
|
||
|
},
|
||
|
to: {
|
||
|
cx: point.cx,
|
||
|
cy: point.cy,
|
||
|
cz: point.cz,
|
||
|
tx: point.tx,
|
||
|
ty: point.ty,
|
||
|
tz: point.tz
|
||
|
},
|
||
|
duration: point.time,
|
||
|
|
||
|
delayTime: 1,
|
||
|
onUpdate: (obj) => {
|
||
|
this.ThreeObjs.camera.position.set(obj.cx, obj.cy, obj.cz)
|
||
|
this.ThreeObjs.orbitControls.target.set(obj.tx, obj.ty, obj.tz)
|
||
|
},
|
||
|
onComplete: () => {
|
||
|
this.patrolTween = null
|
||
|
this.patrolIndex++
|
||
|
if (this.patrolIndex >= this.patrolPoints.length) {
|
||
|
// 模型加完成
|
||
|
return
|
||
|
}
|
||
|
},
|
||
|
easing: TWEEN.Easing.Linear.None
|
||
|
})
|
||
|
},
|
||
|
// 相机视角移动动画
|
||
|
startAutoPatrol(val, data) {
|
||
|
this.patrolPoints = data
|
||
|
this.patrolIndex = 0
|
||
|
this.doPatrol(this.patrolPoints[this.patrolIndex])
|
||
|
},
|
||
|
// 相机移动
|
||
|
doPatrol(point) {
|
||
|
const cameraPos = this.ThreeObjs.camera.position.clone()
|
||
|
const targetPos = this.ThreeObjs.orbitControls.target.clone()
|
||
|
this.patrolTween = C3S3D.createTween({
|
||
|
start: {
|
||
|
cx: cameraPos.x,
|
||
|
cy: cameraPos.y,
|
||
|
cz: cameraPos.z,
|
||
|
tx: targetPos.x,
|
||
|
ty: targetPos.y,
|
||
|
tz: targetPos.z
|
||
|
},
|
||
|
to: {
|
||
|
cx: point.cx,
|
||
|
cy: point.cy,
|
||
|
cz: point.cz,
|
||
|
tx: point.tx,
|
||
|
ty: point.ty,
|
||
|
tz: point.tz
|
||
|
},
|
||
|
duration: point.time,
|
||
|
delayTime: 1,
|
||
|
onUpdate: (obj) => {
|
||
|
this.ThreeObjs.camera.position.set(obj.cx, obj.cy, obj.cz)
|
||
|
this.ThreeObjs.orbitControls.target.set(obj.tx, obj.ty, obj.tz)
|
||
|
},
|
||
|
onComplete: () => {
|
||
|
this.patrolTween = null
|
||
|
this.patrolIndex++
|
||
|
if (this.patrolIndex >= this.patrolPoints.length) {
|
||
|
this.moveSatate = true
|
||
|
this.$bus.$emit('animateState', true)
|
||
|
return
|
||
|
}
|
||
|
this.doPatrol(this.patrolPoints[this.patrolIndex])
|
||
|
},
|
||
|
easing: TWEEN.Easing.Linear.None
|
||
|
})
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
</script>
|
||
|
|
||
|
<style lang="scss">
|
||
|
@import "@/assets/stylesheet/index";
|
||
|
.ModelLoading {
|
||
|
width: 100%;
|
||
|
position: absolute;
|
||
|
height: 100%;
|
||
|
top: 0;
|
||
|
z-index: 1;
|
||
|
.el-loading-spinner {
|
||
|
position: fixed;
|
||
|
left: 50% !important;
|
||
|
transform: translateX(-50%) !important;
|
||
|
}
|
||
|
.el-loading-spinner .el-loading-text {
|
||
|
color: #28c4fe !important;
|
||
|
font-size: vw(32) !important;
|
||
|
}
|
||
|
.el-loading-spinner i {
|
||
|
color: #28c4fe !important;
|
||
|
font-size: vw(44) !important;
|
||
|
}
|
||
|
}
|
||
|
#modelContainers {
|
||
|
width: 100%;
|
||
|
height: 100%;
|
||
|
position: absolute;
|
||
|
top: 0;
|
||
|
overflow: hidden;
|
||
|
}
|
||
|
|
||
|
.control-box-baozha {
|
||
|
width: 300px;
|
||
|
/* height: 40px; */
|
||
|
}
|
||
|
.device {
|
||
|
width: 100%;
|
||
|
height: vw(80);
|
||
|
line-height: vw(80);
|
||
|
text-align: center;
|
||
|
}
|
||
|
.progress {
|
||
|
min-width: vw(300);
|
||
|
height: vw(120);
|
||
|
display: flex;
|
||
|
flex-flow: column;
|
||
|
align-items: center;
|
||
|
justify-content: center;
|
||
|
position: absolute;
|
||
|
top: 50%;
|
||
|
left: 50%;
|
||
|
border-radius: vw(10);
|
||
|
margin-top: vw(-60);
|
||
|
margin-left: vw(-200);
|
||
|
background: rgba(13, 159, 228, 0.2);
|
||
|
color: #fff;
|
||
|
padding: 0 vw(20);
|
||
|
span {
|
||
|
margin-top: vw(20);
|
||
|
}
|
||
|
}
|
||
|
/deep/ .el-progress {
|
||
|
width: vw(500) !important;
|
||
|
}
|
||
|
/deep/ .el-progress-bar {
|
||
|
padding-right: 0px;
|
||
|
}
|
||
|
/deep/ .el-progress__text {
|
||
|
display: none;
|
||
|
}
|
||
|
</style>
|