Author Topic: Switching Between Pivot Points  (Read 3813 times)

Offline paulscode

  • double
  • *****
  • Posts: 863
    • View Profile
    • PaulsCode.Com
Switching Between Pivot Points
« on: February 22, 2008, 05:29:16 am »
Each frame, I am trying to change the rotation pivot of an object from (0,-135,0) to (0,0,0) before doing a rotateAxis() on it, and then change the rotation pivot back to (0,-135,0) afterwards.  It seems like the following code should work:

Code: [Select]
        myObject.setRotationPivot( new SimpleVector( 0, 0, 0 ) );
        myObject.rotateAxis( myObject.getZAxis(), radZ );
        myObject.setRotationPivot( new SimpleVector( 0, -135.0f, 0 ) );

Instead, the object just rotates around the original pivot (0,-135,0), the same as if I don't put any setRotationPivot()'s in there at all.  I am sure there is a simple solution to this, but I can't seem figure it out.

Offline EgonOlsen

  • Administrator
  • quad
  • *****
  • Posts: 11777
    • View Profile
    • http://www.jpct.net
Re: Switching Between Pivot Points
« Reply #1 on: February 22, 2008, 06:37:47 am »
The rotation is applied to the rotation matrix, not to the object when calling rotateXXX(). It can't take the pivot into account at that stage. Only renderScene() takes the pivot and the matrix and applies that to the object. In your case, the pivot has been set back to ...,-135,... at that time, which is why it works with that value instead of the 0,0,0.

Offline paulscode

  • double
  • *****
  • Posts: 863
    • View Profile
    • PaulsCode.Com
Re: Switching Between Pivot Points
« Reply #2 on: February 22, 2008, 01:35:27 pm »
Ahh, I see.  That makes sense.  So, how would I accomplish rotations around different pivots within the same frame (short of rendering the scene twice per call to paint)?  I suppose this could maybe be done with a rotation followed by a translation, to create the appearance of using a different pivot.
Has anyone out there tackeled this problem before? (planets revolving around a sun while also rotating around their axis, gear assemblies, etc.)

Offline EgonOlsen

  • Administrator
  • quad
  • *****
  • Posts: 11777
    • View Profile
    • http://www.jpct.net
