2
votes

my first post here but hopefully I can explain my dilemma with building a perspective projection matrix similar to the one in OpenGL. Being new to the 3D graphics space, I'm having trouble understanding what to do after multiplying my matrix after using a perspective projection multiplication. I'm attempting to create this in Flutter but it should be a moot point as I believe my conversion is off.

Here is what I have:

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

And these are the 2 custom functions I've created:

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

My projection matrix that I'm multiplying each point with is:

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

I believe I am using the correct projection matrix to multiply each vector point that I have. The only thing is, after I get the result from this multiplication, I'm not entirely sure what to do with the resultant vector. I've read about the perspective divide so I am dividing the x, y and z values by the 4th values but I could be incorrect.

Any insight or help is much appreciated. Have been stumped for a long time as I have been learning this online on my own.

1

1 Answers

1
votes

In OpenGL the projection matrix turns from a right handed system to a left handed system. See Right-hand rule). This is accomplished by mirroring the z axis.
The terms in the 3rd column have to be inverted (- (near+far) / (near-far) respectively - (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]
];

The perspective projection matrix defines a Viewing frustum. It defines a 3 dimensional space (clip space) which is projected on the 2 dimensional viewport.
In OponGL all the geometry which is not in clip space is clipped. You have to ensure that the geometry is in between the near and far plane.