[SOLVED] Jme3 Cinematics: Speeding up the animation

function updated, had some float inaccuracies, issue still there though



[java]public class AccelerateTrack extends AbstractCinematicEvent {



private static final Logger log = Logger.getLogger(AccelerateTrack.class.getName());

private Vector3f startPosition;

private Vector3f endPosition;

private Spatial spatial;

private String spatialName = "";

private float value = 0;

private float accelerationFactor;

private float maxSpeed;

private float acceleration;

private float previous_speed;

float epsilon = 0.001f; // used to compare floats accurately

private float currentSpeed = 0;



public AccelerateTrack(Spatial spatial, Vector3f endPosition) {

this.endPosition = endPosition;

this.spatial = spatial;

spatialName = spatial.getName();

}







public AccelerateTrack(Spatial spatial, Vector3f endPosition, float initialDuration,

float accelerationFactor, float acceleration, float previous_speed, float maxSpeed,

LoopMode loopMode)

{

super(initialDuration, loopMode);

this.endPosition = endPosition;

this.spatial = spatial;

this.accelerationFactor = accelerationFactor;

this.acceleration = acceleration;

this.maxSpeed = maxSpeed;

this.previous_speed = previous_speed;

this.initialDuration = initialDuration;

this.currentSpeed = previous_speed;

}





@Override

public void initEvent(Application app, Cinematic cinematic) {

super.initEvent(app, cinematic);

if (spatial == null) {



spatial = cinematic.getScene().getChild(spatialName);

if (spatial == null) {

} else {

log.log(Level.WARNING, "spatial {0} not found in the scene", spatialName);

}

}

}





@Override

public void onPause() {

// do nothing



}



@Override

public void onPlay() {

if (playState != playState.Paused) {

startPosition = spatial.getWorldTranslation().clone();

}

if (initialDuration == 0 && spatial != null) {



spatial.setLocalTranslation(endPosition);

}



}



@Override

public void onStop() {

value = 0;



}



@Override

public void onUpdate(float tpf) {







// acceleration

if(acceleration > epsilon)

{

System.out.println("Accelerated Speed: "+currentSpeed);

currentSpeed += tpf * accelerationFactor;





if( currentSpeed - maxSpeed > epsilon )

{

currentSpeed = maxSpeed;

}

}



// deceleration

else if(acceleration < epsilon)

{



System.out.println("reduced Speed: "+currentSpeed);

currentSpeed -= tpf * accelerationFactor;





if( currentSpeed < epsilon )

{

currentSpeed = 0;

}

}







if (spatial != null) {

Vector3f dir = endPosition.subtract( startPosition );

dir.normalize();

Vector3f velocity = dir.mult( currentSpeed * tpf );

Vector3f pos = spatial.getLocalTranslation();

spatial.setLocalTranslation( pos.add(velocity) );

}

}



@Override

public void write(JmeExporter ex) throws IOException {

super.write(ex);

OutputCapsule oc = ex.getCapsule(this);

oc.write(spatialName, "spatialName", "");

oc.write(endPosition, "endPosition", null);

}



@Override

public void read(JmeImporter im) throws IOException {

super.read(im);

InputCapsule ic = im.getCapsule(this);

spatialName = ic.readString("spatialName", "");

endPosition = (Vector3f) ic.readSavable("endPosition", null);

}











}[/java]

Sorry i thought i answered your question.

You use tpf to compute the acceleration on each frame. thatā€™s what i did at first for every cinematicEvents.

For the seTime(float) to be possible I had to change every event to use the time variable of the AbstractCinematicEvent (the time elapsed since the play method was called).



What you should do is to choose an arbitrary amount of time your acceleration should occur per seconds (30 for example), and accelerate or decelerate like you were doing before but based on the time elapsed since the beginning.

This way you know exactly how many times the acceleration occur for a given time, (1 second 30 times, 2 second 60 times and so on)

So when the setTime is called you can easily recompute the parameters for a given time.

@nehon thereā€™s something terribly wrong here right?



given the correct duration and speed, the spatial does not stop where itā€™s supposed to stopā€¦



it actually stops at Position: (13.288592, 13.455835, 0.0) instead of what I passed it: (13.268, 13.435, 0.0), although minor , iā€™m curious whyā€¦

@nehon, not sure I quite get it. I have 3 questions.


What you should do is to choose an arbitrary amount of time your acceleration should occur per seconds (30 for example), and accelerate or decelerate like you were doing before but based on the time elapsed since the beginning.


1- Can you give me an example? are you saying to replace the tpf in currentSpeed += tpf * accelerationFactor with time?


2- Also on another note, I am confusing the discussion of setTime with setSpeed(). Are they related as far as the fix? if I fix my event by adding time willl it fix setSpeed() as well?

3- can I call setSpeed DURING the animation to speed up then call it again to slow it down?

Thanks in advance
@garnaout said:
@nehon, not sure I quite get it. I have 3 questions.
1- Can you give me an example? are you saying to replace the tpf in currentSpeed += tpf * accelerationFactor with time?

Look at the RotationTrack code for example

