Wednesday, September 19, 2012

The end of the road...

As my first foray into Python scripting it has been a great learning experience, but the time has come for me to move on. I haven't had time to work on this project for more than six months now (first too busy with my VFX internship & now with starting up my own business) and with the great work done by the mango team this add-on has become obsolete anyway. Be sure to check out the Blender 2.64 release; it is pretty spectacular!

I will leave this blog online for a while longer since it still contains some usefull information on Blender + Python, vector graphics, etc.

Thanks for reading, and till next time!

Matthijs Slijkhuis

Monday, November 21, 2011

Update: feathering and nodes

Just a little update to let you all know this project has not been abandoned yet :).

I have made some improvements to the feathering code to prevent it from overlapping itself so easily. Even though it now works better than before, it still isn't as robust as having a second bézier shape (like in Nuke). So, I've decided to add a bézier feathering mode to give the user the option of using it when the current method fails.

I have also started working on a dedicated Roto2D compositing node. At the moment Roto2D uses a standard Image node which is less than ideal. The new node will fix the current rendering and undo issues. The next release will probably be a intermediate one with parts of the script moved to the node but not all of it yet. I'm still working on the best way to allow the node and the image editor to interact and right now python gives me a faster turn around.

Wednesday, September 14, 2011

0.48a release (alpha)

The first public release! A 64-bit x86 linux build and a 32-bit windows build are available as well as the source code. All archives include the user guide and the script.

Warning: 0.48a is an alpha version, this means that it is for testing purposes only!

unpack & run blender
Load the startup.blend from the archive to get a Nuke-like interface.

Available downloads (the archives include a copy of Blender 2.59):
Linux x86 64-bit binary (15MB)
Windows 32-bit binary (25MB)
Source (22MB)

Additional downloads:
User guide
Python script

Introduction video:

Let me know if and how it works for you!

Saturday, August 20, 2011

Almost there...

I'm currently finishing things up for the first public release. There is still an annoying issue with loading a new or existing .blend while Roto2D is active but as long as you activate Roto2D after loading the .blend it is, dare I say it, useable!
Here's a list of changes since the last post:
  • MUCH faster image updates. I've added a couple of functions to Blender that gives me a more direct route to the pixel data. This allows for 15-20x (guesstimated) faster updates. It can now play back filled in animated masks at an acceptable speed.
  • Feathering!!! I finally managed to get it to work. There are some issues with large feather distances and sharp corners but since it is intended to be used to match the soft-edge of an in focus image element it is already useable. For bigger blurs you can attach a blur node to the mask's image node.
  • The feather distance can be adjusted per point. The feather distance for every curve point between two points is calculated using the logistic function mentioned here. This gives it a nice sigmoid slope.
  • Every mask now has a corresponding node in the Node editor. These nodes are fully managed (created/removed/updated) by Roto2D. The nodes can be forced to update by enabling 'Update nodes' in the panel.
  • The masks now match the render settings instead of the image size. A dotted line shows the size of the mask in the editor.
  • Inverting a mask. Just as fast as a non-inverted mask thanks to the new pixel functions mentioned above.
  • Changing the Bézier resolution per mask. range: 10-80
  • Translate, rotate & scale a mask or the selected points. Uses the standard Blender 'g', 'r' & 's' keys.
Example of an Inverted, feathered mask showing the variable feather distance. Inset: corresponding alpha mask generated by Roto2D

Most of the desired functionality is there. Now it's a matter of fixing a couple (Fingers crossed, knock on wood, etc.) of bugs and releasing it.

Monday, July 18, 2011

Animation and more

I was planning on adding the soft edge feature but even the most stripped down blur implementation was simply too slow. So, I shifted my focus towards animation and useability for a while. Here's a quick overview of the changes:
  • Making changes to a mask now automatically adds/updates a keyframe for the current frame. This means that as you jump back and forth through the footage and make adjustments to the mask(s), you don't have to worry about adding keyframes, etc. Roto2D takes care of all that. Of course, you can also edit the animation using the Graph Editor or Dopesheet.
  • All masks are now correctly stored in the .blend file. So, you don't have to worry about saving them seperately. 
  • Added selecting a mask by clicking on the outline.
  • Adding a point to a mask by double-clicking on the outline.
  • Added removing all selected points by pressing 'x' or 'del' or using the 'Remove' button. When drawing a new mask this will remove the last added point (pressing it again removes the point before that, etc.).
  • Added smoothing all selected points by pressing 'Shift'+'s' or using the 'Smooth' button.
  • Mask names can now be changed.
  • Mask color and alpha can now be changed.
  • Visibility of the outlines can now be toggled.
  • The use of 'Ctrl' and 'Shift' when editing points now matches the Foundry's Nuke
  • Tested it in Windows for the first time and fixed some strange OpenGL issues. 
And a new screenshot:
Animated mask.

With all that taken care of, it's time to dive back into the pixel buffers. Updating the Image object is still a bit too slow (about 1 sec. for 1920x1080) so I need to find a more direct way to pass the bgl.Buffer data to the Image object's buffer. If only I could get Image.gl_load() to stop causing a segmentation fault, or get direct access to the buffer... I feel another patch coming up! (And this one will be seriously serious :)

Friday, July 1, 2011

Finally a fully functioning rasterizer

In my previous post I expressed my fondness for triangles. Well, the triangles are no more. For every problem I solved, two more appeared. So, I threw out some 350 lines of code, including all the triangulation stuff, and replaced it with a good old scan line bucket rasterizer. It is a modified version of the one described here. This one is so simple that it actually works with any kind of mask I throw at it!
Here is a little example of the rasterizer in action:
The new rasterizer showing 3 masks (including a self-intersecting one)
For every mask a bgl.Buffer is filled, converted into an OpenGL texture, mapped to a 2d quad and displayed on top of the image in the UV/Image editor. It still needs some optimization and the anti-aliasing needs some more work but it is already fast enough for panning, zooming, etc. because OpenGL handles most of the heavy lifting.

I will try to make a video this weekend and post it here.
Next up: gaussian blur madness!

Friday, June 24, 2011

Cubic v. Quadratic

After the past couple of days I can now honestly say that the triangle is by far my favorite geometric shape. Once I got my head around drawing a quadratic curve by mapping the barycentric (texture) coordinates to cartesian (image) coordinates, using Blender's mathutils.geometry.barycentric_transform(), i saw the beauty that is the triangle.
Unfortunately, by adding just one more point to the equation it all gets a lot more complicated. First and second derivatives, Inflection points, etc. (check out the stuff here and here to get the idea). So, I figured, I already have the function to fill in a quadratic curve and I know you can approximate a cubic curve by using 4 (or more for better results) quadratic curves; why not draw them that way? It's a masking tool so it doesn't matter if the cubics aren't exactly cubic. I gave it a go and in most cases it produced acceptable results, with the notable exception of the loop:
The problem with approximating a cubic with quadratics...

It's pretty obvious that the yellow bits should be drawn inside out. However, figuring out what the yellow bits are is a bit tricky. I could subdivide the curves at the intersection. But that would require determining or calculating the intersection in the first place. I'm wondering if it wouldn't be better to take the cubic road after all...