I am writing a little game with the Java 3D API and I use objects of javax.media.j3d.BoundingBox to store the Bounds of a model.
The constructor of the BoundingBox is the following one:
public BoundingBox(Point3d lower, Point3d upper) {
boundId = BOUNDING_BOX;
this.lower = new Point3d(lower);
this.upper = new Point3d(upper);
updateBoundsStates();
}
Now I want to translate and rotate the BoundingBox because the model itself does and I use the following method of BoundingBox:
/**
* Transforms this bounding box by the given matrix.
* @param matrix a transformation matrix
*/
public void transform(Transform3D matrix) {
if(boundsIsInfinite)
return;
if (tmpP3d == null)
tmpP3d = new Point3d();
double ux, uy, uz, lx, ly, lz;
ux = upper.x;
uy = upper.y;
uz = upper.z;
lx = lower.x;
ly = lower.y;
lz = lower.z;
tmpP3d.set(ux, uy, uz);
matrix.transform( tmpP3d );
upper.x = tmpP3d.x;
upper.y = tmpP3d.y;
upper.z = tmpP3d.z;
lower.x = tmpP3d.x;
lower.y = tmpP3d.y;
lower.z = tmpP3d.z;
tmpP3d.set(lx, uy, uz);
matrix.transform( tmpP3d );
if ( tmpP3d.x > upper.x ) upper.x = tmpP3d.x;
if ( tmpP3d.y > upper.y ) upper.y = tmpP3d.y;
if ( tmpP3d.z > upper.z ) upper.z = tmpP3d.z;
if ( tmpP3d.x < lower.x ) lower.x = tmpP3d.x;
if ( tmpP3d.y < lower.y ) lower.y = tmpP3d.y;
if ( tmpP3d.z < lower.z ) lower.z = tmpP3d.z;
tmpP3d.set(lx, ly, uz);
matrix.transform( tmpP3d );
if ( tmpP3d.x > upper.x ) upper.x = tmpP3d.x;
if ( tmpP3d.y > upper.y ) upper.y = tmpP3d.y;
if ( tmpP3d.z > upper.z ) upper.z = tmpP3d.z;
if ( tmpP3d.x < lower.x ) lower.x = tmpP3d.x;
if ( tmpP3d.y < lower.y ) lower.y = tmpP3d.y;
if ( tmpP3d.z < lower.z ) lower.z = tmpP3d.z;
tmpP3d.set(ux, ly, uz);
matrix.transform( tmpP3d );
if ( tmpP3d.x > upper.x ) upper.x = tmpP3d.x;
if ( tmpP3d.y > upper.y ) upper.y = tmpP3d.y;
if ( tmpP3d.z > upper.z ) upper.z = tmpP3d.z;
if ( tmpP3d.x < lower.x ) lower.x = tmpP3d.x;
if ( tmpP3d.y < lower.y ) lower.y = tmpP3d.y;
if ( tmpP3d.z < lower.z ) lower.z = tmpP3d.z;
tmpP3d.set(lx, uy, lz);
matrix.transform( tmpP3d );
if ( tmpP3d.x > upper.x ) upper.x = tmpP3d.x;
if ( tmpP3d.y > upper.y ) upper.y = tmpP3d.y;
if ( tmpP3d.z > upper.z ) upper.z = tmpP3d.z;
if ( tmpP3d.x < lower.x ) lower.x = tmpP3d.x;
if ( tmpP3d.y < lower.y ) lower.y = tmpP3d.y;
if ( tmpP3d.z < lower.z ) lower.z = tmpP3d.z;
tmpP3d.set(ux, uy, lz);
matrix.transform( tmpP3d );
if ( tmpP3d.x > upper.x ) upper.x = tmpP3d.x;
if ( tmpP3d.y > upper.y ) upper.y = tmpP3d.y;
if ( tmpP3d.z > upper.z ) upper.z = tmpP3d.z;
if ( tmpP3d.x < lower.x ) lower.x = tmpP3d.x;
if ( tmpP3d.y < lower.y ) lower.y = tmpP3d.y;
if ( tmpP3d.z < lower.z ) lower.z = tmpP3d.z;
tmpP3d.set(lx, ly, lz);
matrix.transform( tmpP3d );
if ( tmpP3d.x > upper.x ) upper.x = tmpP3d.x;
if ( tmpP3d.y > upper.y ) upper.y = tmpP3d.y;
if ( tmpP3d.z > upper.z ) upper.z = tmpP3d.z;
if ( tmpP3d.x < lower.x ) lower.x = tmpP3d.x;
if ( tmpP3d.y < lower.y ) lower.y = tmpP3d.y;
if ( tmpP3d.z < lower.z ) lower.z = tmpP3d.z;
tmpP3d.set(ux, ly, lz);
matrix.transform( tmpP3d );
if ( tmpP3d.x > upper.x ) upper.x = tmpP3d.x;
if ( tmpP3d.y > upper.y ) upper.y = tmpP3d.y;
if ( tmpP3d.z > upper.z ) upper.z = tmpP3d.z;
if ( tmpP3d.x < lower.x ) lower.x = tmpP3d.x;
if ( tmpP3d.y < lower.y ) lower.y = tmpP3d.y;
if ( tmpP3d.z < lower.z ) lower.z = tmpP3d.z;
if (VirtualUniverse.mc.releaseBoundingBoxMemory) {
// Free memory
tmpP3d = null;
}
}
But: if you use this method to rotate the BoundingBox it produces a new BoundingBox that may be larger in volume than the old one. It only delivers the same volume if you rotate exactly by 90, 180, 270 or 360 degrees.
Additional information: I must calculate the BoundingBox manually because I use manual bounds (and not the too large automatically calculated Bounds) by calling setAutoComputeBounds(false) and setBounds(XYZ) on the model (in this case it is actually an instance of javax.media.j3d which points to a javax.media.j3d.SharedGroup) and it seems that the Java 3d Engine (at least in this scenario) doesn’t recalculate your manual bounds automatically in the case of translation/rotation of the corresponding model.
My question is: how must I (re-)implement the above shown method transform() to get BoundingBoxes which have always the same volume?
BoundingBox actually always remains aligned with the axes, no matter where its two points are. Two points cannot define an arbitrary cube. No matter how you rewrite the transform function, it will not work.
You might consider the BoundingPolytope class. It provides more general bounds, formed from planes, though it does have a constructor which accepts another Bounds object, so you need not actually define the planes yourself.