2016-01-08 36 views
1

我正在處理創建一些3D對象,並創建了一個遞歸方法,我希望能夠生成更多自由度的手指狀對象。這個想法是,每個分段顯示爲一個框,生成一個新的分段,以便它的底面與前一個分段的底部位於相同的位置(如下所示)。 Segment Finger矩形棱鏡的3D旋轉

問題是,當我嘗試旋轉多個軸(即將deltaX和deltaZ設置爲0.3)時,我的算法失敗,我得到了一些奇怪的東西(如下所示)。 Broken Segment Finger

我使用了旋轉矩陣,以便嘗試計算新段的基礎應該基於舊段,它只適用於1個旋轉軸,但在多個時失敗(數學運算在if語句中) 。我已經看過有關Quaternion的文章,但我真的只是好奇爲什麼我的矩陣數學運算不起作用,或者如果Quaternion真的好得多,我可以在我的代碼中實現它們。提前致謝!

void finger(float x, float y, float z, float rx, float ry, float rz, float r, 
float h){ 
    translate(x,-y,z); 
    rotateX(rx); 
    rotateY(ry); 
    rotateZ(rz); 
    translate(0,-h/2,0); 
    box(r,h,r); 
    translate(0,h/2,0); 
    rotateZ(-rz); 
    rotateY(-ry); 
    rotateX(-rx); 
    translate(-x,y,-z); 
    if(r>10){ 
    finger(x+h*sin(rx)*sin(ry)*cos(rz)+h*cos(rx)*sin(rz),y-h*sin(rx)*sin(ry)*sin(rz)+ 
    h*cos(rx)*cos(rz),z-h*sin(rx)*cos(ry),rx+deltaX,ry+deltaY,rz+deltaZ,r-4,h-5); 
    } 
} 

[編輯:MCVE下面,包括我的用於在3D空間中移動的代碼,和設置/變量初始化] [編輯(2):MCVE更新,改變DELTAX,移動deltaY,deltaZ用於移動]

float deltaX,deltaY,deltaZ; 
void setup(){ 
    deltaX=0; 
    deltaY=0; 
    deltaZ=0; 
    fullScreen(P3D); 
} 
void draw(){ 
    noStroke(); 
    camera(-600, -400, -600, 0, -300, 0, 0, 1, 0); 
    background(#51B6F5); 
    directionalLight(255,255,255,0.5,1,0.5); 
    directionalLight(255,255,255,-0.5,1,-0.5); 
    box(400,10,400); 
    tree(0,0,0,0,0,0,40,100); 
} 
void tree(float x, float y, float z, float rx, float ry, float rz, float r, float h){ 
    translate(x,-y,z); 
    rotateX(rx); 
    rotateY(ry); 
    rotateZ(rz); 
    translate(0,-h/2,0); 
    box(r,h,r); 
    translate(0,h/2,0); 
    rotateZ(-rz); 
    rotateY(-ry); 
    rotateX(-rx); 
    translate(-x,y,-z); 
    if(r>10){ 
    tree(x+h*sin(rx)*sin(ry)*cos(rz)+h*cos(rx)*sin(rz),y-h*sin(rx)*sin(ry)*sin(rz)+h*cos(rx)*cos(rz),z-h*sin(rx)*cos(ry),rx+deltaX,ry+deltaY,rz+deltaZ,r-4,h-5); 
    } 
} 
+1

你可以發佈一個[MCVE](http://stackoverflow.com/help/mcve)而不只是你的'finger()'方法嗎? –

+0

當然,補充。它只包含我在3D空間中移動的代碼,繪製方法中繪製的框和變量初始化。 – Changming

+0

我並不想討厭,但這對MCVE來說太多了。你可以用一個簡單的'draw()'函數發佈一個基本的草圖來調用你的'finger()'函數嗎?您不需要任何額外的用戶交互內容。當我嘗試從你的例子中獲得最小值時,我會得到一個黑色的草圖。只需硬編碼顯示問題所需的變量,然後將其他所有內容排除在外。 –

回答

2

我不完全確定你有什麼旋轉和翻譯你畫的每個盒子都在做。他們正在導致你的轉換不真正「堆疊」。我可以盯着他們一個小時,想出爲什麼他們導致了這種行爲,但我不擅長3D的東西。

不過想想這樣說:

在每次調用tree()末,你希望你的起源是在剛繪製(你是盒子的底部箱體的頂部即將畫),並且你想旋轉「堆疊」。

如果你這樣做,那麼你只需要做一些事情 - 首先你會做你的旋轉(因爲原點已經在底部),然後你會翻譯到中心畫你的框,然後您將翻譯到您的框的頂部,這是您希望下一個框的底部的位置。可能更容易只是向你展示的代碼:

void tree2(float x, float y, float z, float rx, float ry, float rz, float r, float h){ 

    //assume current origin is at bottom of box 

    //rotate around bottom 
    rotateX(rx); 
    rotateY(ry); 
    rotateZ(rz); 

    //move to center 
    translate(0,-h/2,0); 

    //draw the box 
    box(r,h,r); 

    //move origin to the top of the box- the bottom of the next box 
    translate(0,-h/2,0); 

    //draw the next box 
    if(r>10){ 
    tree2(x+h*sin(rx)*sin(ry)*cos(rz)+h*cos(rx)*sin(rz),y-h*sin(rx)*sin(ry)*sin(rz)+h*cos(rx)*cos(rz),z-h*sin(rx)*cos(ry),rx+deltaX,ry+deltaY,rz+deltaZ,r-4,h-5); 
    } 
} 

該代碼似乎做你want-它更像一個「蛇」與每節開始前一節結束的地方。

順便說一下,這是一個有趣的小玩具,我會很好奇,看看你最終會用它做什麼!

+0

非常感謝!這看起來幾乎和我想要的完全一樣。然而,我原本希望所有的角度在這些片段之間是相同的,但是正如你可以看到每次旋轉角度並且每次角度變得越來越大時增加角度,這就是爲什麼我在那裏進行了相反的變換。這絕對是一個很大的進步,如果我在某個時候最終做出一些很酷的事情,我一定會回來並在這裏分享!再次感謝! – Changming

+0

實際上,對於上面提到的輕微問題,只需從遞歸調用中刪除rx,ry,rz就可以輕鬆解決問題。 – Changming

+0

@長明,那就是我要說的!感謝您抽出時間製作MCVE,這非常有趣。 –