123
parent
ff2ae358d9
commit
d1e8f0b9a5
|
@ -17,6 +17,7 @@
|
|||
"dependencies": {
|
||||
"@element-plus/icons-vue": "2.0.10",
|
||||
"@jiaminghi/data-view": "^2.10.0",
|
||||
"@tweenjs/tween.js": "^21.0.0",
|
||||
"@vueup/vue-quill": "1.2.0",
|
||||
"@vueuse/core": "9.5.0",
|
||||
"axios": "0.27.2",
|
||||
|
@ -31,7 +32,12 @@
|
|||
"jsencrypt": "3.3.1",
|
||||
"nprogress": "0.2.0",
|
||||
"pinia": "2.0.22",
|
||||
"three": "^0.134.0",
|
||||
"three": "^0.146.0",
|
||||
"three-css2drender": "^1.0.0",
|
||||
"three-gltf-loader-wtower": "^1.112.2",
|
||||
"three-obj-mtl-loader": "^1.0.3",
|
||||
"three-orbit-controls": "^82.1.0",
|
||||
"three-orbitcontrols_liuyipeng": "^2.110.3",
|
||||
"troisjs": "^0.3.4",
|
||||
"vue": "3.2.45",
|
||||
"vue-cropper": "1.0.3",
|
||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -30622,8 +30622,8 @@
|
|||
function nf(e, t, n) {
|
||||
for (const i in n.extensions)
|
||||
void 0 === e[i] &&
|
||||
((t.userData.gltfExtensions = t.userData.gltfExtensions || {}),
|
||||
(t.userData.gltfExtensions[i] = n.extensions[i]));
|
||||
((t.userDatscene.gltfExtensions = t.userDatscene.gltfExtensions || {}),
|
||||
(t.userDatscene.gltfExtensions[i] = n.extensions[i]));
|
||||
}
|
||||
function rf(e, t) {
|
||||
void 0 !== t.extras &&
|
||||
|
|
|
@ -39,7 +39,7 @@ const data = reactive({
|
|||
{
|
||||
label: '原料糖化车间',
|
||||
id: '0',
|
||||
url: '/jz/glb/jz.gltf',
|
||||
url: '/jz/glb/scene.gltf',
|
||||
info: {
|
||||
name: '原料糖化车间',
|
||||
area: '9436 ㎡',
|
||||
|
@ -72,8 +72,16 @@ const data = reactive({
|
|||
{
|
||||
label: '原料糖化车间一',
|
||||
id: '0-1',
|
||||
url: '/jz/glb/jz.gltf',
|
||||
children: [],
|
||||
url: '/jz/glb/scene.gltf',
|
||||
children: [{
|
||||
label: '罐子1',
|
||||
id: '0-0-1',
|
||||
children:[]
|
||||
},{
|
||||
label: '罐子2',
|
||||
id: '0-0-2',
|
||||
children:[]
|
||||
}],
|
||||
info: {
|
||||
name: '原料糖化车间一',
|
||||
area: '5200 ㎡',
|
||||
|
@ -107,7 +115,7 @@ const data = reactive({
|
|||
{
|
||||
label: '原料糖化车间二',
|
||||
id: '0-2',
|
||||
url: '/jz/glb/jz.gltf',
|
||||
url: '/jz/glb/scene.gltf',
|
||||
children: [],
|
||||
info: {
|
||||
name: '原料糖化车间二',
|
||||
|
|
|
@ -48,7 +48,7 @@ const data = reactive({
|
|||
{
|
||||
label: '原料糖化车间',
|
||||
id: '0',
|
||||
url: '/jz/glb/jz.gltf',
|
||||
url: '/jz/glb/scene.gltf',
|
||||
info: {
|
||||
name: '原料糖化车间',
|
||||
area: '9436 ㎡',
|
||||
|
@ -132,7 +132,7 @@ const data = reactive({
|
|||
{
|
||||
label: '原料糖化车间二',
|
||||
id: '0-2',
|
||||
url: '/jz/glb/jz.gltf',
|
||||
url: '/jz/glb/scene.gltf',
|
||||
children: [],
|
||||
info: {
|
||||
name: '原料糖化车间二',
|
||||
|
|
|
@ -41,7 +41,7 @@ const data = reactive({
|
|||
{
|
||||
label: '立仓',
|
||||
id: '0-1',
|
||||
url: '/jz/glb/jz.gltf',
|
||||
url: '/jz/glb/scene.gltf',
|
||||
info: {
|
||||
name: '立仓',
|
||||
type: '生产设备',
|
||||
|
|
|
@ -0,0 +1,377 @@
|
|||
<template>
|
||||
<div class="container">
|
||||
<div id="model"></div>
|
||||
<button
|
||||
id="btns"
|
||||
:style="{ cursor: isDisabled ? '' : 'pointer' }"
|
||||
:disabled="isDisabled"
|
||||
type="isDisabled:"
|
||||
@click="toHomeView(1)"
|
||||
>
|
||||
主视角
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import * as THREE from "three";
|
||||
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
|
||||
|
||||
import { EffectComposer } from "three/examples/jsm/postprocessing/EffectComposer.js";
|
||||
import { RenderPass } from "three/examples/jsm/postprocessing/RenderPass.js";
|
||||
import { OutlinePass } from "three/examples/jsm/postprocessing/OutlinePass.js";
|
||||
import TWEEN from "@tweenjs/tween.js";
|
||||
export default {
|
||||
name: "ThreeModel",
|
||||
data() {
|
||||
return {
|
||||
isDisabled: true,
|
||||
scene: null,
|
||||
renderer: null,
|
||||
controls: null,
|
||||
light: null,
|
||||
light2: null,
|
||||
group: new THREE.Group(),
|
||||
composer: null, // 控制发光
|
||||
outlinePass: null,
|
||||
renderPass: null,
|
||||
// 选中的模型
|
||||
selectedObjects: [],
|
||||
mouse: new THREE.Vector2(),
|
||||
raycaster: new THREE.Raycaster(),
|
||||
tween: null,
|
||||
//定义模型架子的长度
|
||||
long: 100,
|
||||
//定义模型架子的宽度
|
||||
tall: 24,
|
||||
//定义模型架子横纵板的宽度
|
||||
thickness: 0.4,
|
||||
positionObj: null,
|
||||
};
|
||||
},
|
||||
computed: {},
|
||||
watch: {},
|
||||
created() {},
|
||||
mounted() {
|
||||
this.init();
|
||||
},
|
||||
methods: {
|
||||
//创建模型视图
|
||||
initScene() {
|
||||
this.scene = new THREE.Scene();
|
||||
},
|
||||
//初始化相机
|
||||
initCamera() {
|
||||
const { long, tall } = this;
|
||||
this.camera = new THREE.PerspectiveCamera(
|
||||
45,
|
||||
window.innerWidth / window.innerHeight,
|
||||
0.1,
|
||||
50000
|
||||
);
|
||||
|
||||
this.camera.position.set(0, -(5 * tall) / 12, (6 * long) / 5);
|
||||
},
|
||||
//初始化灯光
|
||||
initLight() {
|
||||
let ambientLight = new THREE.AmbientLight(0x404040);
|
||||
this.scene.add(ambientLight);
|
||||
this.light = new THREE.DirectionalLight(0x333333);
|
||||
this.light.position.set(60, 30, 40);
|
||||
this.light2 = new THREE.DirectionalLight(0xdddddd);
|
||||
this.light2.position.set(-20, 20, -20);
|
||||
this.scene.add(this.light);
|
||||
this.scene.add(this.light2);
|
||||
},
|
||||
//加载渲染器
|
||||
initRender() {
|
||||
//dom元素渲染器
|
||||
this.renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
|
||||
this.renderer.setSize(window.innerWidth, window.innerHeight); // 设置渲染区域尺寸
|
||||
this.renderer.setClearColor(0x000000, 0); // 设置背景颜色
|
||||
//window.devicePixelRatio 当前设备的物理分辨率与css分辨率之比
|
||||
this.renderer.setPixelRatio(window.devicePixelRatio);
|
||||
//按层级先后渲染
|
||||
this.renderer.sortObjects = true;
|
||||
document.getElementById("model").appendChild(this.renderer.domElement);
|
||||
},
|
||||
//创建载入模型
|
||||
initModel() {
|
||||
const { long, tall, thickness } = this;
|
||||
//坐标系
|
||||
// let axes = new THREE.AxesHelper(4000);
|
||||
// this.scene.add(axes);
|
||||
|
||||
//所有横板
|
||||
for (let index = 1; index <= tall / 4 - 1; index++) {
|
||||
let geometry = new THREE.BoxGeometry(long, thickness, 12);
|
||||
let material = new THREE.MeshLambertMaterial({
|
||||
color: 0x808080,
|
||||
opacity: 0.7,
|
||||
transparent: true,
|
||||
}); //材质对象Material
|
||||
let mesh = new THREE.Mesh(geometry, material); //网格模型对象Mesh
|
||||
mesh.position.set(0, index * 4, 0); //设置mesh3模型对象的xyz坐标为120,0,0
|
||||
this.scene.add(mesh); //网格模型添加到场景中
|
||||
}
|
||||
//所有纵板
|
||||
for (let index = 1; index <= long / 4 + 1; index++) {
|
||||
let geometry = new THREE.BoxGeometry(thickness, tall, 12);
|
||||
let material = new THREE.MeshLambertMaterial({
|
||||
color: 0x808080,
|
||||
opacity: 0.7,
|
||||
transparent: true,
|
||||
}); //材质对象Material
|
||||
let mesh = new THREE.Mesh(geometry, material); //网格模型对象Mesh
|
||||
mesh.position.set(-long / 2 + (index - 1) * 4, tall / 2, 0); //设置mesh3模型对象的xyz坐标为120,0,0
|
||||
this.scene.add(mesh); //网格模型添加到场景中
|
||||
}
|
||||
//正面所有箱子
|
||||
let list1 = new Array(tall / 4);
|
||||
for (let i = 0; i < list1.length; i++) {
|
||||
list1[i] = new Array(long / 4);
|
||||
//不一定写for循环赋值,还可以直接赋值,在数量有限的情况下
|
||||
for (let j = 0; j < long / 4; j++) {
|
||||
// a[i][j] = i + j;
|
||||
let geometry = new THREE.BoxGeometry(3, 3, 5);
|
||||
let material = new THREE.MeshLambertMaterial({
|
||||
color: 0x00b1f7,
|
||||
opacity: 0.4,
|
||||
transparent: true,
|
||||
});
|
||||
let mesh = new THREE.Mesh(geometry, material);
|
||||
mesh.name = i + 1 + "-" + (j + 1);
|
||||
mesh.position.set(-long / 2 + j * 4 + 2, i * 4 + 2, 3);
|
||||
this.scene.add(mesh);
|
||||
}
|
||||
}
|
||||
//背面所有箱子
|
||||
let list2 = new Array(tall / 4);
|
||||
for (let i = 0; i < list2.length; i++) {
|
||||
list2[i] = new Array(long / 4);
|
||||
//不一定写for循环赋值,还可以直接赋值,在数量有限的情况下
|
||||
for (let j = 0; j < long / 4; j++) {
|
||||
// a[i][j] = i + j;
|
||||
let geometry = new THREE.BoxGeometry(3, 3, 5);
|
||||
let material = new THREE.MeshLambertMaterial({
|
||||
color: 0x00b1f7,
|
||||
opacity: 0.4,
|
||||
transparent: true,
|
||||
});
|
||||
let mesh = new THREE.Mesh(geometry, material);
|
||||
|
||||
mesh.name = "-" + (i + 1) + "-" + (j + 1);
|
||||
mesh.position.set(-long / 2 + j * 4 + 2, i * 4 + 2, -3);
|
||||
this.scene.add(mesh);
|
||||
}
|
||||
}
|
||||
},
|
||||
//高亮显示模型(呼吸灯)
|
||||
outlineObj(selectedObjects) {
|
||||
// 创建一个EffectComposer(效果组合器)对象,然后在该对象上添加后期处理通道。
|
||||
this.composer = new EffectComposer(this.renderer);
|
||||
// 新建一个场景通道 为了覆盖到原理来的场景上
|
||||
this.renderPass = new RenderPass(this.scene, this.camera);
|
||||
this.composer.addPass(this.renderPass);
|
||||
// 物体边缘发光通道
|
||||
this.outlinePass = new OutlinePass(
|
||||
new THREE.Vector2(window.innerWidth, window.innerHeight),
|
||||
this.scene,
|
||||
this.camera,
|
||||
selectedObjects
|
||||
);
|
||||
this.outlinePass.edgeStrength = 8.0; // 高光边缘边框的亮度
|
||||
this.outlinePass.edgeGlow = 1; // 光晕[0,1] 边缘微光强度
|
||||
this.outlinePass.usePatternTexture = false; // 是否使用父级的材质,纹理覆盖
|
||||
this.outlinePass.edgeThickness = 3; // 边框宽度,高光厚度
|
||||
this.outlinePass.downSampleRatio = 1; // 边框弯曲度
|
||||
this.outlinePass.pulsePeriod = 2; // 呼吸闪烁的速度,数值越大,律动越慢
|
||||
this.outlinePass.visibleEdgeColor.set(parseInt(0x00f6ff)); // 呼吸显示的颜色
|
||||
this.outlinePass.hiddenEdgeColor = new THREE.Color(0, 0, 0); // 呼吸消失的颜色
|
||||
// this.outlinePass.clear = true
|
||||
this.composer.addPass(this.outlinePass); // 加入高光特效
|
||||
this.outlinePass.selectedObjects = selectedObjects; // 需要高光的模型
|
||||
},
|
||||
// 鼠标点击模型
|
||||
onMouseClick(event) {
|
||||
//通过鼠标点击的位置计算出raycaster所需要的点的位置,以屏幕中心为原点,值的范围为-1到1
|
||||
this.mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
|
||||
this.mouse.y = -(event.clientY / (window.innerHeight - 50)) * 2 + 1;
|
||||
// 通过鼠标点的位置和当前相机的矩阵计算出raycaster
|
||||
this.raycaster.setFromCamera(this.mouse, this.camera);
|
||||
// 获取raycaster直线和所有模型相交的数组集合
|
||||
let intersects = this.raycaster.intersectObjects(this.scene.children);
|
||||
if (!intersects[0]) {
|
||||
return;
|
||||
} else {
|
||||
if (!intersects[0].object.name == "") {
|
||||
this.selectedObjects = [];
|
||||
this.selectedObjects.push(intersects[0].object);
|
||||
this.outlineObj(this.selectedObjects);
|
||||
this.positionObj = {
|
||||
x: intersects[0].object.position.x,
|
||||
y: intersects[0].object.position.y,
|
||||
z: intersects[0].object.position.z,
|
||||
};
|
||||
|
||||
this.initTween(
|
||||
this.positionObj.x,
|
||||
this.positionObj.y,
|
||||
this.positionObj.z
|
||||
);
|
||||
this.isDisabled = false;
|
||||
|
||||
this.controls.autoRotate = false;
|
||||
}
|
||||
}
|
||||
},
|
||||
// 相机移动动画
|
||||
initTween(targetX, targetY, targetZ) {
|
||||
// 需要保留this
|
||||
let initPosition = {
|
||||
x: this.camera.position.x,
|
||||
y: this.camera.position.y,
|
||||
z: this.camera.position.z,
|
||||
};
|
||||
let tween = new TWEEN.Tween(initPosition)
|
||||
.to({ x: targetX, y: targetY, z: targetZ }, 2000)
|
||||
.easing(TWEEN.Easing.Sinusoidal.InOut);
|
||||
let onUpdate = (pos) => {
|
||||
let x = pos.x;
|
||||
let y = pos.y;
|
||||
let z = pos.z;
|
||||
if (pos.z < 0) {
|
||||
this.camera.position.set(x, y, z - 12);
|
||||
} else {
|
||||
this.camera.position.set(x, y, z + 12);
|
||||
}
|
||||
};
|
||||
tween.onUpdate(onUpdate);
|
||||
tween.start();
|
||||
// this.controls.target.set(0, 0, 0);
|
||||
if (this.positionObj.z < 0) {
|
||||
this.controls.target.set(
|
||||
this.positionObj.x,
|
||||
this.positionObj.y - 0.4,
|
||||
-12
|
||||
);
|
||||
} else {
|
||||
this.controls.target.set(
|
||||
this.positionObj.x,
|
||||
this.positionObj.y - 0.4,
|
||||
12
|
||||
);
|
||||
}
|
||||
},
|
||||
toHomeView(id) {
|
||||
const { long, tall } = this;
|
||||
if (id === 1) {
|
||||
let initPosition = {
|
||||
x: this.camera.position.x,
|
||||
y: this.camera.position.y,
|
||||
z: this.camera.position.z,
|
||||
};
|
||||
let tween = new TWEEN.Tween(initPosition)
|
||||
.to({ x: 0, y: -(5 * tall) / 12, z: (6 * long) / 5 }, 2000)
|
||||
.easing(TWEEN.Easing.Sinusoidal.InOut);
|
||||
let onUpdate = (pos) => {
|
||||
let x = pos.x;
|
||||
let y = pos.y;
|
||||
let z = pos.z;
|
||||
this.camera.position.set(x, y, z);
|
||||
};
|
||||
tween.onUpdate(onUpdate);
|
||||
tween.start();
|
||||
this.controls.target.set(0, 0, 0);
|
||||
this.isDisabled = true;
|
||||
this.controls.autoRotate = true;
|
||||
}
|
||||
},
|
||||
//根据浏览器窗口自适应
|
||||
onWindowResize() {
|
||||
this.renderer.setSize(window.innerWidth, window.innerHeight);
|
||||
this.camera.aspect = window.innerWidth / window.innerHeight;
|
||||
this.camera.updateProjectionMatrix();
|
||||
},
|
||||
//使用OrbitControls控制三维场景缩放和旋转等功能
|
||||
initControls() {
|
||||
this.controls = new OrbitControls(this.camera, this.renderer.domElement);
|
||||
//动态阻尼系数 即鼠标拖拽旋转的灵敏度
|
||||
this.controls.dampingFactor = 0.25;
|
||||
// this.controls.target.set(0, 900, 0)
|
||||
// //上下旋转范围
|
||||
this.controls.minPolarAngle = 0;
|
||||
this.controls.maxPolarAngle = 1.5;
|
||||
this.controls.autoRotate = true;
|
||||
//惯性滑动,滑动大小默认0.25
|
||||
this.controls.dampingFactor = 0.25;
|
||||
//滚轮是否可控制zoom,zoom速度默认1
|
||||
//缩放倍数
|
||||
this.controls.zoomSpeed = 1.0;
|
||||
//最大最小相机移动距离(景深相机)
|
||||
this.controls.minDistance = 1;
|
||||
this.controls.maxDistance = Infinity;
|
||||
//水平方向视角限制
|
||||
this.minAzimuthAngle = -Math.PI * 2;
|
||||
this.maxAzimuthAngle = Math.PI * 2;
|
||||
this.controls.enabledPan = true;
|
||||
this.keyPanSpeed = 7.0;
|
||||
},
|
||||
//运行动画
|
||||
animate() {
|
||||
TWEEN.update();
|
||||
this.renderer.render(this.scene, this.camera);
|
||||
this.controls.update();
|
||||
if (this.composer) {
|
||||
this.composer.render();
|
||||
}
|
||||
requestAnimationFrame(this.animate);
|
||||
},
|
||||
//初始化函数,页面加载完成是调用
|
||||
init() {
|
||||
this.initScene();
|
||||
this.initCamera();
|
||||
this.initLight();
|
||||
this.initRender();
|
||||
this.initModel();
|
||||
this.initControls();
|
||||
this.animate();
|
||||
window.onresize = this.onWindowResize;
|
||||
window.onclick = this.onMouseClick;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
}
|
||||
#btns {
|
||||
position: absolute;
|
||||
background-color: #031b34;
|
||||
bottom: 0;
|
||||
left: 50%;
|
||||
width: 80px;
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
transform: translate(-50%, -50%);
|
||||
text-align: center;
|
||||
z-index: 9999;
|
||||
color: #00eeff;
|
||||
font-weight: bold;
|
||||
box-shadow: 0px 0px 2px 1px #00f6ff;
|
||||
border-radius: 6px;
|
||||
border: 1px solid #00f6ff;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/*模型样式*/
|
||||
#model {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
</style>
|
|
@ -1,5 +1,11 @@
|
|||
<template>
|
||||
<canvas id="three"></canvas>
|
||||
<div>
|
||||
<canvas id="three"></canvas>
|
||||
<div class="button" @click="toHomeView">
|
||||
主视角
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</template>
|
||||
<script setup>
|
||||
import * as THREE from "three";
|
||||
|
@ -14,16 +20,20 @@ import {
|
|||
} from "three/examples/jsm/renderers/CSS2DRenderer";
|
||||
// import renderModel from "../renderModel";
|
||||
import homeIcon from '@/assets/image/bg7.jpg'
|
||||
import TWEEN from "@tweenjs/tween.js";
|
||||
|
||||
let scene = ref(null);
|
||||
let renderer = ref(null);
|
||||
let camera = ref(null);
|
||||
// 控制器
|
||||
let orbit = ref(null);
|
||||
let group = ref(null);
|
||||
let mouse = new THREE.Vector2();
|
||||
let raycaster = new THREE.Raycaster();
|
||||
let labelRenderer = new CSS2DRenderer(); //新建CSS2DRenderer
|
||||
// let originalColors = ref([]);
|
||||
let positionObj = ref(null);
|
||||
// 选中的模型
|
||||
let selectedObjects = ref([]);
|
||||
|
||||
const props = defineProps({
|
||||
background: { // 背景颜色
|
||||
|
@ -31,7 +41,7 @@ const props = defineProps({
|
|||
type: String
|
||||
},
|
||||
sceneUrl: { // 模型路径
|
||||
default: '/jz/glb/jz.gltf',
|
||||
default: '/jz/glb/scene.gltf',
|
||||
type: String
|
||||
},
|
||||
light: {
|
||||
|
@ -71,17 +81,11 @@ const init = () => {
|
|||
renderer.shadowMap.enabled = true;
|
||||
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
|
||||
|
||||
camera = new THREE.PerspectiveCamera(
|
||||
55,
|
||||
window.innerWidth / window.innerHeight,
|
||||
0.1,
|
||||
20000
|
||||
);
|
||||
camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 0.25, 2000)
|
||||
// 将摄像机对准场景的中心
|
||||
camera.position.x = 100;
|
||||
camera.position.y = 80;
|
||||
camera.position.z = -150;
|
||||
camera.lookAt(scene.position);
|
||||
camera.position.set(0, 0, 50);
|
||||
// camera.lookAt(scene.position);
|
||||
|
||||
// 创建控件对象
|
||||
orbit = new OrbitControls(camera, renderer.domElement);
|
||||
orbit.autoRotate = true;
|
||||
|
@ -113,33 +117,42 @@ const renderScene = () => {
|
|||
// 写在requestAnimationFrame之后,否则会报错
|
||||
labelRenderer.render(scene, camera);
|
||||
};
|
||||
|
||||
const modelMouseClick = (event) => {
|
||||
if (event.button != 0) return;
|
||||
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
|
||||
mouse.y = - (event.clientY / window.innerHeight) * 2 + 1;
|
||||
const raycaster = new THREE.Raycaster();
|
||||
raycaster.setFromCamera(mouse, camera);
|
||||
var intersects = raycaster.intersectObjects(scene.children);
|
||||
// 恢复其他物体的颜色
|
||||
if (originalColors && originalColors.length > 0) {
|
||||
for (var i = 0; i < originalColors.length; i++) {
|
||||
originalColors[i].object.material.color.set(originalColors[i].color);
|
||||
}
|
||||
// 相机移动动画
|
||||
const initTween = (targetX, targetY, targetZ) => {
|
||||
let initPosition = {
|
||||
x: camera.position.x,
|
||||
y: camera.position.y,
|
||||
z: camera.position.z,
|
||||
};
|
||||
let tween = new TWEEN.Tween(initPosition)
|
||||
.to({ x: targetX, y: targetY, z: targetZ }, 2000)
|
||||
.easing(TWEEN.Easing.Sinusoidal.InOut);
|
||||
let onUpdate = (pos) => {
|
||||
let x = pos.x;
|
||||
let y = pos.y;
|
||||
let z = pos.z;
|
||||
if (pos.z < 0) {
|
||||
camera.position.set(x, y, z - 12);
|
||||
} else {
|
||||
camera.position.set(x, y, z + 12);
|
||||
}
|
||||
// 清空原始颜色数组
|
||||
var originalColors = [];
|
||||
// 如果有交点,改变其材质颜色并记录其他物体的颜色
|
||||
if (intersects.length > 0) {
|
||||
intersects[0].object.material.color.set(0xff0000);
|
||||
// 设置选中物体的颜色
|
||||
scene.traverse((object) => {
|
||||
if (object.isMesh && object !== intersects[0].object) {
|
||||
originalColors.push({ object: object, color: object.material.color.clone() });
|
||||
}
|
||||
});
|
||||
};
|
||||
tween.onUpdate(onUpdate);
|
||||
tween.start();
|
||||
if (positionObj.z < 0) {
|
||||
orbit.target.set(
|
||||
positionObj.x,
|
||||
positionObj.y - 0.4,
|
||||
-12
|
||||
);
|
||||
} else {
|
||||
orbit.target.set(
|
||||
positionObj.x,
|
||||
positionObj.y - 0.4,
|
||||
12
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// 储存被选中的模型和材质
|
||||
let selectedObject = null;
|
||||
|
@ -171,6 +184,46 @@ const onMouseDown = (event) => {
|
|||
// 修改材质为绿色
|
||||
selectedObject.material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
|
||||
}
|
||||
// 拉近场景
|
||||
if (!intersects[0]) {
|
||||
return;
|
||||
} else {
|
||||
|
||||
if (intersects[0].object.name.indexOf('box') > -1) {
|
||||
selectedObjects = [];
|
||||
selectedObjects.push(intersects[0].object);
|
||||
positionObj = {
|
||||
x: intersects[0].object.position.x,
|
||||
y: intersects[0].object.position.y,
|
||||
z: intersects[0].object.position.z,
|
||||
};
|
||||
|
||||
initTween(
|
||||
positionObj.x,
|
||||
positionObj.y,
|
||||
positionObj.z
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
const toHomeView = () => {
|
||||
let initPosition = {
|
||||
x: camera.position.x,
|
||||
y: camera.position.y,
|
||||
z: camera.position.z,
|
||||
};
|
||||
let tween = new TWEEN.Tween(initPosition)
|
||||
.to({ x: 0, y: -(5 * 24) / 12, z: (6 * 100) / 5 }, 2000)
|
||||
.easing(TWEEN.Easing.Sinusoidal.InOut);
|
||||
let onUpdate = (pos) => {
|
||||
let x = pos.x;
|
||||
let y = pos.y;
|
||||
let z = pos.z;
|
||||
camera.position.set(x, y, z);
|
||||
};
|
||||
tween.onUpdate(onUpdate);
|
||||
tween.start();
|
||||
orbit.target.set(0, 0, 0);
|
||||
}
|
||||
</script>
|
||||
<style lang='scss' scoped>
|
||||
|
@ -178,4 +231,18 @@ const onMouseDown = (event) => {
|
|||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
.button {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
line-height: 80px;
|
||||
border-radius: 50%;
|
||||
border: 1px solid rgb(7, 207, 221);
|
||||
position: absolute;
|
||||
z-index: 1000000;
|
||||
bottom: 15px;
|
||||
left: 10px;
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
background: rgb(7, 207, 221);
|
||||
}
|
||||
</style>
|
|
@ -2,6 +2,7 @@
|
|||
<div class="app-container">
|
||||
<!-- 场景模型 -->
|
||||
<ThreeView background="#353535" light="0xffffff" :sceneUrl="sceneUrl" v-if="sceneUrl !== ''"></ThreeView>
|
||||
<!-- <ThreeModel /> -->
|
||||
<!-- 底部菜单 -->
|
||||
<MenuTab @changeMenu="changeMenu"></MenuTab>
|
||||
<!-- 左侧建筑菜单 -->
|
||||
|
@ -48,6 +49,7 @@ import ApplicationTree from './components/ApplicationTree.vue';
|
|||
import EquipmentInfo from './components/EquipmentInfo.vue';
|
||||
import RealData from './components/RealData.vue';
|
||||
import ThreeView from './components/ThreeView.vue';
|
||||
// import ThreeModel from './components/ThreeModel.vue';
|
||||
import DeviceInfoDialog from './components/DeviceInfoDialog.vue';
|
||||
import RealInfoDialog from './components/RealInfoDialog.vue';
|
||||
import DeviceDetial from './components/DeviceDetial.vue';
|
||||
|
|
|
@ -54,7 +54,7 @@ import {
|
|||
const renderer = ref(null);
|
||||
|
||||
const data = reactive({
|
||||
bimUrl: '/jz/glb/jz.gltf'
|
||||
bimUrl: '/jz/glb/scene.gltf'
|
||||
});
|
||||
|
||||
const { bimUrl } = toRefs(data);
|
||||
|
|
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue