我在这里的第一篇文章,但希望我可以通过构建类似于OpenGL中的透视投影矩阵来解释我的困境。作为3D图形领域的新手,在使用透视投影乘法后将矩阵相乘后,我很难理解该怎么做。我正在尝试在Flutter中创建此文件,但这应该是有争议的,因为我认为我的转换已关闭。
这就是我所拥有的:
var center = {
'x': size.width / 2,
'y': size.height / 2
};
List points = [];
points.add(createVector(-50, -50, -50, center));
points.add(createVector(50, -50, -50, center));
points.add(createVector(50, 50, -50, center));
points.add(createVector(-50, 50, -50, center));
points.add(createVector(-50, -50, 50, center));
points.add(createVector(50, -50, 50, center));
points.add(createVector(50, 50, 50, center));
points.add(createVector(-50, 50, 50, center));
for (int i = 0; i < points.length; i++) {
var matrix = matmul(projection, points[i]);
var w = matrix[3][0];
projected.add(
Offset(
(matrix[0][0] / w),
(matrix[1][0] / w)
)
);
}
这些是我创建的2个自定义函数:
List createVector(x, y, z, center) {
return [
[center['x'] + x],
[center['y'] + y],
[z],
[0]
];
}
List matmul(a, b) {
int colsA = a[0].length;
int rowsA = a.length;
int colsB = b[0].length;
int rowsB = b.length;
if (colsA != rowsB) {
return null;
}
List result = [];
for (int j = 0; j < rowsA; j++) {
result.add([]);
for (int i = 0; i < colsB; i++) {
double sum = 0.0;
for (int n = 0; n < colsA; n++) {
sum += a[j][n] * b[n][i];
}
result[j].add(sum);
}
}
return result;
}
与每个点相乘的投影矩阵为:
var aspect = size.width / size.height;
var fov = 100;
var near = 200;
var far = 300;
List projection = [
[1 / (aspect * tan(fov / 2)), 0, 0, 0],
[0, 1 / (tan(fov / 2)), 0, 0],
[0, 0, (near + far) / (near - far), (2 * near * far) / (near - far)],
[0, 0, -1, 0]
];
我相信我正在使用正确的投影矩阵来乘以我拥有的每个矢量点。唯一的事情是,从该乘法得到结果后,我不确定要如何处理所得向量。我已经了解了透视图划分,所以我将x,y和z值除以第4个值,但是我可能是错误的。
任何见解或帮助都将受到赞赏。我已经在网上自行学习了很长一段时间,为此感到沮丧。
答案 0 :(得分:1)
在OpenGL中,投影矩阵从右手系统变为左手系统。参见Right-hand rule)。这是通过镜像z轴来实现的。
第三列中的术语必须颠倒(分别为- (near+far) / (near-far)
- (2*near*far) / (near-far)
):
List projection = [
[1 / (aspect * tan(fov/2)), 0, 0, 0],
[0, 1 / (tan(fov/2)), 0, 0],
[0, 0, - (near+far) / (near-far), - (2*near*far) / (near-far)],
[0, 0, -1, 0]
];
透视投影矩阵定义Viewing frustum。它定义了一个投影在2维视口上的3维空间(剪辑空间)。
在OponGL中,所有不在剪辑空间中的几何都将被剪辑。您必须确保几何形状在近平面和远平面之间。