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

<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>