Java3D : SpaceMouseDevice : Object Mode and Camera Mode

Post questions, comments and feedback to our 3Dconnexion Windows Development Team.

Moderator: Moderators

lololem
Posts: 37
Joined: Sat Mar 24, 2007 10:25 am

Java3D : SpaceMouseDevice : Object Mode and Camera Mode

Post by lololem »

Hi jwick

It's still me ;)

I have a new problem, you're class SpaceMouseDevice.java has been created for a mode with object deplacement.

I explain :

When you move for exemple in the axe x, you're listen the spaceMouse and increase the object in tx.

Ok this methode runs for object deplacement but when you change in viewer deplacement (camera mode) the probleme is the coordonate is absolute and for a viewer mode with have several change of successive mark.

When you move for example in the axe X, you're try an rotation in Y and after you still quite want to go up, you deplacement is not good, it is lateral because you're coordonate is absolute, whereas the axes of translations should change with the landmark changing.

Have u got corrected this problem? Have u already do a class with viewer deplacement (camera) in universe3D?

In the absolute, i want the same deplacement of Google Earth.

I try to inspirate with the keyboard behavior but the code is particulary complex.

Thank u so much for u helpful !

Bye
lololem
Posts: 37
Joined: Sat Mar 24, 2007 10:25 am

Post by lololem »

i review the code, the principle is the same but for me, a little cleary

Code: Select all

package device;
//package materiel.capteur3d;
//package device;

import java.awt.event.MouseEvent;
import javax.media.j3d.InputDevice;
import javax.media.j3d.Sensor;
import javax.media.j3d.Transform3D;
import javax.vecmath.*;
import utils.Constantes.MovementType;
import java.io.*;
import javax.media.j3d.SensorRead;
import javax.media.j3d.TransformGroup;
import scene.Scene3D;


public class SpacemouseDevice implements InputDevice
{
	protected static Vector3d	translation = new Vector3d();
        protected static Matrix3d	rotation = new Matrix3d();
        protected static Matrix3d	rX =		new Matrix3d();
        protected static Matrix3d	rY =		new Matrix3d();
        protected static Matrix3d	rZ =		new Matrix3d();
	protected static Sensor	spaceMouseSensor;
	protected static JNIsiapp siapp;
	private static boolean firstTime = true;
	private Scene3D s3d;
        private MovementType typeMouvement;
        private String nomFrame;
        private float angularRate;
        private float sensitivity;
        private SensorRead spaceMouseSensorRead	= new SensorRead();
        private Transform3D vueTransform = new Transform3D();
	
	
        /*TransformGroup scene = s3d.getSceneTrans();
                      Transform3D t3d = new Transform3D(); 
                      scene.getTransform(t3d);
                      t3d.get(translation);*/

	public SpacemouseDevice(Scene3D _s3d)
	{
		setNomFrame("VRMiner");
                spaceMouseSensor = new Sensor( this, 1 );
                s3d = _s3d;         
	}
	public boolean initialize()
	{   
            return true;
        }
        
	public int getProcessingMode()
	{
		return InputDevice.BLOCKING;
	}
	
	public int getSensorCount()
	{
		//System.out.println( "SpacemouseDevice.getSensorCount()" );
		return 1;
	}
	
	public Sensor getSensor(int sensorIndex)
	{
		//System.out.println( "SpacemouseDevice.getSensor(" + sensorIndex + ")" );
		return spaceMouseSensor;
	}
        public void SpacePositionTransform() {
        
//I think for the viewer mode the changement is here.
//According to i look, the incrementation of axes must change.

Code: Select all

           
          translation.add(new Vector3d((siapp.event.mData[JNIsiapp.SI_TX] * sensitivity),
                    (siapp.event.mData[JNIsiapp.SI_TY] * sensitivity),
                    -(siapp.event.mData[JNIsiapp.SI_TZ] * sensitivity)));
            
          
	}
        
