我有这个旧的图形项目(用 oberon 写的),因为我把它写成我的第一个项目之一,它看起来有点混乱。所以我决定,反正我很无聊,我会用java重写它。
到目前为止,一切似乎都有效......直到我尝试旋转和/或进行眼点转换。如果我忽略上述操作,图像会很好,但是当我尝试执行任何需要我将点与变换矩阵相乘的操作时,一切都会变糟。
- 眼点变换会生成非常小的数字,其末端坐标如 [-0.002027571306540029, 0.05938634628270456, -123.30022583847628] 这会导致生成的图像看起来很空,但是如果我将每个点乘以 1000,结果却是非常非常小,相反被旋转,刚刚被翻译成一些(看似)随机的方向。
如果我然后忽略眼点并只关注我的旋转结果也很奇怪(注意:图像自动缩放取决于坐标范围):
- 将 xRotation 设置为 90° 只会使图像非常窄且太高(分辨率应约为 1000x1000,然后是 138x1000
- 将 yRotation 设置为 90° 使其非常宽 (1000x138)
- 将 zRotation 设置为 90° 似乎只是将图像一直平移到屏幕的右侧。
到目前为止我检查过的内容:
- 我已经检查并重新检查了我的旋转矩阵至少 15 次,所以它们(可能)是正确的
- 用向量进行测试乘法,并且单位矩阵确实返回原始向量
- 我的矩阵在用作旋转矩阵之前被初始化为单位矩阵
- 文件中的角度以度为单位,但在读取时转换为弧度。
话虽如此,我还有 2 个注释:
- 在这种情况下,向量是一个简单的 3 值双精度数组(代表 x、y 和 z 值)
- 矩阵是一个 4x4 的双精度数组,初始化为单位矩阵
当尝试旋转它们时,我按以下顺序进行:
- 比例(乘以比例因子)
- 沿 x 轴旋转
- 沿y轴旋转
- 沿 z 轴旋转
- 翻译
- 做眼点变换
- 然后,如果该点尚未在 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;
}
我已经用我的旧代码检查并重新检查了这个代码(注意:旧代码有效)并且在操作方面它是相同的。
所以我在这里不知所措,我确实四处寻找类似的问题,但他们并没有真正提供任何有用的信息。
谢谢 :)
小补充:
如果我同时忽略眼点和旋转(所以我只投影图像),它会非常好。我可以看到除了旋转之外图像是完整的。
还有什么建议吗?