添加标签
parent
14b51f2e43
commit
59bbb8358c
|
@ -48,6 +48,7 @@ const data = reactive({
|
||||||
type: '生产设备',
|
type: '生产设备',
|
||||||
status: '启用'
|
status: '启用'
|
||||||
},
|
},
|
||||||
|
children: []
|
||||||
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -59,6 +60,7 @@ const data = reactive({
|
||||||
type: '生产设备',
|
type: '生产设备',
|
||||||
status: '启用'
|
status: '启用'
|
||||||
},
|
},
|
||||||
|
children: []
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '设备三',
|
label: '设备三',
|
||||||
|
@ -69,6 +71,7 @@ const data = reactive({
|
||||||
type: '空调设备',
|
type: '空调设备',
|
||||||
status: '启用'
|
status: '启用'
|
||||||
},
|
},
|
||||||
|
children: []
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '设备四',
|
label: '设备四',
|
||||||
|
@ -79,6 +82,7 @@ const data = reactive({
|
||||||
type: '安防设备',
|
type: '安防设备',
|
||||||
status: '启用'
|
status: '启用'
|
||||||
},
|
},
|
||||||
|
children: []
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
@ -89,15 +93,16 @@ const { deviceValue, treeData, checkedkeys } = toRefs(data);
|
||||||
const emit = defineEmits(['handleNodeClick'])
|
const emit = defineEmits(['handleNodeClick'])
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
checkedkeys.value = treeData.value[0].children[0].id;
|
checkedkeys.value = treeData.value[0].id;
|
||||||
handleNodeClick(treeData.value[0].children[0]);
|
handleNodeClick(treeData.value[0]);
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
const handleNodeClick = (value) => {
|
const handleNodeClick = (value) => {
|
||||||
bimStore().setActivateDeviceTree(value);
|
bimStore().setActivateDeviceTree(value);
|
||||||
emit('handleNodeClick', value);
|
const isParent = value.children.length > 0;
|
||||||
|
emit('handleNodeClick', value, isParent);
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
Bus.emit('clickDevice');
|
Bus.emit('clickDevice', isParent);
|
||||||
}, 100)
|
}, 100)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,18 @@
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<canvas id="three"></canvas>
|
<canvas id="three"></canvas>
|
||||||
|
<div class="btnGroup">
|
||||||
<div class="button" @click="toHomeView">
|
<div class="button" @click="toHomeView">
|
||||||
主视角
|
主视角
|
||||||
</div>
|
</div>
|
||||||
|
<div class="button" @click="setLabel">
|
||||||
|
{{ isAddLabel ? '添加标签' : '移除标签' }}
|
||||||
|
</div>
|
||||||
|
<div class="button" @click="walk">
|
||||||
|
漫游
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="dom"></div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script setup>
|
<script setup>
|
||||||
|
@ -13,6 +22,12 @@ import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
|
||||||
// 引入轨道控制器:支持鼠标左中右键操作和键盘方向键操作
|
// 引入轨道控制器:支持鼠标左中右键操作和键盘方向键操作
|
||||||
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
|
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
|
||||||
import { OBJLoader } from "three/examples/jsm/loaders/OBJLoader";
|
import { OBJLoader } from "three/examples/jsm/loaders/OBJLoader";
|
||||||
|
// 引入轨道控制器:支持鼠标左中右键操作和键盘方向键操作
|
||||||
|
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 { ShaderPass } from "three/examples/jsm/postprocessing/ShaderPass.js";
|
||||||
|
import { FXAAShader } from "three/examples/jsm/shaders/FXAAShader.js";
|
||||||
import {
|
import {
|
||||||
CSS2DObject,
|
CSS2DObject,
|
||||||
CSS2DRenderer,
|
CSS2DRenderer,
|
||||||
|
@ -51,9 +66,11 @@ const props = defineProps({
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
const data = reactive({
|
const data = reactive({
|
||||||
gltfObj: null
|
gltfObj: null,
|
||||||
|
btnLabelName: '添加标签',
|
||||||
|
isAddLabel: true
|
||||||
});
|
});
|
||||||
const { gltfObj } = toRefs(data);
|
const { gltfObj, isAddLabel } = toRefs(data);
|
||||||
|
|
||||||
watch(() => props.sceneUrl, val => {
|
watch(() => props.sceneUrl, val => {
|
||||||
init();
|
init();
|
||||||
|
@ -67,21 +84,33 @@ Bus.on('clickBuild', (isParent) => {
|
||||||
console.log('clickBuild', isParent);
|
console.log('clickBuild', isParent);
|
||||||
if (!isParent) {// 点击子级
|
if (!isParent) {// 点击子级
|
||||||
var clickName = bimStore().activateTree.clickName;
|
var clickName = bimStore().activateTree.clickName;
|
||||||
cleanColor();
|
// cleanColor();
|
||||||
var Floor = gltfObj.value.scene.getObjectByName(clickName);
|
var Floor = gltfObj.value.scene.getObjectByName(clickName);
|
||||||
|
// 染色
|
||||||
Floor.traverse(e => {
|
// Floor.traverse(e => {
|
||||||
e.material = new THREE.MeshLambertMaterial({
|
// e.material = new THREE.MeshLambertMaterial({
|
||||||
color: 0x00ff00,
|
// color: 0x00ff00,
|
||||||
});
|
// });
|
||||||
})
|
// })
|
||||||
|
// 高亮轮廓
|
||||||
|
outlineObj([Floor]);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
// 父级
|
||||||
|
toHomeView();
|
||||||
})
|
})
|
||||||
// 设备树点击
|
// 设备树点击
|
||||||
Bus.on('clickDevice', e => {
|
Bus.on('clickDevice', (isParent) => {
|
||||||
// Todo
|
if (!isParent) {// 点击子级
|
||||||
console.log('clickDevice');
|
var clickName = bimStore().activateDevice.clickName;
|
||||||
|
var Floor = gltfObj.value.scene.getObjectByName(clickName);
|
||||||
|
console.log(1, Floor);
|
||||||
|
// 高亮轮廓
|
||||||
|
outlineObj([Floor])
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 父级
|
||||||
|
toHomeView();
|
||||||
})
|
})
|
||||||
|
|
||||||
// 系统树点击
|
// 系统树点击
|
||||||
|
@ -96,8 +125,47 @@ onMounted(() => {
|
||||||
// 启动动画
|
// 启动动画
|
||||||
renderScene();
|
renderScene();
|
||||||
document.addEventListener("click", onMouseDown);
|
document.addEventListener("click", onMouseDown);
|
||||||
|
document.addEventListener("mousemove", onMouseDown);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
const setLabel = () => {
|
||||||
|
if(isAddLabel.value) {
|
||||||
|
addLabel();
|
||||||
|
} else {
|
||||||
|
removeLabel();
|
||||||
|
}
|
||||||
|
isAddLabel.value = !isAddLabel.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
const removeLabel = () => {
|
||||||
|
document.body.removeChild(labelRenderer.domElement);
|
||||||
|
}
|
||||||
|
// 添加标签
|
||||||
|
|
||||||
|
const addLabel = () => {
|
||||||
|
let obj = gltfObj.value.scene.getObjectByName('set2');
|
||||||
|
let text = "设备二";
|
||||||
|
let pointLabel = createLableObj(text);
|
||||||
|
obj.add(pointLabel);
|
||||||
|
labelRenderer.setSize(window.innerWidth, window.innerHeight);
|
||||||
|
labelRenderer.domElement.style.position = "absolute";
|
||||||
|
labelRenderer.domElement.style.top = 0;
|
||||||
|
labelRenderer.domElement.style.pointerEvents = 'none';// 必须加上
|
||||||
|
document.body.appendChild(labelRenderer.domElement);
|
||||||
|
|
||||||
|
// 将呈现器的输出添加到HTML元素
|
||||||
|
document.getElementById("dom").appendChild(renderer.domElement);
|
||||||
|
};
|
||||||
|
|
||||||
|
const createLableObj = (text) => {
|
||||||
|
let laberDiv = document.createElement("div"); //创建div容器
|
||||||
|
laberDiv.className = "laber_name";
|
||||||
|
laberDiv.innerHTML = `<div class="arrow_outer"></div><span>设备名称:${text}</span><span>状态:启用</span><span>压力:50 Pa</span>`
|
||||||
|
let pointLabel = new CSS2DObject(laberDiv);
|
||||||
|
return pointLabel;
|
||||||
|
};
|
||||||
|
// 清除模型颜色
|
||||||
const cleanColor = () => {
|
const cleanColor = () => {
|
||||||
|
|
||||||
// 恢复之前被选中模型的材质
|
// 恢复之前被选中模型的材质
|
||||||
|
@ -122,7 +190,7 @@ const init = () => {
|
||||||
// scene.environment = texture
|
// scene.environment = texture
|
||||||
|
|
||||||
scene = new THREE.Scene();
|
scene = new THREE.Scene();
|
||||||
console.log(123,props.background);
|
console.log(123, props.background);
|
||||||
scene.background = new THREE.Color(props.background);
|
scene.background = new THREE.Color(props.background);
|
||||||
const canvas = document.querySelector("#three");
|
const canvas = document.querySelector("#three");
|
||||||
var cubeLoader = new THREE.CubeTextureLoader();
|
var cubeLoader = new THREE.CubeTextureLoader();
|
||||||
|
@ -163,12 +231,15 @@ const loadSence = () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const renderScene = () => {
|
const renderScene = () => {
|
||||||
orbit.update(); // 拖动
|
// orbit.update(); // 拖动
|
||||||
// 使用requestAnimationFrame函数进行渲染
|
// 使用requestAnimationFrame函数进行渲染
|
||||||
requestAnimationFrame(renderScene);
|
requestAnimationFrame(renderScene);
|
||||||
renderer.render(scene, camera);
|
renderer.render(scene, camera);
|
||||||
// 写在requestAnimationFrame之后,否则会报错
|
// 写在requestAnimationFrame之后,否则会报错
|
||||||
labelRenderer.render(scene, camera);
|
labelRenderer.render(scene, camera);
|
||||||
|
if (composer) {
|
||||||
|
composer.render()
|
||||||
|
}
|
||||||
};
|
};
|
||||||
// 相机移动动画
|
// 相机移动动画
|
||||||
const initTween = (targetX, targetY, targetZ) => {
|
const initTween = (targetX, targetY, targetZ) => {
|
||||||
|
@ -210,14 +281,44 @@ const initTween = (targetX, targetY, targetZ) => {
|
||||||
// 储存被选中的模型和材质
|
// 储存被选中的模型和材质
|
||||||
let selectedObject = null;
|
let selectedObject = null;
|
||||||
let selectedMaterial = null;
|
let selectedMaterial = null;
|
||||||
|
// 能选中的组
|
||||||
|
const enableGroup = [
|
||||||
|
'set1',
|
||||||
|
'set2',
|
||||||
|
'set3',
|
||||||
|
'set4',
|
||||||
|
'yuanliao_room',
|
||||||
|
'tanghua_room',
|
||||||
|
'touliao_room',
|
||||||
|
]
|
||||||
|
// const onMouseDown = (event) => {
|
||||||
|
// // 计算鼠标点击位置的归一化设备坐标
|
||||||
|
// mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
|
||||||
|
// mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
|
||||||
|
|
||||||
|
// var raycaster = new THREE.Raycaster()
|
||||||
|
// cleanColor();
|
||||||
|
// // 更新射线的起点和方向
|
||||||
|
// raycaster.setFromCamera(mouse, camera);
|
||||||
|
// // 计算射线和场景中所有可点击物体的相交情况
|
||||||
|
// const intersects = raycaster.intersectObjects(scene.children, true);
|
||||||
|
// // 如果找到了模型,将其材质修改为绿色
|
||||||
|
// if (intersects.length > 0) {
|
||||||
|
// const clickedObject = intersects[0].object;
|
||||||
|
// // 储存被选中的模型和材质
|
||||||
|
// selectedObject = clickedObject;
|
||||||
|
// // // 修改材质为绿色
|
||||||
|
// selectedObject.material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
|
||||||
|
// nearCamera(intersects);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// }
|
||||||
const onMouseDown = (event) => {
|
const onMouseDown = (event) => {
|
||||||
|
var raycaster = new THREE.Raycaster()
|
||||||
// 计算鼠标点击位置的归一化设备坐标
|
// 计算鼠标点击位置的归一化设备坐标
|
||||||
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
|
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
|
||||||
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
|
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
|
||||||
|
|
||||||
var raycaster = new THREE.Raycaster()
|
|
||||||
cleanColor();
|
|
||||||
// 更新射线的起点和方向
|
// 更新射线的起点和方向
|
||||||
raycaster.setFromCamera(mouse, camera);
|
raycaster.setFromCamera(mouse, camera);
|
||||||
// 计算射线和场景中所有可点击物体的相交情况
|
// 计算射线和场景中所有可点击物体的相交情况
|
||||||
|
@ -226,14 +327,39 @@ const onMouseDown = (event) => {
|
||||||
if (intersects.length > 0) {
|
if (intersects.length > 0) {
|
||||||
const clickedObject = intersects[0].object;
|
const clickedObject = intersects[0].object;
|
||||||
// 储存被选中的模型和材质
|
// 储存被选中的模型和材质
|
||||||
selectedObject = clickedObject;
|
selectedObject = clickedObject.parent;
|
||||||
// 修改材质为绿色
|
if (enableGroup.indexOf(selectedObject.name) != -1) {
|
||||||
selectedObject.material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
|
outlineObj([selectedObject])
|
||||||
nearCamera(intersects);
|
// nearCamera(intersects);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let composer = null
|
||||||
|
let outlinePass = null
|
||||||
|
let renderPass = null
|
||||||
|
const outlineObj = (selectedObject_list) => {
|
||||||
|
// 创建一个EffectComposer(效果组合器)对象,然后在该对象上添加后期处理通道。
|
||||||
|
composer = new EffectComposer(renderer)
|
||||||
|
// 新建一个场景通道 为了覆盖到原理来的场景上
|
||||||
|
renderPass = new RenderPass(scene, camera)
|
||||||
|
composer.addPass(renderPass);
|
||||||
|
// 物体边缘发光通道
|
||||||
|
outlinePass = new OutlinePass(new THREE.Vector2(window.innerWidth, window.innerHeight), scene, camera, selectedObject_list)
|
||||||
|
outlinePass.selectedObjects = selectedObject_list
|
||||||
|
// 下面都注掉。不然太开了
|
||||||
|
outlinePass.edgeStrength = 10.0 // 边框的亮度
|
||||||
|
outlinePass.edgeThickness = 1.0 // 边框宽度
|
||||||
|
outlinePass.visibleEdgeColor.set(0x00ff00) // 边框颜色
|
||||||
|
composer.addPass(outlinePass)
|
||||||
|
// 自定义的着色器通道 作为参数
|
||||||
|
var effectFXAA = new ShaderPass(FXAAShader)
|
||||||
|
effectFXAA.uniforms.resolution.value.set(1 / window.innerWidth, 1 / window.innerHeight)
|
||||||
|
effectFXAA.renderToScreen = true
|
||||||
|
composer.addPass(effectFXAA)
|
||||||
|
}
|
||||||
|
|
||||||
const nearCamera = (intersects) => {
|
const nearCamera = (intersects) => {
|
||||||
console.log(5555, intersects)
|
console.log(5555, intersects)
|
||||||
// 拉近场景
|
// 拉近场景
|
||||||
|
@ -258,9 +384,10 @@ const nearCamera = (intersects) => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const toHomeView = () => {
|
const toHomeView = () => {
|
||||||
camera.position.set(-192.936, 180.990, -28.179);
|
camera.position.set(-92.936, 180.990, -28.179);
|
||||||
camera.lookAt(scene.position);
|
camera.lookAt(scene.position);
|
||||||
cleanColor();
|
// cleanColor();
|
||||||
|
outlineObj([]);
|
||||||
}
|
}
|
||||||
// 返回主页
|
// 返回主页
|
||||||
const toHomeView1 = () => {
|
const toHomeView1 = () => {
|
||||||
|
@ -283,25 +410,73 @@ const toHomeView1 = () => {
|
||||||
orbit.target.set(0, 0, 0);
|
orbit.target.set(0, 0, 0);
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style lang='scss' scoped>
|
<style lang='scss'>
|
||||||
#three {
|
#three {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.button {
|
.btnGroup {
|
||||||
width: 80px;
|
width: 180px;
|
||||||
height: 80px;
|
|
||||||
line-height: 80px;
|
|
||||||
border-radius: 50%;
|
|
||||||
border: 1px solid rgb(7, 207, 221);
|
|
||||||
position: absolute;
|
position: absolute;
|
||||||
z-index: 1000000;
|
left: 0px;
|
||||||
bottom: 15px;
|
bottom: 40px;
|
||||||
left: 10px;
|
z-index: 999;
|
||||||
color: #fff;
|
display: flex;
|
||||||
text-align: center;
|
flex-direction: column;
|
||||||
background: rgb(7, 207, 221);
|
justify-content: space-between;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
color: #ffff;
|
||||||
|
|
||||||
|
>div {
|
||||||
|
background: #477efa;
|
||||||
|
width: 120px;
|
||||||
|
height: 40px;
|
||||||
|
border-radius: 0 50px 50px 0;
|
||||||
|
line-height: 40px;
|
||||||
|
text-align: center;
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.laber_name {
|
||||||
|
width: 120px;
|
||||||
|
height: 90px;
|
||||||
|
padding: 5px 10px;
|
||||||
|
white-space: nowrap;
|
||||||
|
background-color: #ffffffb3;
|
||||||
|
border-top-right-radius: 12px;
|
||||||
|
border-bottom-right-radius: 12px;
|
||||||
|
font-size: 12px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
// content: "";
|
||||||
|
// display: inline-block;
|
||||||
|
// width: 0;
|
||||||
|
// height: 0;
|
||||||
|
// border: 12px solid transparent;
|
||||||
|
// border-right-color: #ffffffb3;
|
||||||
|
// position: absolute;
|
||||||
|
// left: -23px;
|
||||||
|
// top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.arrow_outer {
|
||||||
|
// position: absolute;
|
||||||
|
// left: -22px;
|
||||||
|
// top: 6px;
|
||||||
|
// margin: 0;
|
||||||
|
// width: 12px;
|
||||||
|
// height: 12px;
|
||||||
|
// background-color: #eb6852;
|
||||||
|
// border-radius: 100%;
|
||||||
|
// border: 1px solid #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
span {
|
||||||
|
line-height: 24px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
Loading…
Reference in New Issue