What's the best simple way to handle the update pattern?

The idea behind the update pattern is to make each object in the scene responsible for updating itself. It’s described in detail in gameprogrammingpatterns, but here’s the short version:

function update() {
   const delta = clock.getDelta();

   scene.traverse(child => {
      if(typeof child.update === 'function') child.update(delta);
   })
}

renderer.setAnimationLoop(() => {
  update();
  render();
});

Rather than one huge and complicated update method, there are several simple update methods encapsulated at their point of use.

To avoid traversing the entire scene and using typeof, you can store only the objects that need to be updated in a separate list and traverse that.

This pattern is very handy for attaching a mixer to an object, for example:

GLTFLoader.load(url, (gltf) => {
   const object = gltf.scene.children[0];
   const mixer = new AnimationMixer(object);

   const action = mixer.clipAction(gltf.animations[0]);
   action.play();

   object.update = (delta) => {
      mixer.update(delta);
   }
});

This is wonderfully simple and easy to explain. However, I’ve added a custom property to Object3D:

object.update = ...

This is generally considered bad practice and I don’t feel entirely happy about this, especially if I put it in my book.

Another possibility is to add the property to .userData:

object.userData.update = ...

However, the docs explicitly state that userData should not hold references to functions (neither method works with copy or clone, for that matter).

I’ve been trying to think of a simple way of doing this without adding a custom property to Object3D, and so far I haven’t come up with anything .

Does anybody have any ideas?

Otherwise, @mrdoob, @Mugen87 what do you guys think of reserving the Object3D.update method to facilitate this pattern? Quite a few people are already doing this, for example Matt DesLauriers:

2 Likes

Since Object3D inherits from EventDispatcher, you could use that:

var event = new CustomEvent( 'tick', { detail: { delta: 0 } } );

object.addEventListener( 'tick', function ( e ) {

  mixer.update( e.detail.delta );

} );

// later
event.detail.delta = clock.getDelta();
object.dispatchEvent( event );
1 Like

