Three.js是基于原生WebGL封装运行的三维引擎,在所有WebGL引擎中,Three.js是国内文资料最多、使用最广泛的三维引擎。使用Three.js可以给前端展示页面增加很多酷炫的效果。
项目需要,想在大屏上加上风力发电机叶片旋转的效果,研究了一点点,我不是专业的前端人员,写起来有点业余,只是简单的把功能实现了,视觉效果方面还需要努力。
风机模型是obj格式的,分了好多个部件,各叶片、柱子都是分开的:
三维模型软件的链接在文章末尾,支持几十种常见的三维模型格式,很方便。
效果如下,显示的好看的话还要研究一下光线、材质这些:
代码如下,每个关键点都加了注释了:
<template>
<div class="VRScene">
<div id="container"></div>
</div>
</template>
<script>
import * as THREE from 'three';
import { OBJLoader } from 'three/examples/jsm/loaders/OBJLoader';
var camera;
var renderer;
var scene;
var fans = new THREE.Group();
var beam = new THREE.Group();
export default {
data() {
return {
bigImg: require('../assets/pic.jpg')
}
},
mounted() {
this.$nextTick(() => {
this.init();
this.animate();
})
},
methods:{
init() {
let container = null
container = document.getElementById('container');
// 创建渲染器
renderer = new THREE.WebGLRenderer();
renderer.setPixelRatio(window.devicePixelRatio);
// 设置画布的宽高
// renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setSize(window.innerWidth-30, window.innerHeight-200);
// 判断容器中子元素的长度
let childs = container.childNodes;
if (container.childNodes.length > 0) {
container.removeChild(childs[0]);
container.appendChild(renderer.domElement);
} else {
container.appendChild(renderer.domElement);
}
// container.appendChild(renderer.domElement);
// 创建场景
scene = new THREE.Scene();
// 创建相机
// camera = new THREE.PerspectiveCamera(100, window.innerWidth / window.innerHeight, 0.1, 100);
camera = new THREE.PerspectiveCamera(50, (window.innerWidth-30)/(window.innerHeight-200), 0.1, 2000);
camera.position.set(0, 450, 200);
camera.up.set(0, -1, 0);
camera.lookAt(0, 0, 0);
// 材质、天空盒暂时没用
var material = new THREE.MeshBasicMaterial(
// {color: 0xffff00}
); //材质
var texture = new THREE.TextureLoader().load(this.bigImg); // 底图
material.map = texture;
var skyBox = new THREE.Mesh(
new THREE.SphereBufferGeometry(100, 32, 32),
material
);
// 平行光源
var light = new THREE.DirectionalLight();
light.position.set(0, 1000, 0);
scene.add(light);
// 环境光
let ambientLight = new THREE.AmbientLight( 0xffffff, 0.4 );
scene.add( ambientLight );
// skyBox.geometry.scale(1, 1, -1);
// scene.add(skyBox);
let loader = new OBJLoader();
loader.load(
// 路径
'/static/1.obj',
// 当模型加载完成(100%)后执行
(object) => {
//console.log(object);
this.object = object;
var objBbox = new THREE.Box3().setFromObject(object.children[0]);
// console.log(objBbox);
// var center = (objBbox.max + objBbox.min) / 2;
// //var center = object.children[0].
// getCenter、center方法或属性怎么用不了,只好用这个笨方法
var cx = (objBbox.max.x + objBbox.min.x) / 2;
var cy = (objBbox.max.y + objBbox.min.y) / 2;
var cz = (objBbox.max.z + objBbox.min.z) / 2;
object.position.y = cy;
object.position.x = cx;
object.position.z = cz;
// 风机叶片group,旋转
var l0 = this.object.children[0];
var l1 = this.object.children[1];
var l2 = this.object.children[2];
var l3 = this.object.children[5];
var l4 = this.object.children[6];
var l5 = this.object.children[7];
var l6 = this.object.children[8];
// 柱子group,不动
var m0 = this.object.children[3];
var m1 = this.object.children[4];
// 将各个零件位置移到0点
l0.position.set(-cx, -cy, -cz);
l1.position.set(-cx, -cy, -cz);
l2.position.set(-cx, -cy, -cz);
l3.position.set(-cx, -cy, -cz);
l4.position.set(-cx, -cy, -cz);
l5.position.set(-cx, -cy, -cz);
l6.position.set(-cx, -cy, -cz);
m0.position.set(-cx, -cy, -cz);
m1.position.set(-cx, -cy, -cz);
// 添加到group中
fans.add(l0);
fans.add(l1);
fans.add(l2);
fans.add(l3);
fans.add(l4);
fans.add(l5);
fans.add(l6);
beam.add(m0);
beam.add(m1);
// 添加到场景
scene.add(beam);
scene.add(fans);
//scene.add(object);
renderer.render(scene, camera)
}
)
window.addEventListener('resize', this.onWindowResize, false);
var bMouseDown = false;
var x = -1;
var y = -1;
// 添加鼠标事件
container.onmousedown = function(event) {
event.preventDefault(); //取消默认事件
x = event.clientX;
y = event.clientY;
bMouseDown = true;
}
container.onmouseup = function(event) {
event.preventDefault();
bMouseDown = false;
}
container.onmousemove = function(event) {
event.preventDefault();
if (bMouseDown) {
skyBox.rotation.y += -0.005 * (event.clientX - x);
skyBox.rotation.x += -0.005 * (event.clientY - y);
if (skyBox.rotation.x > Math.PI / 2) {
skyBox.rotation.x = Math.PI / 2
}
if (skyBox.rotation.x < -Math.PI / 2) {
skyBox.rotation.x = -Math.PI / 2
}
x = event.clientX;
y = event.clientY;
}
}
container.onmousewheel = function(event) {
event.preventDefault();
if (event.wheelDelta != 0) {
camera.fov += event.wheelDelta > 0 ? 1 : -1;
if (camera.fov > 150) {
camera.fov = 150;
} else if (camera.fov < 30) {
camera.fov = 30;
}
camera.updateProjectionMatrix();
}
},
container.mouseout = function(event) {
event.preventDefault();
bMouseDown = false;
}
},
onWindowResize() {
// 窗口缩放的时候,保证场景也跟着一起缩放
// camera.aspect = window.innerWidth / window.innerHeight;
camera.aspect = window.innerWidth / 500;
camera.updateProjectionMatrix();
// renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setSize(window.innerWidth, 500);
},
animate() {
this.animateId = requestAnimationFrame(this.animate);
fans.rotation.y -= 0.01;
//requestAnimationFrame(this.animate);
renderer.render(scene, camera);
}
}
}
</script>
<style scoped>
#container {
width: 100%;
height: 200px;
margin-top: 200px;
}
模型load完成事件中可以用,console.log(object)在控制台查看模型零件,然后决定怎么分组:
代码和模型下载地址,模型是在网上花了好几块钱买的 ^_^ :
三维模型参看软件: