Rotate node toward another

Hello,

I have 2 nodes A an B. I would like to rotate the node A toward the center of the node B

Actually I am rotating the node like that in the simpleUpdate method :

[java]Vector3f axis = new Vector3f(0 ,0 ,1);

Quaternion rotQuat = new Quaternion();

rotQuat.fromAngleAxis(FastMath.PI/400, axis);

pivotNode.rotate(rotQuat);[/java]

My problem is when to stop the rotation.

I need to calculate the angle between the vector facing node A and the vector AB.

Calculating the vector AB is easy. But the vector facing A (it starts at something like (0,1,0))…

pivotNode.getWorldRotation() is giving me a Quaternion but I don’t know what to do with it

http://img857.imageshack.us/img857/3864/sc1k.png



Thanks for help !

I found out :

I apply the current rotation to the front vector (Unit_Y), then I calculate the angle between the two vectors and finally I rotate while the angle is > 0



[java]Quaternion rot2 = pivotNode.getWorldRotation();

Vector3f front = rot2.mult(Vector3f.UNIT_Y);

ab = ab.normalize();

float ang = ab.angleBetween(front);

if( FastMath.abs(ang ) > 0.01f){

Vector3f axis = new Vector3f(0 ,0 ,1);

Quaternion rotQuat = new Quaternion();

rotQuat.fromAngleAxis(FastMath.PI/400, axis);

pivotNode.rotate(rotQuat);

}

[/java]

1 Like

Thanks for your post. I try to repeat your code… I cant get what is “ab”? As far as i understand this is some kind of a vector. Thanks.

Yes it is the vector between my two nodes (A, B)



[java]Vector3f a = nodeA.getLocalTranslation();

Vector3f b = nodeB.getLocalTranslation();

Vector3f ab = a.subtract(b);[/java]

Thanks! But it works only with possitive value of an angle. What if value is negative? Just have a try my simple test (move camera left and right(wasd)).



[java]



package mygame;



import com.jme3.app.SimpleApplication;

import com.jme3.material.Material;

import com.jme3.math.;

import com.jme3.scene.Geometry;

import com.jme3.scene.shape.Box;





public class Main4 extends SimpleApplication {



public static void main(String[] args) {

Main4 app = new Main4();

app.start();

}



Geometry geom;





@Override

public void simpleInitApp() {

Box b = new Box(Vector3f.ZERO, 1, 1, 1);

geom = new Geometry("Box", b);

geom.updateModelBound();



Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");

mat.setColor("m_Color", ColorRGBA.Blue);

geom.setMaterial(mat);



rootNode.attachChild(geom);









flyCam.setMoveSpeed(30);

}





public void move (float tpf) {



// amount += tpf
scale;

// geom.setLocalTranslation(maLocation.mult(amount));

// System.out.println(geom.getWorldTranslation());



Vector3f a = geom.getWorldTranslation();

Vector3f b = cam.getLocation();

Vector3f ab = a.subtractLocal(b);



Quaternion rot2 = geom.getWorldRotation();

Vector3f front = rot2.mult(Vector3f.UNIT_Z);

ab = ab.normalize();

float ang = ab.angleBetween(front);

if( FastMath.abs(ang ) > 0.01f){

Vector3f axis = new Vector3f(0 ,1 ,0);

Quaternion rotQuat = new Quaternion();

rotQuat.fromAngleAxis(FastMath.PI/400, axis);

geom.rotate(rotQuat);

}



}



@Override

public void simpleUpdate(float tpf) {





move(tpf);



}



}

[/java]

In theory It works with positive or negative value. Since you rotate It will goes from 0 to 2pi or 0 to -2pi. You just may want to change the sign of the rotation angle to rotate faster.

err… what about spatial1.lookAt(spatial2.getWorldTransform()); ??

1 Like

In my case I wanted to show the animation of the tower rotating toward the enemy to shoot at instead of instant facing it.

So determine the final rotation once using lookAt, then use quaternion.slerp() to interpolate between the spatial rotation and that target rotation.

1 Like

it sounds nice. I didn’t knew about this slerp method. I never worked also with interpolation.



If I understand well I have :



q1 which is a quaternion of the current rotation.

q2 which is a quaternion of the final rotation (given by lookat method)

q3 which is a quaternion given by the method quaternion.slerp(q2, changeamt) (what is the value of changeAmt ?)



So q3 represents the transformation to apply to move from q1 to q2 ?



But I don’t know how works interpolation is there some example in the wiki ?

changeAmount is the amount of rotation you actually want. 0 is the rotation of the start quaternion, 1 is the rotation of the end quaternion. The values in between are the rotations in between.

@ipprade

You can also think of changeAmt as “step” or “time”. From the original position 0 up to final position 1, you could, for example, use an algorithm depending on the turret’s turn rate (in radian) per second. I’ve done something similar with the ship’s autopilot in my game.

Yes, you are right in what you said above, interpolation is just smoothing out the momevement for a gradual, smooth, movement. You have the current, target, and (as explained above) the changeAmount, although I am more used to the DeltaTime approach (depending on frame rate), and it gives you a quaternion, this has to be placed in simpleUpdate if I am correct, and you simply put this in a loop, it will keep spitting out values until you reach your goal.

jpprade said:
...
q1 which is a quaternion of the current rotation.
q2 which is a quaternion of the final rotation (given by lookat method)
q3 which is a quaternion given by the method quaternion.slerp(q2, changeamt) (what is the value of changeAmt ?)
...


Guys can you help? How to get "q2" as you described?
When I make spatial.LookAt(VecAim, tpf*3f) ... so my spatial is rotated by that thing, but I need only to get a quaternion... Should I
clone a spatial?

something like like:
[java]Spatial sp2 = spatial.clone(false);
sp2.LookAt(VecAim, tpf*3f);
Quaternion q2 = sp2.getLocalRotation();[/java]

But if I have 500 moving spatials? What about productivity?




I also tried Quaternion.LookAt(VecAim, tpf*3f) but my spatial rotates incorrectly.
HERE IS MY TEST:
[java]
import com.jme3.app.SimpleApplication;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.FastMath;
import com.jme3.math.Quaternion;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import com.jme3.scene.Spatial;
import com.jme3.scene.shape.Box;



public class SpatialEvents extends SimpleApplication {

public static void main(String[] args) {
SpatialEvents app = new SpatialEvents();
app.start();
}

Geometry geom;


Vector3f vecAim;
Vector3f vec1;
Vector3f vec2;
Vector3f vec3;
Quaternion qua1;
Quaternion qua2;
Quaternion qua3;
float angla;



public void vectorz(){
vec1 = new Vector3f(1,0,1);
vec2 = new Vector3f(20,0,5);
vec3 = new Vector3f(5,0,15);
}


@Override
public void simpleInitApp() {

vectorz();

Box b = new Box(Vector3f.ZERO, 1, 1, 1);
geom = new Geometry("Box", b);
geom.setLocalScale(1,1,2);
geom.updateModelBound();

Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
mat.setColor("m_Color", ColorRGBA.Blue);
geom.setMaterial(mat);
geom.setLocalTranslation(vec1);
rootNode.attachChild(geom);

flyCam.setMoveSpeed(30);
viewPort.setBackgroundColor(ColorRGBA.Gray);
cam.setLocation(new Vector3f(23.0f, 35.0f, 33.0f));
cam.setRotation(new Quaternion (-0.16484f, 0.83351f, -0.40033f, -0.34323f));

}


public void transObj (float tpf, Spatial spatial, boolean boo) {

//Aim to move
if (spatial.getLocalTranslation().equals(vec1) == true) vecAim = vec2;
if (spatial.getLocalTranslation().equals(vec2) == true) vecAim = vec3;
if (spatial.getLocalTranslation().equals(vec3) == true) vecAim = vec1;


//rotation
angla = tpf * 2.1f; //speed

Quaternion vectry = spatial.getWorldRotation();
Quaternion vectry2 = new Quaternion();

Quaternion qRot = new Quaternion();
qRot.lookAt(vecAim.clone().setY(spatial.getWorldTranslation().y), Vector3f.UNIT_Y);

vectry2.slerp(vectry, qRot, angla);

spatial.setLocalRotation(vectry2);

System.out.println(spatial.getWorldTransform());

//translation
float moveMe = tpf * 7f; //speed
float remainingDist = spatial.getLocalTranslation().distance(vecAim);
geom.setLocalTranslation(FastMath.interpolateLinear(moveMe/remainingDist, spatial.getLocalTranslation(), vecAim));

}


@Override
public void simpleUpdate(float tpf)
{

transObj(tpf,geom,true);

}

}
[/java]

