Basic rotation in Python
From Digital Spaces
We recommend reading Basic motion in Python before this example.
Here is a more complex example, showing how to rotate an object. Rotations in Digital Spaces use quaternions, so a familiarity with these will help you understand what is happening in this script. If you are not familiar with quaternions, they are a way of representing an orientation or rotation. This is a similar concept to the more familiar matrix, but with some mathematical advantages.
if 'rotateNode' not in locals().keys(): global multiplyQuaternions def multiplyQuaternions( lhs, rhs ): """ Multiply two quaternions and return the result. """ w1,x1,y1,z1 = lhs w2,x2,y2,z2 = rhs w = w1*w2 - x1*x2 - y1*y2 - z1*z2 x = w1*x2 + x1*w2 + y1*z2 - z1*y2 y = w1*y2 + y1*w2 + z1*x2 - x1*z2 z = w1*z2 + z1*w2 + x1*y2 - y1*x2 return (w,x,y,z) global fromAxisAngle def fromAxisAngle( x,y,z, r ): """Create a new quaternion from a VRML-style rotation. x,y,z are the axis of rotation r is the rotation in radians.""" from math import cos,sin return ( cos(r/2.0), x*(sin(r/2.0)), y*(sin(r/2.0)), z*(sin(r/2.0)) ) class NodeRotator: """ This class takes a node name, or a list of node names, and will rotate those nodes continuously. The speed of the rotation is hard coded, see self.perHeartbeat below. """ def __init__(self, nodeNames): self.sceneNodes = list() # Check if the constructor was just passed a string, not a list of strings. if isinstance(nodeNames, str ): nodeNames = ( nodeNames, )
This section queries all the available scene graph managers for nodes of the specified names. There should only be one, but GetFactoriesWithInterface always returns a list. Using every DigitalSpaces::DISGManager (scene graph manager), for every node name provided, check for a scenenode by that name. If found, store the interface to the scene node.
# Rubbish comment for wiki highlighter for scenegraphManager in dss_core.DISGManager.GetFactoriesWithInterface(): for nodeName in nodeNames: sceneNode = scenegraphManager.GetSGNode(nodeName) if sceneNode: self.sceneNodes.append(sceneNode) from math import pi # Calculate how more rotation to apply. # The 0,1,0 means the rotation is around the Y axis. # The 10000 means pi radians per 10000 heartbeats, which comes out to a full circle every 20 seconds. self.perHeartbeat = fromAxisAngle(0,1,0, pi / 10000) def PerformHeartbeat(self): """ This function will be called each run of the script, which is each Heartbeat of Digital Spaces. """
For each of the stored scene node objects, retrieve its current orientation (as a quaternion). Multiplie it's current orientation by the pre-calculated per heartbeat rotation. Then apply the updated orientation to the scene node object.
# Rubbish comment for wiki highlighter for sceneNode in self.sceneNodes: orientation = sceneNode.GetOrientation() orientation = multiplyQuaternions( orientation, self.perHeartbeat ) sceneNode.SetOrientation( orientation ) # Create an instance of the NodeRotator class, providing it with the name of the scene node to be rotated rotateNode = NodeRotator("Omni01") # Each time this script is ran (each Digital Spaces Heartbeat), call NodeRotator::PerformHeartbeat rotateNode.PerformHeartbeat()
When used on a node that contains an entity, this will cause the object to rotate around its center point. When used with a node that contains a childnode with a position offset, the contents of the child node will seem to orbit around the space. For example:
<node name="Omni01"> <node> <position x="-0.86682" y="144.632" z="-376.857" /> <light name="Omni01" type="directional" visible="true"> <colourDiffuse r="1" g="1" b="1" /> <colourSpecular r="1" g="1" b="1" /> <normal x="0.00215" y="-0.3583" z="0.9336" /> <lightAttenuation range="1000" constant="0" linear="1" quadratic="0" /> </light> <billboardSet material="sunflare" name="flare1" width="150" height="150"> <billboard> <position x="0" y="0" z="0" /> </billboard> </billboardSet> </node> </node>
When using this scene graph definition, combined with the above script, the billboard sun, and associated directional light, will orbit the space. Because of the light, any real time shadows will also update, and constantly be cast away from the moving sun.
See the next tutorial Tracking a physics object in Python, or all the tutorials at Documentation/Tutorials.