Building a Perspective Projection Matrix

359

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.

Share:
359
majesticglue
Author by

majesticglue

Updated on December 21, 2022

Comments

  • majesticglue
    majesticglue over 1 year

    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.

  • majesticglue
    majesticglue almost 4 years
    I have inverted the columns and I seem to still be receiving negative values for some points. I don't think I have any issue with it being clipped which is odd. Even if I set the near and far plane values to be equal, I still am able to see my points. Also if I multiply one of the points with my projection matrix and I get something like this: [ [1400], [1300], [-6], [5] ] would I happen to divide the x, y, z values by 5?