Of course you have to compute every discrete value, how else you imagine you should get them? :slight_smile:

Sorry, i’m stupid. What is “discrete value”?

Can you tell what should i do to make it proper?

My stupid head found the problem and found how to get “q2” described above! Yahoo!!! Thanks to @normen tip!



The main idea is vecC=vecA.substract(vecB) … and then q2.LookAt(vecC, tpf*3) .

vecA and vecB are locations of an object and the aim to rotate.

Thanks to Normen’s math for dummies!! :slight_smile:





The only thing I want to know is how to make interpolation not smooth? FastMath.interpolate() works too smooth. It’s god, but sometimes I need not smooth movements(like machinery).





Here is my working code:



[java]

import com.jme3.app.SimpleApplication;

import com.jme3.material.Material;

import com.jme3.math.ColorRGBA;

import com.jme3.math.FastMath;

import com.jme3.math.Quaternion;

import com.jme3.math.Vector3f;

import com.jme3.scene.Geometry;

import com.jme3.scene.Spatial;

import com.jme3.scene.shape.Box;







public class SpatialEvents extends SimpleApplication {



public static void main(String[] args) {

SpatialEvents app = new SpatialEvents();

app.start();

}



Geometry geom;





Vector3f vecAim;

Vector3f vec1;

Vector3f vec2;

Vector3f vec3;

Quaternion qua1;

Quaternion qua2;

Quaternion qua3;

float angla;







public void vectorz(){

vec1 = new Vector3f(1,0,1);

vec2 = new Vector3f(20,0,5);

vec3 = new Vector3f(5,0,15);

}





@Override

public void simpleInitApp() {



vectorz();



Box b = new Box(Vector3f.ZERO, 1, 1, 1);

geom = new Geometry(“Box”, b);

geom.setLocalScale(1,1,2);

geom.updateModelBound();



Material mat = new Material(assetManager, “Common/MatDefs/Misc/Unshaded.j3md”);

mat.setColor(“m_Color”, ColorRGBA.Blue);

geom.setMaterial(mat);

geom.setLocalTranslation(vec1);

rootNode.attachChild(geom);



flyCam.setMoveSpeed(30);

viewPort.setBackgroundColor(ColorRGBA.Gray);

cam.setLocation(new Vector3f(23.0f, 35.0f, 33.0f));

cam.setRotation(new Quaternion (-0.16484f, 0.83351f, -0.40033f, -0.34323f));



}





public void transObj (float tpf, Spatial spatial, boolean boo) {



//Aim to move

if (spatial.getLocalTranslation().equals(vec1) == true) vecAim = vec2;

if (spatial.getLocalTranslation().equals(vec2) == true) vecAim = vec3;

if (spatial.getLocalTranslation().equals(vec3) == true) vecAim = vec1;





//rotation

angla = tpf * 3.0f; //speed



Quaternion vectry = spatial.getWorldRotation();





Vector3f vecB = spatial.getWorldTranslation().subtract(vecAim).setY(spatial.getWorldTranslation().y);



Quaternion qRot = new Quaternion();

qRot.lookAt(vecB, Vector3f.UNIT_Y);





Vector3f vecC = new Vector3f();





vectry.slerp(qRot, angla);

float x = vectry.toAngleAxis(vecC);



spatial.setLocalRotation(vectry);



// System.out.println();



//translation

float moveMe = tpf * 7f; //speed

float remainingDist = spatial.getLocalTranslation().distance(vecAim);

geom.setLocalTranslation(FastMath.interpolateLinear(moveMe/remainingDist, spatial.getLocalTranslation(), vecAim));



}





@Override

public void simpleUpdate(float tpf)

{



transObj(tpf,geom,true);



}



}[/java]

