Java:旋转和3D扭曲

时间:2016-03-19 14:46:19

标签: java 3d rotation raytracing distortion

我正在编写一个程序,可以围绕一个点旋转矩形棱镜。它通过3种旋转方法处理旋转,每种方法围绕单个轴(X,Y和Z)管理旋转。这是代码

public void spinZ(Spin spin) {

    if (x == 0 && y == 0) {
        return;
    }
    double mag = Math.sqrt(x * x + y * y);
    double pxr = Math.atan(y / x);
    x = Math.cos(spin.zr + pxr) * mag;
    y = Math.sin(spin.zr + pxr) * mag;
}
public void spinY(Spin spin) {

    if (z == 0 && x == 0) {
        return;
    }
    double mag = Math.sqrt(x * x + z * z);
    double pxr = Math.atan(z / x);
    x = Math.cos(spin.yr + pxr) * mag;
    z = Math.sin(spin.yr + pxr) * mag;
}
public void spinX(Spin spin) {

    if (z == 0 && y == 0) {
        return;
    }
    double mag = Math.sqrt(y * y + z * z);
    double pxr = Math.atan(z / y);
    y = Math.cos(spin.xr + pxr) * mag;
    z = Math.sin(spin.xr + pxr) * mag;
}

public void addSpin(Spin spin) {

    spinY(spin);
    spinX(spin);
    spinZ(spin);

}

旋转是一个无用的类,存储三个双精度(旋转)。这些方法基本上将旋转转换为2D矢量(我如何存储点)并将它们旋转。第一个if语句确保2D向量的大小为0.允许它们,但在这种情况下,不需要执行旋转计算。另一部分只处理trig。底部方法只是将所有内容联系在一起,并允许我快速更改旋转的顺序(因为顺序应该并且确实会影响最终旋转)。

问题不在于个别轮换,而是在它们全部聚集在一起时。我可以轻松地围绕单个轴进行单次旋转,而不会扭曲矩形棱镜。当我把它们放在一起时,就好像你要调用addSpin()一样。

当首先调用spinY时,当旋转包括Y旋转时,棱镜失真(如果旋转的y分量为零,并且不会发生围绕y轴的旋转,则不会发生失真)。实际上,如果随时调用spinY(),但最后会发生立方体的扭曲。

spinZ()的情况也是如此。如果最后调用spinZ(),则立方体不会变形。但是,spinX()可以去任何地方而不会导致失真。

所以问题是:我是如何进行轮换的?另一个问题是,虽然所有旋转都不能被沿X轴和Y轴或任何其他不同轴(如X和Z,或Y和Z)的旋转所包围,但这三组可以共同进行所有旋转吗?为了澄清,围绕X轴和Y轴的一组旋转无法达到的旋转是否可以通过围绕X轴和Z轴或Y轴和Z轴的一组旋转来达到?

我相信我用来显示棱镜的介质。它是我制作的光线跟踪器,适用于矩形棱镜。这是一个更基于数学的问题,但它有一个相当全面的编程组件。

这些是一些并行计算仍然会产生扭曲。

public void spinZ(Spin spin) {

    double c = Math.cos(spin.yr);
    double s = Math.sin(spin.yr);
    double xp = x*c - y*s;
    double yp = y*s + x*c;
    x = xp;
    y = yp;
}
public void spinY(Spin spin) {

    double c = Math.cos(spin.yr);
    double s = Math.sin(spin.yr);
    double zp = z*c - x*s;
    double xp = z*s + x*c;
    x = xp;
    z = zp;
}
public void spinX(Spin spin) {

    double c = Math.cos(spin.yr);
    double s = Math.sin(spin.yr);
    double yp = y*c - z*s;
    double zp = z*c + y*s;
    y = yp;
    z = zp;
}

1 个答案:

答案 0 :(得分:1)

您检查

之类的内容
x == 0

是不必要和危险的,因为双重几乎永远不会有精确的值0.当你有分裂时,atan可能导致灾难性的精度损失。

他们为什么不必要?因为以下内容以更干净(数字稳定)的方式执行旋转:

double c = Math.cos(spin.yr);
double s = Math.cos(spin.yr);
double zp = z*c - x*s;
double xp = z*s + x*c;
x = xp;
z = zp;

当然,我的例子假设你用右手方向处理y旋转,但是从你的示例代码中你似乎将它视为左手。无论如何,Rotation matrix上的维基百科文章解释了数学。