Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
[gef3d-dev] Re: Model Matrix in OpenGL vs. X3D

Dear Jens,

that will solve our problem well and also enhances the design of the Graphics3D interface package. However, I do also agree that this refactoring will include a lot of changes. Unlike the previous refactoring, this will have drawbacks as this won't be a pure refactoring but also incorporates changes in the logic.

Unfortunetaly, I see no other way than the one you suggested.

Regards,
Matthias


Dear GEF3D developers,

Matthias Thiele found a problem while implementing an X3D version of Graphics3D. The problem is, that X3D provides transformation nodes, which can not store a full transformation matrix but only rotation, scale and location separately. GEF3D/Draw3D currently uses model matrices, which can easily be passed to OpenGL.

Looks like a real show stopper and we have to refactor GEF3D... Let's see, here is a first idea and draft:

First of all, in GEF3D the modelMatrix is an absolute matrix, that is we do not use a depth hierarchy of matrices. This has two advantages: First of all, we don't have to care about the stack-buffer limitation of OpenGL, which allows only 32 matrices to be stored on the stack (this is usually enough, but since we encapsulate OpenGL, a programmer has no control over that limitation). Secondly, we cache the matrices, and so we only have to recalculate them only if something has changed. If nothing has changed, we can simply copy these matrices to OpenGL. Also, somethings become pretty simple, e.g. TransparencyAsapter.getTransparencyDepth(). This flat hierarchy should be no problem with X3D, the scenegraph maybe becomes flatter.

Now, the problem is that while OpenGL expects matrices instead of separated values for location, scale and rotation, X3D expects these three values. Fortunately, we already store these information separately in Figure3D. Unfortunately, we don't do that in the Shapes.

What I suggest in the following: We could create a new class holding the position of an 3D object. That is like Bounds3D, but with the rotation---and a possibly cached model matrix. From a 3DFigure's point of view, this is simply the strategy pattern, as you will see.

I would suggest to create the following classes and interfaces:

interface Host3D {
    Position3D getPosition3D()
    Host3D getParentHost3D()

    positionChanged(PositionHint hint)
}

Host3D is then to be implemented by Figure3D and Shape3D. The getParent-stuff is required in order to make a position absolute. Position3D should be implemented just as Matrix3f etc., i.e. with an immutable and mutable interface. Here's a draft of its implementation, with some things merged:

class Position3DImpl {
    enum PositionHint {
        location, size, rotation
    };

    Host3D host; // e.g. Figure3D;

    // the following attributes and methods are extracted from Figure3D
    Bounds3D bounds3D;
    Vector3f rotation;
Matrix4fImpl modelMatrix; Matrix4fImpl locationMatrix; // was war hier noch einmal der Unterschied?
    MatrixState matrixState;
public IVector3f getLocation3D() ...
    // and other getters
public void setLocation3D(IVector3f i_point) {
        ... analog Figure3D.setLocation3D
        host.positionChanged(location); // notify host
    }
    public void setRotation3D(IVector3f i_rotation)...
    public void setSize3D(IVector3f i_size) ...
public IVector3f getLocation3D(Point i_point2D) ...
    // and other methods extracted from Figure3D
// last but not least:
    public IMatrix4f getModelMatrix() ...
}

The idea behind this class is twofold: First of all we can simplify Figure3D, and Position3D has no setModelMatrix, only a getter (which can cache the result of multiplying location, size and rotation).

Now we have to change Graphics3DDraw and Shapes accordingly. I only give a draft of the required refactorings here:

Graphics3DDraw.glMultMatrix(m_modelMatrixBuffer) has to be replaced---a first step making this interface more abstract and implementation independent. A first guess would be to replace this method with a "setPosition", but we don't want to convert the position or matrix into a buffer everytime this method is called. For that reason, I suggest using Raw-Objects :

For example, to avoid converting the position everytime, a Shape can cache a converted version. How to handle that? Let's see: Before using a raw position object, a little test is required

    // member: Object posititionRaw - cached Postition3D

    if (! g3d.compatible(positionRaw) ) {
        positionRaw = g3d.createPositionRaw(position3D);
    }
and later in the code the position is set: g3d.setPosition(positionRaw); // was g3d.glMultMatrix(..)

The OpenGL implementation (LWJGL) has to be changed as follows:

    Object createPositionRaw(Position3D p) {
        FloatBuffer raw = BufferUtil.createFloatBuffer(16);
        p.getModelMatrix().toBuffer(raw);
        return raw;
}
    boolean compatible(Object raw) {
        return raw instanceof FloatBuffer;
    }

    void setPosition(PositionRaw raw) {
        org.lwjgl.opengl.GL11.glMultMatrix( (FloatBuffer) raw) );
    }

The X3D implementation then could access location, size and rotation separately. Maybe, its createPositionRaw would simply return the given position object. Maybe the method compativle(Object) could be optimized, maybe by introducing a dummy interface Position3DRaw, but I'm not sure of that.

What I like: Figure3D would be further simplified and all that position crap would be moved into one class. And Graphics3DDraw becomes more implementation independent.
What I don't like: Looks like a lot of things to be changed.

What do you think?

Cheers,

Jens


begin:vcard
fn:Matthias Thiele
n:Thiele;Matthias
email;internet:matthias_thiele@xxxxxxx
tel;cell:+49 176 22382250
x-mozilla-html:TRUE
version:2.1
end:vcard


Back to the top