Java:旋转和 3D 扭曲

标签 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);

}

Spin 是一个无用的类,它存储三个 double (即循环)。这些方法基本上将旋转转换为二维 vector (我如何存储点)并按原样旋转它们。第一个 if 语句确保 2D vector 的大小不为 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解释数学。

关于Java:旋转和 3D 扭曲,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36103119/

相关文章:

javascript - 如何旋转 Canvas 上下文

javascript - 旋转和偏移动力学 js

JavaFX:带有图像按钮的工具栏

java - 显示 struts 验证消息

c++ - 求模拟粒子轨迹的3D点和 vector 几何C++库

opengl - 在类似 Minecraft 的游戏中渲染每一面具有不同纹理的立方体的有效方法是什么?

camera - Three.js 相机向上或向下倾斜并保持水平水平

java - JMeter 每秒验证/断言请求数

java - Java如何存储空值?

3d - 使用 three.js 设置 Material (obj + mtl)后网格消失