I have an application, where all scene objects are loaded from .obj
files (they are exported from Blender). And I need to rotate one of this objects around specific point. Currently, I have the following code:
public void rotateTo() {
// translate to origin, rotate, translate back
Vector3f origin = new Vector3f();
Vector3f pivot = new Vector3f(.0f, .5f, .0f);
this.getTransform(this.transform);
this.transform.get(origin);
double angle = -Math.PI / 2;
double newX = origin.getX() + Math.cos(angle) * (pivot.getX() - origin.getX()) - Math.sin(angle) * (pivot.getY() - origin.getY());
double newY = origin.getY() + Math.sin(angle) * (pivot.getX() - origin.getX()) + Math.cos(angle) * (pivot.getY() - origin.getY());
this.transform.set(new Vector3f((float)newX, (float)newY, .0f), 0.15f);
this.setTransform(this.transform);
this.transform.set(origin, 0.15f);
this.setTransform(this.transform);
}
Where this
refers to TransformGroup
object, that I need to rotate, and this.transform
refers to Transform3D
object.
But this method doesn't work as I expected. I have also tried this and this solutions, but they also didn't work for me.
I think, maybe, try to perform this manipulation with the help of GeometryArray
, but I can't understand, how to do this. Also, I can try to export my objects with different origin points, but it's not clean solution, I think, because then I would need to move them to right positions with code.
Here's my object:
I'm trying to rotate it around green point, but in all cases it rotates around red point, or doesn't rotate at all, or translates to some point without rotation.
P.S. I know, that Java3D is an old library and can use more powerful tools, but it's my university professor's requirement and I can't refuse using it.
Composition of transformations can be achieved using matrix multiplication. Below is an example that rotates a cube 180° about the X axis with the pivot at the centre of its top face.
There are three steps as mentioned in the question: translate so that the pivot is at the origin, rotate, and translate back. Comment out steps to see what is happening.
With all steps commented out, the box appears at the centre with its red side facing forward.
Uncomment the first step. The box shifts down so its top is at the centre of the screen.
Uncomment the second step. The box rotates about the X axis (the left-right axis, through the top of the box). The green side now faces forward, and the bottom of the box is now at the centre of the screen.
Uncomment the third step. The box shifts up, and the overall effect is that it rotated about a left-right axis through its top face.
The application of a transformation T to a vector v is defined as T*v in Java 3D, so the composition of two transformations T and U where T is to be done first and U is to be done second is U*T. Note how the order is reversed. In general, the composition of the transformations T1, T2, ..., Tn where T1 is done first and Tn is done last is Tn*...*T2*T1.
This can be expressed in Java 3D using the following pattern:
Transform3D t1 = ..., t2 = ..., t3 = ...;
// first do t1, then t2, then t3
Transform3D all = new Transform3D(); // all = identity
all.mul(t1, all); // all = t1 * all
all.mul(t2, all); // all = t2 * all
all.mul(t3, all); // all = t3 * all
// now all == t3 * t2 * t1
Methods such as Transform3D.set(Vector3d,double)
and TransformGroup.setTransform()
overwrite the existing transformation rather than compose with it, which is one of the reasons your code does not work.
I found the article http://www.developer.com/java/other/article.php/3717101/Understanding-Transforms-in-Java-3D.htm helpful.
// based on http://www.java3d.org/starting.html
import com.sun.j3d.utils.geometry.ColorCube;
import com.sun.j3d.utils.universe.SimpleUniverse;
import javax.media.j3d.*;
import javax.vecmath.*;
public class Demo
{
public Demo() {
SimpleUniverse universe = new SimpleUniverse();
BranchGroup group = new BranchGroup();
group.addChild(createModel());
universe.getViewingPlatform().setNominalViewingTransform();
universe.addBranchGraph(group);
}
Node createModel() {
double radius = 0.3;
ColorCube cube = new ColorCube(radius);
// rotation of cube about the center of the top face
// i.e. the point (x=0, y=radius, z=0)
Transform3D transform = new Transform3D();
// step 1: translate cube down so that (0, radius, 0) is at the origin
Transform3D translate1 = new Transform3D();
translate1.setTranslation(new Vector3d(0.0, -radius, 0.0));
transform.mul(translate1, transform);
// step 2: rotate cube about X axis by 180 degrees
Transform3D rotate = new Transform3D();
rotate.rotX(Math.PI);
transform.mul(rotate, transform);
// step 3: translate cube back up
Transform3D translate2 = new Transform3D();
translate2.setTranslation(new Vector3d(0.0, +radius, 0.0));
transform.mul(translate2, transform);
// create a TransformGroup
TransformGroup tg = new TransformGroup();
tg.setTransform(transform);
tg.addChild(cube);
return tg;
}
public static void main(String[] args) {
new Demo();
}
}