<template>
<div>
<div id="three"></div>
</div>
</template>
<script>
import * as THREE from "three";
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
import { CSS2DRenderer, CSS2DObject } from 'three/examples/jsm/renderers/CSS2DRenderer.js';
export default {
data() {
return {
scene: {}, // 场景
camera: {}, // 摄像机
renderer: {}, // 渲染器
labelRenderer: {}, //
clock: {},
};
},
mounted(){
this.threes();
this.resize(); // 自适应
},
methods: {
// 浏览器窗口发生变化时 自适应
resize(){
window.addEventListener('resize', () => {
// 初始化摄像机
this.camera.aspect = window.innerWidth/window.innerHeight;
// 摄像机矩阵效果
this.camera.updateProjectionMatrix();
// 初始化渲染器
this.renderer.setSize(window.innerWidth, window.innerHeight);
// 文字位置
this.labelRenderer.setSize( window.innerWidth, window.innerHeight );
})
},
threes() {
// 创建场景
this.scene = new THREE.Scene();
// 创建摄像机 // 参数含义: 视角、窗口投影长宽比、摄像机从哪里开始渲染、距离摄像机多远截至渲染
this.camera = new THREE.PerspectiveCamera(100, window.innerWidth/window.innerHeight, 0.1, 10000);
// 创建three渲染器 参数: 去锯齿
this.renderer = new THREE.WebGLRenderer({ antialias: true });
// 开启阴影,加上阴影渲染
this.renderer.shadowMapEnabled = true;
// 设置渲染器场景大小 参数: 宽,高
this.renderer.setSize(window.innerWidth, window.innerHeight);
// 把渲染器添加到页面中
document.getElementById('three').appendChild(this.renderer.domElement);
this.ground() // 地面模型
this.wall({x: 5060, y: 1500, z: 20}, {x: 0, y: 750, z: -1400})
this.wall({x: 5060, y: 1500, z: 20}, {x: 0, y: 750, z: 1400})
this.wall({x: 20, y: 1500, z: 2880}, {x: 2490, y: 750, z: 0})
this.wall({x: 20, y: 1500, z: 2880}, {x: -2490, y: 750, z: 0})
this.wall({x: 5060, y: 30, z: 2880}, {x: 0, y: 1500, z: 0})
// 机柜
for(let i = 0; i < 5; i ++){
this.chartlet((2100 - i * 740), 600, 300)
}
this.chartlet(800, 600, -1100)
// 灭火器
this.extinguisher(-2300, 150, 1200)
// 配电柜
this.power(1400, 240, -1170)
// 烟感
this.smokeSensor(200, 1470, 200)
this.smokeSensor(1400, 1470, 200)
this.smokeSensor(-1400, 1470, -700)
// 温湿度
this.humitureSensor(200, 1470, -700)
this.humitureSensor(1400, 1470, -700)
// 监控
this.monitorSentor(2400, 1470, 900)
this.monitorSentor(2400, 1470, -900)
// 门
this.door(-1500, 450, 1395)
// 精密空调
this.stulz(2300, 500, -1050)
this.stulz(-2100, 500, -1180, 0, 200, 128, 90)
// 创建光源
this.createLight()
// 辅助坐标系 参数表示坐标系大小,可以根据场景大小去设置
// this.axesHelper = new THREE.AxesHelper(3000);
// this.scene.add(this.axesHelper);
// 摄像机空间轴位置
this.camera.position.x = 0
this.camera.position.y = 3000
this.camera.position.z = 3000
// 创建鼠标控件对象
this.controls = new OrbitControls( this.camera, this.labelRenderer.domElement );
this.clock = new THREE.Clock();
this.animate()
},
// 添加帧渲染
animate(){
requestAnimationFrame(this.animate);
// 初始化controls
this.controls.update()
this.labelRenderer.render( this.scene, this.camera );
this.render()
},
// 渲染器渲染场景和摄像机
render(){
this.renderer.render(this.scene, this.camera)
},
// 创建光源
createLight () {
// 环境光
const ambint = new THREE.AmbientLight(0xffffff)
this.scene.add(ambint)
this.pointLight(0xffffff, -3000, 3000, -1000, 10000)
},
// 点光灯光源
pointLight (color, x, y, z, dis) {
const pointLight = new THREE.PointLight(color)
pointLight.position.set(x, y, z); // 光源位置
pointLight.castShadow = true; //开启灯光投射阴影
pointLight.intensity = 2; // 强度
pointLight.penumbra = 1; // 半影
pointLight.distance = dis; // 距离
this.scene.add(pointLight)
// 光源寄托
// this.createLightView(color, x, y, z)
},
// 聚光灯光源
spotLight (color, x, y, z, dis) {
const spotLight = new THREE.SpotLight(color)
spotLight.position.set(x, y, z); // 光源位置
spotLight.castShadow = true; //开启灯光投射阴影
spotLight.intensity = 3 // 强度
spotLight.angle = 0.3; // 角度
spotLight.penumbra = 1; // 半影
spotLight.decay = 1; // 衰退
spotLight.distance = dis; // 距离
this.scene.add(spotLight)
// 辅助线
let spotLightHelper = new THREE.SpotLightHelper(spotLight, 0x976fb6);
this.scene.add(spotLightHelper)
// 光源寄托
// this.createLightView(color, x, y, z)
},
// 光源寄托
createLightView(color, x, y, z){
let geometry = new THREE.SphereGeometry(30, 30, 30);
let material = new THREE.MeshPhongMaterial({ color });
let cube = new THREE.Mesh(geometry, material);
cube.position.set(x, y, z)
this.scene.add(cube)
},
// 平面模型
ground(){
let geometry = new THREE.BoxGeometry(5000, 2800, 0);
let material = new THREE.MeshLambertMaterial({ color: 0x659cae });
let cube = new THREE.Mesh(geometry, material);
cube.rotation.x = -0.5 * Math.PI
cube.position.set(0, 0, 0)
cube.receiveShadow = true
this.scene.add(cube)
},
// 墙壁
wall(size, position, opacity = 0.1){
let data = {
color: 0x07313F,
transparent: true,
opacity
}
let geometry = new THREE.BoxGeometry(size.x, size.y,size.z);
let material = new THREE.MeshLambertMaterial(data);
let cube = new THREE.Mesh(geometry, material);
cube.position.set(position.x, position.y, position.z)
this.scene.add(cube);
},
// 机柜
chartlet(x, y, z){
let map = new THREE.TextureLoader().load(require('@/assets/three/zhengm.png'));
let map2 = new THREE.TextureLoader().load(require('@/assets/three/cem.png'));
let map3 = new THREE.TextureLoader().load(require('@/assets/three/fanm.png'));
let group = new THREE.Mesh();
let color = 0x0c0c0c // 0x3C3B42
let mats = [];
let matsItems = [
{ map: map2 },
{ map: map2 },
{ color },
{ color },
{ map },
{ map: map3 },
]
matsItems.forEach(item => {
mats.push(new THREE.MeshPhongMaterial(item))
})
let cubeGeom = new THREE.BoxBufferGeometry(700, 1200, 360);
let cube = new THREE.Mesh(cubeGeom, mats);
cube.position.set(x, y, z)
group.add(cube);
this.scene.add(group)
let objectContent = [
{
name: '名称:',
content: '机柜'
},
{
name: '状态:',
content: '正常'
}
]
this.fontText(cube, objectContent)
},
// 配电柜
power(x = 0, y = 0, z = 0, big = 1){
// 配电柜平面
let powerItem = [
[{x: 440, y: 780, z: 10},{x: 50, y: 150, z: -100}, null], // 后
[{x: 440, y: 780, z: 10},{x: 50, y: 150, z: 30}, 0x888888], // 前
[{x: 60, y: 780, z: 10},{x: -150, y: 150, z: 100}, null], // 前左
[{x: 60, y: 780, z: 10},{x: 250, y: 150, z: 100}, null], // 前右
[{x: 440, y: 60, z: 10},{x: 50, y: 515, z: 100}, null], // 前上
[{x: 440, y: 60, z: 10},{x: 50, y: -210, z: 100}, null], // 前下
[{x: 10, y: 780, z: 210},{x: -170, y: 150, z: 0}, null], // 左
[{x: 10, y: 780, z: 200},{x: 270, y: 150, z: 0}, null], // 右
[{x: 450, y: 10, z: 200},{x: 50, y: 540, z: 0}, null], // 上
[{x: 450, y: 10, z: 200},{x: 50, y: -245, z: 0}, null], // 下
]
for(let i = 0; i < powerItem.length; i ++){
powerItem[i][1].x += x;
powerItem[i][1].y += y;
powerItem[i][1].z += z;
this.powerItem(powerItem[i][0],powerItem[i][1],powerItem[i][2],powerItem[i][3]);
}
// 配电柜指示灯
this.powerLamp({x: -30 + x, y: 280 + y, z: 35 + z}, 0xe73939)
this.pointLight(0xe73939, -30 + x, 280 + y, 50 + z, 300)
this.powerLamp({x: 50 + x, y: 280 + y, z: 35 + z}, 0x15c02d)
this.pointLight(0x15c02d, 50 + x, 280 + y, 50 + z, 300)
this.powerLamp({x: 130 + x, y: 280 + y, z: 35 + z}, 0xd1d81e)
this.pointLight(0xd1d81e, 130 + x, 280 + y, 50 + z, 300)
// 闪电标识
let map = new THREE.TextureLoader().load(require('@/assets/three/shand.png'));
let geometry = new THREE.BoxGeometry(340, 480, 5);
let material = new THREE.MeshLambertMaterial({map, transparent: true});
let cube = new THREE.Mesh(geometry, material);
cube.position.set(50 + x, 50 + y, 100 + z)
this.scene.add(cube);
let objectContent = [
{
name: '名称:',
content: '配电柜'
},
{
name: '状态:',
content: '正常',
},
{
name: 'ABC相电压:',
content: '35KV / 15KV / 20KV',
class: 'success'
},
{
name: 'ABC相电流:',
content: '1100A / 1000A / 1200A',
class: 'warning'
}
]
this.fontText(cube, objectContent)
// 锁子
let map2 = new THREE.TextureLoader().load(require('@/assets/three/suoz.png'));
let geometry2 = new THREE.BoxGeometry(40, 120, 5);
let material2 = new THREE.MeshLambertMaterial({map: map2, transparent: true});
let cube2 = new THREE.Mesh(geometry2, material2);
cube2.position.set(-150 + x, 120 + y, 110 + z)
this.scene.add(cube2);
},
// 配电柜平面
powerItem(size, position, color){
let data = {
color: color ? color : 0xc5c5c3
}
let geometry = new THREE.BoxGeometry(size.x, size.y, size.z);
let material = new THREE.MeshLambertMaterial(data);
let cube = new THREE.Mesh(geometry, material);
cube.position.set(position.x, position.y, position.z)
this.scene.add(cube);
},
// 配电柜指示灯
powerLamp(size, color){
let sphere = new THREE.SphereGeometry(20, 20, 20);
let material = new THREE.MeshLambertMaterial({color});
let cube = new THREE.Mesh(sphere, material);
cube.position.set(size.x, size.y, size.z)
this.scene.add(cube);
},
// 灭火器
extinguisher(x, y, z){
// 圆柱 1
let cylinder = new THREE.CylinderGeometry( 20, 20, 30, 10 );
let material0 = new THREE.MeshLambertMaterial({color: 0x333333});
let cube = new THREE.Mesh(cylinder, material0);
cube.position.set(x, 340, z)
// 球体 2
let sphere = new THREE.SphereGeometry(60, 60, 60);
let material1 = new THREE.MeshLambertMaterial({color: 0xdb2c1f});
let cube2 = new THREE.Mesh(sphere, material1);
cube2.position.set(x, 280, z)
// 圆柱 3
let cylinder2 = new THREE.CylinderGeometry( 60, 60, 280, 100 );
let texture = new THREE.TextureLoader().load(require('@/assets/three/mhq.png'));
let material2 = new THREE.MeshLambertMaterial({map: texture});
let cube3 = new THREE.Mesh(cylinder2, material2);
cube3.position.set(x, y, z)
cube3.rotation.y -= 1.6
this.scene.add(cube);
this.scene.add(cube2);
this.scene.add(cube3);
let objectContent = [
{
name: '名称:',
content: '灭火器'
}
]
this.fontText(cube2, objectContent)
},
// 烟感
smokeSensor(x, y, z){
// 柱状1
let cylinder = new THREE.CylinderGeometry( 55, 55, 4, 20 );
let material = new THREE.MeshLambertMaterial({color: 0xd8d8c0, transparent: true, opacity: 0.8});
let cube = new THREE.Mesh(cylinder, material);
cube.position.set(x, y + 12, z)
this.scene.add(cube);
// 柱状2
let cylinder2 = new THREE.CylinderGeometry( 50, 50, 22, 20 );
let material2 = new THREE.MeshLambertMaterial({color: 0xd8d8c0});
let cube2 = new THREE.Mesh(cylinder2, material2);
cube2.position.set(x, y, z)
this.scene.add(cube2);
// 柱状3
let texture = new THREE.TextureLoader().load(require('@/assets/three/yang.png'));
let cylinder3 = new THREE.CylinderGeometry( 45, 35, 20, 15 );
let material3 = new THREE.MeshLambertMaterial({map: texture});
let cube3 = new THREE.Mesh(cylinder3, material3);
cube3.position.set(x, y-15, z)
this.scene.add(cube3);
let objectContent = [
{
name: '名称:',
content: '烟感'
},
{
name: '状态:',
content: '正常',
class: 'success'
}
]
this.fontText(cube3, objectContent)
},
// 温湿度
humitureSensor(x, y, z){
// 立方体1
let data = {
color: 0xdcdcd9,
transparent: true,
opacity: 0.8
}
let geometry0 = new THREE.BoxGeometry(90, 4, 90);
let material0 = new THREE.MeshLambertMaterial(data);
let cube0 = new THREE.Mesh(geometry0, material0);
cube0.position.set(x, y + 14, z)
this.scene.add(cube0);
// 立方体2
let map = new THREE.TextureLoader().load(require('@/assets/three/wens.png'));
let group = new THREE.Mesh();
let color = 0xdcdcd9
let mats = [];
let matsItems = [
{ color },
{ color },
{ color },
{ map },
{ color },
{ color },
]
matsItems.forEach(item => {
mats.push(new THREE.MeshPhongMaterial(item))
})
let cubeGeom = new THREE.BoxBufferGeometry(80, 25, 80);
let cube = new THREE.Mesh(cubeGeom, mats);
cube.position.set(x, y, z)
group.add(cube);
this.scene.add(group)
let objectContent = [
{
name: '名称:',
content: '温湿度传感器'
},
{
name: '温度:',
content: '24℃',
class: 'warning'
},
{
name: '湿度:',
content: '23%',
class: 'primary'
}
]
this.fontText(cube, objectContent)
},
// 监控
monitorSentor(x, y, z){
// 柱状
let cylinder = new THREE.CylinderGeometry( 30, 30, 10, 20 );
let material = new THREE.MeshLambertMaterial({color: 0xd8d8c0, opacity: 0.6});
let cube = new THREE.Mesh(cylinder, material);
cube.position.set(x, y, z)
this.scene.add(cube);
// 柱状2-1
let cylinder2 = new THREE.CylinderGeometry( 3, 3, 40, 20 );
let material2 = new THREE.MeshLambertMaterial({color: 0xd8d8c0});
let cube2 = new THREE.Mesh(cylinder2, material2);
cube2.position.set(x, y - 20, z)
cube2.rotation.z -= 0.3
this.scene.add(cube2);
// 柱状2-2
let cylinder5 = new THREE.CylinderGeometry( 3, 3, 50, 20 );
let material5 = new THREE.MeshLambertMaterial({color: 0xd8d8c0});
let cube5 = new THREE.Mesh(cylinder5, material5);
cube5.position.set(x - 30, y - 45, z)
cube5.rotation.z += 5
this.scene.add(cube5);
// 柱状3
let cylinder3 = new THREE.CylinderGeometry( 35, 35, 70, 20 );
let material3 = new THREE.MeshLambertMaterial({color: 0xd8d8c0});
let cube3 = new THREE.Mesh(cylinder3, material3);
cube3.position.set(x - 70, y - 60, z)
cube3.rotation.z += 5
this.scene.add(cube3);
// 球体
let sphere = new THREE.SphereGeometry(25, 25, 25);
let material4 = new THREE.MeshPhongMaterial({color: 0x333333});
let cube4 = new THREE.Mesh(sphere, material4);
cube4.position.set(x - 90, y - 65, z)
this.scene.add(cube4);
let objectContent = [
{
name: '名称:',
content: '监控'
},
{
name: '状态:',
content: '正常',
class: 'success'
}
]
this.fontText(cube4, objectContent)
},
// 门
door(x, y, z){
let data = {
color: 0x07313F,
transparent: true,
opacity: 0.3
}
let geometry = new THREE.BoxGeometry(550, 900, 40);
let material = new THREE.MeshLambertMaterial(data);
let cube = new THREE.Mesh(geometry, material);
cube.position.set(x, y, z)
this.scene.add(cube);
},
// 精密空调 rotation-旋转度数
stulz(x, y, z, x1 = 128, y1 = 200, z1 = 0, rotation = 0){
let geometry = new THREE.BoxGeometry(250, 1000, 600);
let material = new THREE.MeshPhongMaterial({color: 0x3e3e3e});
let cube = new THREE.Mesh(geometry, material);
cube.position.set(x, y, z)
rotation = Math.PI/(180/rotation)
cube.rotation.y -= rotation
this.scene.add(cube);
this.stulzDevice(x, y, z, x1, y1, z1, rotation)
let objectContent = [
{
name: '名称:',
content: '精密空调',
class: 'primary'
},
{
name: '开关状态:',
content: '已开',
class: 'success'
},
{
name: '温度:',
content: '24℃',
class: 'success'
},
{
name: '湿度:',
content: '46%',
class: 'warning'
},
{
name: '报警信息:',
content: '暂无报警信息',
class: 'danger'
}
]
this.fontText(cube, objectContent)
},
// 精密空调 显示器
stulzDevice(x, y, z, x1, y1, z1, rotation){
let map = new THREE.TextureLoader().load(require('@/assets/three/jingm.jpg'));
let geometry = new THREE.BoxGeometry(5, 200, 460);
let material = new THREE.MeshPhongMaterial({map, transparent: true});
let cube = new THREE.Mesh(geometry, material);
cube.position.set(x - x1, y + y1, z + z1)
cube.rotation.y -= rotation
this.scene.add(cube);
},
// 文字
fontText(moon, contObj = []){
// 创建文字容器
const moonDiv = document.createElement( 'div' );
moonDiv.className = 'label';
moonDiv.style.marginTop = '3em';
moonDiv.style.color = '#dddddd';
moonDiv.style.fontSize = '12px';
moonDiv.style.padding = '5px';
moonDiv.style.backgroundColor = 'rgba(0,0,0,0.7)';
if(contObj.length){
contObj.forEach(item => {
let moonTitle = document.createElement( 'span' )
let moonContent = document.createElement( 'span' )
let moonBr = document.createElement( 'br' )
if(item.class) moonContent.className = item.class;
moonTitle.textContent = item.name
moonContent.textContent = item.content
moonDiv.appendChild(moonTitle)
moonDiv.appendChild(moonContent)
moonDiv.appendChild(moonBr)
})
}
const moonLabel = new CSS2DObject( moonDiv );
moonLabel.position.set(0, 0.275, 0);
moon.add( moonLabel );
// 每次添加div前 先把原有的删除
let chArr = document.body.getElementsByClassName("labelRenderer")
for(let i = 0;i < chArr.length; i++) if (chArr[i] != null) chArr[i].parentNode.removeChild(chArr[i]);
// 创建2d渲染
this.labelRenderer = new CSS2DRenderer();
this.labelRenderer.setSize( window.innerWidth, window.innerHeight );
this.labelRenderer.domElement.style.position = 'absolute';
this.labelRenderer.domElement.style.top = '0px';
this.labelRenderer.domElement.className = 'labelRenderer'
document.body.appendChild( this.labelRenderer.domElement );
},
},
beforeDestroy(){
// 页面卸载时 删除创建的div
let chArr = document.body.getElementsByClassName("labelRenderer")
for(let i = 0;i < chArr.length; i++) if (chArr[i] != null) chArr[i].parentNode.removeChild(chArr[i]);
}
};
</script>
<style scoped>
body {
margin: 0;
padding: 0;
background-color: #000;
color: #fff;
font-family: Monospace;
font-size: 13px;
line-height: 24px;
overscroll-behavior: none;
}
#info {
position: absolute;
top: 0px;
width: 100%;
padding: 0;
box-sizing: border-box;
text-align: center;
-moz-user-select: none;
-webkit-user-select: none;
-ms-user-select: none;
user-select: none;
pointer-events: none;
z-index: 1; /* TODO Solve this in HTML */
}
</style>
vue-three 3d机房
©著作权归作者所有,转载或内容合作请联系作者
- 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
- 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
- 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
推荐阅读更多精彩内容
- 1、WebGL与threeJS WebGL是一种3D绘图协议,其允许JavaScript和OpenGL ES2.0...