Translation via 4D Matrices

I'm attempting to implement 4D matrices for manual transformation of a mesh (just for learning purposes) and currently have linear transformations working correctly, but application of translation tends to cause... inaccurate results. I have a side-by-side comparison between OpenGL's results with an appropriate transformation, and my own implementation.

Translation and linear transformations work fine on their own, but combining the two is when I get problems. I know that the issue is that the existing transformations aren't having the correct effect on the translation, and I've tried applying the existing transformations to the new translation and then applying it to the matrix. This got me closer, but I'm still not having any luck. I'm planning on throwing away my current implementation of translation (which just assigns components in that row of the matrix) in the hopes that someone has a proper method somewhere.

The code for the current implementation can be found here:
http://pastebin.com/dK0z8pL1
(Ignore the many inefficiencies)

I'm just not sure what I'm doing wrong with translation and linear transformations.




As a side note, I've also seen that OpenGL's matrices seem to be transposed:
http://www.songho.ca/opengl/files/gl_anglestoaxes01.png
(from http://www.songho.ca/opengl/gl_transform.html)

That is, in comparison to how matrices in my book are represented with their basis vectors as rows instead of columns. Is there any particular reason for this difference?
M_{jk} v_k = M'_{kj} v_k
I suppose that they choose row by row, so all the values are contiguous.

I would need to know more details of your errors. But to combine transformations you should need to just multiply them, so I don't understand why you translate is special. (¿trying to optimize?)

Edit: forgot the transpose in the equation.
Last edited on
Is there any particular reason for this difference?


Use of matrix rows vs matrix columns for recording vectors is completely a matter of convention. Every book/author is free to choose his own convention.

More than enough ground for a holy war :)

My favorite convention, and that used by most books I have read, is to write vectors as column matrices.

Choosing vector rows vs. vector columns however *fixes* the "transposition" of all matrices. Once you fix that, there is no further "choice of transposition": all matrices should match the convention you chose by fixing vector rows vs. vector columns.

The two conventions in a nutshell:
1. Convention vector-columns.
- the i^th matrix column denotes the image of the i^th basis vector.

If A and B are two linear operators with matrices mat(A), mat(B), then
mat (A*B)=mat (A)mat(B)

2. Convention vector-rows.
- the i^th matrix row denotes the image of the i^th basis vector.

If A and B are two linear operators with matrices mat(A), mat(B), then
mat (A *B)=mat(B)*mat(A)
Under convention vector-rows, you gotta reverse the order of multiplication of matrices away from the usually accepted one.
Last edited on
More than enough ground for a holy war :)


Hardly. I haven't seen anyone who ever argued that row first or column first is anything but arbitrary. There are some cases in which one or the other convention leads to more "intuitive" looking expressions though.

Oh, and your names sound kinda weird - a matrix doesn't necessarily represent a particular basis, so referring to the row or column vectors as basis vectors is...
Last edited on
I haven't seen anyone who ever argued that row first or column first is anything but arbitrary.


Well, I kinda did (except I didn't use the word arbitrary so I wasn't that careless :). Your motivation?

[Edit:]
Oh, and your names sound kinda weird - a matrix doesn't necessarily represent a particular basis, so referring to the row or column vectors as basis vectors is...


You are confusing here linear operators vs matrices. Linear operators are the object that is basis-invariant. Matrices [Edit: of linear operators (e.g. rotations)] are always associated to a fixed basis.
Last edited on
Before I continue, I thought that this might also help:

1
2
3
4
CMatrix4f transform;
transform.Rotate (-dtr (camera->rotation.x), -dtr (camera->rotation.y), -dtr (camera->rotation.z));
transform.Translate (-camera->position.x, -camera->position.y, -camera->position.z);
tempMesh.ApplyAffineMatrix (transform);


In a nutshell, that's the code making use of the matrix - that's pretty much all of the interaction with the mechanism that's in my code. I make sure to clear out the current transformation matrix used by OpenGL, which means that the effect is entirely the result of my own matrix code.

so I don't understand why you translate is special
I originally attempted to do translation via:
1
2
3
4
5
6
(*this) = (*this) * CMatrix4 (
	1, 0, 0, 0,
	0, 1, 0, 0,
	0, 0, 1, 0,
	x, y, z, 1
);


but got practically the same results as I'm having by using the code above. You can see the results in the following executable:

http://www.filedropper.com/3dt

(Click and drag to look around, WASD to move. The wireframe shows what it's supposed to be (that is to say, that mesh uses OpenGL's transformation system) while the colored cube is the current target of my own transformations.)

