Skip to main content

Alpha and Bullet Time (RFE or Bug?)

14 replies [Last post]
eagle
Offline
Joined: 2004-03-04

I want to create a "Bullet Time" effect, as it is known from games like Max Payne or Chrome (or as in the movie "The Matrix"). For those not familiar with this term: Bullet Time is a slow motion effect, that can be turned on and off.

I identified the following aspects to consider with this effect:
- most animated objects in the scene will have to slow down (e.g. ongoing explosions, light flickers, rotating satellite dishes, ...)
- a few animations however will not participate in bullet time (e.g. animations of the player avatar, HUD animations, etc.)

I think the easiest way to implement this, would be to introduce a Clock interface like this:

interface Clock {<br />
    static final DEFAULT = ... // see below<br />
    long getCurrentTime();<br />
}

The (default) implementation for Clock would just wrap the System clock:

    static final DEFAULT = new Clock() {<br />
        public long getCurrentTime() {<br />
            return System.currentTimeMillis();<br />
        }<br />
    };

A bullet time implementation of Clock would then return slower growing time values for getCurrentTime() while bullet time is enabled.

A quick search brings up 89 places in Java3D core and core-utils where currently System.currentTimeMillis() is used, and I will have to look into each one to identify those, that would have to be rewritten using such a Clock.

I started with the most obvious candidate for some tests: Alpha.

I created a subclass ClockAlpha, that allows a Clock to be assigned. Doing so I encountered the following problems:

1. Alpha cannot easily be subclassed, because many fields that are required for calculations are actually private and have no getter methods provided. ==> workaround: reimplement all methods of Alpha completely in the subclass.

2. Subclasses of Alpha actually can't be used easily, because Interpolator.duplicateAttributes(...) calls the package private internal method Alpha.cloneAlpha(), that I cannot override outside of the javax.media.j3d package. ==> workaround: place the subclass in the javax.media.j3d package.

Now with these findings in mind I have a few questions:

1. Is it a bug, that you effectively can't subclass Alpha? (i.e. shouldn't those private fields be protected instead or provide protected getters? shouldn't cloneAlpha be a protected method or even public? (remember: protected methods are also package visible))

2. It would be much easier to implement my ClockAlpha if Alpha would have a protected getCurrentTimeMillis() method instead of Calling System.currentTimeMillis() directly at several places. Is this an interesting RFE?

3. How about the Clock-Approach? (or call it TimeProvider or ...) Wouldn't it be nice to have this a feature in core Java3D? So is this also an interesting RFE?

4. Is it a bug, that Alpha does not override cloneNodeComponent(boolean)? (and shouldn't Interpolator use cloneNodeComponent instead of directly calling cloneAlpha()?)

ad 2) this is easily implemented within a few minutes.

ad 3) I'd be willing to investigate all 89 occurences of System.currentTimeMillis() and provide (untested*) implementations using the Clock-Approach, if this feature is interesting enough to become part of core Java3D. (* I do not have a C-Compiler, so I don't know if I could build j3d-core to test those changes)

So, now I'd like to know your opinions.

Thanks
Ralf

Message was edited by: eagle

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
eagle
Offline
Joined: 2004-03-04

Hi pepe,

I'd like to propose a join of our ideas. Meanwhile I have my ClockAlpha running and it's is really nice to view, that I can stop multiple Interpolators by a single call to (StoppableClock)gameClock.pause() while other animations still continue.

A few comments on your post before I start to outline a join of our ideas.

> The idea i had was a bit different as it would be
> global. For onscreen, i think that what is needed is
> as you said: the possibility for bullet time. For
> that i thought about a time factor sent to Universe.
Global means all objects would be affected equally, which is less flexible than my aproach. An example for a game: all game objects base their timing on a (StoppableClock)gameClock, while the (animated) user interface is based on (Clock)guiClock. Now if a user presses the Pause key it would be very simple to code as:[code]gameClock.pause();
gui.showGamePausedWindow();[/code]

> For Offscreen, a date would be sent to Universe
> before each render.
Is this MT safe? A Universe can have multiple Views attached. Some of them might be onscreen, other offscreen. I don't know enough about internal threading of Java3D, but here's my question: If offscreen rendering sets the time explicitly, how do you ensure that onscreen rendering is not affected by this?

(I will probably have to use this approach, to implement live monitors of security cameras, that show (offscreen) views of the same universe painted as textures on scene objects in the main (onscreen) canvas.)

> void setTime( long )
> long getTime()
> void setSubTime( long )
> long getSubTime()
I really don't like this naming scheme. An API user will have to read docs to understand what is the concept behind "sub time"

How about:

void setTimeMillis( long )
long getTimeMillis()
void setTimeMicros( long )
long getTimeMicors()

or

void setTime( long )
long getTime()
void setHiResTime( long )
long getHiResTime()

