1. 项目概述
基于Three.js和Vue.js实现的3D变压器可视化组件,主要展示了三维模型。
2.技术引用
首先引入技术文件依赖,先下载three.js,再引入到需要的页面和页面所需要的模型控件。 再将我们下载的3D模型,格式为.obj / .glb 最好也引入到页面。
js
import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
import { OBJLoader } from "three/examples/jsm/loaders/OBJLoader.js";
3.div区域
要有3D渲染容器,canvas-container 作为Three.js渲染的主容器。
html
<div ref="canvasContainer" class="canvas-container">
4.data数据定义
Three.js实例:主要是一些场景、相机、渲染器、控制器等核心对象的初始化数据;
动画控制 :动画帧ID和状态标志
js
data() {
return {
scene: null,
camera: null,
renderer: null,
controls: null,
square: null,
animationId: null,
isModelLoaded: false
};
},
5.生命周期钩子
组件挂载:初始化Three.js、加载模型、设置事件监听、启动动画循环 组件销毁:清理事件监听器、停止动画、释放Three.js资源
js
mounted() {
this.initThreeJS();
this.loadModel();
this.updateTags();
// 监听窗口大小变化
window.addEventListener('resize', this.onWindowResize);
// 开始动画循环
this.animate();
},
beforeDestroy() {
// 清理事件监听器
window.removeEventListener('resize', this.onWindowResize);
// 停止动画循环
cancelAnimationFrame(this.animationId);
// 清理Three.js资源
if (this.renderer) {
this.renderer.dispose();
}
}
6.three.js的初始化函数
主要用于
- 获取渲染容器尺寸并创建Three.js场景
- 设置场景背景色(深蓝色)
- 创建光源(环境光和方向光)提供照明
- 创建透视相机,设置位置和视角
- 创建WebGL渲染器,启用抗锯齿和透明度
- 初始化轨道控制器,启用阻尼效果使旋转更平滑
js
initThreeJS() {
const container = this.$refs.canvasContainer;
const width = container.clientWidth;
const height = container.clientHeight;
// 创建场景
this.scene = new THREE.Scene();
// 添加环境光(适中亮度,避免过度反光)
const ambientLight = new THREE.AmbientLight(0xffffff, 1.8);
this.scene.add(ambientLight);
// 添加主方向光(适中强度)
const directionalLight = new THREE.DirectionalLight(0xffffff, 1.2);
directionalLight.position.set(5, 10, 7.5);
this.scene.add(directionalLight);
// 添加辅助方向光(柔和补光)
const directionalLight2 = new THREE.DirectionalLight(0xffffff, 0.8);
directionalLight2.position.set(-5, 5, -5);
this.scene.add(directionalLight2);
// 创建相机
this.camera = new THREE.PerspectiveCamera(75, width / height, 0.1, 1000);
this.camera.position.z = 3; // 增加相机与模型的距离
this.camera.position.y = 1; // 提高相机高度
// 创建渲染器
this.renderer = new THREE.WebGLRenderer({ antialias: true });
this.renderer.setClearColor(0x000000, 0);
this.renderer.setSize(width, height);
container.appendChild(this.renderer.domElement);
// 添加轨道控制器
this.controls = new OrbitControls(this.camera, this.renderer.domElement);
this.controls.enableDamping = true;
this.controls.dampingFactor = 0.05;
this.controls.enableZoom = true;
this.controls.autoRotate = true;
this.controls.autoRotateSpeed = 0.5;
},
7.3D模型的加载
根据模型文件类型(OBJ/GLB)选择合适的加载器 用户可以通过鼠标旋转、平移和缩放3D模型,动画循环确保场景持续渲染
js
loadGLBModel() {
const transformerType = this.currentTransformerType || this.type;
const isOBJ = this.modelPath.endsWith(".obj");
this.camera.position.set(0, 1, 3);
if (isOBJ) {
const loader = new OBJLoader();
loader.load(
this.modelPath,
(object) => {
// 保存模型引用
this.model = object;
// 给模型添加材质(OBJ文件不包含材质信息)
const material = new THREE.MeshPhongMaterial({
color: 0xffffff, // 白色
emissive: 0xcccccc, // 微弱的自发光(浅灰色)
emissiveIntensity: 0.15, // 降低自发光强度
shininess: 30, // 降低光泽度,减少反光
specular: 0x333333, // 降低高光反射
});
this.model.traverse((child) => {
if (child instanceof THREE.Mesh) {
child.material = material;
}
});
// 计算模型的边界盒以自动居中和缩放
const box = new THREE.Box3().setFromObject(this.model);
const center = box.getCenter(new THREE.Vector3());
const size = box.getSize(new THREE.Vector3());
// 计算最大尺寸
const maxDim = Math.max(size.x, size.y, size.z);
const scale = 2.5 / maxDim; // 让模型适配到2.5个单位大小
// 应用缩放
this.model.scale.set(scale, scale, scale);
// 重新计算边界盒(应用缩放后)
box.setFromObject(this.model);
box.getCenter(center);
// 将模型中心移到原点
this.model.position.set(-center.x, -center.y, -center.z);
// 将模型添加到场景
this.scene.add(this.model);
// 标记模型加载完成
this.isModelLoaded = true;
console.log("OBJ模型加载成功", {
model: this.model,
原始尺寸: size,
缩放比例: scale,
});
},
// 进度回调
(xhr) => {
console.log("OBJ加载进度: " + (xhr.loaded / xhr.total) * 100 + "%");
},
// 错误回调
(error) => {
console.error("加载OBJ模型失败:", error);
}
);
} else {
// 原有GLB模型加载逻辑
const loader = new GLTFLoader();
loader.load(
this.modelPath,
(gltf) => {
// 保存模型引用
this.model = gltf.scene;
// 完全保留模型原始材质,不做任何修改
// GLB模型自带材质和颜色,直接使用即可
// 设置模型位置、缩放和旋转
this.model.position.set(0, -1.2, 0);
this.model.scale.set(0.6, 0.6, 0.6);
// 将模型添加到场景
this.scene.add(this.model);
// 标记模型加载完成
this.isModelLoaded = true;
},
// 进度回调
(xhr) => {
console.log((xhr.loaded / xhr.total) * 100 + "% loaded");
},
// 错误回调
(error) => {
console.error("加载GLB模型失败:", error);
}
);
}
},
8.动画循环
- 使用requestAnimationFrame创建动画循环
- 更新轨道控制器状态
- 渲染3D场景
js
animate() {
this.animationId = requestAnimationFrame(this.animate);
if (this.controls) {
this.controls.update();
}
},
9.窗口大小响应
- 获取更新后的容器尺寸
- 更新相机的宽高比并重新计算投影矩阵
- 调整渲染器大小以匹配容器
js
onWindowResize() {
const container = this.$refs.canvasContainer;
const width = container.clientWidth;
const height = container.clientHeight;
if (this.camera) {
this.camera.aspect = width / height;
this.camera.updateProjectionMatrix();
}
if (this.renderer) {
this.renderer.setSize(width, height);
}
},