Sign in to follow this  

why use homogeneous coordinates?

This topic is 3631 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

hi, I'm positing this because I don't really understand the use of homogeneous coordinates in a 4x4 matrix. I understand that the extra dimension is just a dividing factor so...
[ 1 0 0 px ]
[ 0 1 0 py ]
[ 0 0 1 pz ]
[ 0 0 0 1  ]

makes sense as the x, y and z axis would extend to infinity and the point p would remain the same. When adding a vector though, if the w component of each vector in this matrix remain the same, will the resultant vectors w component not be the same as the point/vector to be translated? eg.
[ 1 0 0 0 ]   [ 10 ]   [ 10 ]
[ 0 1 0 0 ]   [ 10 ]   [ 10 ]
[ 0 0 1 0 ] X [ 10 ] = [ 10 ]
[ 0 0 0 1 ]   [  1 ]   [  1 ]

or do the values in the w components in the matrix change?

Share this post


Link to post
Share on other sites
Since nobody answered yet, I will try to add my 2 cents. 4x4 matrices are useful because they let you use linear and affine transformations in the 3x3 space. If you wanted to translate a point, with a 3x3 matrix (and 3-components vectors) you should perform it separately from rotation and scale. Using 4x4 matrices you can perform scale, translation and rotation using just one matrix. Using 4-components vectors lets you use the same classes for vectors and point, since they are semantically different: i.e you can't translate a direction, or get a point length. If you use w = 0 for directions and w = 1 for points, translation wont apply on directions (w = 0). In addition, point + vector = point (1+0=1), point - point = direction (1-1=0), point+direction = point (1+0=1) and so on. Of course, you cannot do point + point or direction - point directly (because these operations are not legal really).
4x4 matrices make possible to apply transformations such as translation with the same matrix you use for rotations and scaling.

Hope this help

Share this post


Link to post
Share on other sites
Homogeneous coordinates are used for projections
e.g.: perspective projections

set w=0 would translate the point infinitely far away after dehomogenization


here is a derivation of the perspective transformation matrix

http://www.cs.kuleuven.ac.be/cwis/research/graphics/INFOTEC/viewing-in-3d/node8.html

there are also some nice properties that you will likely learn when studying computer science

Share this post


Link to post
Share on other sites
Quote:

4x4 matrices make possible to apply transformations such as translation with the same matrix you use for rotations and scaling.

Right.

Quote:

I thought that perspective projection was achieved by dividing the x and y components of the translated coordinate by the z component?

Kinda. The typical projection matrix is most real-time 3D graphics applications looks like

A 0 0 0
0 B 0 0
0 0 C D
0 0 1 0

so when a vertex is multiplied by this vector, we have

x y z w * A 0 0 0 = xA yB zC + wD zE
0 B 0 0
0 0 C E
0 0 D 0

(for row vectors, like D3D; transpose everything for column vectors), and typically E and w are both 1, so we end up with a clip-space vector (xA, yB, zC + D, z). Once clipping is performed, the vector is component-wise divided by it's w component, which is proportional to the original z component of the vector.

So while technically the pipeline performs division by w, in practice, the value of w is usually proportional to the view-space z of the vertex.

Quote:

When adding a vector though, if the w component of each vector in this matrix remain the same, will the resultant vectors w component not be the same as the point/vector to be translated?

How the w component is handled depends on the context in which you are handling it; frequently most CPU-side manipulation uses 3-vectors, and the API understands that 3-vectors should be extended to 4-vectors by setting w to one.

Share this post


Link to post
Share on other sites
Quote:
Original post by staticVoid2
in the last matrix diagram - would the result vector not be:
xA
yB
zC + wE
zD
?

In his example, [x y z w] is a row on the left. In your examples, the vector is a column on the right.

Share this post


Link to post
Share on other sites
Quote:

in the last matrix diagram - would the result vector not be:

Nope.

Looking at the multiplication visually and isolated to this specific scenario, we calculate element i of the result matrix as the dot product of the left vector and column i from the right matrix, for example:

X: (x y z w) <dot> (A 0 0 0) = (xA + 0 + 0 + 0) = xA
Y: (x y z w) <dot> (0 B 0 0) = (0 + yB + 0 + 0) = xB
Z: (x y z w) <dot> (0 0 C D) = (0 + 0 + zC + wD) = zC + wD
W: (x y z w) <dot> (0 0 E 0) = (0 + 0 + zE + 0) = zE

The columns, above, are written as rows to save space.

You can achive the answer you thought would be correct, as JohnBolton says. However, in doing so you change the result of the operation. As I said before, if you want to use columns on the right (and still want to have the same result, but obtained through a different process), you should transpose the matrix as well (consider a translation matrix).

Share this post


Link to post
Share on other sites
so if was to code a camera class that stored a 3x4 matrix:

a b c d
1 0 0 0
0 1 0 0
0 0 1 0

where a was the x axis vector, b - the y axis vector, c - the z axis vector and d the camera location. then I had a function to transform a 3d point.

eg.

1 0 0 10 50
0 1 0 10 x 100
0 0 1 10 50
-1

40
= 90
40




then with the new coordinate (40, 90, 40), divide the x and y components by z
(x/z, y/z) = (1, 2) to give the 2d screen coord.

why do you need an extra component(w) for each vector?

Share this post


Link to post
Share on other sites
Quote:

divide the x and y components by z
(x/z, y/z) = (1, 2) to give the 2d screen coord.

The actual pipeline is more complex than this; the projection matrix which is applied after the view matrix brings the view-space vertices into clip space, where clipping is performed. The vertices that survive are divided by their w coordinates to bring them into normalized-device-coordinate space, which is then offset and scaled by further matrices to bring them into actual pixel coordinates.

Quote:

why do you need an extra component(w) for each vector?

Because otherwise you cannot use a 4x4 matrix. If you don't use a 4x4 matrix, you can't use a single matrix to represent rotational, scaling, and translation.

You can't actually multiply a 3x4 matrix and a 3x1 vector. It's mathematically impossible for the accepted definition of matrix multiplication.

Share this post


Link to post
Share on other sites
I know this isn't really to do with homogeneous coordinates but would this function be correct for performing a z axis rotation on a matrix:

void set_z_rotation(double z_rot) {
if(z_rot >= 0 && z_rot <= 360) {

matrix[0][0] = matrix[0][0] * cos(z_rot) +
matrix[0][0] * sin(z_rot);
matrix[0][1] = matrix[0][1] * cos(z_rot) +
matrix[0][1] * sin(z_rot);
matrix[0][2] = matrix[0][2] * cos(z_rot) +
matrix[0][2] * sin(z_rot);

matrix[1][0] = matrix[1][0] * -sin(z_rot) +
matrix[1][0] * cos(z_rot);
matrix[1][1] = matrix[1][1] * -sin(z_rot) +
matrix[1][1] * cos(z_rot);
matrix[1][2] = matrix[1][2] * -sin(z_rot) +
matrix[1][2] * cos(z_rot);

}
}


where the matrix contains row vectors.?

Share this post


Link to post
Share on other sites
You will probably get a better response if you asked this question as a new thread but I tried to work this out on paper and I think the proper function would be:

void set_z_rotation(double z_rot) {
if(z_rot >= 0 && z_rot <= 360) {

matrix[0][0] = matrix[0][0] * cos(z_rot) +
matrix[1][0] * sin(z_rot);
matrix[0][1] = matrix[0][1] * cos(z_rot) +
matrix[1][1] * sin(z_rot);
matrix[0][2] = matrix[0][2] * cos(z_rot) +
matrix[1][2] * sin(z_rot);
matrix[0][3] = matrix[0][3] * cos(z_rot) +
matrix[1][3] * sin(z_rot);

matrix[1][0] = matrix[0][0] * -sin(z_rot) +
matrix[1][0] * cos(z_rot);
matrix[1][1] = matrix[0][1] * -sin(z_rot) +
matrix[1][1] * cos(z_rot);
matrix[1][2] = matrix[0][2] * -sin(z_rot) +
matrix[1][2] * cos(z_rot);
matrix[1][3] = matrix[0][3] * -sin(z_rot) +
matrix[1][3] * cos(z_rot);

}
}

Although I could be wrong.

Share this post


Link to post
Share on other sites
I take it this is what a y rotation might look like (as a function):

void set_y_rotation(double y_rot) {
if(y_rot >= 0 && y_rot <= 360) {

matrix[0][0] = matrix[0][0] * cos(y_rot) +
matrix[0][2] * -sin(y_rot);

matrix[0][2] = matrix[0][0] * sin(y_rot) +
matrix[0][2] * cos(y_rot);

matrix[2][0] = matrix[2][0] * cos(y_rot) +
matrix[2][2] * -sin(y_rot);

matrix[2][2] = matrix[2][0] * sin(y_rot) +
matrix[2][2] * cos(y_rot);

}
}