Hm, maybe quantize it by not updating the values every frame?

@normen , thanks for your tip. I solved it with:

qua1.slerp(qua2, tpf/angleBetween);

angleBetween is a an angle between 2 vectors (object’s frontLocalVector and a vector to rotate)… Sorry my explanation is not good. I did it in SpatialEventsLinear.java below.



So, finally, I found 4 differen movements:



SpatialEventsLinear.java:

[java]import com.jme3.app.SimpleApplication;

import com.jme3.material.Material;

import com.jme3.math.ColorRGBA;

import com.jme3.math.FastMath;

import com.jme3.math.Quaternion;

import com.jme3.math.Vector3f;

import com.jme3.scene.Geometry;

import com.jme3.scene.Spatial;

import com.jme3.scene.shape.Box;

import com.jme3.system.AppSettings;







public class SpatialEventsLinear extends SimpleApplication {



public static void main(String[] args) {

SpatialEventsLinear app = new SpatialEventsLinear();



//set vSinc on to get stable 60 fps

AppSettings aps = new AppSettings(true);

aps.setVSync(true);

app.setSettings(aps);

app.start();



}



Geometry geom;

Vector3f vecAim;

Vector3f vec1;

Vector3f vec2;

Vector3f vec3;

float angla;

Quaternion vectry;

Vector3f front;

Vector3f vecB;

Quaternion qRot=new Quaternion();

float ang;

float moveMe;

float remainingDist;







public void vectorz(){

vec1 = new Vector3f(1,0,1);

vec2 = new Vector3f(20,0,5);

vec3 = new Vector3f(5,0,15);

}





@Override

public void simpleInitApp() {



vectorz();



Box b = new Box(Vector3f.ZERO, 1, 1, 1);

geom = new Geometry(“Box”, b);

geom.setLocalScale(1,1,2);

geom.updateModelBound();



Material mat = new Material(assetManager, “Common/MatDefs/Misc/Unshaded.j3md”);

mat.setColor(“m_Color”, ColorRGBA.Blue);

geom.setMaterial(mat);

geom.setLocalTranslation(vec1);

rootNode.attachChild(geom);



flyCam.setMoveSpeed(30);

viewPort.setBackgroundColor(ColorRGBA.Gray);

cam.setLocation(new Vector3f(23.0f, 35.0f, 33.0f));

cam.setRotation(new Quaternion (-0.16484f, 0.83351f, -0.40033f, -0.34323f));



}





public void transObj (float tpf, Spatial spatial, boolean boo) {



//Aim to move

if (spatial.getLocalTranslation().equals(vec1) == true) vecAim = vec2;

if (spatial.getLocalTranslation().equals(vec2) == true) vecAim = vec3;

if (spatial.getLocalTranslation().equals(vec3) == true) vecAim = vec1;





//rotation

angla = tpf * 2.1f; //speed



vectry = spatial.getWorldRotation();

front = vectry.mult(Vector3f.UNIT_Z).normalize();



vecB = spatial.getWorldTranslation().subtract(vecAim).setY(spatial.getWorldTranslation().y).normalize();





qRot.lookAt(vecB, Vector3f.UNIT_Y);



ang = vecB.angleBetween(front);



if (ang>0.01f) {



vectry.slerp(qRot, angla/ang);

spatial.setLocalRotation(vectry);

}

else spatial.setLocalRotation(qRot);



// System.out.println(tpf);



//translation

moveMe = tpf * 7f; //speed

remainingDist = spatial.getLocalTranslation().distance(vecAim);



if (remainingDist > 0.01f) {

spatial.setLocalTranslation(FastMath.interpolateLinear(moveMe/remainingDist, spatial.getLocalTranslation(), vecAim));

}

else spatial.setLocalTranslation(vecAim);



}





@Override

public void simpleUpdate(float tpf)

{



transObj(tpf,geom,true);



}



}[/java]





