On Wed, 19 Feb 2003 18:45:51 -0800, Mark Hood <[EMAIL PROTECTED]> wrote:
>> Date: Wed, 19 Feb 2003 03:26:03 -0700
>> From: Joost Verschuren <[EMAIL PROTECTED]>
>>
>> Updating the position and orientation of the target object and
>> viewplatform is done in the preRender() callback function. First the
>> transform group of the target object is updated. Then the transformgroup
>> of the viewplatform is calculated from the transformgroup of the target
>> object.
>
>This sounds OK so far. You're updating both the view platform and target
>object transform at the same time, so they should be in sync.
>
>> Most of the time this will work but sometimes the view flickers. It looks
>> like the viewplatform transform is one frame behind the target transform
>> for a frame. The next frame the camera seems to target the object OK.
>
>Odd result given that it seems you updated the transforms simultaneously.
>Odder still that you only get the flicker on certain platforms. It
>suggests a race condition that favors one outcome or the other depending
>upon the timing of concurrent threads.
>
>It's difficult to suggest a solution without seeing the code. Are the
>object and view platform transforms really updated sequentially in the
>same thread as you indicate? Do you compute the object and view platform
>transforms from data that you know is current, or are you perhaps relying
>on data derived from internally maintained Java 3D state?
I have extracted some fragments of the code and included it at the end of this
message. Some of the code could use some optimization :)
>There are a few latency issues in the Java 3D 1.3 architecture that could
>affect what you're doing:
>
>1) Updates to geometry and texture data have a 1-frame latency.
>2) Updates to transforms and scene graph structure have a 2-frame latency.
>3) Methods such as getImagePlateToVworld() in Canvas3D query the internal
> representation of the Java 3D scene graph, which has the 2-frame latency
> previously mentioned, so you can't use those methods directly to
> synchronize view dependent scene graph updates.
>
>We have a workaround for issue 1) that involves a behavior post mechanism
>to delay geometry and texture updates by 1 frame, and I've developed a
>utility, ViewInfo, that works around issues 2) and 3). Let me know if
>you'd find those of any interest. ViewInfo should be available in Java 3D
>1.3.1 beta2 but I can get you an early copy. In the mean time, a test
>case would help us determine if your problem is a bug in Java 3D.
>
>Thanks -- Mark Hood
Mark, thanks for your input. I'm certainly interested in these utilities.
I'll try to produce a test case if I can find the time and if you're still interested.
Since the code was written by a former colleague (he works at another company now) and
the code is spread over a lot of classes this will need some investigating.
Thanks in advance,
Joost Verschuren
=============================================================
public class J3D_VCEClient extends Thread {
// Receives the data from a buffered datainputstream
...
public void run() {
try {
int typeMsg;
int index;
while (runthread) {
typeMsg = dataIn.readInt();
switch (typeMsg) {
case J3D_VCECommon.J3D_CONF_MSG : { break; }
case J3D_VCECommon.J3D_VARIABLES : {
dataIn.readFloat(); // dummy float
if (firstmessage) {
dataIn.readFloat(); // dummy float
firstmessage = false;
}
// Read data from server in buffer[0]
Vector buf = buffers[0];
for (int i = 0; i < numRecords; i++) {
float[] bufRow = (float[])buf.get(i);
for (int j = 0; j < bufRow.length; j++) {
bufRow[j] = dataIn.readFloat();
}
}
// Deep copy to buffer[1]
// Synchronized with updateGraphics() to avoid writing to buffer
// while updating players etc.
// Naive implementation for so far. Needs optimization, buts
// solves some problems
synchronized(monitor) {
for (int i = 0; i < numRecords; i++) {
System.arraycopy( (buffers[0]).get(i), 0,
(buffers[1]).get(i), 0,
((float[])(buffers[0].get(i))).length );
}
} //sync
break;
}
default: {}
}
}
} catch (IOException e) {
J3D_VCEVisGui.setMBoxText("client thread failed: " + e, "error");
J3D_VCEVisGui.setMBoxText("Stop client application and restart", "error");
}
}
}
-------------
public class J3D_VCECanvas extends Canvas3D {
...
public void preRender() {
if (updater.updateGraphics()) {
if (tether != null) {
if (tether.getTetherEnabled()) {
tether.updateVP();
}
}
}
}
}
-------------
public class J3D_VCEComponentsUpdater {
...
public boolean updateGraphics() {
Vector theNewBuffer = null;
Vector currentBuffer = null; //
synchronized(monitor) {
theNewBuffer = (Vector)(theClient.getCurrentBuffer());
currentBuffer = new Vector();
// Deep copy
for (int i = 0; i < theNewBuffer.size() ; i++) {
int tempArrayLength = ((float[]) (theNewBuffer.get(i)) ).length;
float[] tempArray = new float[tempArrayLength];
System.arraycopy( theNewBuffer.get(i), 0,
tempArray, 0,
tempArrayLength );
currentBuffer.add(tempArray);
}
// Update players and lights with contents of the buffer
for (int i = 0; i < thePlayers.length; i++) {
((J3D_VCEPlayer)thePlayers[i]).update(currentBuffer);
}
for (int i = 0; i < theLights.length; i++) {
((J3D_VCELight)theLights[i]).update(currentBuffer);
}
} //sync
return true;
}
}
-------------
public class J3D_VCEComponent {
public void updatePosition(float[] newPosition) {
rtM = eulerToMatrix(newPosition[3]*DEG2RAD,
newPosition[4]*DEG2RAD,
newPosition[5]*DEG2RAD);
rtTranslation.set((double)newPosition[0],
(double)newPosition[1],
(double)newPosition[2]);
rtT3d.set(rtM);
rtT3d.setTranslation(rtTranslation);
tg_position.setTransform(rtT3d);
}
}
-------------
public class J3D_VCEPlayer extends J3D_VCEComponent {
public void update(Vector buffer) {
//The Player
if (positionInBuf) {updatePosition((float[])buffer.get(posPositionInBuf));}
if (switchInBuf) {updateSwitch((float[])buffer.get(posSwitchInBuf));}
if (scaleInBuf) {updateScale((float[])buffer.get(posScaleInBuf));}
//Player Objects
updateObjects(buffer);
}
public void updateObjects(Vector buffer) {
for (int i = 0; i < objectArray.length; i++) {
((J3D_VCEObject)objectArray[i]).update(buffer);
}
}
}
-------------
public class J3D_VCETether {
...
public void updateVP(){
tg_obj.getTransform(t3d_obj);
t3d_obj.get(trans);
center.set(trans.x,trans.y,trans.z);
//Determine the new absolute eye position
eyeabs.set(eyePoint.x+center.x,
eyePoint.y+center.y,
eyePoint.z+center.z);
congruency.sub(center, eyeabs);
// Normalize vectors, for check on dot product
congruency.normalize();
up.normalize();
if (Math.abs(congruency.dot(up)) < 0.995) { //only if non-congruent
t3d.lookAt(eyeabs, center, up);
t3d.invert();
tg_vp_rot.setTransform(t3d);
trans.set(0.0,0.0,0.0);
t3dtrans.setIdentity();
t3dtrans.setTranslation(trans);
tg_vp_trans.setTransform(t3dtrans);
}
}
}
===========================================================================
To unsubscribe, send email to [EMAIL PROTECTED] and include in the body
of the message "signoff JAVA3D-INTEREST". For general help, send email to
[EMAIL PROTECTED] and include in the body of the message "help".