<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: {}, // 場(chǎng)景
camera: {}, // 攝像機(jī)
renderer: {}, // 渲染器
labelRenderer: {}, //
clock: {},
};
},
mounted(){
this.threes();
this.resize(); // 自適應(yīng)
},
methods: {
// 瀏覽器窗口發(fā)生變化時(shí) 自適應(yīng)
resize(){
window.addEventListener('resize', () => {
// 初始化攝像機(jī)
this.camera.aspect = window.innerWidth/window.innerHeight;
// 攝像機(jī)矩陣效果
this.camera.updateProjectionMatrix();
// 初始化渲染器
this.renderer.setSize(window.innerWidth, window.innerHeight);
// 文字位置
this.labelRenderer.setSize( window.innerWidth, window.innerHeight );
})
},
threes() {
// 創(chuàng)建場(chǎng)景
this.scene = new THREE.Scene();
// 創(chuàng)建攝像機(jī) // 參數(shù)含義: 視角、窗口投影長(zhǎng)寬比、攝像機(jī)從哪里開始渲染、距離攝像機(jī)多遠(yuǎn)截至渲染
this.camera = new THREE.PerspectiveCamera(100, window.innerWidth/window.innerHeight, 0.1, 10000);
// 創(chuàng)建three渲染器 參數(shù): 去鋸齒
this.renderer = new THREE.WebGLRenderer({ antialias: true });
// 開啟陰影,加上陰影渲染
this.renderer.shadowMapEnabled = true;
// 設(shè)置渲染器場(chǎng)景大小 參數(shù): 寬,高
this.renderer.setSize(window.innerWidth, window.innerHeight);
// 把渲染器添加到頁(yè)面中
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})
// 機(jī)柜
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)
// 監(jiān)控
this.monitorSentor(2400, 1470, 900)
this.monitorSentor(2400, 1470, -900)
// 門
this.door(-1500, 450, 1395)
// 精密空調(diào)
this.stulz(2300, 500, -1050)
this.stulz(-2100, 500, -1180, 0, 200, 128, 90)
// 創(chuàng)建光源
this.createLight()
// 輔助坐標(biāo)系 參數(shù)表示坐標(biāo)系大小,可以根據(jù)場(chǎng)景大小去設(shè)置
// this.axesHelper = new THREE.AxesHelper(3000);
// this.scene.add(this.axesHelper);
// 攝像機(jī)空間軸位置
this.camera.position.x = 0
this.camera.position.y = 3000
this.camera.position.z = 3000
// 創(chuàng)建鼠標(biāo)控件對(duì)象
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()
},
// 渲染器渲染場(chǎng)景和攝像機(jī)
render(){
this.renderer.render(this.scene, this.camera)
},
// 創(chuàng)建光源
createLight () {
// 環(huán)境光
const ambint = new THREE.AmbientLight(0xffffff)
this.scene.add(ambint)
this.pointLight(0xffffff, -3000, 3000, -1000, 10000)
},
// 點(diǎn)光燈光源
pointLight (color, x, y, z, dis) {
const pointLight = new THREE.PointLight(color)
pointLight.position.set(x, y, z); // 光源位置
pointLight.castShadow = true; //開啟燈光投射陰影
pointLight.intensity = 2; // 強(qiáng)度
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 // 強(qiáng)度
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);
},
// 機(jī)柜
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: '機(jī)柜'
},
{
name: '狀態(tài):',
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)
// 閃電標(biāo)識(shí)
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: '狀態(tài):',
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: '狀態(tài):',
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)
},
// 監(jiān)控
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: '監(jiān)控'
},
{
name: '狀態(tài):',
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);
},
// 精密空調(diào) rotation-旋轉(zhuǎn)度數(shù)
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: '精密空調(diào)',
class: 'primary'
},
{
name: '開關(guān)狀態(tài):',
content: '已開',
class: 'success'
},
{
name: '溫度:',
content: '24℃',
class: 'success'
},
{
name: '濕度:',
content: '46%',
class: 'warning'
},
{
name: '報(bào)警信息:',
content: '暫無報(bào)警信息',
class: 'danger'
}
]
this.fontText(cube, objectContent)
},
// 精密空調(diào) 顯示器
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 = []){
// 創(chuàng)建文字容器
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]);
// 創(chuàng)建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(){
// 頁(yè)面卸載時(shí) 刪除創(chuàng)建的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機(jī)房
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
相關(guān)閱讀更多精彩內(nèi)容
- 1、WebGL與threeJS WebGL是一種3D繪圖協(xié)議,其允許JavaScript和OpenGL ES2.0...
- 上次說到需要準(zhǔn)備的有了, 這是一種開發(fā)的思路,就是如果做東西的技術(shù)已經(jīng)儲(chǔ)備的沒問題了,那就先想好要做什么,然后再準(zhǔn)...
- 之前在公司做項(xiàng)目的時(shí)候接到過一個(gè)需求, 因公司業(yè)務(wù)是做IT監(jiān)控,所以客戶要一個(gè)機(jī)房的3D展示,展示環(huán)境啊設(shè)備什么的...
- 機(jī)房的抽象準(zhǔn)備好了,下面該做唄做了, 但是呢,突然有個(gè)想法, 就是,IT項(xiàng)目很多,每個(gè)機(jī)房都不一樣,不可能每個(gè)都寫...
- 由于對(duì)WebGL的興趣,初步接觸Three.js,決定將學(xué)習(xí)過程進(jìn)行記錄,以便于后期復(fù)習(xí)。 初步以實(shí)現(xiàn)3D機(jī)房為目...