解答: 將以下加入 fillScene()

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
for ( var i = 0; i < 24 ; i++ )
{
    var cylinder = new THREE.Mesh( cylGeom, petalMaterial );
    cylinder.scale.x = 0.25;
    cylinder.position.y = petalLength / 2;
    //cylinder.rotation.z = -20 * Math.PI/180;

    var petal = new THREE.Object3D();
    petal.add( cylinder );
    petal.rotation.y = 15*i * Math.PI/180;
    petal.rotation.z = (90-20) * Math.PI/180;
    petal.position.y = flowerHeight;

    flower.add( petal );
}

影片裡的解答還蠻短的,如果你作業寫對了可以跳過以下的說明。如果卡關了不要氣餒,這是最困難的作業之一。但不要跳過這個作業。如果你熟悉這個領域的基礎並了解為什麼答案是這樣,你會深刻理解如何在電腦圖學裡控制座標變換。

如果你不懂我的答案,我的建議是把解答貼進去然後註解掉不同行看看結果。註解掉莖可以看到花瓣的全貌。底下是我的思考過程。

目標是要把一個垂直的圓錐壓扁成花瓣的形狀,旋轉它使其接近水平,然後側面旋轉使其散開像花朵,最後平移到整朵花的頂端。

1
cylinder.scale.x = 0.25;

圓錐形狀的花瓣一開始是沿 Y 軸垂直站立,沿 X 軸壓扁讓它更像花瓣。

1
cylinder.position.y = petalLength / 2;

圓錐預設中心在原點,這個平移讓圓錐的頂端到原點。

1
//cylinder.rotation.z = -20 * Math.PI/180;

我忘記旋轉發生在平移之前,在這裡旋轉花瓣會進入對的角度,但是是繞圓錐的中心轉。

1
2
var petal = new THREE.Object3D();
petal.add( cylinder );

要克服這個問題,我創造了 petal 物件作為圓錐的父物件。這樣我能在平移之後繞原點旋轉。這是我創造 petal 物件的唯一理由。

1
petal.rotation.y = 15*i * Math.PI/180;

繞 Y 軸旋轉讓花瓣沿中心散開。這個旋轉其實是發生在 Z 軸旋轉之後。你設定旋轉值的順序不等於旋轉實際發生順序。你能用 reorder() 改變 Three.js 的旋轉順序,但在這裡我是想先轉 Z 再轉 Y 沒錯。

1
petal.rotation.z = (90-20) * Math.PI/180;

現在花瓣繞頂端旋轉,是我想要的效果。我再轉 70 度到定位。注意到我沿 Z 軸轉,因為先前我是沿 X 軸壓扁。我希望扁的一面朝上。試試看用 cylinder.scale.z = 0.25; 會有甚麼不同,你也可以試 petal.rotation.x 取代 Z 軸旋轉看看明顯的差別。因為 Y 軸旋轉先發生,你會轉到還是垂直的花瓣,接著所有花瓣沿同一個軸轉 70 度。

1
petal.position.y = flowerHeight;

最後將花瓣上移到花朵的中心。