Object3D, matrices and transformations

Started by Enk, April 02, 2009, 03:20:52 PM

Previous topic - Next topic

Enk

Hi, I have some questions that maybe are more related to game engine design than jPCt, but anyway :)

I am currently working on a little 3D-engine in Java using LWJGL just for learning purposes, and the last couple of days I have been reading a lot about 3D-mathematics. I have some questions on how jPCT has implemented translation/rotation-matrices.

I got a working Matrix-class to handle basic 4x4-matrix operations and a simple Vector-class. I've built a little polygon-system on top of that, so currently I can load OBJ-files.

My question is how to implement the translation- and rotation-matrices in my "Object3D"-class. I got functions in my Matrix class for transforming the Matrix (translate, rotate XYZ).

Should I store the location in a Vector and have a translationMatrix in the Object-class, and have a Object3D.translate-function something like this:

public void translate(Vector3D trans) {
    this.translationMatrix.translate(trans);
    this.location.mul(translationMatrix);
}


I am very green on this subject and I haven't found any good books/resouces for this (found A LOT of books on Matrices and 3D-math but none about how you actually implements them in your program). So I just wondered how you experienced programmers would do it  ;D


Enk

#1
Now I kind of realized that the location of an object is in the translationMatrix, and translating the object is then the trivial task of translating the translationMatrix. So the position (relative to its origin) would be the m3, m7 and m11 in a row-ordered matrix.

Should every polygon have its own translationMatrix? E.g. if I want to scale the polygon vertices and not just use glScale().

And how should use the rotationMatrix of the object (e.g. with OpenGL glRotatef). 

I know that these questions may seem odd, but this subject it (currently) a few inches over my head, and I haven't found any example code :)


EgonOlsen

You are right about the translation matrix. It already stores the translation. That's what jPCT does too: It stores a translation and a rotation matrix per Object3D (not per polygon, that would be very memory intense and very very slow to render). Another way would be to store the translation simply as a vector and create/fill the translation matrix in case you need one. In fact, jPCT does it the other round, i.e. storing the data in a matrix but doing most calculation "by hand" using the actual translation values. It's cheaper to do 3 adds or subs than a complete matrix multiplication. On hardware however, it's always a matrix anyway.

Enk

#3
OK, but how is the rotationMatrix actually used?

I guess jPCT uses it own type of rendering-pipeline, but I am trying to get it to work with OpenGL only.

My "rendering" class works like this:
render scene -> render object (translates to the objects translationMatrix) -> render polygon-groups -> render polygons.

I want to be able to rotate an object around it own axis and be able to translate in a direction relative to the objects rotation, much like:
Vector v = obj.getXAxis();
v.mul(2.0f);
obj.translate(v);

EgonOlsen

jPCT does both (own pipeline and hw pipeline)...even more in the 1.18 beta that has been released yesterday. What i do in OpenGL native mode, is to create a transformation matrix out of an object's rotation, transformation, its parents transformation and the camera transformation and feed that into OpenGL's modelview matrix (after a conversion, because the formats differ, but this may not apply to you).

Enk

#5
Ok, thanks. I'll look into it. Just discovered the glLoadMatrix-function and added a transpose and toGLFloatBuffer-function to my Matrix class :D

So I guess the rendering will look something like this:
public void renderScene(Scene scene) {

glPushMatrix();
    // the Camera-transformation will be inverted
    glLoadMatrix(scene.getCamera().toBuffer());
        glPushMatrix();
               // Iterate through objects in the scene
               glLoadMatrix(obj.getTranslation().toBuffer));
               drawObject(obj);

               // If the object has children, iterate through them
               glPushMatrix();
                    glLoadMatrix(child.getTranslation().toBuffer));
                    drawObject(child)
               glPopMatrix();
        glPopMatrix();

glPopMatrix();


}

Enk

Update: No I think I really got it (the translation bit at least).

The rendering "pipe-line" should look something like this (the [C] etc. just shows what Matrices are on the stack).


glLoadTransposeMatrix(CameraMatrix);               [C]
glPushMatrix();                                               [C, C]