(I'd prefer Millis/Micros, as the method names then clearly tell the API user what they do.)

> About the impossibility to subclass Aplha's behavior,
> i guess that it's normal. [...] Where is the problem lying?
For example in overriding Alpha.finished(). Just try it and you will end up copying a lot of original Alpha code into your subclass.

Another possible problem with your approach:

MasterControl.systemStartTime is used to synchronize Alphas and Behaviors. On your offscreen rendering on multiple machines this value would be different on all machines and you have no API to set this value.

Now my join proposal:

The new Clock interface and changes to Behavior and VirtualUniverse equivalent to your proposal:

[code]interface Clock {
// special implementations of clock (e.g.
// StoppableClock) still need to be based on a
// real (hardware) time source. Hence it is best
// to allow to build Clock-trees. But this introduces
// the problem, that you could configure dependancy
// cycles. To prevent this we need a way to query
// the parent of a clock.
Clock getParent();

// for synchronisation purposes we need to be able
// to query a common fixpoint in time. This is
// provided through getStartTime
long getStartTimeMillis();
long getStartTimeMicros();

// well I think no comment needed
long getCurrentTimeMillis();
long getCurrentTimeMicros();
}

class VirtualUniverse {
Clock getClock();
setClock(Clock clock);
}

class Behavior {
Clock getClock();
setClock(Clock clock);
}
[/code]

All other special timing behavior (stopping, tuning(=bullet time), explicit stepping (for your animations), etc.) would be done in concrete implementations of the clock interface, no need to pollute the API of VirtualUnivers with "time factors" or "time offsets".

Actually I think we could even realize all of this without any change to the APIs of Behavior and VirtualUniverse by introducing a "RenderClock" that is actually stored as ThreadLocal and shared between associated Render- and BehaviorScheduling-Threads. MasterControl would then create such RenderClock objects and base them by default on a (HiRes)SystemClock. Onscreen rendering would not be allowed to modify this Clock, while offscreen render would be allowed to set the Clock that is proxied by RenderClock. RenderClock API could look like this:
[code]class RenderClock implements Clock {

// Provides access to the ThreadLocal where RenderClock
// is stored.
static RenderClock getRenderClock();

// only allowed to be called through MasterControl or
// other RenderClock methods calls from other locations
// should throw an appropriate exception. Provides
// access to the ThreadLocal where RenderClock is stored.
static setRenderClock(RenderClock clock);

// equal to getRenderClock().getParent();
static Clock getCurrentRenderingClock();

// equal to getRenderClock().setParent();
// only allowed to be called from an offscreen-thread.
static Clock setCurrentRenderingClock();

// equal to getCurrentRenderingClock().getXXX();
static long getStartTimeMillis();
static long getStartTimeMicros();
static long getCurrentTimeMillis();
static long getCurrentTimeMicros();

private setParent();

// and Clock.methods ...
}[/code]

Now instead of introducing get/setClock to Behavior and VirtualUniverse one could simply use RenderClock.get/setCurrentRenderingClock(), where set is not allowed for onscreen.

(There is a little bit more needed as Alphas/Behaviors/etc and so on should be able to have Clocks that not directly depend on renderClock's parent but a proxy to renderClock's current parent But this post is already very long.)

I'd be glad to provide you with basic Clock implementations according to this proposal so you can start experimenting. Just ask and give me a few hours.

cu
Ralf

pepe
Offline
Joined: 2003-06-10

Eagle,
After trying to think to how to make it per branch, i had to join to your second proposal, which seems the best mix. I agree my first shot was... mhhh. messy and bad thought.
The possibility to change clock globally for a group looks fine.

The naming was bad, but i didn't want to tie it to a particular resolution, which is why i had to find 'something else'. Of course, a better name would have to be set when a resolution is decided.

About the MasterControl handling Clocks, i would ask you a question related to one of yours... how would universes be if they both had onscreen and offscreen canvases? What if two offscreen set different timings?

On the subject of WakeupOnElapsedTime, they are definitly not compatible with reverse clocks and imho should be deprecated in favor of a new WakeupAtDate in this vision of time handling.
If someone was to plan starting an event at a point in time, the date of that event should be used, and not a delay. It is, in our vision, much clearer and can be handled.
Nevertheless, going reverse would impose to create those conditions at end of the event, for example, or have an end of wakeup date for each wakeup, so that reversing can work a bit easier... much hassle for.. mhhh. nothing?

eagle
Offline
Joined: 2004-03-04

> About the MasterControl handling Clocks, i would ask
> you a question related to one of yours... how would
> universes be if they both had onscreen and offscreen
> canvases? What if two offscreen set different
> timings?

Well, there are still many unsolvable problems, for example if a sceen graph changes over time, let's say at 5.0s a new avatar has been added, how should an offscreen render with its time base set to 4.0s ignore this avatar? The answer is, it would not. Those are scene graph design issues we have to leave to the programmer (=J3D API user), and hope he is doing it right. (I am about to say the same applies to WakeupOnElapsedTime with reverse Clocks. It may be left in the responsibility of the programmer, that he does not try to do something like this.)

But what we can achieve, is that everything that is pre-determined on time will work, i.e. everything that is a function of time f(t) and that will produce the same results Xt = f(t) regardless of the order in which we calculate them, for different values of t will work.

Alpha is such an example. After you have created and set up an Alpha object you can feed time values in any order to its value(long) method and it will always produce the same results for the same time values.

A complex scene graph sg(t) will almost never satisfy this condition. This essentially means it is not pre-determined over time. But this actually is a result from behaviors (either in the scene graph itself triggered by WakeUpConditions or from the application triggered by something else, e.g. game script events) it is not a characteristic of the visible scene graph.

This means for the result rendered to the canvas it is more important to have the correct Clock during beavior scheduling. During the rendering phase AFAIK the Clock would only be required for mixed-mode-rendering.

So for complex scenarios behavior scheduling and rendering should apply to following rules regarding Clocks (and Clock sharing):

- Only one behavior scheduler (and therefor only one Clock-Tree with a fixed top-level Clock) per Universe should run.
- For onscreen canvases Java3D already runs this single behavior scheduler, even if rendering itself may occur in other threads than the behavior scheduler's thread. (At least IIRC correctly what little I know about J3Ds internals) The rendering threads for these onscreen canvases MUST share the same Clock as the behavior scheduler uses.
- For offscreen canvases behaviors currently are not run, but you are working on a solution for it, correct? Well if those offscreen canvases are attached to a VirtualUniverse that already has onscreen canvases attached, then they MUST share the same clock as the (already running) behavior scheduler, i.e. although they are offscreen canvases, they act like onscreen canvases.
- If a VirtualUniverse has only offscreen canvases attached, then it currently doesn't run a behavior scheduler. I don't know how you want to implement this, but because offscreen rendering is done in a way that the application has to request each frame, I would assume you provide something similar for behaviors: e.g. scheduleBehaviorsOffScreen(), waitForBehaviorsOffScreen(). Again, running behaviors and the subsequent rendering MUST use the same Clock.

Now that I have written this and thought once again about this topic I conclude: [b]A VirtualUniverse can only have ONE top-level-Clock at any given time and this top-level-Clock has to be used for both behaviors and rendering (on- and offscreen).[/b] This means: the top-level-Clock to use is a field of the VirtualUniverse AND we have to make it visible through API. However, other scene graph objects that need a time base can use Clocks, but all Clocks will be arranged in a tree whose root would be the Clock of the VirtualUniverse.

And you can [b]forget everything I wrote above about RenderClock, ThreadLocals and their management through MasterControl[/b], because on second (or third) thought, it does not work this way. (e.g. RenderClock.getCurrentRenderClock() would return null for application threads)

I am currently investigating if it would be possible to implement Clocks as scene graph Nodes or NodeComponents.
As Nodes would be easier, because each NodeRetained already has a reference to the VirtualUniverse to which it belongs. (However a Clock is more like a NodeComponent and it seems to be easier to introduce new NodeComponents.) This would allow "parentless" Clocks to get a reference to the top-level-Clock as soon as they are live. However, I only investigate this because I thought it would be bad if an Alpha in VirtualUniverse A references a Clock in VirtualUniverse B, but this is an unchecked conditionen even for TransformInterpolators, so we could probably live without such checks and just create the Clock Tree outside the scene graph hierarchy.

> On the subject of WakeupOnElapsedTime, they are
> definitly not compatible with reverse clocks and imho
> should be deprecated in favor of a new WakeupAtDate
> in this vision of time handling.

WakeUpAtDate doesn't solve the problem of not waking up Behaviors, because the specified date also will never be reached, but it introduces extra calculations into processStimulus implementations:
atDateCondition.setDate(clock.getCurrentTimeMillis()+100);
wakeUpOn(atDateCondition)

It would be a lot easier to extend semantics of "elapsed time" to "elapsed time either in forward or backward direction" and then simply remove the "wait < 0" check from the WakeupOnElapsedTime constructor. To catch a Wakeup even if clock direction is dynamically changed you could write: "new WakeupOr(new WakeupCriterion[] {new WakeupOnElapsedTime(10), new WakeupOnElapsedTime(-10)})"

Actually I just reviewed how WakeupOnElapsedTime is scheduled. And I have found, that a priority queue (although comments name it time heap) is used. This is good because it allows fairly good scheduling performance. But it is also something we would have to keep in mind. We will need another pair of methods in the Clock interface "convertToSystemTimeMillis/Micros(long)" and TimerThread will have to manage a priority queue for every Clock and calculate the time for runMonitor(WAIT, waitTime) through one of these methods. Also modifyable Clocks will have to call VirtualUniverse.mc.timerThread.runMonitor(NOTIFY), otherwise scheduling will be inaccurate.

Wow it's late now, perhaps more tomorrow.

cu

guiramos
Offline
Joined: 2004-11-09

Wow! Very healthy discussion!

Congrats eagle! Do you have any progress on this subject?

pepe
Offline
Joined: 2003-06-10

[edit: removed duplicate part...]
When rendering offscreen, the alpha and other time related behaviors cause problem. We can't generate animations at the fake framerate we want, and due to System.currentTimeMillis() defaults, (imprecision) i think it can generate stutter and shaking at 'high' framerates on windows with onscreen canvases. Right now, this is not really a problem for offscreen, as behaviors are not run, but this will soon become one.

For 1.4, this can't be done because API is locked now, but here is what i wanted to propose for 1.5.

The idea i had was a bit different as it would be global. For onscreen, i think that what is needed is as you said: the possibility for bullet time. For that i thought about a time factor sent to Universe. For Offscreen, a date would be sent to Universe before each render. For offscreen, one of the need is to generate animations at a fixed framerate ( for generating animated media ), higher than the one you can generate and with perfect timing or to span a rendering across many machines and be sure of what is generated on them. (i need both for one of my projects)

The implementation would be as follow:
instead of using System.currentTimeMillis(), we would use an internal date, still on 64 bits.That timer would not be using milliseconds but microsecond or nanosecond (TBD), which is needed for slow motion correctness. Of course, we would loose long ( pretty long ) term precision on that date. We would use a convenience method to get the real date at lower precision if dating with jre libs are necessary.
The date would be set by the render thread before each render for onscreen and set by programmer when offscreen. The same mechanism would be used by the behaviors whenever we render and would not know in what kind of render we are. for Onscreen, we would increment the date by using a precision augmented system, using in conjunction System.currentTimeMillis() and the high res timer. We would compute the high precision difference between previous invocation and actual one, multiply it by the factor and add it to the internal date.

changes would include ( but not limited to ):
- adding some methods
[code]
void setTimeFactor( double )
double getTimeFactor()
void setTime( long )// sets normal time, the one retrieved by System.currentTimeMillis(),
// so that we can set the date we want. would setSubTime() (see offsetSubTime() for more comments
// on setting date in past)
long getTime()
void setSubTime( long )// sets sub time, the one that is using an enhanced precision.
// Would setTime() at ms precision (see offsetSubTime() for more comments on setting date in past)
long getSubTime()
void offsetSubTime( long )// would offset subtime by choosen precision (negatively or positively),
// which would be more convenient for onscreen renders and certainly for offscreen too.
//(negative offset would of course be problematic for some behaviors (starting at a certain date),
//but that can be stated as a problem user need to resolve on case basis,
// as this is something that the user CAN solve if he needs to)
[/code] to VirtualUniverse.

[code]
double getTimeFactor()
long getTime()
long getSubTime()
[/code] to Behavior.
Behavior would have a new private field pointing to its Universe (as we can't find it programmatically, afaik), get the Universe and call the appropriate methods, OR throw an exception if not added to an Universe. The place to set the field is unknown to me, but a wild guess would be that Universe is known or can be known easily when behaviors are run.
We should also add a new Behavior, let's call it RelativityBehavior, that would have the possibility to set subTime or the time ratio for next rendering to occur and override any normal mechanism. (would have to be run first on next render so that everyone is on sync)

Eventually, the system could be modified so that it is per branch, but i guess that it would complicate pipeline a bit. (and it is already much for a newcomer...). Nevertheless, i think it could be done anyway. I'll think about it during the next days.

If the team agrees, i can start a RFE for 1.5, which i could handle. Out of the bullet time thing, i need the possibility to set time for time accurate offscreen rendering.

About the impossibility to subclass Aplha's behavior, i guess that it's normal. The variables you access seem to be implementation related. Looking at the class, i don't see why you can't change the behavior simply by changing the parameters through public methods. Where is the problem lying?

Nevertheless, i agree on something, we have to get rid of that System.currentTimeMillis() wherever it is.

aces
Offline
Joined: 2003-07-17

>Alpha cannot easily be subclassed

I subclass Alpha some time ago, and works fine for some systems. But you MUST check if J3DTimer has enough precision. In non-windows System.currentTimeMillis usually is very accurate.

[code]
import javax.media.j3d.*;
import com.sun.j3d.utils.timer.J3DTimer;

/**
* Title: AlphaGT
* Description: A Alpha wich uses J3DTimer for High Precision
* Copyright: Copyright (c) 2003
* Company: CiC-UnB
* @author Alessandro Borges
* @version 1.0
*/
public class AlphaGT extends Alpha
{
final private float factor=0.000001f;
long delta;

public AlphaGT()
{
super();
delta = System.currentTimeMillis() - (long)(J3DTimer.getValue()*factor);
}

public AlphaGT(int loopCount,
int mode,
long triggerTime,
long phaseDelayDuration,
long increasingAlphaDuration,
long increasingAlphaRampDuration,
long alphaAtOneDuration,
long decreasingAlphaDuration,
long decreasingAlphaRampDuration,
long alphaAtZeroDuration)

/*public Alpha(int loopCount, int mode, long triggerTime, long phaseDelayDuration, long increasingAlphaDuration, long increasingAlphaRampDuration, long alphaAtOneDuration, long decreasingAlphaDuration, long decreasingAlphaRampDuration, long alphaAtZeroDuration)
*/
{
super( loopCount,
mode,
triggerTime,
phaseDelayDuration,
increasingAlphaDuration,
increasingAlphaRampDuration,
alphaAtOneDuration,
decreasingAlphaDuration,
decreasingAlphaRampDuration,
alphaAtZeroDuration);
delta = System.currentTimeMillis() + triggerTime +
phaseDelayDuration - (long)(J3DTimer.getValue()*factor);
}

public AlphaGT(int loopCount,
long triggerTime,
long phaseDelayDuration,
long increasingAlphaDuration,
long increasingAlphaRampDuration,
long alphaAtOneDuration)
{
super(loopCount,
1,
triggerTime,
phaseDelayDuration,
increasingAlphaDuration,
increasingAlphaRampDuration,
alphaAtOneDuration,
0L, 0L, 0L);
delta = System.currentTimeMillis() + triggerTime +
phaseDelayDuration - (long)(J3DTimer.getValue()*factor);
}

public AlphaGT(int loopCount, long increasingAlphaDuration)
{
super(loopCount,increasingAlphaDuration);
delta = System.currentTimeMillis() - (long)(J3DTimer.getValue()*factor);
}

/* synchronized*/ public float value()
{
long l = this.isPaused()?this.getPauseTime() : (long)(J3DTimer.getValue()*factor) + delta;
return value(l);
}

}
[/code]

aces
Offline
Joined: 2003-07-17

First of all, sorry for this long post :D

> I think the easiest way to implement this, would be to introduce a Clock interface like this:
> ...

You proposed a very elegant approach.
I did something less radical, just using a new Timer class and [b] alpha.getValue(myTimer) [/b] in my target behaviors:
I can have "Bullet time" as well a "RoadRunner timer (blip-blip)", just setting the proper timeModPercent value.

[code]
package unb.lcmm.cvi;
import com.sun.j3d.utils.timer.J3DTimer;

/**
*

Título: CVI

*

Descrição: Criaturas Virtuais Inteligentes - A Character Animation API for Java3D

*

Departamento LCMM - Laboratório de Computação Multimidia - Universidade de Brasilia

* @author Alessandro Borges
* @version 1.0
*/

public class Timer
{
/** Enables/disables J3DTimer.

* Use useJ3DTimer(boolean use)
* to enable/disable J3DTimer as the time counter **/
protected static boolean useJ3DTimer = false;

/** Enables/disables the timeMod **/
public static boolean useTimeModPercent = false;

/** the J3DTimer initial time in nanoseconds.

* Used for convertion back to miliseconds */
private long initialTime = 0;

/** The maximum resolution for J3DTimer.getResolution().
* Resolution greater than it is not good as System.currentTimeMillis() **/
public static long maxResolution = 2000L;
/** the max resolution for J3DTimer.getResolution().
* Resolution less than this values may hide J3DTimer bad function. **/
public static long minResolution = 200L;

protected static final float factor=0.000001f;
/** The timeMod value.**/
protected static float timeModPercent = 1.0f;

/**
* When the clockTime starts.

* By default it is ZERO.
*/
public long startTime = 0L;

/** True is this Timer is paused.
* false otherwise. */
public boolean isPaused = false;

/** the time when the chronograph stops **/
public long stopTime = 0L;

/**
* Construct a new Timer using J3DTimer as timer counting, if available and
* with enough precision.

* J3DTimer is used if and only if J3DTimer is available and J3DTimer.getResolution() is
* between Timer.maxResolution and Timer.minResolution. Otherwise the time
* counting is performed by System.currentTimeMillis().
*/
public Timer()
{
useJ3DTimer(true);
startTime = 0L;
}

/**
* Get the current time clock in milisseconds.

* If useTimeModPercent is true, it modifies the time counting as timeModPercent
* value, allowing faster, slower or even negative time counting.
* @return long the current time in millisseconds
*/
public long getTime()
{
if (isPaused) return stopTime;

long value;
if (useJ3DTimer)
{
value = ((long)(J3DTimer.getValue()*factor) - initialTime) ;
}
else
{
value = System.currentTimeMillis() - startTime;
}

if (useTimeModPercent)
{
value = (long)(value*timeModPercent);
}
return value;
}

/**
* return the currentTime in milliseconds, using J3DTimer is available, or
* System.currentTimeMillis() otherwise
* @return long the current time in milliseconds (ms).
*/

public long getCurrentTimeMillis()
{
if (useJ3DTimer)
{
return ((long)(J3DTimer.getValue()*factor) - initialTime) ;
}
else
{
return System.currentTimeMillis() ;
}
}

/**
*


* Trys to use J3DTimer if available and with enough precision for real time
* animation.

* J3DTimer is high precision timer for MS Windows platform, but may fails under
* another platforms.
* @param use boolean toogle J3DTimer for time counting.
* @return boolean true if J3DTimer are available and has enough precision.
*
*/
public boolean useJ3DTimer(boolean use)
{
if (!use)
{
this.useJ3DTimer = false;
return useJ3DTimer;
}

try
{
if (J3DTimer.getResolution() <= maxResolution && J3DTimer.getResolution() >= minResolution )
{
initialTime = (long)(J3DTimer.getValue()*factor) - System.currentTimeMillis();
return useJ3DTimer = true;
}
else
{
System.err.println("Warning : Timer error. J3DTimer resolution is out of bounds: " +
(J3DTimer.getResolution()/1000L)+
"ms. Using System.currentTimeMillis() as timer by default.");
return useJ3DTimer = false;
}
}
catch(Exception ex)
{
System.err.println("Timer error. J3DTimer is unsupported or not available.");
ex.printStackTrace();
}
return false;
}

/**
* Force the time counting be modified by a float value.

* This allows:

*

    • fast-forwading for values greater then 1.0f
  • *

    • slow-motion like for values between 0.0f and 1.0f
      *
  • *

    • backwards motion like for values less than 1.0f
      *
  • * The float pTimeModPercent must be between [-10.0f, 10.0f].

    * TimeModPercent is a static operation. If you enable modTimer in a
    * Timer all Timer's instances will have it too.

    * @param timePercent a time modiefier value. 1.0 means 100%, 2.0 is 200%
    * @throws Exception if pTimeModPercent is outside the bounds [-10.0f, 10.0f]
    */
    public void setTimeModPercent(float pTimeModPercent)
    {
    if (pTimeModPercent > 10.0f || pTimeModPercent < -10.0f)
    {
    useTimeModPercent = false;
    new CVIException("Error Timer. timePercent " + pTimeModPercent +
    " value out of range. Values must be in [-10.0, 10.0]");
    }

    this.timeModPercent = pTimeModPercent;
    if (Math.abs(timeModPercent - 1.0f) >= 0.0001f)
    {
    timeModPercent = 1.0f;
    useTimeModPercent = false;
    }
    else
    {
    useTimeModPercent = true;
    }
    }

    /**
    *
    * @return boolean true if J3DTimer is beeing used fot time counting. False otherwise.
    */
    public boolean isUsingJ3DTimer()
    {
    return useJ3DTimer;
    }

    /**
    * toogles time counting modifier.
    * @param enableMod boolean true enables time mod.
    */
    public void enableTimeModPercent(boolean enableMod)
    {
    this.useTimeModPercent = enableMod;
    }

    /**
    * Reset the clock Counter.

    * The startTime will be the current time: NOW.

    * The clocktime will start with ZERO.

    */
    public void reset()
    {
    startTime = getCurrentTimeMillis();
    if (useJ3DTimer)
    {
    initialTime = (long)(J3DTimer.getValue()*factor);
    }
    }

    /**
    * Stops the time counting.

    * Use start() to reinit the time counting where it stops.
    */
    public void stop()
    {
    if (!isPaused)
    {
    stopTime = this.getTime();
    isPaused = true;
    }
    }

    /**
    * Starts/restarts the clock timer after a stop() call.

    * If you wish to restart the time counting use reset()
    */
    public void start()
    {
    if (isPaused)
    {
    long delta = getCurrentTimeMillis() - stopTime;
    initialTime -= delta;
    startTime -= delta;
    isPaused = false;
    }
    }

    }
    [/code]

    Message was edited by: aces

    eagle
    Offline
    Joined: 2004-03-04

    > First of all, sorry for this long post :D
    I don't mind, I write even longer posts :D

    > I did something less radical, just using a new Timer
    > class and [b] alpha.getValue(myTimer) [/b] in my
    > target behaviors:
    > I can have "Bullet time" as well a "RoadRunner timer
    > (blip-blip)", just setting the proper timeModPercent
    > value.

    Thanks for sharing your code, but I see a problem with your code:
    [code]Timer timer = new Timer();
    timer.startTime = timer.getTime();
    Thread.sleep(1000);
    System.out.println("A:"+timer.getTime());
    Thread.sleep(1000);
    System.out.println("B:"+timer.getTime());
    timer.setTimeModPercent(0.5f); // enable BulletTime
    System.out.println("C:"+timer.getTime());
    Thread.sleep(1000);
    System.out.println("D:"+timer.getTime());[/code]

    If I am not mistaken, your code will result in this output:
    A:1000
    B:2000
    C:1000
    D:1500

    while for "real" bullet-time behavior it should be this:

    A:1000
    B:2000
    C:2000
    D:2500

    Your code will result in Alpha's instantly jumping to another phase when enabling bullet-time if they where based on this Timer.

    And a remark to your Alpha subclass in the other post: Yes this subclass works, but it's only so easy to subclass because you ignore the HiRes timer for pause()/resume()/finished(). You cannot ignore those methods if your timebase can be slowed down, speeded up or stopped, otherwise your Alpha will return true on finished() even though you already stopped your timebase long ago.

    cu
    Ralf

    aces
    Offline
    Joined: 2003-07-17

    >Thanks for sharing your code, but I see a problem with your code:

    yes, you are right. I should take the current timestamp when setting new timeModPercent. But it is easy to fix ;)

    >And a remark to your Alpha subclass...

    I see Alpha was just a wrapper for a timer. But as we need a new kind of timer, we will also need a new kind of Alpha, as you proposed.

    Did you also think about a "rewind" Timer/Clock ? As we can go faster and slower, why not have it backward capable ?

    Alessandro

    eagle
    Offline
    Joined: 2004-03-04

    > Did you also think about a "rewind" Timer/Clock ? As
    > we can go faster and slower, why not have it backward
    > capable ?

    Yes I did. But I am still not sure, that everything will work fine if time suddenly goes backwards. For example what will WakupOnElapsedTime do when based on an rewinding clock? Probably it will never wake up again.

    I still have no satifisfying solution how objects could ensure, that they wont get a "rewindable clock" as argument to their setClock() methods or their constructors.

    cu

    Kyle McDonald

    java3d-interest@javadesktop.org wrote:

    >>Did you also think about a "rewind" Timer/Clock ? As
    >>we can go faster and slower, why not have it backward
    >>capable ?
    >>
    >>
    >
    >Yes I did. But I am still not sure, that everything will work fine if time suddenly goes backwards. For example what will WakupOnElapsedTime do when based on an rewinding clock? Probably it will never wake up again.
    >
    >I still have no satifisfying solution how objects could ensure, that they wont get a "rewindable clock" as argument to their setClock() methods or their constructors.
    >
    >
    >
    Create a Non-rewinding Interface. Then objects can declare parameters of
    that interface type, anything passed to them that doesn't implement the
    non-rewinding interface won't be accepted by the compiler.

    -Kyle

    >cu
    >---
    >[Message sent by forum member 'eagle' (Ralf Ullrich)]
    >
    >http://www.javadesktop.org/forums/thread.jspa?messageID=103643𙓛
    >
    >---------------------------------------------------------------------
    >To unsubscribe, e-mail: interest-unsubscribe@java3d.dev.java.net
    >For additional commands, e-mail: interest-help@java3d.dev.java.net
    >
    >
    >

    ---------------------------------------------------------------------
    To unsubscribe, e-mail: interest-unsubscribe@java3d.dev.java.net
    For additional commands, e-mail: interest-help@java3d.dev.java.net

    eagle
    Offline
    Joined: 2004-03-04

    > Create a Non-rewinding Interface. Then objects can
    > declare parameters of
    > that interface type, anything passed to them that
    > doesn't implement the
    > non-rewinding interface won't be accepted by the
    > compiler.

    I thought about that one and it does not really satisfy me. Consider this:

    [code]
    // a Clock wrapper System.currentTimeMillis();
    class SystemClock implements Clock, NonRewindingClock {
    SystemClock(); // hardware clock, hence no parent
    ...
    }

    // a Clock whose speed can be tuned (or even reversed)
    class TunableClock implements Clock {
    TunableClock(Clock parent)
    ...
    }

    // A Clock that can be stopped
    class StoppableClock implements Clock {
    Clock(Clock parent)
    }

    ...
    Clock guiClock = new StoppableClock(
    new SystemClock());
    Clock gameClock = new StoppableClock(
    new TunableClock(
    new SystemClock()));
    [/code]

    Now with this code WakeUpOnElapsedTime should accept guiClock as time base, but reject gameClock. You cannot do this with a marker interface.

    (BTW: For WakeUpOnElapsedTime the better solution would be to wake up also if the specified amount of time elapsed in backward direction. However, its good enough for this example to assume, that it only works with forwarding clocks.)

    cu

    Pablo Figueroa

    There is this article at the New Scientist Magazine that may be of your
    interest:

    Matrix-style ‘bullet-time’ in multiplayer gaming
    19:00 20 July 2005
    NewScientist.com news service
    Duncan Graham-Rowe

    http://www.newscientist.com/article.ns?id=dn7703

    Best Regards,

    On 1-Aug-05, at 6:50 PM, java3d-interest@javadesktop.org wrote:

    > I want to create a "Bullet Time" effect, as it is known from games
    > like Max Payne or Chrome (or as in the movie "The Matrix"). For those
    > not familiar with this term: Bullet Time is a slow motion effect, that
    > can be turned on and off.
    >
    > I identified the following aspects to consider with this effect:
    > - most animated objects in the scene will have to slow down (e.g.
    > ongoing explosions, light flickers, rotating satellite dishes, ...)
    > - a few animations however will not participate in bullet time (e.g.
    > animations of the player avatar, HUD animations, etc.)
    >
    > I think the easiest way to implement this, would be to introduce a
    > Clock interface like this:
    >
    > [code]interface Clock {
    > static final DEFAULT = ... // see below
    > long getCurrentTime();
    > }[/code]
    >
    > The (default) implementation for Clock would just wrap the System
    > clock:
    > [code] static final DEFAULT = new Clock() {
    > public long getCurrentTime() {
    > return System.currentTimeMillis();
    > }
    > };[/code]
    >
    > A bullet time implementation of Clock would then return slower growing
    > time values for getCurrentTime() while bullet time is enabled.
    >
    > A quick search brings up 89 places in Java3D core and core-utils where
    > currently System.currentTimeMillis() is used, and I will have to look
    > into each one to identify those, that would have to be rewritten using
    > such a Clock.
    >
    > I started with the most obvious candidate for some tests: [b]Alpha[/b].
    >
    > I created a subclass ClockAlpha, that allows a Clock to be assigned.
    > Doing so I encountered the following problems:
    >
    > 1. Alpha cannot easily be subclassed, because many fields that are
    > required for calculations are actually private and have no getter
    > methods provided. ==> workaround: reimplement all methods of Alpha
    > completely in the subclass.
    >
    > 2. Subclasses of Alpha actually can't be used easily, because
    > Interpolator.duplicateAttributes(...) calls the package private
    > internal method Alpha.cloneAlpha(), that I cannot override outside of
    > the javax.media.j3d package. ==> workaround: place the subclass in the
    > javax.media.j3d package.
    >
    >
    > Now with these findings in mind I have a few questions:
    >
    > 1. [b]Is it a bug[/b], that you effectively [b]can't subclass
    > Alpha?[/b] (i.e. shouldn't those private fields be protected instead
    > or provide protected getters? shouldn't cloneAlpha be a protected
    > method or even public? (remember: protected methods are also package
    > visible))
    >
    > 2. It would be much easier to implement my ClockAlpha if Alpha would
    > have a protected getCurrentTimeMillis() method instead of Calling
    > System.currentTimeMillis() directly at several places. Is this an
    > [b]interesting RFE?[/b]
    >
    > 3. How about the Clock-Approach? (or call it TimeProvider or ...)
    > Wouldn't it be nice to have this a feature in core Java3D? So is this
    > also an [b]interesting RFE?[/b]
    >
    >
    > ad 2) this is easily implemented within a few minutes.
    >
    > ad 3) I'd be willing to investigate all 89 occurences of
    > System.currentTimeMillis() and provide (untested*) implementations
    > using the Clock-Approach, if this feature is interesting enough to
    > become part of core Java3D. (* I do not have a C-Compiler, so I don't
    > know if I could build j3d-core to test those changes)
    >
    >
    > So, now I'd like to know your opinions.
    >
    > Thanks
    > Ralf
    > ---
    > [Message sent by forum member 'eagle' (Ralf Ullrich)]
    >
    > http://www.javadesktop.org/forums/thread.jspa?messageID=103132&#103132
    >
    > ---------------------------------------------------------------------
    > To unsubscribe, e-mail: interest-unsubscribe@java3d.dev.java.net
    > For additional commands, e-mail: interest-help@java3d.dev.java.net
    >

    ---------------------------------------------------------------------
    To unsubscribe, e-mail: interest-unsubscribe@java3d.dev.java.net
    For additional commands, e-mail: interest-help@java3d.dev.java.net

    pepe
    Offline
    Joined: 2003-06-10

    This is something i have been thinking about and reviewed a moment ago when i started looking at offscreen rendering for issue 131.
    Please let me some time to type a complete description of what i thought. I'll post it around the end of afternoon (GMT+1)