SpatialEventsNonLinear.java:

[java]import com.jme3.app.SimpleApplication;

import com.jme3.material.Material;

import com.jme3.math.ColorRGBA;

import com.jme3.math.FastMath;

import com.jme3.math.Quaternion;

import com.jme3.math.Vector3f;

import com.jme3.scene.Geometry;

import com.jme3.scene.Spatial;

import com.jme3.scene.shape.Box;

import com.jme3.system.AppSettings;







public class SpatialEventsNonLinear extends SimpleApplication {



public static void main(String[] args) {

SpatialEventsNonLinear app = new SpatialEventsNonLinear();



//set vSinc on to get stable 60 fps

AppSettings aps = new AppSettings(true);

aps.setVSync(true);

app.setSettings(aps);

app.start();

}



Geometry geom;

Vector3f vecAim;

Vector3f vec1;

Vector3f vec2;

Vector3f vec3;

float angla;

float timerAim;

Quaternion vectry;

Vector3f front;

Vector3f vecB;

Quaternion qRot=new Quaternion();

float ang;

float moveMe;

float remainingDist;





public void vectorz(){

vec1 = new Vector3f(1,0,1);

vec2 = new Vector3f(20,0,5);

vec3 = new Vector3f(5,0,15);

}





@Override

public void simpleInitApp() {



vectorz();



Box b = new Box(Vector3f.ZERO, 1, 1, 1);

geom = new Geometry(“Box”, b);

geom.setLocalScale(1,1,2);

geom.updateModelBound();



Material mat = new Material(assetManager, “Common/MatDefs/Misc/Unshaded.j3md”);

mat.setColor(“m_Color”, ColorRGBA.Blue);

geom.setMaterial(mat);

geom.setLocalTranslation(vec1);

rootNode.attachChild(geom);



flyCam.setMoveSpeed(30);

viewPort.setBackgroundColor(ColorRGBA.Gray);

cam.setLocation(new Vector3f(23.0f, 35.0f, 33.0f));

cam.setRotation(new Quaternion (-0.16484f, 0.83351f, -0.40033f, -0.34323f));



}





public void transObj (float tpf, Spatial spatial, boolean boo) {





//Aim to move

if (spatial.getLocalTranslation().equals(vec1) == true) {

vecAim = vec2;

timerAim = 0;

}

if (spatial.getLocalTranslation().equals(vec2) == true) {

vecAim = vec3;

timerAim = 0;

}

if (spatial.getLocalTranslation().equals(vec3) == true) {

vecAim = vec1;

timerAim = 0;

}





//rotation

angla = tpf * 4f; //speed



vectry = spatial.getWorldRotation();

front = vectry.mult(Vector3f.UNIT_Z).normalize();



vecB = spatial.getWorldTranslation().subtract(vecAim).setY(spatial.getWorldTranslation().y).normalize();



qRot.lookAt(vecB, Vector3f.UNIT_Y);



ang = vecB.angleBetween(front);



if (ang>0.11f) {



vectry.slerp(qRot, angla/ang);

spatial.setLocalRotation(vectry);

}

else spatial.setLocalRotation(qRot);







//translation

moveMe = 0.5f; //speed



remainingDist = spatial.getLocalTranslation().distance(vecAim);



if (remainingDist > 0.13f) {

spatial.move(front.negateLocal().multLocal(moveMe));

}

else spatial.setLocalTranslation(vecAim);



//Timer to change the Aim

timerAim += tpf;

if (timerAim > 5f && remainingDist > 0.13f) {

if (vecAim.equals(vec1)) vecAim = vec2;

else if (vecAim.equals(vec2)) vecAim = vec3;

else if (vecAim.equals(vec3)) vecAim = vec1;

timerAim = 0;

}



System.out.println(timerAim);



}





@Override

public void simpleUpdate(float tpf)

{



transObj(tpf,geom,true);



}



}[/java]