@garnaout said:
@nehon, not sure I quite get it. I have 3 questions.
2- Also on another note, I am confusing the discussion of setTime with setSpeed(). Are they related as far as the fix? if I fix my event by adding time willl it fix setSpeed() as well?

Mhh sorry, i'm the one confusing things.I don't know why i though your issue was with setTime...not setSpeed.
Ok, so this should be easier you only have to multiply tpf by the speed variable in your update method and speed will be taken into account.

@garnaout said:
3- can I call setSpeed DURING the animation to speed up then call it again to slow it down?

I see no reason why you couldn't, it should work.
1 Like

Actually itā€™s both! haha Iā€™ll give it a shot



btw is it fine to let onPause in all ofthe cinematic events empty?



I noticed that when I pause and then resume, the timings get messed up.

@garnaout said:
Actually it's both! haha I'll give it a shot

btw is it fine to let onPause in all ofthe cinematic events empty?

I noticed that when I pause and then resume, the timings get messed up.

Yeah, i also take care of that in AbstractCinematicEvent, it's one more good reason to use the time attribute instead of tpf, because the time spent during the pause is taken into account.

so solving one issue at a time for setSpeed to work efficiently I did update my AccelerateTrack to



currentSpeed -= tpf * accelerationFactor * myApp.getAnimationSpeed(); //in deceleration

currentSpeed += tpf * accelerationFactor * myApp.getAnimationSpeed(); // in acceleration



it is still funky when I accelerate the speedā€¦

@garnaout said:
so solving one issue at a time for setSpeed to work efficiently I did update my AccelerateTrack to

currentSpeed -= tpf * accelerationFactor * myApp.getAnimationSpeed(); //in deceleration
currentSpeed += tpf * accelerationFactor * myApp.getAnimationSpeed(); // in acceleration

it is still funky when I accelerate the speed...

no...
you have a protected speed attribute in the AbstractCinematicEvent, that's the one you have to use.

I added : [java] value = Math.min(time / initialDuration, 1.0f);[/java]



for setSpeed issues:



in my AccelerateTrack and changed the speed variable to the protected speed variable you created. Animation looks fine now when I speed it up. However, when I pause, it still gets messed up. Should I add anything onPause()? I currently have it empty just like your cinematic events.



As for setTime(), I will work on it today and let you know. I still didnā€™t figure out the issue I am having in my Eclipse compiler not recognizing setTime() (although it is in the class).



Thanks @nehon

What are the libralies that are in your project classpath? maybe you missed this post.

sorry was using Maven and I needed to do a clean and clean also my repository and now it worksā€¦



@nehon I tried



cinematic.setTime(100);



however nothing happensā€¦ it continues reading w/o skipping.



I did include the time as u suggested in AccelerateTrack

@nehon for this one u said as an example look at the rotationTrack.java (http://code.google.com/p/jmonkeyengine/source/browse/branches/jme3/src/core/com/jme3/cinematic/events/RotationTrack.java?r=6681)



however in that example you donā€™t use time, u use tpf

yeahā€¦that was 3000 revisions beforeā€¦

check the up to date code

http://code.google.com/p/jmonkeyengine/source/browse/trunk/engine/src/core/com/jme3/cinematic/events/RotationTrack.java

well then I thought of thta and added value = Math.min(time / initialDuration, 1.0f); inside the onUpdate()



and set the speed += time * acceleration; and the time doesnā€™t update if thereā€™s no tpf involved

anyways I fixed my animation acceleration by simply passing to the spatial the direction as @pspeed suggested and it works perfectly now. IHowever, I am still using tpf.



I want setTime() to work, can you help me with that? when I call it, animation just freezes as if there are no events to be read.



edit: it actually jumps to a certain time (assuming itā€™s 100) but animation gets messed up - nothing is synchronized.

@nehon, Can you at least explain to me how to implement it ā€œyour wayā€ to get rid of tpf variable? I really donā€™t understand and your explanation is a little bit too summarized.

time != tpf

time is the time elapsed since the beginning of the animation

tpf is time spent on last frame.



so the idea is to compute what acceleration value you should have for time = n. n being a float between 0 and initalDuration

since for now you have currentSpeed += tpf * accelerationFactor;



thatā€™s pretty simple this means that you just stack accelerationFactor over time so for time n, current acceleration is n * accelerationFactor.



Soā€¦ your currentSpeed is computed like that : currentSpeed = time * accelerationFactor;

Well I already tried that but like I mentioned before:

the variable time does not update unless I have speed += tpf * acceleration; Thats why I wanted to know how ā€œtimeā€ updatesā€¦



In addition you mentioned using:

[java]value = Math.min(time / initialDuration, 1.0f);[/java]



how do I use value? I looked at PositionTrack and RotationTrack and itā€™s used depending on the relative function. How would I use it in acceleration with:



[java] if (spatial != null) {

Vector3f dir = endPosition.subtract( startPosition );

dir.normalize();

Vector3f velocity = dir.mult( speed * tpf );

Vector3f pos = spatial.getLocalTranslation();

spatial.setLocalTranslation( pos.add(velocity) );

}[/java]

and btw I am using speed and not currentSpeed as you suggested before