java 3D旋转无法正常工作

时间:2013-08-09 23:29:39

标签: java vector matrix 3d rotation

我已经有了这个旧的图形项目(用oberon编写),因为我把它写成我的第一个项目之一,它看起来有点混乱。 所以我决定,因为无论如何我都会觉得无聊,我会用java重写它。

到目前为止,一切似乎都有效...直到我尝试旋转和/或进行我的眼点转换。 如果我忽略了所说的操作,那么图像就会很好,但是当我尝试进行任何需要我将一个点与变换矩阵相乘的操作时,这一切都会变坏。

  1. 眼点转换会产生愚蠢的小数字,例如[-0.002027571306540​​029,0.05938634628270456,-123.30022583847628] 这会导致生成的图像看起来是空的,但是如果我将每个点乘以1000就会发现它非常非常小,而不是被旋转,只是在一些(看似)随机方向上进行了翻译。
  2. 如果我忽略了眼点,只关注我的旋转,结果也很奇怪(注意:图像根据坐标范围自动缩放):

    1. 将xRotation设置为90°只会使图像非常窄而且太高(分辨率应该是大约1000x1000,然后是138x1000
    2. 将yRotation设置为90°使其非常宽(1000x138)
    3. 将zRotation设置为90°似乎只是将图像一直转换到屏幕的右侧。
    4. 到目前为止我检查了什么:

      1. 我已经检查并重新检查了我的旋转矩阵至少15次,所以它们(可能)是正确的
      2. 使用向量进行测试乘法,并且单位矩阵确实返回原始向量
      3. 我的矩阵在用作旋转矩阵之前被初始化为单位矩阵
      4. 文件中的角度以度为单位,但在读取时会转换为弧度。
      5. 说过我还有两个笔记:

        1. 这种情况下的向量是一个简单的3值双精度数组(表示x,y和z值)
        2. 矩阵是初始化为单位矩阵的4x4双精度数组
        3. 尝试旋转时,按顺序执行:

          1. 比例(乘以比例因子)
          2. 沿x轴旋转
          3. 沿y轴旋转
          4. 沿z轴旋转
          5. 翻译
          6. 做眼点转换
          7. 然后,如果该点尚未在z平面上,则将其投影
          8. 像这样:

            protected void rotate() throws ParseException
                {
                    Matrix rotate_x = Transformations.x_rotation(rotateX);
                    Matrix rotate_y = Transformations.y_rotation(rotateY);
                    Matrix rotate_z = Transformations.z_rotation(rotateZ);
                    Matrix translate = Transformations.translation(center.x(), center.y(), center.z());
            
                    for(Vector3D point : points)
                    {
                        point = Vector3D.mult(point, scale);
                        point = Vector3D.mult(point, rotate_x);
                        point = Vector3D.mult(point, rotate_y);
                        point = Vector3D.mult(point, rotate_z);
                        point = Vector3D.mult(point, translate);
                        point = Vector3D.mult(point, eye);
            
                        if(point.z() != 0)
                        {
                            point.setX(point.x()/(-point.z()));
                            point.setY(point.y()/(-point.z()));
                        }
            
                        checkMinMax(point);
                    }
                }
            

            如果你有兴趣,这里是初始化旋转矩阵的代码:

            public static Matrix eye_transformation(Vector3D eye)throws ParseException
                {
                    double r = eye.length();
                    double teta = Math.atan2(eye.y(), eye.x());
                    double zr = eye.z()/r;
                    double fi = Math.acos(zr);
            
                    Matrix v = new Matrix();
            
                    v.set(0, 0, -Math.sin(teta));
                    v.set(0, 1, -Math.cos(teta) * Math.cos(fi));
                    v.set(0, 2, Math.cos(teta) * Math.sin(fi));
                    v.set(1, 0, Math.cos(teta));
                    v.set(1, 1, -Math.sin(teta) * Math.cos(fi));
                    v.set(1, 2, Math.sin(teta) * Math.sin(fi));
                    v.set(2, 1, Math.sin(fi));
                    v.set(2, 2, Math.cos(fi));
                    v.set(3, 2, -r);
            
                    return v;
                }
            
                public static Matrix z_rotation(double angle) throws ParseException
                {
                    Matrix v = new Matrix();
            
                    v.set(0, 0, Math.cos(angle));
                    v.set(0, 1, Math.sin(angle));
                    v.set(1, 0, -Math.sin(angle));
                    v.set(1, 1, Math.cos(angle));
            
                    return v;
                }
            
                public static Matrix x_rotation(double angle) throws ParseException
                {
                    Matrix v = new Matrix();;
            
                    v.set(1, 1, Math.cos(angle));
                    v.set(1, 2, Math.sin(angle));
                    v.set(2, 1, -Math.sin(angle));
                    v.set(2, 2, Math.cos(angle));
            
                    return v;
                }
            
                public static Matrix y_rotation(double angle) throws ParseException
                {
                    Matrix v = new Matrix();
            
                    v.set(0, 0, Math.cos(angle));
                    v.set(0, 2, -Math.sin(angle));
                    v.set(2, 0, Math.sin(angle));
                    v.set(2, 2, Math.cos(angle));
            
                    return v;
                }
            
                public static Matrix translation(double a, double b, double c) throws ParseException
                {
                    Matrix v = new Matrix();;
            
                    v.set(3, 0, a);
                    v.set(3, 1, b);
                    v.set(3, 2, c);
            
                    return v;
                }
            

            将点与旋转矩阵相乘的实际方法

            注意:NR_DIMS定义为3。

            public static Vector3D mult(Vector3D lhs, Matrix rhs) throws ParseException
                {
                    if(rhs.get(0, 3)!=0 || rhs.get(1, 3)!=0 || rhs.get(2, 3)!=0 || rhs.get(3, 3)!=1)
                        throw new ParseException("the matrix multiplificiation thingy just borked");
            
                    Vector3D ret = new Vector3D();
                    double[] vec = new double[NR_DIMS];
            
                    double[] temp = new double[NR_DIMS+1];      
                    temp[0] = lhs.x;
                    temp[1] = lhs.y;
                    temp[2] = lhs.z;
                    temp[3] = lhs.infty? 0:1;
            
                    for (int i = 0; i < NR_DIMS; i++)
                    {
                            vec[i] = 0;
            
                            // Multiply the original vector with the i-th column of the matrix.
                            for (int j = 0; j <= NR_DIMS; j++)
                            {
                                    vec[i] += temp[j] * rhs.get(j,i);
                            }
                    }
            
                    ret.x = vec[0];
                    ret.y = vec[1];
                    ret.z = vec[2];
                    ret.infty = lhs.infty;
            
                    return ret;
                }
            

            我已经用旧代码检查并重新检查了这段代码(注意:旧代码可以正常工作),并且在操作方面它是完全相同的。

            所以我在这里不知所措,我确实四处寻找类似的问题,但他们并没有真正提供任何有用的信息。

            谢谢:)

            小补充:

            如果我忽略了眼点和旋转(所以我只投影图像)它完全没问题。 我可以看到除了旋转之外图像是完整的。

            还有其他建议吗?

2 个答案:

答案 0 :(得分:0)

我能想到的一些可能的错误:

  • 在Matrix的构造函数中,您没有加载单位矩阵。
  • 您将以度数而不是弧度传递角度。
  • 您的眼球投影矩阵是否在您认为的另一个范围内?我的意思是,在OpenGL中,所有投影矩阵都应该投影到矩形[(-1,-1),(1,1)]上。此矩形代表屏幕。
  • 混合预乘和后乘。 Id est:我通常这样做:矩阵*向量,在你的代码中,你好像在做vector *矩阵,如果我没弄错的话。
  • 在Matrix中混合列和行?

明天我要再看一下你的问题。希望其中一个建议对您有所帮助。

编辑:我忽略了你已经检查了前两项。

答案 1 :(得分:0)

好吧,我现在感觉像个完全白痴。问题是一个简单的逻辑错误。 错误位于代码的这一部分:

for(Vector3D point : points)
        {
            point = Vector3D.mult(point, scale);
            point = Vector3D.mult(point, rotate_x);
            point = Vector3D.mult(point, rotate_y);
            point = Vector3D.mult(point, rotate_z);
            point = Vector3D.mult(point, translate);
            point = Vector3D.mult(point, eye);

            if(point.z() != 0)
            {
                point.setX(point.x()/(-point.z()));
                point.setY(point.y()/(-point.z()));
            }

            checkMinMax(point);
        }

我忘了,当你从列表中获取一个对象时,它是一个具有相同数据的对象的新实例,而不是对它的引用。

所以我所做的只是删除旧条目并将其替换为新条目。

问题解决了。