SpatialEventsSmooth1.java:



[java]import com.jme3.app.SimpleApplication;

import com.jme3.material.Material;

import com.jme3.math.ColorRGBA;

import com.jme3.math.FastMath;

import com.jme3.math.Quaternion;

import com.jme3.math.Vector3f;

import com.jme3.scene.Geometry;

import com.jme3.scene.Spatial;

import com.jme3.scene.shape.Box;

import com.jme3.system.AppSettings;







public class SpatialEventsSmooth1 extends SimpleApplication {



public static void main(String[] args) {

SpatialEventsSmooth1 app = new SpatialEventsSmooth1();



//set vSinc on to get stable 60 fps

AppSettings aps = new AppSettings(true);

aps.setVSync(true);

app.setSettings(aps);

app.start();

}



Geometry geom;





Vector3f vecAim;

Vector3f vec1;

Vector3f vec2;

Vector3f vec3;

float angla;

Quaternion vectry;

Vector3f front;

Vector3f vecB;

Quaternion qRot=new Quaternion();

float ang;

float moveMe;

float remainingDist;







public void vectorz(){

vec1 = new Vector3f(1,0,1);

vec2 = new Vector3f(20,0,5);

vec3 = new Vector3f(5,0,15);

}





@Override

public void simpleInitApp() {



vectorz();



Box b = new Box(Vector3f.ZERO, 1, 1, 1);

geom = new Geometry(“Box”, b);

geom.setLocalScale(1,1,2);

geom.updateModelBound();



Material mat = new Material(assetManager, “Common/MatDefs/Misc/Unshaded.j3md”);

mat.setColor(“m_Color”, ColorRGBA.Blue);

geom.setMaterial(mat);

geom.setLocalTranslation(vec1);

rootNode.attachChild(geom);



flyCam.setMoveSpeed(30);

viewPort.setBackgroundColor(ColorRGBA.Gray);

cam.setLocation(new Vector3f(23.0f, 35.0f, 33.0f));

cam.setRotation(new Quaternion (-0.16484f, 0.83351f, -0.40033f, -0.34323f));



}





public void transObj (float tpf, Spatial spatial, boolean boo) {



//Aim to move

if (spatial.getLocalTranslation().equals(vec1) == true) vecAim = vec2;

if (spatial.getLocalTranslation().equals(vec2) == true) vecAim = vec3;

if (spatial.getLocalTranslation().equals(vec3) == true) vecAim = vec1;





//rotation

angla = tpf * 3.1f; //speed



vectry = spatial.getWorldRotation();

front = vectry.mult(Vector3f.UNIT_Z).normalize();



vecB = spatial.getWorldTranslation().subtract(vecAim).setY(spatial.getWorldTranslation().y).normalize();



qRot.lookAt(vecB, Vector3f.UNIT_Y);



ang = vecB.angleBetween(front);



if (ang>0.01f) {



vectry.slerp(qRot, angla);

spatial.setLocalRotation(vectry);

}

else spatial.setLocalRotation(qRot);



System.out.println(ang);



//translation

moveMe = tpf * 3f; //speed

remainingDist = spatial.getLocalTranslation().distance(vecAim);



if (remainingDist > 0.1f) {

spatial.setLocalTranslation(FastMath.interpolateLinear(moveMe, spatial.getLocalTranslation(), vecAim));

}

else spatial.setLocalTranslation(vecAim);



}





@Override

public void simpleUpdate(float tpf)

{



transObj(tpf,geom,true);



}



}[/java]



