简体   繁体   中英

QMatrix4x4 Model View Projection OpenGL Can't Get Scene to Render

Given this vertex shader:

attribute vec3 vertex;
uniform mat4 mvp;

void main() {
    gl_Position = mvp * vec4(vertex, 1.0);
}

And this fragment shader:

void main() {
    gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}

Which is able to render the data below, when the mvp matrix is the identity or if the model matrix is a scale, rotate, or tranlate transform:

GLfloat values[] = {
    -1.0, -1.0, +0.0,
    +1.0, -1.0, +0.0,
    +0.0, +1.0, +0.0,
};

Why does the following usage of Qt's QMatrix4x4::lookAt and QMatrix4x4::perspective cause the scene to be rendered as if no object is there?

QMatrix4x4 model;
QMatrix4x4 view;
view.lookAt(
  QVector3D(0.0, 0.0, 10.0), // Eye
  QVector3D(0.0, 0.0, 0.0), // Focal Point
  QVector3D(0.0, 1.0, 0.0)); // Up vector
QMatrix4x4 proj;
// Window size is fixed at 800.0 by 600.0
proj.perspective(45.0, 800.0 / 600.0, 1.0, 100.0);
QMatrix4x4 mvp = (model * view * proj);

What I am looking for is not only how to fix the code but by which means I can attempt to debug these things in the future.


Just on a hunch I changed mvp to p * v * m and it fixed the issue. Why is it mvp if you have to do the multiplication in the opposite order? I know matrix multiplication is not transitive. That is if A and B are matrices, A * B != B * A if A and B are not I.

It's called MVP because... somebody named it that way. ;)

It makes some sense, though. It basically lists the transformations in the order they are applied. You first apply the Model matrix to your vertices, then the View matrix to the result of that, then the projection matrix to the result of both.

Or mathematically, for an input vertex vObj , you could write:

vWorld = M * vObj
vEye = V * vWorld
vClip = P * vEye

If you substitute the equations, you get:

vClip = P * vEye = P * (V * vWorld) = P * (V * (M * vObj))

Matrix multiplications are associative, so this can be rewritten as:

P * (V * (M * vObj)) = (P * V * M) * vObj

Therefore, the combined matrix is calculated as P * V * M .

Reto Koradi is right. And it's not because of memory layout or something, it's because OpenGL uses column vectors - matrix with four rows and one column or 4x1 matrix. Transformations are Matrix4x4 * Vector to meet criteria for matrix multiplications (result is column vector again).

Another approach is to define vector as row (1x4 matrix) and then all transformations are vWorld = vObj * M etc to meet criteria for matrix multiplication resulting in row vector. Out of sudden, last row is rewritten as vClip = vObj * M * V * P .

Matrix multiplication is always the same, you should not need to care how matrices are stored in the memory (well, unless it's linear array and you need to address element at row/column), but transform matrices are different depending on definition of vector.

In OpenGL always compose transforms from right to left. Remember that left-most matrix is applied last.

For some reason (history?), vectors are usually considered column vectors and transform matrices are applied from right to left, but as noted in the comment below, it's possible to use both approaches in GL Shading Language (GLSL).

It's to do with the dimensionality of matrices and mathematical notation. The dimensions of a matrix are defined as rows x columns. So a 1x3 matrix is M = [abc]. Then a 4x4 matrix is as expected.

Multiplying two matrices of dimension AxB and CxD can only be done if B=C (row into column and sum the result).

A list of N vertices with XYZW coordinates can be defined as a matrix Nx4 or 4xN in size, but only 4xN works with the definition of the multiplication operator if the block of vertices come after the matrix:

V' (4xN) = M (4x4) x V (4xN)

So vertices are considered as column vectors to make this notation work.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM