[
Date Prev][
Date Next][
Thread Prev][
Thread Next][
Date Index][
Thread Index]
[
List Home]
| 
[gef3d-dev] Model Matrix in OpenGL vs. X3D
 | 
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