Blender 2.49 Scripting: Animating the Visibility of objects

0
114
8 min read

(Read more interesting articles on Blender 2.49 Scripting here.)

Script links are scripts that may be associated with Blender objects (Meshes, Cameras, and so on, but also Scenes and World objects) and that can be set up to run automatically on the following occasions:

  • Just before rendering a frame
  • Just after rendering a frame
  • When a frame is changed
  • When an object is updated
  • When the object data is updated

Scene objects may have script links associated with them that may be invoked on two additional occasions:

  • On loading a .blend file
  • On saving a .blend file

Space handlers are Python scripts that are invoked each time the 3D view window is redrawn or a key or mouse action is detected. Their primary use is to extend the capabilities of Blender’s user interface.

Animating the visibility of objects

An often recurring issue in making an animation is the wish to make an object disappear or fade away at a certain frame, either for the sake of the effect itself or to replace the object by another one to achieve some dramatic impact (such as an explosion or a bunny rabbit changing into a ball).

There are many ways to engineer these effects, and most of them are not specifically tied to script links reacting on a frame change (many can simply be keyed as well). Nevertheless, we will look at two techniques that may easily be adapted to all sorts of situations, even ones that are not easily keyed. For example, we demand some specific behavior of a parameter that is easy to formulate in an expression but awkward to catch in an IPO.

Fading a material

Our first example will change the diffuse color of a material. It would be just as simple to change the transparency, but it is easier to see changes in diffuse color in illustrations.

Our goal is to fade the diffuse color from black to white and back again, spaced over a period of two seconds. We therefore define a function setcolor() that takes a material and changes its diffuse color (the rgbColor attribute). It assumes a frame rate of 25 frames per second and, therefore, the first line fetches the current frame number and performs a modulo operation to determine what fraction of the current whole second is elapsed.

The highlighted line in the following code snippet determines whether we are in an odd or even second. If we are in an even second, we ramp up the diffuse color to white so we just keep our computed fraction. If we are in an odd second, we tone down the diffuse color to black so we subtract the fraction from the maximum possible value (25). Finally, we scale our value to lie between 0 and 1 and assign it to all three color components to obtain a shade of gray:

import Blender
def setcolor(mat):
s = Blender.Get('curframe')%25
if int(Blender.Get('curframe')/25.0)%2 == 0:
c = s
else:
c = 25-s
c /= 25.0
mat.rgbCol = [c,c,c]if Blender.bylink and Blender.event == 'FrameChanged':
setcolor(Blender.link)

The script ends with an important check: Blender.bylink is True only if this script is called as a script handler and in that case Blender.event holds the event type. We only want to act on frame changes so that is what we check for here. If these conditions are satisfied, we pass Blender.link to our setcolor() function as it holds the object our scriptlink script is associated with—in this case that will be a Material object. (This script is available as MaterialScriptLink.py in scriptlinks.blend– download full code from here)

The next thing on our list is to associate the script with the object whose material we want to change. We therefore select the object and in the Buttons Window we select the Script panel. In the Scriptlinks tab, we enable script links and select the MaterialScriptLinks button. (If there is no MaterialScriptLinks button then the selected object has no material assigned to it. Make sure it has.) There should now be a label Select Script link visible with a New button. Clicking on New will show a dropdown with available script links (files in the text editor). In this case, we will select MaterialScriptLink.py and we are done. We can now test our script link by changing the frame in the 3D view (with the arrow keys). The color of our object should change with the changing frame number. (If the color doesn’t seem to change, check whether solid or shaded viewing is on in the 3D view.)

Changing layers

If we want to change the visibility of an object, changing the layer(s) it is assigned to is a more general and powerful technique than changing material properties. Changing its assigned layer has, for instance, the advantage that we can make the object completely invisible for lamps that are configured to illuminate only certain layers and many aspects of an animation (for example, deflection of particles by force fields) may be limited to certain layers as well. Also, changing layers is not limited to objects with associated materials. You can just as easily change the layer of a Lamp or Camera.

For our next example, we want to assign an object to layer 1 if the number of elapsed seconds is even and to layer 2 if the number of seconds is odd. The script to implement this is very similar to our material changing script. The real work is done by the function setlayer(). The first line calculates the layer the object should be on in the current frame and the next line (highlighted) assigns the list of layer indices (consisting of a single layer in this case) to the layers attribute of the object. The final two lines of the setlayer() function ensure that the layer’s change is actually visible in Blender.

import Blender
def setlayer(ob):
layer = 1+int(Blender.Get('curframe')/25.0)%2
ob.layers = [ layer ] ob.makeDisplayList()
Blender.Window.RedrawAll()
if Blender.bylink and Blender.event == 'FrameChanged':
setlayer(Blender.link)

As in our previous script, the final lines of our script check whether we are called as a script link and on a frame change event, and if so, pass the associated object to the setlayer() function. (The script is available as OddEvenScriptlink.py in scriptlinks.blend.)

All that is left to do is to assign the script as a scriptlink to a selected object. Again, this is accomplished in the Buttons Window | Script panel by clicking on Enabling Script Links in the Scriptlinks tab (if necessary, it might still be selected because of our previous example. It is a global choice, that is, it is enabled or disabled for all objects). This time, we select the object scriptlinks instead of the material scriptlinks and click on New to select OddEvenScriptlink.py from the dropdown.

Countdown—animating a timer with script links

One of the possibilities of using a script link that acts on frame changes is the ability to modify the actual mesh either by changing the vertices of a Mesh object or by associating a completely different mesh with a Blender object. This is not possible when using IPOs as these are limited to shape keys that interpolate between predefined shapes with the same mesh topology (the same number of vertices connected in the same way). The same is true for curves and text objects.

One application of that technique is to implement a counter object that will display the number of seconds since the start of the animation. This is accomplished by changing the text of a Text3d object by way of its setText() method. The setcounter() function in the following code does exactly that together with the necessary actions to update Blender’s display. (The script is available as CounterScriptLink.py in scriptlinks.blend.)

import Blender
objectname='Counter'
scriptname='CounterScriptLink.py'
def setcounter(counterob):
seconds = int(Blender.Get('curframe')/25.0)+1
counterob.getData().setText(str(seconds))
counterob.makeDisplayList()
Blender.Window.RedrawAll()
if Blender.bylink:
setcounter(Blender.link)
else:
countertxt = Blender.Text3d.New(objectname)
scn = Blender.Scene.GetCurrent()
counterob = scn.objects.new(countertxt)
setcounter(counterob)
counterob.clearScriptLinks([scriptname])
counterob.addScriptLink(scriptname,'FrameChanged')

This script may be associated as a script link with any Text3d object as shown before. However, if run with Alt + P from the text editor it will create a new Text3d object and will associate itself to this object as a script link. The highlighted lines show how we check for this just like in the previous scripts, but in this case we take some action when not called as a script link as well (the else clause). The final two highlighted lines show how we associate the script with the newly created object. First, we remove (clear) any script links with the same name that might have been associated earlier. This is done to prevent associating the same script link more than once, which is valid but hardly useful. Next, we add the script as a script link that will be called when a frame change occurs. The screenshot shows the 3D view with a frame from the animation together with the Buttons window (top-left) that lists the association of the script link with the object.

Note that although it is possible to associate a script link with a Blender object from within a Python script, script links must be enabled manually for them to actually run! (In the ScriptLinks tab.) There is no functionality in the Blender Python API to do this from a script.

LEAVE A REPLY

Please enter your comment!
Please enter your name here