three.js 对象绕任意轴旋转--模拟门转动

时间:2024-01-27 09:50:27

说了几篇的数学方法,这篇放松一下,郭先生说说绕任意轴转动。说一说其中一种方法,也是比较容易理解的一种,它的原理就是将子对象放到一个盒子中,然后改变子对象相对于父对象的位置(因为子对象的原点默认还是在盒子的中心),最后转动盒子,这样子对象的旋转就不是绕盒子的中心了。如图所示。在线案例点击模拟门旋转(更多three.js相关文章和案例请点击原文)。

说到这里就不得不说THREE.Group对象了,除了isGroup和type这两个属性,它几乎和Object3D是相同的。其目的是使得组中对象在语法上的结构更加清晰。它的作用就像一个容器。
下面说一下主要代码(为了练习,门框使用THREE.Geometry())

var geometry = new THREE.Geometry();//新建门框的几何体
var vertices = [
    new THREE.Vector3(-30, 70, 4), new THREE.Vector3(30, 70, 4), new THREE.Vector3(30, -70, 4), new THREE.Vector3(-30, -70, 4),
    new THREE.Vector3(-30, 70, -4), new THREE.Vector3(30, 70, -4), new THREE.Vector3(30, -70, -4), new THREE.Vector3(-30, -70, -4),
    new THREE.Vector3(-27, 67, 4), new THREE.Vector3(27, 67, 4), new THREE.Vector3(27, -67, 4), new THREE.Vector3(-27, -67, 4),
    new THREE.Vector3(-27, 67, -4), new THREE.Vector3(27, 67, -4), new THREE.Vector3(27, -67, -4), new THREE.Vector3(-27, -67, -4),
];
var faces = [
    new THREE.Face3(0, 8, 9), new THREE.Face3(0, 9, 1), new THREE.Face3(1, 9, 10), new THREE.Face3(1, 10, 2),
    new THREE.Face3(2, 10, 11), new THREE.Face3(2, 11, 3), new THREE.Face3(3, 11, 8), new THREE.Face3(3, 8, 0),
    new THREE.Face3(4, 5, 13), new THREE.Face3(4, 13, 12), new THREE.Face3(5, 6, 14), new THREE.Face3(5, 14, 13),
    new THREE.Face3(6, 7, 15), new THREE.Face3(6, 15, 14), new THREE.Face3(7, 4, 12), new THREE.Face3(7, 12, 15),
    new THREE.Face3(0, 1, 5), new THREE.Face3(0, 5, 4), new THREE.Face3(2, 3, 7), new THREE.Face3(2, 7, 6),
    new THREE.Face3(1, 2, 6), new THREE.Face3(1, 6, 5), new THREE.Face3(0, 4, 7), new THREE.Face3(0, 7, 3),
    new THREE.Face3(9, 8, 12), new THREE.Face3(9, 12, 13), new THREE.Face3(14, 15, 11), new THREE.Face3(14, 11, 10),
    new THREE.Face3(13, 14, 10), new THREE.Face3(13, 10, 9), new THREE.Face3(12, 8, 11), new THREE.Face3(12, 11, 15),
];
geometry.vertices = vertices;//几何体添加顶点数组
geometry.faces = faces;//几何体添加面数组
geometry.computeFaceNormals();//计算 face normals 值。
var material = new THREE.MeshPhongMaterial({ color: 0x330000, shininess: 40 });//新建和门搭调的材质
var mesh = new THREE.Mesh(geometry, material);
mesh.position.x = -27;//x方向偏移27,是门宽的一般
mesh.position.y = 70;//将门框偏移一定的单位
group.add(mesh);//在group中添加门框

var doorGeom = new THREE.BoxGeometry(54, 134, 6);//新建门的几何体,注意这里的门宽度为54
var texture = new THREE.TextureLoader().load(require(\'../assets/images/base/door.jpg\'));//创建一个纹理贴图
var doorMate = new THREE.MeshPhongMaterial({ color: 0xffffff, shininess: 200, specular: 0x090909, map: texture });//为门添加一个高光材质和纹理贴图
var doorMesh = new THREE.Mesh(doorGeom, doorMate);
doorMesh.position.x = -27;//给门添加偏移量和门框相同
doorMesh.position.y = 70;
doorGroup.add(doorMesh);//将门添加到doorGroup中
group.add(doorGroup);然后将doorGroup添加到group中

group.position.x = 27;//因为之前的所有都添加了-27的偏移量,为了保证门在世界坐标系的中心,我在将门的Group的x方向平移27。
scene.add(group);//最后将scene中添加group。

这里主要注意的就是门的长宽高,还有门和group的移动距离需要简单的计算一下,

接下来可以添加tween动画进行开关门的动画,这里就不多说了,直接上代码。

initTween() {
    var config = { rotate: 0 };
    tween1 = new TWEEN.Tween(config).to({ rotate: 1 }, 1000);
    tween2 = new TWEEN.Tween(config).to({ rotate: 0 }, 1000);
    tween1.easing(TWEEN.Easing.Quadratic.InOut);
    tween2.easing(TWEEN.Easing.Quadratic.InOut);
    tween1.onUpdate(onUpdate);
    tween2.onUpdate(onUpdate);
},
function onUpdate() {
    let rotate = this._object.rotate;
    doorGroup.rotation.y = Math.PI / 3 * rotate;
}

这里说的是简单的绕中心轴的转动,当然还有很多方法,比如骨骼动画什么的(当然骨骼动画的原理和这个也很相似)。

 

转载请注明地址:郭先生的博客