• Advertisement
Sign in to follow this  
  • entries
    155
  • comments
    100
  • views
    94117

Signalling transforms / transforming signals

Sign in to follow this  

91 views

Ok, so another entry for today. It seems I missed two critical parts: the overall sequence of how signals work in the scene graph, and transforms. So here they are, starting with signals.

I'll give a couple of examples of what happens when you add a new node or change an attribute in a node.

Setting an attribute:

myWorld = World()
myWorld.rootNode.logic = coolUpdateFunction
-> myNode.dirtyAttributeSignal(myNode, "logic", coolUpdateFunction)
-> myWorld._dirtyAttribute(myNode, "logic", coolUpdateFunction)
-> myWorld.space._dirtyAttribute(...)
-> myWorld.logic._dirtyAttribute(...)
-> attribute name was "logic", so if we're not already storing this node, store it so we can update it when myWorld.update() is called
-> myWorld.physics._dirtyAttribute(...)
-> for view in myWorld.views: view._dirtyAttribute(...)
-> view.renderer._dirtyAttribute(...)
-> view.audio._dirtyAttribute(...)



As you can see, setting an attribute results in quite a fuss inside the engine, but as I said in the last entry, setting an attribute is rare compared to using an attribute (Node.__getattr__ is not replaced so it's fast), so this makes sense. If I want to optimize this later, I guess I could implement a registry in the World class, telling which workers are interested in which attributes. At the moment, this is far from being the bottleneck.

Adding a new node to the tree:

myNode = Node()
myNode.render = myGeometry.createPrimitive().render
myNode.collisionGeometry = myGeometry.createCollisionGeometry()
myWorld.rootNode.addChild(myNode)
myWorld.rootNode.newChildSignal(myNode)
myWorld._newNode(myNode)
myWorld.space._newNode(myNode)
...etc



_newNode methods of the various workers will then inspect the node for attributes they are interested in (see the example in last post). That's really all there is to signals in scene graphs. All the rest is the various workers keepin track of interesting nodes and updating them as needed.

I'm also using Signals for event passing in my engine: I don't have a centralized event manager (anymore), and this seems to be a much more elegant solution, and didn't really add any dependencies that weren't there already. I'm littering signals around in various places where I find them useful. Last I added was stepSignal to World, which is called for each step; step size is always constant, and there might be zero to many steps per frame depending on FPS.

About transforms then. Since they are so common an operator, all functions for working with Node transforms are in an external module (they could have been in the Node itself since they are so commonly needed, but I decided I want to keep the Node class clean). You get the world transform of a node by calling transform.getWorldPosition/Rotation/Scaling/Matrix(). They will check if there's a cached world transform available, and calculate one if there isn't. When the node's "position", "rotation" or "scaling" attributes are set, World._dirtyAttribute() in turn calls transform._invalidateWorldTransform(), which just clears the cached world transforms from the Node. An example is probably in order:


myNode.position = Vector(1, 2, 3)
# World transform cache is invalidated, so the following call will calculate it
print transform.getWorldPosition(myNode)
# World transform is now cached, so the following call will use the one from cache
print transform.getWorldRotation(myNode)



There are two transform utility functions at the moment in addition to world transform functions: lookAt() and getVelocity(). lookAt() is just a wrapper for quaternion.lookAt(), and gets a node whose rotation is to be calculated, and a target node to look at. getVelocity() calculates the velocity of a node based on time since last update and the previous position (which it stores itself).

More questions are welcome as always. :)

Btw. I have a reeeally basic heightmap working for my game, but it doesn't even have normals calculated (Spineless doesn't calculate normals automatically yet), so no screenshots for now. :)
Sign in to follow this  


0 Comments


Recommended Comments

There are no comments to display.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Advertisement