SpatialEventsSmooth2.java:

[java]import com.jme3.app.SimpleApplication;

import com.jme3.material.Material;

import com.jme3.math.ColorRGBA;

import com.jme3.math.FastMath;

import com.jme3.math.Quaternion;

import com.jme3.math.Vector3f;

import com.jme3.scene.Geometry;

import com.jme3.scene.Spatial;

import com.jme3.scene.shape.Box;

import com.jme3.system.AppSettings;







public class SpatialEventsSmooth2 extends SimpleApplication {



public static void main(String[] args) {

SpatialEventsSmooth2 app = new SpatialEventsSmooth2();



//set vSinc on to get stable 60 fps

AppSettings aps = new AppSettings(true);

aps.setVSync(true);

app.setSettings(aps);

app.start();

}



Geometry geom;





Vector3f vecAim;

Vector3f vec1;

Vector3f vec2;

Vector3f vec3;

float angla;

float moveMe;

Quaternion vectry;

Vector3f front;

Vector3f vecB;

Quaternion qRot=new Quaternion();

float ang;

float remainingDist;





public void vectorz(){

vec1 = new Vector3f(1,0,1);

vec2 = new Vector3f(20,0,5);

vec3 = new Vector3f(5,0,15);

}





@Override

public void simpleInitApp() {



vectorz();



Box b = new Box(Vector3f.ZERO, 1, 1, 1);

geom = new Geometry(“Box”, b);

geom.setLocalScale(1,1,2);

geom.updateModelBound();



Material mat = new Material(assetManager, “Common/MatDefs/Misc/Unshaded.j3md”);

mat.setColor(“m_Color”, ColorRGBA.Blue);

geom.setMaterial(mat);

geom.setLocalTranslation(vec1);

rootNode.attachChild(geom);



flyCam.setMoveSpeed(30);

viewPort.setBackgroundColor(ColorRGBA.Gray);

cam.setLocation(new Vector3f(23.0f, 35.0f, 33.0f));

cam.setRotation(new Quaternion (-0.16484f, 0.83351f, -0.40033f, -0.34323f));



}





public void transObj (float tpf, Spatial spatial, boolean boo) {



//Aim to move

if (spatial.getLocalTranslation().equals(vec1) == true) vecAim = vec2;

if (spatial.getLocalTranslation().equals(vec2) == true) vecAim = vec3;

if (spatial.getLocalTranslation().equals(vec3) == true) vecAim = vec1;





//rotation

vectry = spatial.getWorldRotation();

front = vectry.mult(Vector3f.UNIT_Z).normalize();



vecB = spatial.getWorldTranslation().subtract(vecAim).setY(spatial.getWorldTranslation().y).normalize();



qRot.lookAt(vecB, Vector3f.UNIT_Y);



ang = vecB.angleBetween(front);



if (ang>0.03f) {

angla += tpf/5f; //speed

vectry.slerp(qRot, angla);

spatial.setLocalRotation(vectry);

}

else {

angla=0;

spatial.setLocalRotation(qRot);

}







//translation

moveMe += tpf/10f; //speed

remainingDist = spatial.getLocalTranslation().distance(vecAim);



if (remainingDist > 0.1f) {

spatial.setLocalTranslation(FastMath.interpolateLinear(moveMe, spatial.getLocalTranslation(), vecAim));

}

else {

moveMe = 0;

spatial.setLocalTranslation(vecAim);

}

System.out.println(moveMe);

}





@Override

public void simpleUpdate(float tpf)

{



transObj(tpf,geom,true);



}



}[/java]