Share this post


Link to post
Share on other sites
No you need to do a full matrix multiplication. If you do you will notice that when you multiply a 4x4 matrix with a rotation matrix more than just 4 members change. You really should look into downloading or implementing a matrix class (or set of functions if you are using C). You don't gain much by implementing the multiplication this way and the code readability is a huge gain.

Also replacing all the cos(y_rot) and sin(y_rot) with temporary variables will be beneficial as well.

Share this post


Link to post
Share on other sites
I thought implementing it this way was a lot fater than looping though the matrix because whatever axis you are rotating will stay the same so there is no point in multiplying by 1. And does it matter if the matrix contains row or column vectors when multiplying?

[Edited by - staticVoid2 on January 9, 2008 3:53:20 AM]

Share this post


Link to post
Share on other sites
In that sense I think u're right.
If u have H' = H * Rot_x(angle), the 1-st and 4-th columns of H don't change, so u can update only the 2-nd and 3-rd columns.

Share this post


Link to post
Share on other sites
would this be right when multiplying the full 3x3 matrix with the y rotation matrix.
As you can see there are bits that can be cancelled out but this is just to make things simpler.

matrix[0][0] = matrix[0][0] * cos(y_rot) +
matrix[0][1] * 0 +
matrix[0][2] * -sin(y_rot);

matrix[0][1] = matrix[0][0] * 0 +
matrix[0][1] * 1 +
matrix[0][2] * 0;

matrix[0][2] = matrix[0][0] * sin(y_rot) +
matrix[0][1] * 0 +
matrix[0][2] * cos(y_rot);




matrix[1][0] = matrix[1][0] * cos(y_rot) +
matrix[1][1] * 0 +
matrix[1][2] * -sin(y_rot);

matrix[1][1] = matrix[1][0] * 0 +
matrix[1][1] * 1 +
matrix[1][2] * 0;

matrix[1][2] = matrix[1][0] * cos(y_rot) +
matrix[1][1] * 0 +
matrix[1][2] * sin(y_rot);




matrix[2][0] = matrix[2][0] * cos(y_rot) +
matrix[2][1] * 0 +
matrix[2][2] * -sin(y_rot);

matrix[2][0] = matrix[2][0] * 0 +
matrix[2][1] * 1 +
matrix[2][2] * 0;

matrix[2][0] = matrix[2][0] * cos(y_rot) +
matrix[2][1] * 0 +
matrix[2][2] * sin(y_rot);



would this be right?

Share this post


Link to post
Share on other sites
It would be infinitely better for you to simply implement generic 4x4 matrix operation. The algorithm is provided in the link I gave you in an earlier post.

Special-casing it in this fashion is brittle and error-prone, and in practice there is no good reason for it.

Share this post


Link to post
Share on other sites
The process is basically the same, so long as your matrices are in the correct form. Your solution does not address the issue anyway, it has the same assumptions. You don't need to automagically cope for sense or layout; just pick one as a convention and remain consistent.

Share this post


Link to post
Share on other sites
I wrote this function for multiplying a matrix a while ago (I think it works)

public double[][] multiply(double[][] matrix1, double[][] matrix2) {

double result[][] = new double[matrix1.length][matrix2[0].length];
for(int i = 0; i < matrix1.length; i++) { // loop the rows of matrix1
for(int j = 0; j < matrix2[0].length; j++) { // loop the columns of matrix2
for(int k = 0; k < matrix2.length; k++) { // loop the rows of matrix2
result[i][j] += (matrix1[i][k] * matrix2[k][j]);
}
}
}
return result;

}





Quote:

It would be infinitely better for you to simply implement generic 4x4 matrix operation.


how do I multiply a 3x3 rotation matrix by the 4x4 matrix?

do you fill the extra elements with one:

[ cos@ sin@ 0]
[ -sin@ cos@ 0]
[ 0 0 1]
[ 1 1 1]




????

Share this post


Link to post
Share on other sites
Rot_z =
|c(@) -s(@) 0 0|
|s(@) c(@) 0 0|
| 0 0 1 0|
| 0 0 0 1|

u can see it as a matrix composed by a sub-3x3-matrix, two zero-vectors and 1:
| R 0|
| 0' 1|
R: your 3x3 rotation matrix
0: column vector with 3 zeroes
0': row vector with 3 zeroes
1: last cell

Share this post


Link to post
Share on other sites

This topic is 3631 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this