那么,我们该怎么办呢?我们查找手册,发现three.js中有一个类,Object3D()。这个类生成一个3D的模型,也可以说是容器。那么,我们可不可以通过生成一个容器,然后再将我们需要的图形放入这个容器,再调整容器和图形的位置来实现图形绕任意轴旋转呢?很显然,是可以的,如果你能想到,说明你的智商还是值得称道的。不过想不到也没有任何问题,因为我们需要承认自己的平庸,才能激励自己努力学习。接下来,我们来探讨,如何进行旋转操作。
首先,我们先生成一个容器对象,并且加入坐标轴显示,看看我们生成的容器是什么样的
1 var upbox = new THREE.Object3D(); 2 scene.add(upbox); 3 upbox.add(new THREE.AxisHelper(3));
效果如下:
可以看出,虽然我们无法看到这个容器,但这个容器还是有其对应的坐标位置。我们可以通过设置其position属性来移动它的位置,或者旋转它。接下来,我们把我们生成的立方体放入这个容器,同时也显示我们立方体的坐标轴。代码如下:
1 var geometry = new THREE.BoxGeometry(1, 1, 1, 8, 8, 8); 2 var material = new THREE.MeshBasicMaterial({ 3 color: 0x00ff00, }); 6 var cube = new THREE.Mesh(geometry, material); 7 cube.add(new THREE.AxisHelper(3)); upbox = new THREE.Object3D(); 10 scene.add(upbox); 11 upbox.add(new THREE.AxisHelper(3)); render = function() { 14 requestAnimationFrame(render); renderer.render(scene, camera); 17 }
效果如图:
可以看到,新加入的这个立方体的坐标轴和这个容器的坐标轴重叠了。而此时,关键的来了,此时我们的立方体的位移已经不是相对于世界坐标了,而是相对于其父容器的坐标。也就是说,我们的立方体现在已经不是相对于世界坐标系的原点来移动了,而是相对于容器的坐标原点。由于截图来表示世界坐标系不是很直观,所以大家可以试着移动一下容器的位置,移动容器的位置,立方体的位置也会跟着容器的变化而变化。
接下来,我们来移动立方体的位置:
1 cube.position.x = 1; 2 cube.position.y = -1;
效果如下:
可以看出,我们的立方体已经移动了,而且是相对于容器的原点来移动的。那么,我们来试一下旋转我们的容器:
1 upbox.rotation.z = 1;
效果如下:
我们的立方体就跟着容器转了起来。
那么,我么就可以得到一个结论:我们可以将我们的容器的坐标轴当作我们需要移动的坐标轴,然后把我们的图形移动到适当的的位置,我们需要让立方体按x=1旋转,就把容器移动到x=1的位置;我们需要让立方体按y=1转,就把我们的容器移动到y=1的位置来旋转。不过这样也有一个问题,那就是我们的立方体的坐标已经不是相对于世界坐标了,这里需要注意。之前说道,只要把立方体移到适当的位置就可以了,那么这个适当的位置是哪里呢?文字描述非常复杂,我们用代码和效果来说明:
1 cube.add(new THREE.AxisHelper(1)); 2 cube.position.x = 0.5; 3 cube.position.y = 0.5; 4 cube.position.z = -0.5;
效果图:
这个位置就可以说成是适当的位置,我们直接设置好容器的坐标,再让容器旋转,就达到了我们绕任意轴旋转的功能。当然,按照个人的需求,这个适当位置是可以调整的。
如果我们需要实现复杂的控制,那么我们就可以采用容器里套容器的方法。这个和动画中的骨骼非常像,不过也不一样。接下来,我们就可以继续接着之前的那个机器人来绘制我们的机器人手臂了。
upbox = new THREE.Object3D(); 3 upbox.position.x = 0.5; 4 upbox.position.y = -1.0; 5 scene.add(upbox); 6 upbox.add(new THREE.AxisHelper(2)); 7 var geometry = new THREE.BoxGeometry(1, 0.1, 0.1); 8 var material = new THREE.MeshBasicMaterial({ 9 color: 0xFF2E67, 10 wireframe: true 11 } 12 13 ); 14 var ge = new THREE.Mesh(geometry, material); 15 ge.position.x = 0.5; 16 ge.position.y = 0; box = new THREE.Object3D(); 19 box.position.x = 1.0; 20 box.position.y = 0.0; 21 scene.add(box); geometry = new THREE.BoxGeometry(0.1, 1, 0.1); 24 var material = new THREE.MeshBasicMaterial({ 25 color: 0xFF2E67, 26 wireframe: true 27 } 28 29 ); 30 var ge_next = new THREE.Mesh(geometry, material); 31 ge_next.position.y = 0.5; 32 box.add(ge_next); handbox = new THREE.Object3D(); 35 handbox.position.x = 0; 36 handbox.position.y = 0.0; 37 scene.add(handbox); geometry = new THREE.BoxGeometry(0.5, 0.5, 0.5, 4, 4, 4); 40 var material = new THREE.MeshBasicMaterial({ 41 color: 0xFF2E67, 42 wireframe: true 43 } 44 45 ); 46 var hand = new THREE.Mesh(geometry, material); 47 hand.position.y = 1.2; zhongzhibox = new THREE.Object3D(); 50 zhongzhibox.position.x = 0; 51 zhongzhibox.position.y = 1.5; 52 scene.add(zhongzhibox); geometry = new THREE.BoxGeometry(0.1, 0.5, 0.1); 55 var material = new THREE.MeshBasicMaterial({ 56 color: 0xFF2E67, 57 wireframe: true 58 } 59 60 ); 61 var zhongzhi = new THREE.Mesh(geometry, material); 62 zhongzhi.position.y = 0.2; 63 scene.add(cube); 64 scene.add(sp); 65 scene.add(ge); 66 scene.add(ge_next); 67 scene.add(hand); 68 scene.add(zhongzhi); 69 scene.add(left_leg); 70 scene.add(right_leg);
其中,也有容器中嵌套容器的操作。
那么,就该解决第二个问题了。我们如何通过键盘控制我们的机器人手臂呢?
很简单,使用事件绑定。我们可以给onkeydown这个事件绑定操作,来实现控制机器人的手臂。类似于: