1. 程式人生 > >使用three.js實現機器人手臂的運動效果

使用three.js實現機器人手臂的運動效果

rotation 讓我 mes 特殊性 骨骼 都是 包括 跟著 實現圖

  Three.js 是一款運行在瀏覽器中的 3D 引擎,你可以用它創建各種三維場景,包括了攝影機、光影、材質等各種對象。你可以在它的主頁上看到許多精彩的演示。不過,這款引擎目前還處在比較不成熟的開發階段,其不夠豐富的 API 以及匱乏的文檔增加了初學者的學習難度(尤其是文檔的匱乏)three.js的代碼托管在github上面。——百度百科

  Three.js封裝了OpenGl ES 2.0 的API,使得我們更容易在瀏覽器上開發各種圖形效果。比起使用winform,MFC等形式,這個代碼庫可以讓我們避開一些winform和MFC的細節問題,而專註於圖形的繪制。不過由於這個庫也並沒有封裝到非常完美,所以有些部分還需要我們自己來實現。

  在此貼上Three.js中文文檔的連接地址Three.js 中文文檔 | 參考手冊 | 使用指南 | 動畫特效實例 | 踏得網

  雖然這個鏈接上的文檔有一些錯誤,還有許多坑,很多東西都沒有說明清楚,不過,也是可以參考的。

  如果要直接看效果,可以直接下載文章末尾的源代碼,附帶了操作方式。還需要使用電腦瀏覽器打開代碼,因為沒有對移動端做適配,所以移動端效果不好。

  接下來,讓我們實現一個機器人的手臂運動效果。效果如下圖

  技術分享

  很醜對不對,但這只是一個教程,所以美化可以自己來做,過多的美化工作反而會增加學習的復雜程度。

  我們制作這個機器人,需要解決的一些問題是:

    1.如何讓我們的圖形沿著任意軸轉動;

    2.如何使用鍵盤控制其轉動;

  這兩個問題解決了,那麽我們的機器人也就非常容易繪制了。接下來,就開始詳解代碼以及思路了。

  首先,我們需要生成一個canvas,因為在html5中,所有的繪圖工作都是在canvas中進行。我們可以寫一個canvas標簽,也可以讓Three.js幫我們生成一個。這裏我們讓Three.js幫我們生成:

  

 1 var scene = new THREE.Scene();
 2 var camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 1, 1000);
3 camera.position.z = 5; 4 camera.position.y = 1; 5 camera.position.x = 1.5; 6 camera.lookAt(new THREE.Vector3(0, 0, 0)); 7 scene.add(camera); 8 var renderer = new THREE.WebGLRenderer(); 9 renderer.setSize(window.innerWidth, window.innerHeight); 10 document.body.appendChild(renderer.domElement);

  為什麽相機要進行位置的調整呢?這是因為,如果我們不調整位置,那麽我們的視角是正對著物體的,物體的3D效果會因為視角問題而顯得不那麽明顯。

  接下來,我們要繪制機器人的頭,腿,身體。需要註意的是,如果我們為我們生成的圖形選擇了不合適的材質,會導致3D效果觀察不明顯。關於材質的選擇,已經超出了要講述的範圍,所以為了演示簡單,我們只使用基本材質。代碼如下:

  

 1 //機器人身體
 2 var geometry = new THREE.BoxGeometry(1, 1, 1, 8, 8, 8);
 3 var material = new THREE.MeshBasicMaterial({
 4                     color: 0x00ff00,
 5                     wireframe: true //這裏是為了讓其變成網格狀態,從而使其更容易觀察,默認為false
 6                 });
 7 var cube = new THREE.Mesh(geometry, material);
 8 cube.position.y = -1;
 9 //機器人頭部
