java3drotationjava-3d

Rotate around specific point in Java3D


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:

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.


Solution

  • 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.

    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();
      }
    }