        public void SpaceRotationTransform() {
               
            rX.rotX( siapp.event.mData[JNIsiapp.SI_RX] * angularRate );
	    rY.rotY( siapp.event.mData[JNIsiapp.SI_RY] * angularRate );
	    rZ.rotZ( siapp.event.mData[JNIsiapp.SI_RZ] * angularRate );

	    rotation.mul( rY, rotation );
	    rotation.mul( rZ, rotation );
	    rotation.mul( rX, rotation );
               
	}
	public void pollAndProcessInput()
	{
		try {
                  	if (firstTime) {
                                initialize();
                                siapp = new JNIsiapp();
				siapp.SiInitialize();
				siapp.SiOpenWinInit(nomFrame,"eventCallback");
	                        siapp.SiOpen();
                                firstTime = false;        
			}

			//Fonction bloquante qui attend un évenement
                        siapp.SiWaitForEvent();
                        //Si un nouvel évenement est survenu alors
			if (siapp.SiIsNewDataAvail()) {
			         //On recupère cette evenement
                                 siapp.SiGetEvent();
			        
                                 //Evenement d'appui sur la souris   
                                 if (siapp.event.type == JNIsiapp.SiEventType.SI_MOTION_EVENT)
				 {
				    spaceMouseSensorRead.setTime(System.currentTimeMillis());
                                    
                                    //Lecture
                                    vueTransform = s3d.getVueTrans();
                                    vueTransform.get(translation);
                                    vueTransform.get(rotation);
                                    
                                    //Transformation
                                    SpaceRotationTransform();
                                    SpacePositionTransform();
                                    
                                    //Ecriture
                                    vueTransform.set(rotation);
                                   vueTransform.setTranslation(translation);
                                  
                                    spaceMouseSensor.setNextSensorRead(
						System.currentTimeMillis(),
						vueTransform,
						new int[0]
				     );
                                    
                                    
                                    //spaceMouseSensorRead.set(spaceMouseTransform);
                                    //spaceMouseSensor.setNextSensorRead(spaceMouseSensorRead);
                                    
                                }//Bouton d'évenemenent
				else if (siapp.event.type == JNIsiapp.SiEventType.SI_BUTTON_EVENT)
				{
				        setNominalPositionAndOrientation();	
				}
                                // Button event
				else if (siapp.event.type == JNIsiapp.SiEventType.SI_ZERO_EVENT)
				{
					
                                        
				}else if(siapp.event.type == JNIsiapp.SiEventType.SI_KEYBOARD_EVENT){
                                        
                                }
                                    
                                   
			}	
		} catch (Exception e) {
			System.out.println("Exception in JNIsiappThread: "+e);
			siapp.SiClose();
			siapp.SiTerminate();
		}
	}
	
	/** This method will not be called by the Java 3D implementation and should be implemented as an empty method.
	 */
	public void processStreamInput()
	{
	}

	/** used by j3d framework, not to be called by application - NOT IMPLEMENTED
	 */
	public void setNominalPositionAndOrientation()
	{
		initialize();
		 
                rotation.setIdentity();
                float[] trans = s3d.getPosition("42");
                
                translation.x = trans[0];
                translation.y = trans[1];
                translation.z = trans[2];
                
                spaceMouseSensor.setNextSensorRead(
						System.currentTimeMillis(),
						new Transform3D(
							rotation,
							translation,
							1
						),
						new int[0]
		);
	}
	
	/** used by j3d framework, not to be called by application - NOT IMPLEMENTED
	 */
	public void setProcessingMode(int mode)
	{
		System.out.println( "SpacemouseDevice.setProcessingMode(" + mode + ")" );
	}

        public void close() {
                    siapp.SiClose();
         }
        
       
        
        public void setAngularRate(float value){
            angularRate = value;
        }
        public float getAngularRate() {
            return angularRate;
        }
        public void setSensitivity(float value){
            sensitivity = value;
        }
        public float getSensitivity() {
            return sensitivity;
        }

    	/**
	 * obtient le nom de la frame
	 * @return le nom de la frame
	 */
	public String getNomFrame() {
		return nomFrame;
	}
	/**
	 * definit le nom de la frame
	 * @param nomFrame le nom de la frame
	 */
	public void setNomFrame(String nomFrame) {
		this.nomFrame = nomFrame;
	}

}
jwick
Moderator
Moderator
Posts: 3341
Joined: Wed Dec 20, 2006 2:25 pm
Location: USA
Contact:

