Java:旋转和 3D 扭曲
Java: Rotations and 3D distortions
我正在编写一个程序,该程序将围绕一个点旋转直角棱镜。它通过 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);
}
Spin 是一个无用的 class,它存储三个双打(旋转)。这些方法基本上将旋转转换为 2D 向量(我如何存储点)并旋转它们。第一个 if 语句确保 2D 向量的大小不为 0。它们是允许的,但在那种情况下没有必要执行旋转计算。另一部分只是处理触发。底部方法只是将所有内容联系在一起,并允许我快速更改旋转顺序(因为顺序应该并且确实会影响最终旋转)。
问题不在于单独的轮换,而在于当它们全部聚集在一起时。我可以很容易地绕一个轴旋转一次,而不会扭曲直角棱镜。当我将它们放在一起时,就像您要调用 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;
}
您检查
x == 0
是不必要的和危险的,因为 double 几乎永远不会有精确的值 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 上的维基百科文章解释了数学。
我正在编写一个程序,该程序将围绕一个点旋转直角棱镜。它通过 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);
}
Spin 是一个无用的 class,它存储三个双打(旋转)。这些方法基本上将旋转转换为 2D 向量(我如何存储点)并旋转它们。第一个 if 语句确保 2D 向量的大小不为 0。它们是允许的,但在那种情况下没有必要执行旋转计算。另一部分只是处理触发。底部方法只是将所有内容联系在一起,并允许我快速更改旋转顺序(因为顺序应该并且确实会影响最终旋转)。
问题不在于单独的轮换,而在于当它们全部聚集在一起时。我可以很容易地绕一个轴旋转一次,而不会扭曲直角棱镜。当我将它们放在一起时,就像您要调用 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;
}
您检查
x == 0
是不必要的和危险的,因为 double 几乎永远不会有精确的值 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 上的维基百科文章解释了数学。