在处理/Java 中,3D 旋转矩阵随着时间的推移而变形

发布于 2024-11-03 05:07:53 字数 2796 浏览 1 评论 0原文

我正在开发一个项目,我想生成 3D 网格来表示一定量的数据。

为了创建这个网格,我想使用变换矩阵,因此我根据在几个网站上找到的数学算法创建了一个类。

一切似乎都有效,缩放/平移,但一旦我在其 x 轴上旋转网格,它就会在 2 到 3 个完整旋转后开始变形。感觉我的比例值正在增加,这改变了我的网格。我在这个问题上苦苦挣扎了几天,但我不知道出了什么问题。

为了使事情更清楚,您可以在此处下载我的完整设置。

我定义了一个盒子的坐标,并在将它们写入屏幕之前将它们放入变换矩阵

这是旋转我的对象的公式

    void appendRotation(float inXAngle, float inYAngle, float inZAngle, PVector inPivot ) {

    boolean setPivot = false;

    if (inPivot.x != 0 || inPivot.y != 0 || inPivot.z != 0) {
        setPivot = true;
    }

    // If a setPivot = true, translate the position
    if (setPivot) {

        // Translations for the different axises need to be set different
        if (inPivot.x != 0) { this.appendTranslation(inPivot.x,0,0); }
        if (inPivot.y != 0) { this.appendTranslation(0,inPivot.y,0); }
        if (inPivot.z != 0) { this.appendTranslation(0,0,inPivot.z); }

    }

    // Create a rotationmatrix
    Matrix3D rotationMatrix = new Matrix3D();

    // xsin en xcos
    float xSinCal = sin(radians(inXAngle));
    float xCosCal = cos(radians(inXAngle));      
    // ysin en ycos
    float ySinCal = sin(radians(inYAngle));
    float yCosCal = cos(radians(inYAngle));     
    // zsin en zcos
    float zSinCal = sin(radians(inZAngle));
    float zCosCal = cos(radians(inZAngle));           

    // Rotate around x
    rotationMatrix.setIdentity();
    // --
    rotationMatrix.matrix[1][1] = xCosCal;
    rotationMatrix.matrix[1][2] = xSinCal;
    rotationMatrix.matrix[2][1] = -xSinCal;
    rotationMatrix.matrix[2][2] = xCosCal;
    // Add rotation to the basis matrix
    this.multiplyWith(rotationMatrix);

    // Rotate around y
    rotationMatrix.setIdentity();
    // --
    rotationMatrix.matrix[0][0] = yCosCal;
    rotationMatrix.matrix[0][2] = -ySinCal;
    rotationMatrix.matrix[2][0] = ySinCal;
    rotationMatrix.matrix[2][2] = yCosCal;
    // Add rotation to the basis matrix
    this.multiplyWith(rotationMatrix);

    // Rotate around z
    rotationMatrix.setIdentity();
    // --
    rotationMatrix.matrix[0][0] = zCosCal;
    rotationMatrix.matrix[0][1] = zSinCal;
    rotationMatrix.matrix[1][0] = -zSinCal;
    rotationMatrix.matrix[1][1] = zCosCal;
    // Add rotation to the basis matrix
    this.multiplyWith(rotationMatrix);

    // Untranslate the position
    if (setPivot) {

        // Translations for the different axises need to be set different
        if (inPivot.x != 0) { this.appendTranslation(-inPivot.x,0,0); }
        if (inPivot.y != 0) { this.appendTranslation(0,-inPivot.y,0); }
        if (inPivot.z != 0) { this.appendTranslation(0,0,-inPivot.z); }

    }

}

有人知道吗?

Im working on a project where i want to generate a 3D mesh to represent a certain amount of data.

To create this mesh i want to use transformation Matrixes, so i created a class based upon the mathematical algorithms found on a couple of websites.

Everything seems to work, scale/translation but as soon as im rotating a mesh on its x-axis its starts to deform after 2 to 3 complete rotations. It feels like my scale values are increasing which transforms my mesh. I'm struggling with this problem for a couple of days but i can't figure out what's going wrong.

To make things more clear you can download my complete setup here.

I defined the coordinates of a box and put them through the transformation matrix before writing them to the screen

