2016-01-08 32 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,这非常有趣。 –