....

// Object:

glMultTransposeMatrix(ObjectMatrix);                 [CO, C ]
glPushMatrix();                                               [CO, CO, C]


// Child

glMultTransposeMatrix(ChildMatrix);            [COK, CO, C]
           



I also found the glLoadTransposeMatrix and glMultTransposeMatrix (in OpenGL 1.3) which takes row-ordered matrices as arguments (guess OpenGL's transpose-function is as good as mine :P ).

EgonOlsen

Yes, something like that. Except that you aren't taking the rotation into account, are you? I wasn't aware of that TransposeMatrix-thing. I don't need it anyway, because jPCT's Matrix-dump-method "accidently" transposes the matrix in the way OpenGL needs it, but it's good to know that it exists.

Enk

#8
I am working on the rotations now. Not quite sure how to implement it though. Tried multiplying the rotation matrix and translation matrix but got some strange results :D

Do jPCT use matrices for camera-movement also? I thought it was just to -translate and -rotate the camera values first and everything was OK, but doesn't seem like it. Haven't started reading about quaternions yet :/

Edit: fixed the rotation of objects now (I use just one Matrix in the Object3D-class which handles both translation and rotation, and objects are translated -x, -y, -z before rotation and translated back afterwards to rotate around its own axis). Just have to get the camera class to work now, and some getXAxis-like function so that translation from the objects rotation is trivial.

EgonOlsen

Yes, jPCT uses matrices for the camera too. Don't go into quaternions. You absolutely don't need them for what you want to do. In fact, you actually don't need them at all, because they are mathematically equivalent to matrices, just harder to handle. Them *might* be useful for some rotation interpolation stuff, but personally, i've never ever feeled the urge to prefer them over matrices.

Enk

Thanks again for all the help.

Now I have a working Camera class and I can rotate all objects around their own axis. Just one quick questing about the Camera-class.

Since the transformation of the Camera is applied inverted to the Scene, should add a Invert-matrix method and use it? Inverting matrices seems like a time (and CPU) stealer. Guess the best way is just to create functions that invert the values beforehand e.g.:
public class Camera {
private Matrix transformation;

...

public void rotateX(float theta) {
    transformation.rotateX(-theta);
}


public void translate(Vector3D v) {
    v.mul(-1.0f);
    transformation.translate(v);
}

EgonOlsen

I don't do this. I'm inverting them when i have to. You are actually inverting the camera once per frame...it usually isn't a performance issue. Apart form that, inverting a rotation matrix (which is in fact a 3x3 matrix wrapped into a 4x4) is much easier...just transpose it. That what jPCT Matrix.invert3x3()-method does. It's a lot faster that way.

Enk

My camera-rotation works before I invert (just have to rotateX(-theta) to rotate the right way). But when I try to invert it (by transposing the upper left 3x3 of the matrix I get some strange results). I (trying at least) to have both the translation and the rotation in one matrix.

In the Matrix-class I got a function which returns a FloatBuffer with the inverted matrix:
public FloatBuffer getInvertedBuffer() {
    Matrix temp = new Matrix(this);        // Creates a temporary matrix with this matrix' values.

    temp.invertTranslation();                // This function just negate the values in m3, m7 and m11 (the translation)
    temp.transpose3x3();                    // This function transposes the upper left 3x3 of the matrix

    return temp.getBuffer();
}


I have tested the transpose3x3-functions and it works fine. But doesn't seem like the getInvertedBuffer-functions gives me the right values. Really want this to work since pre-negating all values in all functions of the isn't elegant :P

EgonOlsen

#13
I'm not sure if i got this correctly, but if i did: You can't invert a transformation matrix (i.e. rotation and translation combined) that way. It will work on rotation matrices only.

Enk

#14
Ok, I will try to seperate the camera into two matrices then.

Again thanks for the replies. Allways great to get advice from experienced nerds :)


Edit: Worked like a charm now. Objects and the camera got 2 matrices now and they are multiplied once per frame. Time to clean my code now :D