This is the formula for rotating my object

    void appendRotation(float inXAngle, float inYAngle, float inZAngle, PVector inPivot ) {

    boolean setPivot = false;

    if (inPivot.x != 0 || inPivot.y != 0 || inPivot.z != 0) {
        setPivot = true;
    }

    // If a setPivot = true, translate the position
    if (setPivot) {

        // Translations for the different axises need to be set different
        if (inPivot.x != 0) { this.appendTranslation(inPivot.x,0,0); }
        if (inPivot.y != 0) { this.appendTranslation(0,inPivot.y,0); }
        if (inPivot.z != 0) { this.appendTranslation(0,0,inPivot.z); }

    }

    // Create a rotationmatrix
    Matrix3D rotationMatrix = new Matrix3D();

    // xsin en xcos
    float xSinCal = sin(radians(inXAngle));
    float xCosCal = cos(radians(inXAngle));      
    // ysin en ycos
    float ySinCal = sin(radians(inYAngle));
    float yCosCal = cos(radians(inYAngle));     
    // zsin en zcos
    float zSinCal = sin(radians(inZAngle));
    float zCosCal = cos(radians(inZAngle));           

    // Rotate around x
    rotationMatrix.setIdentity();
    // --
    rotationMatrix.matrix[1][1] = xCosCal;
    rotationMatrix.matrix[1][2] = xSinCal;
    rotationMatrix.matrix[2][1] = -xSinCal;
    rotationMatrix.matrix[2][2] = xCosCal;
    // Add rotation to the basis matrix
    this.multiplyWith(rotationMatrix);

    // Rotate around y
    rotationMatrix.setIdentity();
    // --
    rotationMatrix.matrix[0][0] = yCosCal;
    rotationMatrix.matrix[0][2] = -ySinCal;
    rotationMatrix.matrix[2][0] = ySinCal;
    rotationMatrix.matrix[2][2] = yCosCal;
    // Add rotation to the basis matrix
    this.multiplyWith(rotationMatrix);

    // Rotate around z
    rotationMatrix.setIdentity();
    // --
    rotationMatrix.matrix[0][0] = zCosCal;
    rotationMatrix.matrix[0][1] = zSinCal;
    rotationMatrix.matrix[1][0] = -zSinCal;
    rotationMatrix.matrix[1][1] = zCosCal;
    // Add rotation to the basis matrix
    this.multiplyWith(rotationMatrix);

    // Untranslate the position
    if (setPivot) {

        // Translations for the different axises need to be set different
        if (inPivot.x != 0) { this.appendTranslation(-inPivot.x,0,0); }
        if (inPivot.y != 0) { this.appendTranslation(0,-inPivot.y,0); }
        if (inPivot.z != 0) { this.appendTranslation(0,0,-inPivot.z); }

    }

}

Does anyone have a clue?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

じее 2024-11-10 05:07:53

你永远不想累积变换矩阵。这会在矩阵中引入错误,并导致正交组件缩放或倾斜等问题。

正确的方法是记录累积的俯仰角、偏航角、横滚角。然后每次更新时从这些角度重建变换矩阵。

You never want to cumulatively transform matrices. This will introduce error into your matrices and cause problems such as scaling or skewing the orthographic components.

The correct method would be to keep track of the cumulative pitch, yaw, roll angles. Then reconstruct the transformation matrix from those angles every update.

情何以堪。 2024-11-10 05:07:53

如果有任何机会:避免旋转矩阵相乘。跟踪累积旋转并在每一步计算新的旋转矩阵。

如果无法避免旋转矩阵相乘,则 重新规范化它们(从第16页开始)。它对我来说适用于超过 10,000 次乘法。

然而,我怀疑这对你没有帮助,数值错误通常需要超过 2 个步骤才能显现出来。在我看来,你的问题的原因是在其他地方。

偏航、俯仰和滚动不适合任意旋转。欧拉角存在奇异性和不稳定性。请观看 38:25(David Sachs 的演讲)

http://www.youtube.com/watch ?v=C7JQ7Rpwn2k

祝你好运!

If there is any chance: avoid multiplying rotation matrices. Keep track of the cumulative rotation and compute a new rotation matrix at each step.

If it is impossible to avoid multiplying the rotation matrices then renormalize them (starts on page 16). It works for me just fine for more than 10 thousand multiplications.

However, I suspect that it will not help you, numerical errors usually requires more than 2 steps to manifest themselves. It seems to me the reason for your problem is somewhere else.

