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".

Reply via email to