Java 矩形棱镜的三维旋转

Java 矩形棱镜的三维旋转,java,3d,processing,quaternions,rotational-matrices,Java,3d,Processing,Quaternions,Rotational Matrices,我在处理创建一些3D对象时搞砸了,我创建了一个递归方法,我希望生成一个具有更多自由度的手指状对象。其思想是,显示为长方体的每个线段生成一个新线段,使其底面与前一个线段的底面位于同一位置(如下所示) 问题是,当我尝试旋转多个轴(即,将deltaX和deltaZ都设置为0.3)时,我的算法失败,我得到了一些奇怪的结果(如下所示) 我使用旋转矩阵来计算新线段的基准应基于旧线段的位置,它仅适用于一个旋转轴,但在多个旋转轴上失败(数学在if语句中)。我看过关于四元数的帖子,但我真的很好奇为什么我的矩阵数学

我在处理创建一些3D对象时搞砸了,我创建了一个递归方法,我希望生成一个具有更多自由度的手指状对象。其思想是,显示为长方体的每个线段生成一个新线段,使其底面与前一个线段的底面位于同一位置(如下所示)

问题是,当我尝试旋转多个轴(即,将deltaX和deltaZ都设置为0.3)时,我的算法失败,我得到了一些奇怪的结果(如下所示)

我使用旋转矩阵来计算新线段的基准应基于旧线段的位置,它仅适用于一个旋转轴,但在多个旋转轴上失败(数学在if语句中)。我看过关于四元数的帖子,但我真的很好奇为什么我的矩阵数学不起作用,或者如果四元数真的好得多,我该如何在代码中实现它们。提前谢谢

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);
  }
}

我不太确定在绘制每个框之后,你的旋转和平移是什么。它们导致您的转换不是真正的“堆栈”。我可以再盯着他们看一个小时,想一想为什么他们会做出这种行为,但我不擅长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);
  }
}
这段代码似乎做了你想做的事情——它的行为更像一条“蛇”,每一节都从上一节结束的地方开始


顺便说一句,这是一个有趣的小玩具,我很想看看你最后用它做了什么

你能发布一个而不仅仅是你的
finger()
方法吗?当然,添加了。它只包括我在3D空间中移动的代码,在draw方法中绘制的一个框,以及变量初始化。我不想让人讨厌,但这对于MCVE来说太多了。你能用一个调用你的
finger()
函数的简单
draw()
函数发布一个基本的草图吗?你不需要任何额外的用户交互功能。当我试图从你的例子中得到最小值时,我得到了一个黑色的草图。只需硬编码您需要演示问题的变量,而忽略其他所有内容。对不起,没有太多的MCVEs经验,我认为这应该更好?非常感谢!这看起来几乎和我想要的一模一样。然而,我原本打算让所有的角度在线段之间都是相同的,但是你可以看到,如果每次旋转,并且每次角度越来越大时都增加角度,这就是为什么我在那里进行了反向变换。这无疑是向前迈出的一大步,如果我最终在某个时候用它做了一些很酷的东西,我一定会回来在这里分享!再次感谢!实际上,对于我上面提到的那个小问题,这是一个很容易解决的问题,只需从递归调用中删除rx、ry、rz就可以解决它。@Changming Yep,这就是我要说的!感谢您花时间制作MCVE,玩起来很有趣。