简介
Three.js 是一款运行在浏览器中的3D 引擎,你可以用它创建各种三维场景,包括了摄影机、光影、材质等各种对象。three.js,一个WebGL引擎,基于JavaScript,可直接运行GPU驱动游戏与图形驱动应用于浏览器。其库提供大量特性与API以绘制3D场景于浏览器。
安装依赖
yarn add three@0.142.0
页面使用
<template>
<div class="three-box">
<div
ref="points"
id="points"
class="points-box"
>
</div>
</div>
</template>
import * as THREE from 'three';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
import { DragControls } from 'three/examples/jsm/controls/DragControls'; // 拖拽控件
import { TransformControls } from 'three/examples/jsm/controls/TransformControls'; // 可视化平移控件
import { CSS3DRenderer, CSS3DObject } from 'three/examples/jsm/renderers/CSS3DRenderer.js'; // CSS3D
export default {
components: {},
props: {},
data() {
return {
container: null, //容器
camera: null, //相机
scene: null, //场景
renderer: null, //渲染器
controls: null, //控制器
cameraTarget: null, //相机方向
width: null,
height: null,
lineGroup: null, // Target实线组
LineSegmentsGroup: null, // Base虚线组
PointsGroup: null, // Distance端点组
top: -100,
left: -100,
name: '',
targetX: null,
targetY: null,
};
},
mounted() {
this.$nextTick(() => {
this._initData();
this.animate();
});
},
beforeDestroy() {},
methods: {
_initData() {
this.container = document.createElement('div');
this.$refs.points.appendChild(this.container);
this.width = this.$refs.points.offsetWidth;
this.height = this.$refs.points.offsetHeight;
//配置相机
this.camera = new THREE.PerspectiveCamera(45, this.width / this.height, 1, 10000);
this.camera.position.set(0, 0, 2200); //通过设置相机的位置转换视角,可以看到物体的不同角度
this.cameraTarget = new THREE.Vector3(0, 0, 0);
this.controls = new OrbitControls(this.camera, this.container);
this.controls.addEventListener('change', this._rendergl, true); //通过控制鼠标操作模型的旋转缩放
this.controls.update();
this.controls.enableRotate = false; //禁止旋转
//创建场景,设置背景色
this.scene = new THREE.Scene();
this.scene.background = new THREE.Color(0x696969);
//网格坐标
// var helper = new THREE.GridHelper( 1200, 60, 0xFF4444, 0x404040 );
// this.scene.add( helper )
//三维直角坐标系
var axisHelper = new THREE.AxesHelper(2);
this.scene.add(axisHelper);
//设置灯源
let spotLight = new THREE.SpotLight(0xffffff);
spotLight.position.set(-100, -100, -100);
let spotLight2 = new THREE.SpotLight(0xffffff);
spotLight2.position.set(100, 100, 100);
this.scene.add(spotLight);
this.scene.add(spotLight2);
this.scene.add(new THREE.HemisphereLight(0x443333, 0x111122));
//渲染器
this.renderer = new THREE.WebGLRenderer({ antialias: true }); //antialias是否开启反锯齿,设置为true开启反锯齿。
this.renderer.setPixelRatio(window.devicePixelRatio); //设置设备像素比
this.renderer.setSize(this.width, this.height);
// this.renderer.gammaInput = true; //全部的纹理和颜色预乘伽马,默认false
// this.renderer.gammaOutput = true; //须要以预乘的伽马输出,默认false
this.renderer.shadowMap.enabled = true;
this.container.appendChild(this.renderer.domElement);
// resize
window.addEventListener('resize', this.onWindowResize, false);
window.addEventListener('mousewheel', this.onMousewheel, true); //通过控制鼠标操作模型的旋转缩放
// 加载模型
this._loadLine();
this.raycaster = new THREE.Raycaster();
this.pointer = new THREE.Vector2();
// pointermove pointerdown
// window.addEventListener('pointermove', this.onPointerMove, true);
this.container.addEventListener('pointerdown', this.onPointerMove, true);
},
onPointerMove(event) {
// 将鼠标位置归一化为设备坐标。x 和 y 方向的取值范围是 (-1 to +1)
let mainCanvas = document.getElementsByTagName('canvas')[0];
// 将屏幕坐标转为标准设备坐标(支持画布非全屏的情况)
this.pointer.x = ((event.clientX - mainCanvas.getBoundingClientRect().left) / mainCanvas.offsetWidth) * 2 - 1;
this.pointer.y = -((event.clientY - mainCanvas.getBoundingClientRect().top) / mainCanvas.offsetHeight) * 2 + 1;
var vector = new THREE.Vector3(this.pointer.x, this.pointer.y);
vector = vector.unproject(this.camera); // 将屏幕的坐标转换成三维场景中的坐标
var raycaster = new THREE.Raycaster(this.camera.position, vector.sub(this.camera.position).normalize());
var intersects = raycaster.intersectObjects(this.scene.children, true);
if (intersects.length > 0) {
for (let item of intersects) {
if (item.object.type == 'Mesh') {
let array = item.object.name.split(',');
this.name = array[4];
this.targetX = array[2];
this.targetY = array[3];
this.top = event.offsetY - 50;
this.left = event.offsetX - 76;
} else {
this.top = -100;
this.left = -100;
}
}
} else {
this.top = -100;
this.left = -100;
}
},
// 绘制线段
_loadLine() {
// Target材质 绿色实线
const material = new THREE.LineBasicMaterial({ color: 0x00ff44 });
// Base材质 灰色虚线
const distanceMaterial = new THREE.LineDashedMaterial({
color: 0xdbdbdb,
dashSize: 3,
gapSize: 1,
});
// Distance材质 偏差值内为绿色点 大于偏差值是红色点
const redMaterial = new THREE.MeshBasicMaterial({ color: 0xff0000 });
const greenMaterial = new THREE.MeshBasicMaterial({ color: 0x00ff44 });
const yellowMaterial = new THREE.MeshBasicMaterial({ color: 0xffeb00 });
this.lineGroup = new THREE.Group();
this.LineSegmentsGroup = new THREE.Group();
this.PointsGroup = new THREE.Group();
this.PointsGroup.name = 'Points';
this.breakData.forEach((item, index) => {
let points = [];
points.push(new THREE.Vector3(item[0], item[1], 1));
points.push(new THREE.Vector3(item[2], item[3], 1));
let geometry = new THREE.BufferGeometry().setFromPoints(points);
let line = new THREE.Line(geometry, material);
this.PointsGroup.add(line);
this.PointsGroup.visible = true;
this.scene.add(this.PointsGroup);
// 虚线
// let topDashedPoints = [];
// topDashedPoints.push(new THREE.Vector3(item[0], item[1], 0));
// topDashedPoints.push(new THREE.Vector3(this.lower[index][0], this.lower[index][1], 0));
// let topGeometry = new THREE.BufferGeometry().setFromPoints(topDashedPoints);
// let topLine = new THREE.LineSegments(topGeometry, distanceMaterial);
// // 计算LineDashedMaterial所需的距离的值的数组。
// topLine.computeLineDistances();
// this.LineSegmentsGroup.add(topLine);
// this.LineSegmentsGroup.visible = true;
// this.scene.add(this.LineSegmentsGroup);
// Base
let topPointsGeometry = new THREE.CircleGeometry(2, 32);
let Points1 = new THREE.Mesh(topPointsGeometry, yellowMaterial);
Points1.position.x = item[0];
Points1.position.y = item[1];
Points1.position.z = 0;
Points1.name = item.toString();
this.LineSegmentsGroup.add(Points1);
this.LineSegmentsGroup.visible = true;
this.scene.add(this.LineSegmentsGroup);
// Target
let bottomMaterial = this.distance > item[4] ? greenMaterial : redMaterial;
let bottomPointsGeometry = new THREE.CircleGeometry(2, 32);
let Points2 = new THREE.Mesh(bottomPointsGeometry, bottomMaterial);
Points2.position.x = item[2];
Points2.position.y = item[3];
Points2.position.z = 1;
Points2.name = item.toString();
this.lineGroup.add(Points2);
this.lineGroup.visible = true;
this.scene.add(this.lineGroup);
});
this.renderer.render(this.scene, this.camera);
// this.initDragControls();
},
// 添加拖拽控件
initDragControls() {
// 添加平移控件
var transformControls = new TransformControls(this.camera, this.renderer.domElement);
this.scene.add(transformControls);
// 过滤不是 Mesh 的物体,例如辅助网格
var objects = [];
for (let i = 0; i < this.scene.children.length; i++) {
if (this.scene.children[i].isLine || this.scene.children[i].isLineSegments || this.scene.children[i].isPoints) {
objects.push(this.scene.children[i]);
}
}
// 初始化拖拽控件
var dragControls = new DragControls(objects, this.camera, this.renderer.domElement);
// 鼠标略过事件
dragControls.addEventListener('hoveron', function (event) {
console.log(event);
// 让变换控件对象和选中的对象绑定
transformControls.attach(event.object);
});
// 开始拖拽
dragControls.addEventListener('dragstart', function (event) {
controls.enabled = false;
});
// 拖拽结束
dragControls.addEventListener('dragend', function (event) {
controls.enabled = true;
});
},
//监听屏幕大小变换
onWindowResize() {
this.$nextTick(() => {
if (this.$refs.points) {
this.width = this.$refs.points.offsetWidth;
this.height = this.$refs.points.offsetHeight;
this.camera.aspect = this.width / this.height;
this.camera.updateProjectionMatrix();
this.renderer.setSize(this.width, this.height);
}
});
},
onMousewheel() {
this.top = -100;
this.left = -100;
},
//渲染函数
_rendergl() {
this.renderer.render(this.scene, this.camera);
},
//运动
animate() {
requestAnimationFrame(this.animate);
this._rendergl();
},
//设置模型居中显示
centerModel(group) {
/**
* 包围盒全自动计算:模型整体居中
*/
var box3 = new THREE.Box3();
// 计算层级模型group的包围盒
// 模型group是加载一个三维模型返回的对象,包含多个网格模型
box3.expandByObject(group);
// 计算一个层级模型对应包围盒的几何体中心在世界坐标中的位置
var center = new THREE.Vector3();
box3.getCenter(center);
// console.log('查看几何体中心坐标', center);
// 重新设置模型的位置,使之居中。
group.position.x = group.position.x - center.x;
// group.position.y = group.position.y - center.y
group.position.z = group.position.z - center.z;
},
},
};