I think ECSY (https://github.com/MozillaReality/ecsy) also solves this problem in a nice way, and integrates cleanly on top of three.js.

1 Like

Hmm, I’ve been meaning to look into ECSY, thanks for the suggestion. I’ve also experimented with creating a simple ECS system myself, which lets me solve this without relying on third-party libraries.

However, my goal now is to solve this in a way that’s more approachable for beginners.

Your EventDispatcher suggestion is interesting, I’ll think about that some more.

What do you think about the idea of reserving Object3D.update?

It’s too late to reserve that particular method… various Helper classes already extend Object3D and rely on it.

I’m not sure what I think about reserving a name for a function that three.js neither neither creates nor invokes. For developers with more JS experience, three.js giving you permission to modify objects this way doesn’t really matter and might seem pretty weird? For newer users, it’s telling you to do something you can’t/shouldn’t normally do anywhere else.

A more idiomatic solution would be to extend default objects:

class FireMesh extends THREE.Mesh {
  tick () {
     // ...
  }
}

That’s unusual in threejs examples, but pretty common in JS frameworks.

1 Like

That’s the clean way, userData shouldn’t contain methods or references, but it can be added to the base classes Mesh and SkinnedMesh as well (prototype), for a more generic approach as loaded assets already created objects with the base classes.

I use tags which can be added to Object3D based classes, these tags can be singletons or instances. This way controllers can be added as well as temporary effects and such, it’s kinda similar to tags in Cinema 4D.

Events implemented in the tag such as step (frame) and input determine what they will listen to, so this logic is detached from the scene hierarchie to avoid unnecessary traversal in rich scenes.

A controller tag is an object/class (singleton or instance) itself to reuse on assets, for example to control an AI a singleton receieves the objects it has to process while an instance is individual to every object the tag is added to.

I shaped this concept over time with focus on performance and memory, it probably isn’t exactly a common existing concept, maybe a mix or extension, but it fits all needs i have .

I think this is actually a strong argument in favor of my suggestion.

We should define the property as an empty function on the base class so the superclasses can safely overwrite it. By “reserve the method”, I meant that either we put an empty placeholder Object3D.update method, or we just make a statement that we’ll never do anything to mess up user code that add this method. I don’t have a preference which, and I also don’t care what name is chosen - tick, onUpdate, etc. All good.

There are already several methods like this in three.js. Usually, their name starts with “on” - onBeforeRender, onAfterRender, onUploadCallback, and so on.

Not saying this is exactly the same - here the user has to manually create the main update function that calls all the small ones, whereas the “on” methods are called automatically. But it’s not that different, and I don’t think it’s unusual to define a placeholder method that users can overwrite.

Yeah, agreed. I have been considering which way do it, but for now settled on just adding the property since it’s simple and I’ve seen other people do it that way. In this case, the end result is the same.

But the main reason (I’m aware of) that adding a property is bad practice is that a future version of the library may add an Object3D.update method. Extending the class to add the method has the same problem.

Can you explain what you mean by this?

I’m not familiar with Cinema4D but this sounds like an interesting approach. However, I doubt it’s going to useful for me. My goal here is to create something simple enough that I can write about it in introductory tutorials.

The reason I’m using this approach is because, when creating small and simple examples, this is the simplest way I have found so far of encapsulating animation/mixer/mesh/geometry/materials and any extra code to update them.

1 Like

Adding properties to instances outside the prototype and constructor will internally create a new “class” in js engines, so you can monkey patch it and add the property to the prototype before your application starts.

Yes your suggested updated callback with traversal definitely will work, especially to be done without an extra plugin or library. For full controllers you might want to have something more reusable, controllers that might temporary create new objects you have to store somewhere, and other events such as create/destroy etc.

1 Like

Hmm, good to know. Do you know of anywhere that documents this? I vaguely remember reading that on the V8 blog recently, not sure where though. Don’t worry if you can’t remember, I’ll take your word for it :slightly_smiling_face:

I had expected this anyway because I’m binding the mixer to the mesh using a closure, which as far as I know creates a new class shape as well.

Seems like I should rename this method to tick or onUpdate to avoid collision with existing update methods inside three.js, and then do this:

Object3D.prototype.tick = () => {}

GLTFLoader.load(url, (gltf) => {
   const object = gltf.scene.children[0];
   const mixer = new AnimationMixer(object);

   const action = mixer.clipAction(gltf.animations[0]);
   action.play();

   object.tick = (delta) => {
      mixer.update(delta);
   }
});

@fyrestar is that similar to what you are suggesting?

@donmccurdy I remember now why I’m not using extend - I want this to work with loaded models, and short of patching the loader I can’t control what they return.

3 Likes

I can’t recall the exact source right now, it probably was the V8 blog actually ^^

I’d go with onUpdate to stick with the “on” pattern like onBeforeRender

Yes, just making sure the property is reserved.

Yes this is why i use a generic class for models too, besides the tags for controllers i use a model for the pure data (just like userData) wich represents the abstracted layer basically, like character data, health, name, items etc to have every layer separated instead trying to store all on one.

Just as a side note as this addresses this architecture, it would be great if THREE internally also would replace the internal condition forest to a faster and more clean and flexible reference based system, so instead checking through many “hardcoded” conditions like isMehsStandardMaterial, isShaderMaterial etc just moving the relevant code to the materials class with abstract methods would be great ^^ could be also applied to many other cases. That would also make extending THREE easier as anything like this currently requires core changes.

1 Like

That would be my preference too, but I’m afraid at some point three.js will add an onUpdate method that breaks my code.

I think tick is usually used to represent a fixed timestep but that’s probably less of an issue.

1 Like

Maybe onTick then? :smiley_cat:

I personally use “step”. And “update” rather for event based methods which might be not called per frame or even multiple times.

1 Like

The reason I want to call this update is that it’s an extremely common name for this method. Along with the animation loop, this seems to be one of the most common patterns in graphics programming.

For example:

1. Game programming patterns chapter that I linked above:

Simulate a collection of independent objects by telling each to process one frame of behavior at a time.

If the Game Loop pattern is the best thing since sliced bread, then the Update Method pattern is its butter. A wide swath of games featuring live entities that the player interacts with use this pattern in some form or other. If the game has space marines, dragons, Martians, ghosts, or athletes, there’s a good chance it uses this pattern.

2. Unity MonoBehaviour.Update

Update is the most commonly used function to implement any kind of game script.

Bonus cool description of the Unity loop.

3. Unreal calls it ticking

Actors and components are ticked once per frame, unless a minimum ticking interval is specified.

I could go on, but I think I’ll probably find that every game engine implements this pattern in some manner.

I know three.js is not a game engine, but any loop based graphics app will inevitably share many concepts with game engines, which is why I’m suggesting reserving one method name on Object3D to make using this pattern easier.

I’ll do some more work on this and open a GH issue. In the meantime I’ll follow Unreal and call the method tick.

2 Likes

Yeah that’s totally valid and more just a matter of taste :smiley_cat: i want to distinguish between the update constantly called in the render loop by the engine and the explicit use of update, for example to update a geometry with a buffer received from a worker. I’ve seen step in other engines too , but the reason i use it is like i said to separate update and the constant game logic per frame update, “update” is used in many ways.

1 Like

From How To Write Fast, Memory-Efficient JavaScript

If you care about speed, try very hard to keep your functions monomorphic, i.e. make sure that variables (including properties, arrays and function parameters) only ever contain objects with the same hidden class.

A single operation like delete o.x can change an object’s hidden class; adding a property would do the same. From What’s up with monomorphism?

Fluffy dictionary nature of JavaScript objects also makes it easy to create accidental polymorphism:

function A() {
  this.x = 1;
}

var a = new A(), b = new A(); // same shape

if (something) {
  a.y = 2;  // shape of a no longer matches b.
}

Thanks for the link. So, as @Fyrestar suggests, doing this:

Object3D.prototype.tick = () => {}

before creating any instances of Object3D or derived classes will prevent deoptimization from occurring.

This is off topic i guess, but maybe it helps you to avoid the same kind of issues that we faced.

At work we’re making a CAD system based on threejs, also a head-less framework for modelling operations similar to three-csg, but at full CAD capacity. Updates were exactly like the method described above. When consumed it was put into a collection to avoid full traverse.

Eventually it became clear that the pattern caused problems. Objects updating themselves turned out to be a recipe for race conditions. The object should be a reflection of state, it shouldn’t bear implicit knowledge of state. Whenever render order changed for whatever reason (server push, etc), it became mind boggling, behaviour was basically switching around in no manageable order.

After years of fighting against it we figured that updates belong to the component level. By that i mean the instance that has access to state or logic as well as the view. That layer receives state and acts upon view objects, also frame based if needed. This is a very prominent pattern in front-end these days, and i think even gaming would benefit from that.

2 Likes

I’d say that’s completely on topic, thanks :slight_smile:

In ECS terms, what you are suggesting is per-component update rather than per-entity update, is that correct?

I don’t think it’s a problem for my use case though. As I mentioned above, my goal is to use this in small and light demos, and introductory tutorials, not large-scale apps. It should be possible to avoid race conditions without much trouble.

Is this also a problem for userData? Will this also change an object’s hidden class?

const o = new Object3D()

o.userData.x = 2;

Using primitives including objects constructed with {} should use a hashmap, but it depends on the assigned values, it shouldn’t be treated the same as an instance of a “class” as they aren’t always final as a class usually is. However i would generally always construct objects with their required fields whenever possible at least with default values.