Best practices for animating nodes... Help!

Hey guys,



I'm probably going to be asking a few "already answered" questions here. Apologies for making a nuisance of myself. I do promise that I will have tried to find it, and not just throw in questions cos' I'm too lazy! I promise!



So… My first very basic question is this: What is the best way to avoid unnecessary animations (eg rotations) taking place for unviewable items?



For instance, Checking out the TestJMEDesktop example in the source, I see there is a Controller.update() task that rotates the box merrily away. Now then, using the NetBeans profiler (which I am really impressed with BTW), I notice that this is also getting called with every simpleUpdate(). That's fine for just one object, but I would imagine it getting unwieldy in a room full of spinning things!



        //let the box rotate
        box.addController(new Controller() {
            public void update(float time) {
                box.getLocalRotation().fromAngleNormalAxis(timer.getTimeInSeconds(), axis);
            }
        });



Hopefully I'm making sense! My initial app is going to have a fair number of animations, and I'd like to adopt "best-practices" early on.

Your advice would be very much appreciated.

Richard

Just to hopefully illustrate my point a bit more clearly, here is the profiler report for TestJMEDesktop. The two methods I am referring to are jmetest1.TestJMEDesktop$11.update(float) - which is the box animation -  and jmetest1.TestJMEDesktop.simpleUpdate(). They have both been run 81217 times, regardless of where I roam.



Got to say though, 1216ms for 81217 calls is bloody impressive. I know it's just a small rotation, but it floats my boat… Perhaps I need to get out more 

maybe use a distance switch node and attach your box with the controller to this node for a distance that the rotation would need to be noticable and then outside of that just add a box or some type of primitive…

Wow, that is a fast response… Thanks.



So is that the standard way to do it? It makes sense I guess.



I can see some examples in the forums, so I'll see if I can make it work for me!

Oh no!!! The switch model works a treat, and happily switches to a box if I move 100 away (see code below). The bad news is that the "update" is still getting called even when the static box is being displayed. Grrrr !



Now I am annoyed cos' that looked very promising. Thinking about it though, I guess nothing has changed when you switch. I would imagine this would save on rendering cycles, as you could potentially use a much lower level model. But it doesn't stop the animation!!!





    private void create3DStuff() {
        // Normal Scene setup stuff...
        final Vector3f axis = new Vector3f(1, 1, 0.5f).normalizeLocal();

        final Box box = new Box("Box", new Vector3f(-5, -5, -5), new Vector3f(5, 5, 5));
        box.setModelBound(new BoundingBox());
        box.updateModelBound();
        box.setLocalTranslation(new Vector3f(0, 0, -10));
        box.setRandomColors();
        box.setLightCombineMode(Spatial.LightCombineMode.Off);

        TextureState ts = display.getRenderer().createTextureState();
        ts.setEnabled(true);
        ts.setTexture(TextureManager.loadTexture(TestJMEDesktop.class.getClassLoader().getResource(
                "jmetest/data/images/Monkey.jpg"),
                Texture.MinificationFilter.BilinearNearestMipMap, Texture.MagnificationFilter.Bilinear));
        box.setRenderState(ts);

        //let the box rotate
        box.addController(new Controller() {

            public void update(float time) {
                box.getLocalRotation().fromAngleNormalAxis(timer.getTimeInSeconds(), axis);
            }
        });

        final Box boxTemp = new Box("Box Temp", new Vector3f(-5, -5, -5), new Vector3f(5, 5, 5));
        boxTemp.setModelBound(new BoundingBox());
        boxTemp.setLocalTranslation(new Vector3f(0, 0, -10));
        boxTemp.setRandomColors();
        boxTemp.setLightCombineMode(Spatial.LightCombineMode.Off);

        DistanceSwitchModel switchModel = new DistanceSwitchModel(2);
        switchModel.setModelDistance(0, 0, 100);
        switchModel.setModelDistance(1, 100, 1000000);

        DiscreteLodNode boxLODNode = new DiscreteLodNode("boxLODNode", switchModel);
        boxLODNode.attachChild(box);
        boxLODNode.attachChild(boxTemp);
        boxLODNode.setActiveChild(0);

        rootNode.attachChild(boxLODNode);
    }

Can you not just add a check at the beginning of the controllers update method and just return if you don't want to run the controller.

Or simply detach / attach the controller when needed.

Ahh thank you. Yes, this was the road I have started going down. Just use a Distance.distance(cam, node) check at the start of the update method.



When you say:


Or simply detach / attach the controller when needed.


How would you go about doing that based on distance?

well i guess i would use two controllers.



The 1. controller is always attached and checks the distance from the camera to the object from time to time.

Based on that distance the first controller would attach/detach the 2nd controller (the actual animation controller).



Instead of the first Controller, you could do that check simply somewhere in your update cycle.

Just because I never shut up, I think my solution will be:



  • Create a spatial adding the various rotating/moving nodes to it (but with no controllers).

  • Add a controller to the spatial that does a distance check on some arbitrary point.

  • Provided it's within range, the controller will perform all of the rotations/movements required.



I think this gives me some great flexibility, and I'm even tempted to have a "master" spatial that adds and removes the spatial controllers. Having said that, my profile is showing me that the distance check is taking 2ns (yes, two nanoseconds!) so perhaps I shouldn't be too concerned about that  :wink:

I'll add some code once I've nailed it.

hmmm…

i just tried out the distance switch node and you're right the controller continues to update after it's parent node has been switched…

apologies about that…

i can see now why the controller would still need to be updated on "invisible" nodes so that when the node becomes visible again it will be exactly where it should be with regards to the controller…

however it might be worth adding an option to only update the currently active node's geometric state for a distance switch node…

No worries ncomp, you at least taught me the wonders of the DiscreteLodNode even if you didn't mean to!



I am going down the road of not using the DistanceSwitchModel, but instead adding a number of nearby animatable nodes to a spatial parent. I then add a controller to that spacial that checks the distance from the camera, and if it's close enough then it does its work on all its children. Therefore, just one distance check for a definable number of actors/boxes etc.



This is working very nicely indeed. Now I am thinking even bigger!  I want to attach and detach these parent spacials from the root node based on broader distances. That should keep the workload down to an absolute minimum.



I'd like to throw in another performance boost by not storing all spacials in memory, but loading them from file quietly in the background, and discarding old (far away) spacials. This might be fiddly, but could potentially mean an unlimited environment… Probably!



Once completed, is this something anyone would like me to share with the community, or is this pretty much standard and teaching granny to suck those eggs?  :stuck_out_tongue:

a streamed version of discrete lod node would be fantastic  :slight_smile: