vue组件部分
<template>
<div class="home">
<div id="container"></div>
<div id="loading">
<div>加载中...</div>
<div id="progress"><div id="progress-bar"></div></div>
<div id="progress-text">0%</div>
</div>
</div>
</template>
js部分
<script>
import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
import { RGBELoader } from "three/examples/jsm/loaders/RGBELoader";
import {
CSS2DRenderer,
CSS2DObject,
} from "three/examples/jsm/renderers/CSS2DRenderer";
import {
CSS3DRenderer,
CSS3DObject,
} from "three/examples/jsm/renderers/CSS3DRenderer";
export default {
name: "HomeView",
components: {},
data() {
return {
scene: null,
camera: null,
renderer: null,
controls: null,
container: null,
css2DRenderer: null,
css3DRenderer: null,
};
},
mounted() {
this.$nextTick(() => {
this.init();
});
},
methods: {
init() {
// const clock = new THREE.Clock();
// 创建场景
const scene = new THREE.Scene();
scene.background = new THREE.Color(0x000000);
this.scene = scene;
// 创建相机
const camera = new THREE.PerspectiveCamera(
45,
window.innerWidth / window.innerHeight,
0.1,
10000
);
camera.position.set(0, 300, 1000);
this.camera = camera;
const container = document.getElementById("container");
const renderer = new THREE.WebGLRenderer({
antialias: true,
logarithmicDepthBuffer: true,
});
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
// renderer.shadowMap.enabled = true;
// renderer.shadowMap.type = THREE.VSMShadowMap;
// renderer.outputEncoding = THREE.sRGBEncoding;
// renderer.toneMapping = THREE.ACESFilmicToneMapping;
container.appendChild(renderer.domElement);
this.renderer = renderer;
this.container = container;
// 坐标轴
let axes = new THREE.AxesHelper(500);
scene.add(axes);
// 创建轨道控制器
const controls = new OrbitControls(camera, renderer.domElement);
// 设置控制器阻尼,让控制器更有真实效果
controls.enableDamping = true;
controls.dampingFactor = 0.05;
controls.minPolarAngle = Math.PI / 4; // 垂直旋转最小角度(54度)
controls.maxPolarAngle = Math.PI / 2.2; // 垂直旋转最大角度(126度)
this.controls = controls;
// 加载天空盒
this.loadSkyBox();
// 加载模型
this.loadModel();
// 渲染循环
this.animate();
// 初始化2d渲染器
this.initCSS2DRenderer();
// 初始化3d渲染器
this.initCSS3DRenderer();
// 缩放时重置页面
window.addEventListener("resize", this.onWindowResize);
},
onWindowResize() {
this.camera.aspect = window.innerWidth / window.innerHeight;
this.camera.updateProjectionMatrix();
this.renderer.setSize(window.innerWidth, window.innerHeight);
// 设置渲染器的像素比
this.renderer.setPixelRatio(window.devicePixelRatio);
},
// 渲染循环
animate() {
this.controls.update();
this.renderer.render(this.scene, this.camera);
requestAnimationFrame(this.animate);
this.css2DRenderer && this.css2DRenderer.render(this.scene, this.camera);
this.css3DRenderer && this.css3DRenderer.render(this.scene, this.camera);
},
// 加载天空盒
loadSkyBox() {
const hdrLoader = new RGBELoader();
hdrLoader.load("./textures/023.hdr", (texture) => {
// texture.mapping = THREE.EquirectangularReflectionMapping;
// texture.anisotropy = 16;
// texture.format = THREE.RGBAFormat;
this.scene.background = texture;
this.scene.environment = texture;
this.scene.environment.mapping = THREE.EquirectangularReflectionMapping;
});
},
// 加载gltf模型
loadModel() {
const loadingManager = new THREE.LoadingManager( () => {
// 加载完成
console.log('所有资源加载完成');
document.getElementById('loading').style.display = 'none';
for (let i = 0; i < 10; i++) {
this.add2DElementToScene(new THREE.Vector3((i - 5) * 100, 100, -300));
this.add3DElementToScene(new THREE.Vector3((i - 5) * 100, 100, 300));
}
// this.add2DElementToScene();
// this.add3DElementToScene();
}, (item, loaded, total) => {
// 加载进度更新
const progress = (loaded / total) * 100;
document.getElementById('progress-bar').style.width = `${progress}%`;
document.getElementById('progress-text').textContent = `${Math.round(progress)}%`;
console.log(`加载进度: ${Math.round(progress)}%`);
}, (url) => {
// 加载错误
console.error('资源加载失败:', url);
}
);
let loader = new GLTFLoader(loadingManager);
loader.load("./model/nsk.glb", (gltf) => {
// gltf.scene.position.set(0, 1.25, 0);
// 把模型旋转45度
// model.rotation.y = -Math.PI / 4;
// gltf.scene.rotation.x = -Math.PI / 2;
// model.rotation.z = Math.PI / 6;
this.scene.add(gltf.scene);
console.log('gltf----', );
});
},
// 初始化CSS2DRenderer
initCSS2DRenderer() {
// 创建 CSS2DRenderer
const css2DRenderer = new CSS2DRenderer();
css2DRenderer.setSize(window.innerWidth, window.innerHeight);
css2DRenderer.domElement.style.position = "absolute";
css2DRenderer.domElement.style.top = 0;
css2DRenderer.domElement.style.pointerEvents = "none"; // 让渲染器不阻挡鼠标事件
css2DRenderer.render(this.scene, this.camera);
document.body.appendChild(css2DRenderer.domElement);
this.css2DRenderer = css2DRenderer;
},
// 添加元素到场景中
add2DElementToScene(position = new THREE.Vector3(0, 100, -300)) {
// 创建dom元素
const div = this.createDomElement();
// 创建 CSS2DObject
let labelObject = new CSS2DObject(div);
// labelObject.position.set(0, 200, -300);
labelObject.position.copy(position)
this.scene.add(labelObject);
// 设置标签所在的层,这里设置为0层
labelObject.layers.set(0);
},
// CSS3DRenderer
initCSS3DRenderer() {
let css3DRenderer = new CSS3DRenderer();
css3DRenderer.setSize(window.innerWidth, window.innerHeight);
css3DRenderer.render(this.scene, this.camera);
css3DRenderer.domElement.style.position = "absolute";
css3DRenderer.domElement.style.top = 0;
css3DRenderer.domElement.style.pointerEvents = "none";
document.body.appendChild(css3DRenderer.domElement);
this.css3DRenderer = css3DRenderer;
},
// 添加元素到场景中
add3DElementToScene(position = new THREE.Vector3(0, 100, 300)) {
// 创建dom元素
const div = this.createDomElement();
let css3DObject = new CSS3DObject(div);
css3DObject.scale.set(0.5, 0.5, 0.5);
// css3DObject.position.set(0, 200, 300);
css3DObject.position.copy(position)
this.scene.add(css3DObject);
css3DObject.layers.set(0);
},
// 创建dom元素
createDomElement() {
// 创建 HTML 元素
const div = document.createElement("div");
div.className = "label";
// div.style.width = '70px';
// div.style.height = '200px';
div.style.backgroundColor = "rgba(0,0,0,0.5)";
div.style.border = "2px solid #000";
div.style.borderRadius = "10px";
div.style.color = "#fff";
// 换行
div.style.whiteSpace = "pre-line";
div.style.wordWrap = "break-word";
// div.style.textAlign = 'center';
const img = document.createElement("img");
img.src = `./img/map/1.png`;
img.style.width = "61px";
img.style.height = "136px";
div.appendChild(img);
// div.innerHTML += '设备名称2';
return div;
},
// 销毁
destroy() {
this.controls.dispose();
this.renderer.dispose();
this.css2DRenderer.dispose();
this.css3DRenderer.dispose();
window.removeEventListener("resize", this.onWindowResize);
this.container.removeChild(this.renderer.domElement);
this.container.removeChild(this.css2DRenderer.domElement);
this.container.removeChild(this.css3DRenderer.domElement);
},
},
};
</script>
css部分
<style>
#container {
width: 100vw;
height: 100vh;
}
#loading {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
color: white;
font-family: Arial, sans-serif;
background: rgba(0, 0, 0, 0.7);
padding: 20px;
border-radius: 10px;
}
#progress {
width: 200px;
height: 20px;
background: #333;
margin-top: 10px;
border-radius: 10px;
overflow: hidden;
}
#progress-bar {
height: 100%;
width: 0%;
background: #4caf50;
transition: width 0.3s;
}
</style>