Skip to content

Ivy growth animator script: leaves now animated too!

January 26, 2013

After quite some effort, wrestling with API bugs, glitches and gaps in my knowledge and with help from the blender community, I finally got one of the toughest parts of this script done: animating the leaves, without splitting the object into hundreds or thousands of separate objects.

Here’s a small, quick demo of how the leaves and branches are animated together on a small Ivy:

How does it work?

So, in case you haven’t read the first blog post about this script which explains the code that animates the branches, an important step in preparing the branches for animation is splitting the single curve object into multiple mesh objects (1 per branch, each with a build modifier all its own).

Even a large ivy like the one you can see in the image below doesn’t have all that many branches (100-200 usually), so that’s not too bad.

But even a small ivy has hundreds of leaves, and large ones can have many thousands. So I didn’t like the idea of splitting the leaves mesh into individual objects – an object per face! even if it would have made animating them really simple and easy.

Instead, I wanted to find a way to animate that single mesh, one face at a time, and the obvious solution to this problem was shape keys.

I haven’t used shape keys before (even if I knew vaguely what they do), so I had to learn how they work first, and it quickly turned out that they are exactly what I was looking for. You can store a change made in the mesh, such as scaling a face (what I needed), in a non destructive, controllable manner that allows you to animate the change gradually via the “Value” of the shape key. Perfect. Well, almost, but we’ll get to that later…

The idea was simple enough:

Iterate over all faces, and create a shapekey for each which scales it from size 0 (invisible) to its original size, and add properly timed keyframes that animate this change.

Of course, there were quite a few obstacles along the way until I finally got it to work. Here’s the highlights, and hopefully if any of you will have to tackle similar problems, this might help you overcome them. I’d also be glad to hear comments and suggestions for better solutions if you know any.

Obstacles along the way

1. Bug with the “closest_point_on_mesh” method:

To time the keyframes that control the growth of each leaf, I had to come up with a way to decide when each leaf should appear. So I decided to coordinate this with the animation of the closest branch to each leaf.

To calculate which branch is closest, I decided to use the “closest_point_on_mesh” method, which gets a vector and returns the coordinates, normal and index of the closest face on that mesh to the vector you assigned into the method.

This enables to calculate the distance between the closest faces on each branch and our leaf, and then its only a matter of sorting these values and choosing the smallest of the bunch to find the closest branch.

The only problem was that… the function refused to work at first. And then, after I tried changing the code a bit to see if I could get it to work, it crashed blender altogether with a “segmentation fault” error.

I filed in a bug report on the bug tracker and decided to write such a function myself to have some way of knowing which branch is closest to each leaf. It was a simple enough thing to do, though its probably much slower than the object method.

2. Face index garbled into imaginary numbers:

For some inexplicable reason, when I assigned a face into a reference variable, then performed various other calculations and commands before using it again, the index of that face got totally garbled and became larger than 80 million, something that triggered runtime errors in my script when I tried to access the face’s data via its index.

So instead of using face object references, I stored all the relevant face indices as commonplace integers in an array (something that’s harder to garble without tinkering directly with these values!), and used them.

3. selecting tessfaces refuses to work:

The only way I found to select mesh elements was quite awkward to begin with. You have to select these elements in OBJECT MODE (!) then only when you go to EDIT mode can you actually manipulate them.

Also, the face data keeps getting erased from memory, and you have to update and recalculate the tessfaces to get it to work:

object.data.update( calc_tessface = True)

I guess that saves memory and speeds up blender, but it’s mighty annoying when coding, testing and debugging.

But even after I got used to both these things, neither helped me in getting faces selected properly. The largest amount of time I lost in debugging and fixing up this script was in trying to select faces, until I had to admit defeat and find a workaround, by selecting all the vertices of each face (which worked well without any hitch) and then going from vertex selection mode to face selection mode, which then got the face selected. It ended up being rather cumbersome and awkward code, but it worked:

bpy.ops.object.mode_set(mode = 'EDIT')              # edit mode to deselect all
bpy.ops.mesh.select_mode(                           # Go to vertex selection mode
use_extend=False,
use_expand=False,
type='VERT')
bpy.ops.mesh.select_all(action='DESELECT')          # Deselect all verts
bpy.ops.object.mode_set(mode = 'OBJECT')            # Go back to object mode
bpy.context.object.data.update(calc_tessface=True)  # Calculate the face data again

