Texture loading events

69 views
Skip to first unread message

Nick

unread,
Mar 22, 2012, 6:38:27 PM3/22/12
to sce...@googlegroups.com
Hi Lindsay & Friends,

First of all many thanks for Scene.js I'm an absolute WebGL (and 3D graphics) newbie but using scene.js (2.0.0) and it's excellent documentation I was able to get up and running very quickly.

I'm attempting to write a Google-maps style client for some 3D imagery captured by a third party. The way the server works is for each scene there is 3 levels of detail available. One that has one tile per skybox side, another with 4 per side and finally the hi-res imagery with 16 tiles per side. The way the client is supposed to work is to load the low-res imagery first then overlay it with the higher res imagery as it loads.

The way I implemented this was to generate three skyboxes with 1, 4, and 16 tiles per side respectively and nest them like Matryoshka dolls. The lowest res imagery is on the walls of the innermost box which is scaled to 0.9 the outer two boxes have scale 1.0 and 1.1 respectively.

The approach I was going to use was to monitor the texture loading of the outer two boxes and remove each of the two inner boxes as the more detailed box outside of it finishes loading. I've tested that this creates the desired effect by creating the scene and removing the inner boxes progressively with a timer, but the ultimate goal is to do that in response to texture loads.

I noticed this page from the 0.8 documentation (http://scenejs.wikispaces.com/SceneJS.bind+-+Monitoring+Scene+Loading) so attempted to use the "loading-status" event in 2.0.0 but it doesn't seem to be fired (or I'm doing it wrong). My sequence of events is as follows:

    // Create the skybox scene
    var scene = SceneJS.createScene(generateSceneGraph(1024, 768, 72));

    ...
        
    // Monitor loading of innermost box
    var smallBox = scene.findNode("smallbox");
    smallBox.bind("loading-status", 
        function( event )
        {
            console.log("loading-status event fired");
        });
        
    // Start the scene rendering
    scene.start( ... );

I'm not seeing the loading-status event ever firing. I noticed some code regarding the event commented out on line ~580 of the scene.js source, but wasn't game to tinker with it at this stage.

Am I doing something wrong? Am I going about this completely the wrong way? Is there a way to get these events to fire?

Any advice is sincerely appreciated.

Kind Regards,
Nick Tindall 

Lindsay Kay

unread,
Mar 26, 2012, 8:14:10 PM3/26/12
to sce...@googlegroups.com
Hi Nick

unfortunately that event was removed from SceneJS 2.0 (which was a partial rewrite).

I replaced it with a much coarser "status" object, obtained from the scene root, which has the total count of textures and geometries (when using a GeoLoadService) still loading.

It's a long shot, but maybe the following snippet has something useful to you..it "blocks" the caller, firing the callback when all pending loads are complete. Perhaps you could synchronise your texture level loads with something like this?

/**
 * Blocks while count of current scene graph asset loads is not zero
 */
(function() {
       var checkLoaded;

       self.blockUntilLoadsFinished = function(onComplete) {

           if (myScene.get("status").numLoading == 0) {
               onComplete();
               return;
           }

           if (checkLoaded) {
               throw "already blocking";   // TODO: could accumulate callbacks
           }

           checkLoaded = window.setTimeout(
                   function() {
                       var sceneStatus = myScene.get("status");
                       if (!sceneStatus.numLoading) {
                           window.clearTimeout(checkLoaded);
                           checkLoaded = null;
                           onComplete();
                       }
                   }, 200);
       };
})();

I could refine this status object a bit perhaps, with IDs of the nodes for which loads are pending, and maybe allow listeners to subscribe via this..

cheers,
Lindsay

Nick

unread,
Mar 26, 2012, 9:51:11 PM3/26/12
to sce...@googlegroups.com
Hi Lindsay,

Thanks for the response!

That's a shame about the coarseness of the event. For my application I really need a way of telling which textures are still loading. I could definitely use the scene status object, I'd probably implement it in a similar way as you have in the example, but without knowing which textures are still loading I'm unable to progressively remove the inner low-detail boxes as the outer boxes finish loading.

Are there plans to implement anything finer grained than the status event? Knowing when textures are loaded seems like it could be useful?

Another way of implementing my progressive skybox might be to have the lowest detail textures on the outer box and as the inner boxes load they could block the view of the outer box, but I don't think that's possible because the textures seem to have an opaque placeholder before they're loaded? Is there a way around that?

Regards,

Nick Tindall

Lindsay Kay

unread,
Mar 28, 2012, 11:42:43 AM3/28/12
to sce...@googlegroups.com
That's a shame about the coarseness of the event. For my application I really need a way of telling which textures are still loading. I could definitely use the scene status object, I'd probably implement it in a similar way as you have in the example, but without knowing which textures are still loading I'm unable to progressively remove the inner low-detail boxes as the outer boxes finish loading.

Are there plans to implement anything finer grained than the status event? Knowing when textures are loaded seems like it could be useful?


Yip, working on that one at the moment.

Still finalizing it, but I'd *probably* support binding a callback on the texture node like this:

scene.findNode("myTextureNode").bind("loaded", function() {  ... });

I also want to be able to subscribe to those events globally as well, perhaps like this:

scene.bind("loaded", function(node) {  ... });

I've been playing around with the first type of callback, works OK in my experiments. 

Ultimately, I also want to report things in the event like how much data was loaded.

ETA on this is next couple of days.

If you have any suggestions on ideally how you'd like the API to look around these events, or what info is useful in them, that would be very cool..

cheers,
LK




Lindsay Kay

unread,
Mar 28, 2012, 5:59:09 PM3/28/12
to sce...@googlegroups.com
I just added "loading" and "loaded" events to the geometry and texture nodes:

var textureNode = scene.findNode("myTextureNode");

textureNode.bind("loading", function() {  ... });
textureNode.bind("loaded", function() {  ... });

Let us know how that goes..

Nick

unread,
Mar 28, 2012, 6:00:37 PM3/28/12
to sce...@googlegroups.com
Hi Lindsay,

That sounds very close to what I'm looking for!

I imagine if I were responding to load events on texture nodes I could fade the alpha in from 0.0 to 1.0 after the texture loaded. 

Textures that haven't loaded currently seem to display whatever texture was loaded most recently. When there's a lot of different textures the effect as they load is pretty spectacular (see here for an example on a 16-tiles-per-side skybox http://www.youtube.com/watch?v=EHQQgZbYTjo). I don't suppose there's a way to make them stay transparent until loaded?

If the load events were "bubbled" up the tree that might be cool too. I think that was how the 0.8 events worked wasn't it? It'd be great to be able to subscribe to a node and respond to events that occurred below it in the graph. Or just know when everything below that point in the graph was finished loading.

Whatever you come up with keep us posted. I look forward to trying it out :)

Thanks again!
Nick Tindall

Nick Tindall
0413 177 761

Nick

unread,
Mar 28, 2012, 6:01:38 PM3/28/12
to sce...@googlegroups.com
Excellent! I'll try that out today and get back to you.

Nick Tindall
0413 177 761


Datenbank archINFORM

unread,
Mar 28, 2012, 6:27:55 PM3/28/12
to sce...@googlegroups.com
H Nick,

this strange behaviour is already an "official" issue:

https://github.com/xeolabs/scenejs/issues/153

I'm waiting for a solution for this bug, too...
Hopefully Lindsay will find a fix.

Sascha


2012/3/29 Nick <pva...@gmail.com>:

--
www.archINFORM.net
Postfach 540103
D-10042 Berlin
Telefon: +49 (30) 44308505
Telefax: +49 (30) 44308178
arc...@archINFORM.de

Lindsay Kay

unread,
Mar 28, 2012, 6:28:06 PM3/28/12
to sce...@googlegroups.com

Textures that haven't loaded currently seem to display whatever texture was loaded most recently.
 
Aha, that sounds like the problem Sascha Hendel was having recently.  From your description it sounds like a state change failure as the draw list is iterated - I'll fix that.
 
When there's a lot of different textures the effect as they load is pretty spectacular (see here for an example on a 16-tiles-per-side skybox http://www.youtube.com/watch?v=EHQQgZbYTjo). I don't suppose there's a way to make them stay transparent until loaded?

There was something like that in previous versions - a boolean "waitForLoad"  property on textures. It's not active in 2.0, but I'll take a look at reactivating it.


If the load events were "bubbled" up the tree that might be cool too. I think that was how the 0.8 events worked wasn't it? It'd be great to be able to subscribe to a node and respond to events that occurred below it in the graph. Or just know when everything below that point in the graph was finished loading.

Right, I had something like that in previous SceneJS versions that traversed the whole scene graph on each frame, and thus had that hierarchical context on each render. In V2.0 however the scene graph is compiled to a flat display list and thus that hierarchy is not available like that at render-time. I think in V2 the best we can do is either a listener on a node that listens to all textures within the subtree, that overrides any listeners on nodes higher in the hierarchy. In other words, just one level of listeners.

A global listener on the scene root, in addition to local listeners on individual texture and geometry nodes, is easy though.

Whatever you come up with keep us posted. I look forward to trying it out :)


OK will do,
cheers
LK

Nick

unread,
Mar 29, 2012, 6:47:51 PM3/29/12
to sce...@googlegroups.com
Hi Lindsay,

I forgot to mention, I've started using the "loaded" event on the texture nodes and it seems to be working well. I take it the loaded event on the geometry is just for the geometry itself and nothing to do with the geometry's textures? I attempted to listen for it on some geometry after I added it to a scene that was already started but I think it was firing in-between me adding the geometry and adding the listener, so I can't confirm or deny that that's working.

Thanks again!

Nick Tindall

Lindsay Kay

unread,
Mar 31, 2012, 7:52:46 PM3/31/12
to sce...@googlegroups.com
Hi Nick,
 
I forgot to mention, I've started using the "loaded" event on the texture nodes and it seems to be working well. I take it the loaded event on the geometry is just for the geometry itself and nothing to do with the geometry's textures?

That's right - "loading" and "loaded" listeners on geometry nodes are only listening for when the geometry data is loaded via a GeoLoader plugin (which loads asynchronously):
 
I'm still working on an API for listening for these load events globally. 

Just finished a work iteration, so can give some much needed attention to SceneJS now. 
Reply all
Reply to author
Forward
0 new messages