r = new Random(0); for (i = 0; i < 100; i++) { sphere = new Sphere(0.05, 0.05, 0.05); pos = new Vec3(r.nextDouble(), r.nextDouble(), r.nextDouble()); script.addObject(sphere, new CoordinateSystem(pos, 0, 0, 0)); }
And that's it! You should now see a cloud of spheres that looks something like this:
Try dragging the cloud around your scene. Notice that it behaves just like any other object. You can move or rotate it, assign a texture or material to it, even convert it to a triangle mesh.
Now select "Edit Object..." from the Object menu. Your script is still there. You can modify the script at any time, and the object will change accordingly.
Let's look at that script a little more carefully and see exactly what it is doing in each line. We want the spheres to be randomly positioned, so the first line creates a random number generator:
r = new Random(0);
Notice that we initialize the random number generator with a seed of 0. This is important to ensure that it always places the spheres in the same locations. Otherwise, the spheres would move every time your object was rendered.
If you have programmed in Java before but not in Groovy, you will probably have noticed a couple of things about this line that seem strange. First, where did that variable r come from? I never declared it. How does the interpreter know what type of variable it is?
Groovy supports dynamic typing, which means (among other things) that you can use variables without ever declaring them. The variables are then "loosely typed", meaning that you can assign any value of any type to them. Type checking is done when you actually use the variable. If I tried to call a method that didn't exist for the object assigned to that variable, I would receive an error message. You do not need to use dynamic typing if you do not want to; you can still declare your variables exactly as you would in Java. But when writing short scripts like this, it can be a great convenience.
Second, how did it know that when I said "Random", I actually meant "java.util.Random"? I never imported that package. The answer to this question is rather simpler: as a convenience, the following packages are automatically imported for all scripts:
Next, the script has a loop which executes 100 times, creating a sphere each time through the loop. This is done by the following commands:
sphere = new Sphere(0.05, 0.05, 0.05);
Sphere is one of the many classes of object defined by Art of Illusion. Its constructor takes three arguments, the X, Y, and Z radii, which means that (contrary to its name) it actually represents a general ellipsoid. In this case, all three are set to be the same, so it really is a sphere.
Next we choose a position for the sphere by randomly selecting X, Y, and Z coordinates:
pos = new Vec3(r.nextDouble(), r.nextDouble(), r.nextDouble());
And finally we add the sphere to the scripted object:
script.addObject(sphere, new CoordinateSystem(pos, 0, 0, 0));
The variable "script" refers to an object of class artofillusion.script.ScriptedObjectController. It is through this object that you actually interact with the scene and generate the geometry of the scripted object. In this case, we called the addObject() method which takes two arguments: the object to add, and a coordinate system (artofillusion.math.CoordinateSystem) defining the object's position and orientation.
The constructor for the CoordinateSystem takes a position (the origin of the coordinate system) and three rotation angles. It has other constructors which allow you to specify the orientation in other ways. Note that your coordinate system will always be interpreted relative to the scripted object's own coordinate system. That is why the object as a whole can be moved and rotated within the scene.
As you can see from this example, a scripted object is really a "collection" of other objects. In this case, the script generates 100 spheres. For most purposes, however, you should still think of the scripted object as only a single object. The spheres are not individually added to the scene. They cannot be selected individually, and if you modified the script to generate cubes instead of spheres, the spheres would immediately disappear and be replaced by cubes.