Tutorial

Revl is all about generating pseudo-random Maya scenes by evaluating a set of weighted commands.

The built-in commands are fairly basic and might not cover all your needs, in which case you are encouraged to provide your own.

Generating a Scene

A scene can be generated in two steps: creating a set of weighted commands, and evaluating it.

Each weighted command can be defined either by using the class Command or by using a tuple that follows the same structure than the Command class. Indeed, all the command definitions below are equal:

>>> import revl
>>> command1 = revl.Command(weight=1.0, function=revl.createTransform)
>>> command2 = revl.Command(1.0, revl.createTransform)
>>> command3 = (1.0, revl.createTransform)

The command functions being evaluated at a later stage, its arguments also need to be passed to the command definition:

>>> import revl
>>> command1 = revl.Command(weight=1.0, function=revl.createTransform,
...                         args=(), kwargs={'parent': True})
>>> command2 = revl.Command(1.0, revl.createTransform, (), {'parent': True})
>>> command3 = (1.0, revl.createTransform, (), {'parent': True})

From there, actually generating a scene is only a matter of adding the commands in a list and calling the run() function:

>>> import revl
>>> commands = [
...     (1.0, revl.createTransform),
... ]
>>> revl.run(commands, 100)

This example creates a scene with 100 transform nodes parented to the world. Setting the createTransform() function’s parameter parent to True like before, already helps with adding a bit of randomness into the result:

>>> import revl
>>> commands = [
...     (1.0, revl.createTransform, (), {'parent': True}),
... ]
>>> revl.run(commands, 100)

The 100 transform nodes are now randomly parented under other transforms. The Command.weight attribute has no effect here, so let’s see it in action:

>>> import revl
>>> Type = revl.PrimitiveType
>>> commands = [
...     (1.0, revl.createPrimitive, (), {'type': Type.POLY_CONE}),
...     (2.0, revl.createPrimitive, (), {'type': Type.POLY_CUBE}),
...     (5.0, revl.createPrimitive, (), {'type': Type.POLY_SPHERE}),
... ]
>>> revl.run(commands, 100)

Revl is invoking here a total of 100 evaluations inequally shared between the three distinct commands provided, leading the resulting scene to contain approximatively 12.5% of cones, 25% of cubes, and 62.5% of spheres.

Writing a Custom Command

The built-in commands don’t offer much features. Instead they aim to be simple and fast, and as such are good contenders to be used as building blocks to compose more advanced commands.

For example, it is possible to extend the function createPrimitive() to set the resulting shapes as templates:

>>> import revl
>>> def createTemplatedPrimitive(context, type=None, name=None,
...                              parent=False):
...     primitive = revl.createPrimitive(context, type=type, name=name,
...                                      parent=parent)
...     for oShape in primitive.shapes:
...         shape = OpenMaya.MFnDependencyNode(oShape)
...         context.dg.newPlugValueBool(shape.findPlug('template'), True)
...     return primitive
>>> commands = [
...     (1.0, revl.createPrimitive),
...     (1.0, createTemplatedPrimitive),
... ]
>>> revl.run(commands, 100)

This example will generate a scene with as much normal primitives than templated ones.

Note

When creating a new transform node, append the resulting maya.MObject object to the Context.transforms list attribute. This will allow the function pickTransform() to have more transform nodes to pick from.

Note

For performance reasons, you are encouraged to make use of the Context.dg and Context.dag attributes. This buffers the DG and DAG operations, and applies them at the end of the run() function.

If a custom command needs to access certain features requiring the graphs to be up-to-date, then feel free to call their doIt() methods.