I am trying to understand what the following code does:
glm::mat4 Projection = glm::perspective(35.0f, 1.0f, 0.1f, 100.0f);
Does it create a projection matrix? Clips off anything that is not in the user's view? I wasn't able to find anything on the API page, and the only thing I could find in the pdf on their website was this:
gluPerspective:
glm::mat4 perspective(float fovy, float aspect, float zNear, float zFar); glm::dmat4 perspective( double fovy, double aspect, double zNear, double zFar); From GLM_GTC_matrix_transform extension: <glm/gtc/matrix_transform.hpp>
But it doesn't explain the parameters. Maybe I missed something.
Perspective Projection in OpenGL In the end, only the ratio between the size of the image plane and the focal length is important, which is uniquely defined by the opening angle \Theta. All configurations with the same opening angle result in the same image (only with scaled x- and y-coordinates).
The camera's field of view and image aspect ratio are used to calculate the left, right, bottom and top coordinates which are themselves used in the construction of the perspective projection matrix. This how, they indirectly contribute to modifying how much of the scene we see through the camera.
OpenGL used a function called glFrustum to create perspective projection matrices. This call takes as arguments, the left, right, bottom and top coordinates in addition to the near and far clipping planes.
It creates a projection matrix, i.e. the matrix that describes the set of linear equations that transforms vectors from eye space into clip space. Matrices really are not black magic. In the case of OpenGL they happen to be a 4-by-4 arrangement of numbers:
X_x Y_x Z_x T_x X_y Y_y Z_y T_y X_z Y_z Z_z T_z X_w Y_w Z_w W_w
You can multply a 4-vector by a 4×4 matrix:
v' = M * v v'_x = M_xx * v_x + M_yx * v_y + M_zx * v_z + M_tx * v_w v'_y = M_xy * v_x + M_yy * v_y + M_zy * v_z + M_ty * v_w v'_z = M_xz * v_x + M_yz * v_y + M_zz * v_z + M_tz * v_w v'_w = M_xw * v_x + M_yw * v_y + M_zw * v_z + M_tw * v_w
After reaching clip space (i.e. after the projection step), the primitives are clipped. The vertices resulting from the clipping are then undergoing the perspective divide, i.e.
v'_x = v_x / v_w v'_y = v_y / v_w v'_z = v_z / v_w ( v_w = 1 = v_w / v_w )
And that's it. There's really nothing more going on in all those transformation steps than ordinary matrix-vector multiplication.
Now the cool thing about this is, that matrices can be used to describe the relative alignment of a coordinate system within another coordinate system. What the perspective transform does is, that it let's the vertices z-values "slip" into their projected w-values as well. And by the perspective divide a non-unity w will cause "distortion" of the vertex coordinates. Vertices with small z will be divided by a small w, thus their coordinates "blow" up, whereas vertices with large z will be "squeezed", which is what's causing the perspective effect.
This is a c standalone version of the same function. This is roughly a copy paste version of the original.
# include <math.h> # include <stdlib.h> # include <string.h> typedef struct s_mat { float *array; int width; int height; } t_mat; t_mat *mat_new(int width, int height) { t_mat *to_return; to_return = (t_mat*)malloc(sizeof(t_mat)); to_return->array = malloc(width * height * sizeof(float)); to_return->width = width; to_return->height = height; return (to_return); } void mat_zero(t_mat *dest) { bzero(dest->array, dest->width * dest->height * sizeof(float)); } void mat_set(t_mat *m, int x, int y, float val) { if (m == NULL || x > m->width || y > m->height) return ; m->array[m->width * (y - 1) + (x - 1)] = val; } t_mat *mat_perspective(float angle, float ratio, float near, float far) { t_mat *to_return; float tan_half_angle; to_return = mat_new(4, 4); mat_zero(to_return); tan_half_angle = tan(angle / 2); mat_set(to_return, 1, 1, 1 / (ratio * tan_half_angle)); mat_set(to_return, 2, 2, 1 / (tan_half_angle)); mat_set(to_return, 3, 3, -(far + near) / (far - near)); mat_set(to_return, 4, 3, -1); mat_set(to_return, 3, 4, -(2 * far * near) / (far - near)); return (to_return); }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With