Post by jwick »

Hey lololem,

You are still around. Terrific!

The fundamental difference between controlling the object and controlling the view is that you are moving the "camera" instead of the object. The characteristics of that the user notices is that all the translations are backwards and all the rotations are centered around "your neck", not the object's center.

The easiest way to do this is to modify the Java3D camera instead of the Vector3d translation and Matrix3d rotation used in this code to control the object. I don't remember where the camera is, perhaps vueTransform?

The hardest way is to do all the math yourself. If you want to do that, I suggest you download our Windows 3DxWare SDK. It contains an example called cityfly which flies a camera around a little cityscape. It does all the math itself--reasonably difficult to follow I'm sure. The math is actually easier when controlling a camera, instead of controlling an object since you don't have to worry about displacing the center of rotation.

Jim
lololem
Posts: 37
Joined: Sat Mar 24, 2007 10:25 am

Post by lololem »

:) I have no choice Jim, it's for my studies and it must turn !

I have done many research and i try many modfication in vector3D and Matrix3D and the modifcation is very complicated and need many knowledge in mathematic.

That's why, i choose the first solution :

vueTransform is in fact my Transform3D from my eye-camera (TransformGroup).

How i can influate in my view camera to go in the good axes when i move the spaceMouse?

I was for the moment in this algorithm :

According to the position of the camera, you increase the good axes.

for exemple :

if u lookat behind u, you do that :

translation.add(new Vector3d((

siapp.event.mData[JNIsiapp.SI_TX] * sensitivity),
(siapp.event.mData[JNIsiapp.SI_TY] * sensitivity),
-(siapp.event.mData[JNIsiapp.SI_TZ] * sensitivity))

);

but if u do an rotation of 45 degrees with axes Y, the axe is changed and you have that :

siapp.event.mData[JNIsiapp.SI_TY] * sensitivity),
-(siapp.event.mData[JNIsiapp.SI_TZ] * sensitivity),
(siapp.event.mData[JNIsiapp.SI_TX] * sensitivity))

You see? But i don't know, how recover the angle's condition, maybe the class Quat4d... too complicated

I think i can use the position of the eyes, but i don't know where i can find a good method that return the direction of my eye's look.

thanks
lololem
Posts: 37
Joined: Sat Mar 24, 2007 10:25 am

Post by lololem »

Other thinking

The problem is :
The coordonnate of SpaceMouse is absolute in the landmark.
The coordonnate of View is relative in the landmark.

Why we don't change the view's relative coordonate to absolute coordonate and the problem is fixed.

You know how to make that ?
jwick
Moderator
Moderator
Posts: 3341
Joined: Wed Dec 20, 2006 2:25 pm
Location: USA
Contact:

Post by jwick »

This is reasonably simple mathematics, unfortunately it isn't taught anywhere except to mechanical engineers...so it isn't very easy to understand for the rest of us. I wrote a small book on it years ago...now long lost.

You need to slow down what you are doing and get the fundamentals right. At some point a light will go on in your head and all this will become simple.

Jim's 10 Step Program to 3D Matrix Mathematics:

1) Forget about rotations for now. Turn them off. Discard all the rotation data from the device. You can do this in the driver if you wish.

2) When you get the translation data eliminate all the data except the axis with the largest magnitude (the driver dominant button can do this for you).

3) In your mind, establish three clear coordinate systems: the camera coordinate system, the object coordinate system and the world coordinate system. Think of these as three Cartesian triads. I actually make two coordinate system triads out of my daughter's wooden toys (Tinker Toys in the US). I name one the camera and one the object. I highly suggest doing something like this.

4) Put the object coordinate system on the table in front of you with the X axis pointed to the right, the Y axis pointed up and the Z axis pointed toward you.

5) Hold the camera coordinate system up next to your head next to your right temple with the X axis pointing away from you, Y toward the ceiling and Z out the back of your head.