10 var head = new THREE.SphereGeometry(0.5, 32, 32);
11 var material = new THREE.MeshBasicMaterial({
12                     color: 0x0909FD,
13                     wireframe: true
14                 });
15 var sp = new THREE.Mesh(head, material);
16 //機器人雙腿
17 var geometry = new THREE.BoxGeometry(0.1, 1, 0.1);
18 var material = new THREE.MeshBasicMaterial({
19                     color: 0xFF2E67,
20                     wireframe: true
21                 });
22 var left_leg = new THREE.Mesh(geometry, material);
23 var right_leg = new THREE.Mesh(geometry, material);
24 left_leg.position.x = -0.3;
25 left_leg.position.y = -2;
26 right_leg.position.x = 0.3;
27 right_leg.position.y = -2;

  我們的機器人就畫成了這樣:

  技術分享

  接下來,就到了最關鍵的地方:機器人手臂的轉動。很多剛學習的同學都發現,我們的圖形的旋轉軸是在圖形的正中心。什麽意思呢?看這個圖:

  技術分享

  我在圖中已經標識了我們生成物體的坐標軸,可以看出,坐標軸實際上是在位置的重心。我們通過函數或者設置屬性的方法,只能繞著這三個軸轉。有同學問,可不可以通過先移位,再旋轉,再移回原位置的方式來解決這個問題呢?我們的計算機圖形學課本上是這麽教的,在winfoem和MFC上也是可以做到的,但由於three.js生成的物體的坐標軸的特殊性,我們無法通過這種形式來解決(親測)。有興趣的同學可以自己試一試。

  那麽,我們該怎麽辦呢?我們查找手冊,發現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,
 4                     wireframe: true //這裏是為了讓其變成網格狀態,從而使其更容易觀察,默認為false
 5                 });
 6 var cube = new THREE.Mesh(geometry, material);
 7 cube.add(new THREE.AxisHelper(3));
 8             
 9 var upbox = new THREE.Object3D();
10 scene.add(upbox);
11 upbox.add(new THREE.AxisHelper(3));
12 
13 var render = function() {
14             requestAnimationFrame(render);
15             upbox.add(cube); //將立方體放入容器
16             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;

  效果圖:

  技術分享

  這個位置就可以說成是適當的位置,我們直接設置好容器的坐標,再讓容器旋轉,就達到了我們繞任意軸旋轉的功能。當然,按照個人的需求,這個適當位置是可以調整的。

  如果我們需要實現復雜的控制,那麽我們就可以采用容器裏套容器的方法。這個和動畫中的骨骼非常像,不過也不一樣。接下來,我們就可以繼續接著之前的那個機器人來繪制我們的機器人手臂了。

  

 1                       //機器人上臂
 2             var 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;
17             //機器人下臂
18             var box = new THREE.Object3D();
19             box.position.x = 1.0;
20             box.position.y = 0.0;
21             scene.add(box);
22             //box.add(new THREE.AxisHelper(2));
23             var 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);
33             //機器人手掌
34             var handbox = new THREE.Object3D();
35             handbox.position.x = 0;
36             handbox.position.y = 0.0;
37             scene.add(handbox);
38             //handbox.add(new THREE.AxisHelper(2));
39             var 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;
48             //機器人中指
49             var zhongzhibox = new THREE.Object3D();
50             zhongzhibox.position.x = 0;
51             zhongzhibox.position.y = 1.5;
52             scene.add(zhongzhibox);
53             //zhongzhibox.add(new THREE.AxisHelper(2));
54             var 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這個事件綁定操作,來實現控制機器人的手臂。類似於:

  

1                      onkeydown = function(event) {
2                 if(angle > 0 || angle <= -1.5) {
3                     angle = 0;
4                     return false;
5                 }
6                  else if(event.keyCode == 38) {
7                     angle -= 0.2;
8                 }
9             }

  為什麽有一個angle呢?因為我們需要判斷我們的機器人的手臂運動的角度,畢竟是手臂,轉動的角度需要有一個限制對吧?但是呢,由於比較復雜(其實是懶),所以我只實現了兩個部位的限制。

  實現了上述的代碼,我們應該就可以畫出一個可以控制的機器人了。

  下面是源代碼:

  機器人手臂源代碼

  

使用three.js實現機器人手臂的運動效果