Yaw, pitch and roll are not good for arbitrary rotations. Euler angles suffer from singularities and instability. Look at 38:25 (presentation of David Sachs)

http://www.youtube.com/watch?v=C7JQ7Rpwn2k

Good luck!

帅气称霸 2024-11-10 05:07:53

正如@don 提到的,尽量避免累积转换,因为你可能会遇到各种各样的问题。一次旋转一个轴可能会导致您出现万向节锁定问题。尝试一次性完成所有旋转。

另外,请记住,Processing 附带了它自己的 Matrix3D 类,名为 PMatrix3D 具有 rotate() 方法,它采用角度(以弧度为单位)和旋转轴的 x、y、z 值。

这是一个可以旋转一堆 PVector 的示例函数:

PVector[] rotateVerts(PVector[] verts,float angle,PVector axis){
  int vl = verts.length;
  PVector[] clone = new PVector[vl];
  for(int i = 0; i<vl;i++) clone[i] = verts[i].get();
  //rotate using a matrix
  PMatrix3D rMat = new PMatrix3D();
  rMat.rotate(angle,axis.x,axis.y,axis.z);
  PVector[] dst = new PVector[vl];
  for(int i = 0; i<vl;i++) {
    dst[i] = new PVector();
    rMat.mult(clone[i],dst[i]);
  }
  return dst;
}

这是一个使用它的示例

旋转矩阵

HTH

As @don mentions, try to avoid cumulative transformations, as you can run into all sort of problems. Rotating by one axis at a time might lead you to Gimbal Lock issues. Try to do all rotations in one go.

Also, bare in mind that Processing comes with it's own Matrix3D class called PMatrix3D which has a rotate() method which takes an angle(in radians) and x,y,z values for the rotation axis.

Here is an example function that would rotate a bunch of PVectors:

PVector[] rotateVerts(PVector[] verts,float angle,PVector axis){
  int vl = verts.length;
  PVector[] clone = new PVector[vl];
  for(int i = 0; i<vl;i++) clone[i] = verts[i].get();
  //rotate using a matrix
  PMatrix3D rMat = new PMatrix3D();
  rMat.rotate(angle,axis.x,axis.y,axis.z);
  PVector[] dst = new PVector[vl];
  for(int i = 0; i<vl;i++) {
    dst[i] = new PVector();
    rMat.mult(clone[i],dst[i]);
  }
  return dst;
}

and here is an example using it.

rotation matrix

HTH

捎一片雪花 2024-11-10 05:07:53

瞎猜:我不知道您正在使用的编程语言的规则或名称,但这个过程看起来很可疑:

void setIdentity() {  
    this.matrix = identityMatrix;
}

您确定要复制 identityMatrix 吗?如果您只是复制一个引用,那么 identityMatrix 将被后续操作修改,很快就没有任何意义了。

A shot in the dark: I don't know the rules or the name of the programming language you are using, but this procedure looks suspicious:

void setIdentity() {  
    this.matrix = identityMatrix;
}

Are you sure your are taking a copy of identityMatrix? If it is just a reference you are copying, then identityMatrix will be modified by later operations, and soon nothing makes sense.

遇见了你 2024-11-10 05:07:53

尽管建议的矩阵重整化在实践中可能效果很好,但从数学的角度来看,它有点特殊。更好的方法是使用四元数表示累积旋转,四元数仅在应用时转换为旋转矩阵。四元数也会从正交性缓慢漂移(尽管速度较慢),但重要的是它们具有明确定义的重整化。

实现这一点的良好起始信息可以是:

有用的学术参考资料可以是:

  • K. Shoemake,“用四元数曲线动画旋转”,ACM
    SIGGRAPH 计算。图,卷。 19、没有。 3,第 245–254 页,1985 年。DOI:10.1145/325165.325242

Though the matrix renormalization suggested probably works fine in practice, it is a bit ad-hoc from a mathematical point of view. A better way of doing it is to represent the cumulative rotations using quaternions, which are only converted to a rotation matrix upon application. The quaternions will also drift slowly from orthogonality (though slower), but the important thing is that they have a well-defined renormalization.

Good starting information for implementing this can be:

A useful academic reference can be:

  • K. Shoemake, “Animating rotation with quaternion curves,” ACM
    SIGGRAPH Comput. Graph., vol. 19, no. 3, pp. 245–254, 1985. DOI:10.1145/325165.325242
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文