6) Do all this with no one else in the room or they will think you've gone batty. <G>

7) Align your head with the surface of the table looking down the Z axis of the object.

8) You've now established your starting position. The object is centered in the table coordinate system and the camera is now displaced somewhat along z in the table coordinate system. The table coordinate system is your world coordinate system. Both the object and the camera are positioned in absolute table/world coordinates.

9) To move the object to the right, you'd add to its X axis value. To move the camera to the right, you'd add to its X axis value. Notice if you are looking down the camera, the object coordinate system moves to the left as you move the camera to the right. Now return each to the start positions and repeat the exercise for the other 2 translation axes.

Here's the take home lesson (thanks KBW): there is a matrix that describes the relationship between the object and the table, another one which describes the relationship between the camera and the table, and another one that describes the relationship between the object and the camera (which you calculate).

Furthermore and most importantly each of these matrices can be easily inverted (non-numerically) to represent the opposite relationship.

Say I name the first matrix ObjectInTable. It describes the position of the object-in-the-table coordinate space. More mathematically it can be called the ObjectToTable matrix because it converts numbers from the object coordinate system to the table coordinate system.

If you invert this matrix (TableToObject), it now converts numbers (vectors) from the table coordinate system to the object coordinate system.

Try it. Take the table vector (0,0,0) and see that it converts to (-1,0,0) in object space if you've moved the object to the right.

I suggest you use these names liberally. Always have the name of the matrix say what it is doing at that time.


10) So now you want to rotate the camera. Once you've established correct matrices with descriptive names, you can convert vectors from any coordinate system to another. The data from the 3Dx device arrives in camera space because that is what you are using to look at your table. To move the object you have to run that vector through your CameraToTable, then TableToObject matrices to move the object in it's coordinate system. If this is working correctly without rotations turned on, it will work correctly when you turn the rotations on. If it doesn't your matrices aren't doing what your name says they are.


That's it. More could be added, but it is a 10 step program afterall.

Jim
3Dx Software Development
lololem
Posts: 37
Joined: Sat Mar 24, 2007 10:25 am

Post by lololem »

Ok jwick,

thanks for u long answer.

I translate that and i try most rapidely.

I give you fast news

++
lololem
Posts: 37
Joined: Sat Mar 24, 2007 10:25 am

Post by lololem »

Jim where i can download the source to CityFly please.

I search in SDK but for C++, you have just

- AtlCube3d.zip
- Cube3DPolling.zip

Thanks
jwick
Moderator
Moderator
Posts: 3341
Joined: Wed Dec 20, 2006 2:25 pm
Location: USA
Contact:

Post by jwick »

The citifly demo is in the old C/C++ SDK.

Go to Support->Driver Downloads->SpaceTraveler->Archive->3DxWare SDK.
lololem
Posts: 37
Joined: Sat Mar 24, 2007 10:25 am

Post by lololem »

Jim, i think i find a begin of solution