# select face vertices
idxmin = 0
length = len(bpy.context.object.data.tessfaces[leaf_idx].vertices)
for i in range(idxmin, length):
vert_index = bpy.context.object.data.tessfaces[leaf_idx].vertices[i]
bpy.context.object.data.vertices[vert_index].select = True

bpy.ops.object.mode_set(mode = 'EDIT')    # edit mode to edit face
bpy.ops.mesh.select_mode(                 # Go to face selection mode
use_extend=False,
use_expand=False,
type='FACE')
bpy.ops.transform.resize(value=(0,0,0))   # resize face to 0 (invisible)
bpy.ops.object.mode_set(mode = 'OBJECT')  # return to object mode

Damn that’s awkward. All of that to select a single bloody face and resize it. If anyone found a shorter way to do this (that consistently works), please let me know!

7. The first branch on the IvyGen branches object is small and annoying:

The Ivy Generator script is wonderful and I really love using it. However I did find one little thing that was a bit strange with the geometry it creates. The very first curve (in the sequence of curves, not in physical placement) is tiny and sits in the middle of the ivy, rather than at the beginning. So at the moment I just get rid of it after I run my script, otherwise its animation (and that of the leaves closest to it) is mistimed.

8. Adding non-standard keyframes (such as to the value of a shape key):

Throughout the writing process of this script, only one issue made me give up on trying to find an answer myself, acknowledge my ignorance and just ask for help. I had no idea how to add a keyframe to the value of a shape key, and couldn’t find any way to do it through the standard application modules (context, data or operators).

So I posted a question on the python support forum on BlenderArtists. I got an answer in less than 30 minutes! And it was exactly what I needed, concise and precise. Thank you batFINGER!

What’s next?

Remember when I said that the shape key based solution isn’t perfect? Well… it works nicely and relatively quickly when you have a small number of leaves. On my PC, it took around 3 minutes or so to calculate the shapkeys for around 650 leaves.

But even then it was clear that this process gets slower as the shapekeys build up (and memory shrinks down, I guess). And when I tried that with a larger amount of leaves (several thousands, which is not uncommon with large Ivy), it became so slow that according to my quick calculation, could take over 15 hours to create shapekeys for 13k leaves!!

So this isn’t all that viable for large ivy. I’ll need to find ways to make the whole process faster or try some other method.

Also, at the moment the script relies on the names the ivy generator produces, and only if you have just one ivy in your scene, otherwise you have to manually change the name in script itself. when this is a proper add on, I intend to allow choosing the branches and leaves’ respective objects through object selection boxes.

And of course, to become a user friendly add on, it needs a visual interface, which is what I will work on next.

Fortune cookie wisdom

Oh and just one more thing. After working in Win7 (which I prefer for compositing and texturing since I have photoshop and some other non-linux programs running there), I decided at some point to reboot and code in ubuntu. And after doing that, I discovered yet again that it’s just infinitely smoother, faster and more convenient to write, test and debug code there.

Cheers!

Post_4_TitleImage

To see the full code that animates both leaves and branches, view the pastebin page here.

Advertisements

From → Blender, Python

2 Comments
  1. Love your work! Its really great and it is a joy to see some development to forward plant objects in Blender + Other software.
    Im diving into it myself soon to look into growing trees.

    I have noticed from timelapses of plants that the leaves and twigs always jitter and twitch when they grow. It would give much to realism in your animation if you could inject simple periodic “noise” factor.

    Also I will try to mimic that the growthrate of trees are periodic from winter to summer.

    Anyway very nicely done and you are great at writing good explained posts!

    Cheers.

    • Thanks for the kind words! 🙂

      You’re right that the natural growth of leaves is twitchy and that would certainly be an interesting thing to try and emulate, maybe in a future release!

      By the way, my script can also be used to animate the growth of Sapling addon trees, as they’re build it much the same way as the Ivy created by the Ivy Generator.

      You’re idea of animating periodic growth cycles from winter to summer sounds awesome!
      I’d be glad to see it in action and hear updates about its development.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: