1

我有这个旧的图形项目(用 oberon 写的),因为我把它写成我的第一个项目之一,它看起来有点混乱。所以我决定,反正我很无聊,我会用java重写它。

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

  1. 眼点变换会生成非常小的数字,其末端坐标如 [-0.002027571306540​​029, 0.05938634628270456, -123.30022583847628] 这会导致生成的图像看起来很空,但是如果我将每个点乘以 1000,结果却是非常非常小,相反被旋转,刚刚被翻译成一些(看似)随机的方向。

如果我然后忽略眼点并只关注我的旋转结果也很奇怪(注意:图像自动缩放取决于坐标范围):

  1. 将 xRotation 设置为 90° 只会使图像非常窄且太高(分辨率应约为 1000x1000,然后是 138x1000
  2. 将 yRotation 设置为 90° 使其非常宽 (1000x138)
  3. 将 zRotation 设置为 90° 似乎只是将图像一直平移到屏幕的右侧。

到目前为止我检查过的内容:

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

话虽如此,我还有 2 个注释:

  1. 在这种情况下,向量是一个简单的 3 值双精度数组(代表 x、y 和 z 值)
  2. 矩阵是一个 4x4 的双精度数组,初始化为单位矩阵

当尝试旋转它们时,我按以下顺序进行:

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

像这样:

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;
    }

我已经用我的旧代码检查并重新检查了这个代码(注意:旧代码有效)并且在操作方面它是相同的。

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

谢谢 :)

小补充:

如果我同时忽略眼点和旋转(所以我只投影图像),它会非常好。我可以看到除了旋转之外图像是完整的。

还有什么建议吗?

4

2 回答 2

0

我能想到的几个可能的错误:

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

我明天再看看你的问题。希望这些建议之一对您有所帮助。

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

于 2013-08-10T00:33:12.933 回答
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);
        }

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

所以我所做的只是删除旧条目并用新条目替换它。

问题解决了。

于 2013-08-16T22:38:02.643 回答