Re: Switching Between Pivot Points
« Reply #3 on: February 22, 2008, 04:43:33 pm »
You should be able to use dummy objects for that and create an object hierarchy (the dummies don't have to belong to the world, they are just lending their transformation to other objects) among them, i.e. place a dummy object in the center of the sun and make the planet its child. That way, the planet executes the rotation of the dummy as well as its own.

Offline paulscode

  • double
  • *****
  • Posts: 863
    • View Profile
    • PaulsCode.Com
Re: Switching Between Pivot Points
« Reply #4 on: February 23, 2008, 03:29:21 am »
Yep, that is definitely the trick.  I had actually solved the problem with a rotation + translation, but this way is a lot cleaner.

I did notice something odd, though.

When I use Object3D.createDummyObj() to make the dummy object, the world looks kind of funky, as though a number of polygons are not being drawn.

Using "new Object3D(0)" instead of "createDummyObj()" also causes the same behavior.

However, using "new Object3D(1)" works perfectly.  There is probably a perfectly reasonable explanation for this behavior, but I thought I would mention it since it did look a bit odd to me.

Here is my source code for reference:
Code: [Select]
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;

import java.io.File;

import javax.swing.JApplet;

import com.threed.jpct.Camera;
import com.threed.jpct.FrameBuffer;
import com.threed.jpct.IRenderer;
import com.threed.jpct.Lights;
import com.threed.jpct.Loader;
import com.threed.jpct.Matrix;
import com.threed.jpct.Object3D;
import com.threed.jpct.SimpleVector;
import com.threed.jpct.World;

import java.lang.System;

public class jPCTGears extends JApplet implements MouseListener, MouseMotionListener
{
    private Object3D redGear, blueGear, assemblyPivot;
    private FrameBuffer buffer = null;
    private World world = null;
    private Camera camera = null;
    private int width = 640;
    private int height = 480;
    private float gear_rotation = 0.02f;
    private int prevMouseX, prevMouseY;
   
    // Initialize all components of the applet
    @Override
    public void init()
    {
        // sign the applet up to receive mouse messages:
        addMouseListener( this );
        addMouseMotionListener( this );
       
        world = new World();  // create a new world

        // create a new buffer to render the world on:
        buffer = new FrameBuffer( width, height, FrameBuffer.SAMPLINGMODE_NORMAL );
        buffer.enableRenderer( IRenderer.RENDERER_SOFTWARE );               

        // load some 3D objects and make sure they have the correct orientation:
        redGear = loadMeshFile( "RedGear.3ds" );
        redGear.rotateY( (float)Math.PI / 2.0f );
        redGear.rotateMesh();
        redGear.setRotationMatrix( new Matrix() );
        redGear.setOrigin( new SimpleVector( 0, 0, 0 ) );
        redGear.build();
        blueGear = loadMeshFile( "BlueGear.3ds" );
        blueGear.rotateY( (float)Math.PI / 2.0f );
        blueGear.rotateZ( 0.35f );
        blueGear.rotateMesh();
        blueGear.setRotationMatrix( new Matrix() );
        blueGear.setOrigin( new SimpleVector( 0, 135.0f, 0 ) );
        blueGear.build();
       
        // Set up a pivot point for the entire gear assembly:
        assemblyPivot = new Object3D(1);
        assemblyPivot.setOrigin( new SimpleVector( 0, 0, 0 ) );
        // Make the gears children to assemblyPivot.
        // Translations and rotations to assemblyPivot
        // will affect the entire gear assembly:
        assemblyPivot.addChild( redGear );
        assemblyPivot.addChild( blueGear );
               
        // add the objects our world:
        world.addObject( redGear );
        world.addObject( blueGear );
        world.buildAllObjects();
       
        lookAt( redGear );  // make sure the camera is facing towards the gear assembly
        letThereBeLight();  // create light sources for the scene
    }

    // Draw the scene
    @Override
    public void paint( Graphics g )
    {
        // rotate the gears:
        redGear.rotateAxis( redGear.getZAxis(), -gear_rotation );
        blueGear.rotateAxis( blueGear.getZAxis(), 2.0f * gear_rotation );
       
        buffer.clear();   // erase the previous frame

        // render the world onto the buffer:
        world.renderScene( buffer );
        world.draw( buffer );
        buffer.update();

        buffer.display(g, 0, 0);  // draw the buffer onto the applet frame
       
        repaint( 200, 0, 0, width, height );  // keep the graphics auto-refreshing
    }

    // Load a 3Ds file, and return its Object3D handle
    private Object3D loadMeshFile( String filename )
    {
        Object3D newObject;
        Object3D[] objs = Loader.load3DS( this.getDocumentBase(), "models" + File.separatorChar + filename, 1.0f );

        if( objs.length==1 )
        {
            // The object loaded fine, just need to initialize it
            newObject=objs[0];
            newObject.setCulling( Object3D.CULLING_DISABLED );
            newObject.build();
        }
        else
        {
            // Didn't load anything, or loaded
            //     more than 1 object (not supposed to happen)
            System.out.println( "Unknown file format: " + filename );
            newObject = null;
        }

        return newObject;
    }

    // point the camera toward the given object
    private void lookAt( Object3D obj )
    {
        camera = world.getCamera();  // grab a handle to the camera
        camera.setPosition( 0, 0, 500 );  // set its *relative* position
        camera.lookAt( obj.getTransformedCenter() );  // look toward the object
    }

    // create light sources for the scene
    private void letThereBeLight()
    {
        world.getLights().setOverbrightLighting (
            Lights.OVERBRIGHT_LIGHTING_DISABLED );
        world.getLights().setRGBScale( Lights.RGB_SCALE_2X );

        // Set the overall brightness of the world:
        world.setAmbientLight( 50, 50, 50 );

        // Create a main light-source:
        world.addLight( new SimpleVector( 50, -50, 300 ), 20, 20, 20 );
    }
   
    // Dragging the mouse should rotate the entire gear assembly
    public void mouseDragged( MouseEvent e )
    {
        // get the mouse's coordinates:
        int x = e.getX();
        int y = e.getY();
        Dimension size = e.getComponent().getSize();

        // Calculate the angles to rotate the assembly:
        float thetaY = (float)Math.PI * ( (float)(x-prevMouseX)/(float)size.width );
        float thetaX = (float)Math.PI * ( (float)(prevMouseY-y)/(float)size.height );
       
        // Apply the rotations to the gear assembly:
        assemblyPivot.rotateAxis( assemblyPivot.getXAxis(), thetaX );
        assemblyPivot.rotateAxis( assemblyPivot.getYAxis(), thetaY );

        // Keep track of the mouse location:
        prevMouseX = x;
        prevMouseY = y;
    }
    public void mousePressed( MouseEvent e )
    {
        // Start keeping track of the mouse location now.
        // This prevent the gear assembly from jerking to the new angle
        // whenever mouseDragged first gets called:
        prevMouseX = e.getX();
        prevMouseY = e.getY();
    }
    public void mouseReleased( MouseEvent e ){}
    public void mouseEntered( MouseEvent e ) {}
    public void mouseExited( MouseEvent e ) {}
    public void mouseClicked( MouseEvent e ) {}
    public void mouseMoved( MouseEvent e ) {}
}

At any rate, my question is solved, and I learned a little bit along the way.  Time for me to try something more difficult  ;D  Thanks a lot!

Offline EgonOlsen

  • Administrator
  • quad
  • *****
  • Posts: 11777
    • View Profile
    • http://www.jpct.net
Re: Switching Between Pivot Points
« Reply #5 on: February 23, 2008, 10:48:17 am »
When I use Object3D.createDummyObj() to make the dummy object, the world looks kind of funky, as though a number of polygons are not being drawn.
I can't find a reason for this neither in your code nor in mine... ??? Can you upload the 3ds-files you are using so that i'm able to run the applet and see for myself. That should definitely not happen and if it does, it's a bug.

Offline EgonOlsen

  • Administrator
  • quad
  • *****
  • Posts: 11777
    • View Profile
    • http://www.jpct.net
Re: Switching Between Pivot Points
« Reply #6 on: February 23, 2008, 01:52:56 pm »
Nevermind, i've found the models on your webpage. I'll now see if i can reproduce the problem.

Edit: No, i can't reproduce it. Your applet looks fine no matter if i'm using createDummyObj() or new Object3D(0) or new Object3D(1). If you are still having the problem, you may try the rc1 of 1.16 (http://www.jpct.net/download/beta/jpctapi116rc1.zip), because that is what i was using, albeit i don't think that i've done anything what may cause/fix this between that versions.
« Last Edit: February 23, 2008, 05:08:15 pm by EgonOlsen »

Offline paulscode

  • double
  • *****
  • Posts: 863
    • View Profile
    • PaulsCode.Com
Re: Switching Between Pivot Points
« Reply #7 on: February 23, 2008, 02:37:35 pm »
The upgrade did the trick.  Whatever the issue was with the other version, it seems to be fixed now  ;)

Thanks again!

Offline EgonOlsen

  • Administrator
  • quad
  • *****
  • Posts: 11777
    • View Profile
    • http://www.jpct.net
Re: Switching Between Pivot Points
« Reply #8 on: February 23, 2008, 04:51:42 pm »
Strange...well, at least it works now, so everything is fine.  ;D