上一篇博客是用浏览器监听事件来控制图片的render,随着项目的深入,发现three.js-master源码里有几种控制器,例如: OrbitControls、TrackballControls ,通过使用可以精简很多代码,本篇只讲OrbitControls.js。
当前demo使用的three.js为0.115.0版本
项目中安装three
npm install three
安装完成再组件如下导入:
import * as THREE from 'three'
import { OrbitControls} from 'three/examples/jsm/controls/OrbitControls'
html文件中写入如下代码图片预览容器,代码如下:
script脚本中如下代码:
data() {
return {
/** VR图片预览start */
camera: null,
scene: null,
renderer: null,
group: [], // 相机 热点通过射线与球面的交点绘制的几何体集合
controls: null,
mesh: {},
radius: 500 // 球几何体半径
/** VR图片预览end */
}
},
methods: {
init() {
let textureLoader = new THREE.TextureLoader(); // 纹理
textureLoader.load("static/img/blank.png", (texture) => {
texture.mapping = THREE.UVMapping;
this.initImg(texture);
this.animate(); // 动画
});
},
initImg(texture) {
let container = this.$refs.container;
// 容器宽度、高度
let containerWidth = container.offsetWidth;
let containerHeight = container.offsetHeight;
this.renderer = new THREE.WebGLRenderer({ antialias: true }); // 需要使用WebGLRenderer
this.renderer.setPixelRatio(window.devicePixelRatio);
this.renderer.setSize(containerWidth, containerHeight);
container.appendChild(this.renderer.domElement);
this.scene = new THREE.Scene();
this.camera = new THREE.PerspectiveCamera(60, containerWidth / containerHeight, 1, 1000);
this.mesh = new THREE.Mesh(new THREE.SphereBufferGeometry(this.radius, 32, 16), new THREE.MeshBasicMaterial({ map: texture }));
this.mesh.geometry.scale(-1, 1, 1);
this.scene.add(this.mesh);
this.group = new THREE.Group();
this.scene.add(this.group);
let position = new THREE.Vector3(100, 6.123233995736766e-15, 0); // 创建相机初始位置
this.camera.position.set(position.x, position.y, position.z);
this.controls = new OrbitControls(this.camera, container );
this.controls.minDistance = 18; // 相机最近
this.controls.maxDistance = 500; // 相机最远
this.controls.autoRotate = true; // 图片自动旋转
this.controls.autoRotateSpeed = 0.8; // 阻尼系数
var axesHelper = new THREE.AxesHelper(500) // 三维坐标辅助线
this.scene.add(axesHelper)
window.addEventListener('resize', this.onWindowResize, false); // 渲染图片区域resize
},
onWindowResize() {
this.camera.aspect = this.$refs.container.offsetWidth / this.$refs.container.offsetHeight;
this.camera.updateProjectionMatrix();
this.renderer.setSize(this.$refs.container.offsetWidth, this.$refs.container.offsetHeight);
},
animate() {
this.requestAnimationId = requestAnimationFrame(this.animate);
this.controls.update(); // required when damping is enabled
this.renderer.render(this.scene, this.camera);
}
}
dispose() {
if (this.controls !== null) {
this.controls.dispose();
this.scene.remove(this.group);
}
}
this.controls.dispose(),轨道控制dispose在插件中实现的代码如下:
this.dispose = function () {
scope.domElement.removeEventListener('contextmenu', onContextMenu, false)
scope.domElement.removeEventListener('mousedown', onMouseDown, false)
scope.domElement.removeEventListener('wheel', onMouseWheel, false)
scope.domElement.removeEventListener('touchstart', onTouchStart, false)
scope.domElement.removeEventListener('touchend', onTouchEnd, false)
scope.domElement.removeEventListener('touchmove', onTouchMove, false)
document.removeEventListener('mousemove', onMouseMove, false)
document.removeEventListener('mouseup', onMouseUp, false)
scope.domElement.removeEventListener('keydown', onKeyDown, false)
// scope.dispatchEvent( { type: 'dispose' } ); // should this be added here?
}
当我们用到window或dom的addEventListener事件时,如果不销毁,监听事件每次执行都会被调用,并不会覆盖上一次的事件,这就导致一些你可能意识不到的bug