if u look in class Transform3D (http://java.sun.com/products/java-media ... tX(double))

u have the the function and u have that :
lookAt

public void lookAt(Point3d eye,
Point3d center,
Vector3d up)

Helping function that specifies the position and orientation of a view matrix. The inverse of this transform can be used to control the ViewPlatform object within the scene graph.

Parameters:
eye - the location of the eye
center - a point in the virtual world where the eye is looking
up - an up vector specifying the frustum's up direction
You apply directely in the view transform.

But i don't know what is the parameters, that i must give it.

have you an idea ?[/quote]
lololem
Posts: 37
Joined: Sat Mar 24, 2007 10:25 am

Post by lololem »

if (siapp.event.type == JNIsiapp.SiEventType.SI_MOTION_EVENT)
{

//Matrice de l'objet
//Matrice de la caméra
//Matrice de l'univers

//Lecture de la Matrice de caméra à partir de la scène3D
vueTransform = s3d.getVueTrans();
vueTransform.get(VecteurTranslation);
vueTransform.get(MatriceRotation);


//TRANSFORMATION DE LA MATRICE DE VUE AVEC MA SOURIS3D
//siapp.event.mData[JNIsiapp.SI_T{X,Y,Z}] renvoi une valeur quand on pousse,tire,translate sur la souris
VecteurTranslation.x += siapp.event.mData[JNIsiapp.SI_TX] * sensitivity;
VecteurTranslation.y += siapp.event.mData[JNIsiapp.SI_TY] * sensitivity;
VecteurTranslation.z += siapp.event.mData[JNIsiapp.SI_TZ] * sensitivity;


//siapp.event.mData[JNIsiapp.SI_R{X,Y,Z}] renvoi une valeur quand on tournela souris
rX.rotX(siapp.event.mData[JNIsiapp.SI_RX] *angularRate);
rY.rotY(siapp.event.mData[JNIsiapp.SI_RY] *angularRate);
rZ.rotZ(siapp.event.mData[JNIsiapp.SI_RZ] *angularRate);

MatriceRotation.mul( rY, MatriceRotation );
MatriceRotation.mul( rZ, MatriceRotation );
MatriceRotation.mul( rX, MatriceRotation );

/* Point3d targetPos = new Point3d(
To define,
To define,
To define);*/

/*Point3d camPos = new Point3d(
To define
,To define
,To define);*/

/* Vecteur3d VectDirection = new Vecteur3d(
Vector3d vectDirection = new Vector3d(
To define
,To define
,To define);*/

//LookAt : position de l'oeil, point vers lequel regarder, vecteur directeur du haut de la caméra
vueTransform.lookAt(camPos,targetPos,VectDirection);

//inversion obligatoire pour agir sur la vue
vueTransform.invert();

//Ecriture sur la Matrice de la caméra
s3d.setVueTrans(vueTransform);


}
lololem
Posts: 37
Joined: Sat Mar 24, 2007 10:25 am

Post by lololem »

Oupss, click to fast.

It's my source code and the problem's is here :

/* Point3d targetPos = new Point3d(
To define,
To define,
To define);*/

/*Point3d camPos = new Point3d(
To define
,To define
,To define);*/

/* Vecteur3d VectDirection = new Vecteur3d(
Vector3d vectDirection = new Vector3d(
To define
,To define
,To define);*/

//LookAt : position de l'oeil, point vers lequel regarder, vecteur directeur du haut de la caméra
vueTransform.lookAt(camPos,targetPos,VectDirection);
jwick
Moderator
Moderator
Posts: 3341
Joined: Wed Dec 20, 2006 2:25 pm
Location: USA
Contact:

Post by jwick »

Usually these coordinates and the vector are given in world space. The camPos is the position of the camera, the targetPos is the position of what you are looking at and the upVector is the vector pointing straight out of the top of your head (your head being the camera).

So a good starting camera position would be along the Z axis far enough away from the object you are viewing to see all if it, say (0,0,10) for a start if your object is smaller than 10 units in width.

A starting targetPos would be (0,0,0) if your object is centered in world space.

A starting upVector would be (0,1,0) (straight upward).

To move the camera, you would add the 3Dx vectors to the cameraPos. To rotate the camera, you would rotate the upVector using a rotation matrix. This would only allow you to tilt the camera. There is probably also a camera Twist parameter somewhere to allow you to roll it.
lololem
Posts: 37
Joined: Sat Mar 24, 2007 10:25 am

Post by lololem »

Ok no problem, i understand that

My problem is just how adapt my matrice of rotation with my upVector ?

and What is this Twist parameter?
jwick
Moderator
Moderator
Posts: 3341
Joined: Wed Dec 20, 2006 2:25 pm
Location: USA
Contact:

Post by jwick »

If you are holding a camera, pointing it at something, and you tilt it to the right or left, that is the twist vector. It isn't a terribly useful parameter to use if you are just walking around in a virtual space. It is the equivalent of falling over--like a drunk--usually not a good thing :)

You can use the ArbitraryAxisToMatrix function from the C SDK to convert the 3Dx rotation data to a matrix that will update the up vector. I may have given you a Java version of that. If not, it converts to Java easily.
Post Reply