[Source] [X3D-Earth] Xj3D property setting for origin manager, for inclusion in X3D-Edit
Rex Melton
rex.melton at comcast.net
Mon Jun 8 05:52:28 PDT 2009
Hi Rune,
Thanks for the info. I will certainly review it closely when I have a
chance to return to tuning up our geospatial component implementation.
Unfortunately, I will not be attending the conference in Darmstadt. So I
will not have the opportunity to meet with you.
However, feel free to abuse Alan Hudson in my stead :-)
-Rex
Rune Aasgard wrote:
> I have worked with similar problems in my Virtual Globe
> http://www.virtual-globe.info/ and http://norgei3d.no/ (Good JWS
> application example showing terrain with buildings and trees:
> http://www.virtual-globe.info/VirtualGlobeStarter.php?dataset=http://www.virtual-globe.info/test/grotte.vgml&viewpoint=5.745274546100676,58.85572300948739,122.23931567609378,217.73784441355252,-13.401403950398965&libs=Xj3D
> <http://www.virtual-globe.info/VirtualGlobeStarter.php?dataset=http://www.virtual-globe.info/test/grotte.vgml&viewpoint=5.745274546100676,58.85572300948739,122.23931567609378,217.73784441355252,-13.401403950398965&libs=Xj3D>)
> and I believe you may find some inspiration in my implementation. It
> solves the problem with long computations that may halt the rendering
> for more that the acceptetd frame-to-frame interval.
>
> From the OriginManager:
> <code>
> // Handling of the hi-resolution origin
> /// The hi resolution origin
> private Point3d origin = new Point3d();
> private Point3d new_origin = new Point3d();
> /// Listeners that expect to be told when the hi-res origin changes
> // WeakReferences are used to assure that deleted objects are
> not retained from GC by the OriginManager
> private final ArrayList<WeakReference<OriginUpdateListener>>
> originUpdateListeners = new ArrayList();
> private final ArrayList<WeakReference<OriginUpdateListener>>
> originRequestListeners = new ArrayList();
> private final ArrayList<WeakReference<OriginUpdateListener>>
> originCompleteListeners = new ArrayList();
>
> /**
> * Check if the hires origin is sufficiently close to the
> interesting areas
> * @param p Point to test
> * @param tol Acceptable tolerance (vWorld scale size)
> */
> public void testOrigin(Point3d p, float tol) {
> synchronized (originRequestListeners) {
> if (originRequestListeners.isEmpty()) {
> double orig_dist = origin.distance(p);
>
> // Move origin?
> if (orig_dist*1e-5f > tol) {
> new_origin.set(p);
> // System.err.println("Flytter origin: " + origin);
> synchronized (originUpdateListeners) {
>
> originRequestListeners.addAll(originUpdateListeners);
> }
> }
> } else {
> Iterator<WeakReference<OriginUpdateListener>> i =
> originRequestListeners.iterator();
> while (i.hasNext()) {
> WeakReference<OriginUpdateListener> ref = i.next();
> OriginUpdateListener l = ref.get();
> if (l == null)
> i.remove();
> else if (l.requestUpdateOrigin(new_origin)) {
> i.remove();
> originCompleteListeners.add(ref);
> }
> }
> }
> if (originRequestListeners.isEmpty()) {
> origin.set(new_origin);
> // Call listeners
> synchronized (originCompleteListeners) {
> for (WeakReference<OriginUpdateListener> ref :
> originCompleteListeners) {
> OriginUpdateListener l = ref.get();
> if (l != null)
> l.updateOrigin(origin);
> }
> originCompleteListeners.clear();
> }
> }
> }
> }
>
>
> /**
> * Add origin update listeners
> * @param l
> */
> public void addOriginUpdateListener(OriginUpdateListener l) {
> // l.requestUpdateOrigin(origin);
> // l.updateOrigin(origin);
> synchronized (originUpdateListeners) {
> originUpdateListeners.add(new WeakReference(l));
> }
> synchronized (originRequestListeners) {
> originRequestListeners.add(new WeakReference(l));
> }
> }
> </code>
>
> The testOrigin method is called once each frame in this way:
>
> <code>
> navigator.getEye(camera_pos);
> float tol = Math.max(0.01f, (float)
> navigator.getTerrainHeight() * (float) (fov * Math.PI / 180. /
> canvas.getWidth()) * pixel_factor);
> getOriginManager().testOrigin(camera_pos, tol);
> </code>
>
> As you can see it uses parameters describing the view system
> resolution (canvas size, fov, camera height over terrain) to compute a
> premissible numerical error tolerance.
>
> The recalculation of the origin is done as a two step process to allow
> some objects to do long background processing that may take several
> frames to complete. This allows the recalculation of large terrain
> models without visible halts in the framerate.
>
> All objects that have interest in the origin implements the
> OriginUpdateListener interface and registers with the origin manager.
> The OriginUpdateListener has two methods:
> <code>
> /**
> * Listener interface for objects that have to recalculate geometry
> because of
> * changes in the origin
> * @author runaas
> */
> public interface OriginUpdateListener {
> /**
> * For objects requiering long calculations this method starts the
> * computation, returns false while the calculations are running
> and finally
> * returns true when the calculations are complete.
> * Objects that don't require calculations running over several
> frames simply return true.
> * @param p The new origin
> * @return true if the update computations are completed
> */
> boolean requestUpdateOrigin(Point3d p);
> /**
> * Complete the origin update process, make new graphic information
> * current etc...
> * @param p The new origin
> */
> void updateOrigin(Point3d p);
> }
> </code>
>
> The requestUpdateOrigin is polled repeatedly (each frame) until it
> returns true. No visible changes in the objects should be performed at
> this stage.
>
> Finally when all objects have returned "true" the updateOrigin method
> of all objects is called, and the origin is really changed.
>
> Typically a simple object containng only a transform matrix is
> implemented like this:
>
> <code>
> public void updateOrigin(Point3d origin) {
> this.origin.set(origin);
> updateTransform();
> }
>
> public boolean requestUpdateOrigin(Point3d origin) {
> return true;
> }
> </code>
>
> While a more complex object that requires long recomputations would be
> something like this:
>
> <code>
> RenderData render_data;
> RenderData new_render_data;
>
> private void computeRenderData(RenderData rd) {
> // ..... long and complex computations ....
> }
>
> private class Updater implements Runnable {
> Point3d origin;
> boolean is_completed = false;
> Updater(Point3d origin) {
> this.origin = origin;
> }
> public void run() {
> computeRenderData(origin, new_render_data);
> synchronized (this) {
> is_completed = true;
> }
> }
> public synchronized boolean isCompleted() {
> return is_completed;
> }
> }
> private Updater updater = null;
> public void updateOrigin(Point3d p) {
> updater = null;
> render_data.set(new_render_data);
> }
> public boolean requestUpdateOrigin(Point3d p) {
> if (updater == null) {
> updater = new Updater(p);
> new Thread(updater).start();
> }
> return updater.isCompleted();
> }
> </code>
>
> I'm coming to web3d in Darmstadt, and I would like to attend the
> earth3d workshop. By the way, I'm planning to raise some noise
> pestering you with questions of why you have not based the geographic
> coordinate format in X3D on GML??????? I believe the ISO standard for
> 3D graphics would be much more useful if there was some
> interoperability with the ISO standard for geographic information....
>
> Rune Aasgaard
>
More information about the Source
mailing list