建立透视投影矩阵

时间:2020-06-21 03:42:48

标签: flutter opengl 3d projection-matrix

我在这里的第一篇文章,但希望我可以通过构建类似于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个值,但是我可能是错误的。

任何见解或帮助都将受到赞赏。我已经在网上自行学习了很长一段时间,为此感到沮丧。

1 个答案:

答案 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中,所有不在剪辑空间中的几何都将被剪辑。您必须确保几何形状在近平面和远平面之间。

相关问题