The problem won't immediately be apparent, but if you go to the side of the cube you start to see some problems.
Last edited on
your compiled program doesn't run under latest ubuntu linux(with wine installed) :(

You are confusing here linear operators vs matrices. Linear operators are the object that is basis-invariant. Matrices are always associated to a fixed basis.


No, you are confusing me. I have a feeling we aren't talking about the same kind of basis here. Also, you make it sound as if a matrix was "something that consists of vectors".

Well, I kinda did (except I didn't use the word arbitrary so I wasn't that careless :). Your motivation?


Well, all you did was argue that row first would "reverse" the order of multiplication from the "usually accepted one" - that's assuming that there is such a convention.
@hanst99:
ok here is the solution: you are talking about matrices in computer science, where you have big choices to make. If a matrix is, say, double ** elements;, it does matter big time how you arrange your matrix entries - for optimal performance, you want to de-reference as few pointers as possible.

[Edit:] In fact, I heard of a programming exercise where you have to square 1000 by 1000 dense matrix. As de-referencing a double pointer is considerably slower than a single one, a transposition operation before carrying out the multiplication gave some serious performance benefits (it was like 10%+ according to the guy who told me of the exercise).

I am talking about matrices as they are used in mathematics (I am mathematician), so we were talking different languages. To be honest, your answers were confusing me too, before I understood you were talking of matrices implemented in computers.
Last edited on
Please provide the source code. I cannot run your executable.
An image could work too

1
2
3
4
5
6
7
CMatrix4<double> a;
a.Translate(1,0,0);
a.Rotate(0,0,M_PI/2);

CMatrix4<double> b;
b.Rotate(0,0,M_PI/2);
b.Translate(1,0,0);

a = [
0  1 0 0
-1 0 0 0
0  0 1 0
0  1 0 1
]

b = [
0  1 0 0
-1 0 0 0
0  0 1 0
0  1 0 1
]
As you can see the matrices are not well constructed.

You are using vector-rows, ¿right?
Edit for testing...

Your multiplication is backwards. It should be *this = Transformation*(*this);
Last edited on
I compiled using the VS2011 Beta, which has proved to be problematic for other testers under WINE as well. Unfortunately, I use a few personal libraries in the project, and setting it up to compile yourself would be a chore. At least, in my own opinion. The entire project consists of at least 35 files. I'll provide these if you still insist.

I am using row vectors.

As for an image...

The matrix sometimes seems to work:http://i776.photobucket.com/albums/yy46/wt2tw/b1.png

But this happens when I even slightly look down:
http://i776.photobucket.com/albums/yy46/wt2tw/b2.png

Here's a view from a different perspective, at a more extreme distance:
http://i776.photobucket.com/albums/yy46/wt2tw/b3.png



EDIT: ... crap. I thought the ordering seemed a bit weird. I'll try that and get back to you.
EDIT 2: I seem to be getting the same result either way. If I had a pre-existing translation then I'd probably get a difference, but since there's only one translation (world-to-upright-space) it doesn't have an effect.
... EDIT 3: I only applied the change to translation - I'll apply it to the linear transformations as well.

PRAISE: That did the trick, thanks! And thanks to everyone else as well!
Last edited on
No, I was talking about matrices in mathematics. I thought YOU were talking about matrices as implemented in a program, because then it often makes sense to think of a matrix as a "number of row vectors" or "number of column vectors", but mathematically, it doesn't really (except for convenience when writing down matrix operations of course).
I don't understand your complaint.
You can construct the transformation matrix using the images of the canonical basis.
M_{jk} = M'_{kj} = T( e^{(k)}_j )
Then decide if using M or M'.
Last edited on
@ne555: that indeed is a much shorter way of saying what I went on at length.
In your notation, M'_{kj} is the "standard" convention (vector-column). M_{jk} is the vector-row notation.

If you write a vector v in e_i coordinates, you must either 1) write v as a vector-column and use matrix M' to multiply the vector -column from the left hand side, or 2) write v as a vector-row and use the matrix M to multiply the vector-row from the right hand side.

If you have two linear operators S (matrices M, M') and T (matrices N, N')
then S*T (which means apply first T and second S S and second T) corresponds to the matrix multiplication

(vector-column convention):
S*T-> M' * N',

(reverse order, vector-row convention):
S*T-> N*M

If ever in doubt, stick to the regular convention (vector-columns), i.e. the matrices M'_{kj} in ne555's notation.
Last edited on
Ok, I'll just assume it's a cultural thing then.
Topic archived. No new replies allowed.