I fixed a bug in Blender!

Summary: I found a bug in one of Blender’s Grease Pencil modifiers. In the process of prepping The Best Bug Report Ever, I fixed the bug instead with help and encouragement from Grease Pencil’s module owners. Read on if you’re interested in how Grease Pencil makes its lines thick and thin, how Grease Pencil’s Thickness modifier does the thing, and how my fix works (in Plain English). Big thanks to Antonio Vazquez and Mathias Mendiola for their patience, encouragement and guidance!

I wanted to test Blender’s Grease Pencil system out as an inking tool, because it allows me to go back and edit my lines a bit after I’ve drawn them. If a line is a bit wobbly or it doesn’t curve nicely or the width doesn’t taper properly, I can sculpt it and fix it after I put the line down, even going point by point if need be.

It was while I was wrestling with ways to adjust particularly lumpy stroke width with the Thickness modifier that I discovered a bug.

The bug and its habitat

The Thickness modifier for Blender’s Grease Pencil adjusts the thickness of Grease Pencil strokes. The Thickness modifier has a Normalize mode which sets the entire stroke to an even width.

Under the hood, “thickness” is a property of the strokes themselves. The strokes are made up of a series of points, and each point has a “pressure” value – the pressure of the graphics tablet for that point. Stroke thickness times point pressure determines the width of the stroke at that point.

Normalize works by setting the thickness for the stroke to whatever the modifier says it should be, then it sets the pressure for all its points to 1.0 – exactly the same pressure on each point means the width of the line becomes even. You can select a particular Vertex Group or Grease Pencil Layer in Normalize mode to target particular strokes and points for evening up while leaving the rest alone… or at least, that’s how it should have worked.

The bug was that the modifier was changing the width of all the strokes whether they had points in that vertex group or not. The effects of a modifier are not meant to leak like that.

I found Grease Pencil expert user Mathias Mendiola on – he created the Grease Pencil Fundamentals course on Blender Cloud. He asked me to report a bug.

The best bug report ever

Now, reporting a bug to a fellow developer is not something I take lightly and I wanted to do it properly as a courtesy.

A good bug report should do the following:

  • reports a bug which hasn’t already been reported (let alone fixed), saving coders more administrative work
  • describes the problem clearly, concisely and precisely (less room for misinterpretation)
  • describes the environment and context the problem occurs in (which version of the software, e.g. stable or build hash on splash screen; which operating system, CPU and graphics card, etc)
  • describes expectations of what should happen (maybe the user’s expectations are not what developers expect them to be)
  • gives explicit instructions on how to replicate the bug with as few steps as possible, or alternatively provides data which shows the bug occurring

That last bit – how to replicate the bug – is super important. If the coder can’t replicate the bug, it’s much more difficult to fix it. If the coder is obliged to fix the bug anyway, they may have to spend a significant amount of time devising their own replication which may or may not be the same as what the user does when they trigger the bug, and even if it’s the same thing the user is doing it’s still time the coder has to spend pinpointing the source of the bug. Reproducing information which a user already knows (but hasn’t passed on) is not a good use of a coder’s time.

Since I’m a programmer myself and I build Blender from source, I wanted my bug report to go further than just instructions on how to replicate the bug – although I’d do that too. Once a coder confirms the bug is there and accepts it, the next step involves finding the bit of code that’s going wrong. I decided to find that bit of code as an exercise and to be extra helpful – one less thing for the coder to do.

Tracking down the bug

I poked around Visual Studio and eventually found the code inside source/blender/bf_gpencil_modifiers/MOD_gpencilthick.c. The function which contains the procedure for the Thickness modifier to modify thickness is called deformStroke.

By now, I wanted to pry even further and figure out what deformStroke was doing wrong so that I could even quote a particular line number in the bug report – again, one less thing for the coder to do. After hours of squinting, I figured out that even with Vertex Groups switched on, deformStroke was changing the thickness of the strokes whether they had points in the vertex group or not. That was fine if the whole stroke was getting normalised, but not if the stroke had some but not all points in the vertex group, or no points at all.. hmm..

Since I was on holidays and had no obligation to be awake and ready for work the next day, and I had Visual Studio open anyway, I decided to have a crack at fixing it myself – without any expectations of success or failure. If I couldn’t fix it, at least I put what I’d already tried in the bug report. Yet again, one less thing for the coder to do.

Failing to report the bug

After a few more hours of tinkering, headscratching, reading code, compiling, swearing and recompiling, I didn’t have a bug report – I had a fix for the bug. It was only a partial fix – for cases where a stroke has a mixture of affected and unaffected points, my original patch left that stroke alone – but in Normalize mode, the modifier had stopped affecting points and strokes outside the Vertex Group and that’s what I wanted it to do.

The fix

My change was to make the function scan over each point in the stroke. When it finds a point within the vertex group, it changes a variable called gps_has_affected_points from FALSE to TRUE. (gps stands for “Grease Pencil stroke”.) When it finds a point outside the vertex group, it sets another variable called gps_has_unaffected_points from FALSE to TRUE. Once both of these are set to TRUE, it stops scanning – neither of them can go back to being false.

What comes next depends on whether one or both of those variables are TRUE or FALSE.

If the stroke doesn’t have any unaffected points (
gps_has_affected_points is TRUE and
gps_has_unaffected_points remains FALSE), it’s safe to normalise the stroke by changing its the width and set all the points to 1.0. If it had both affected and unaffected points (both variables TRUE), originally I skipped handling it. (I tried to experimentally iterate a formula but then gave up and coded around it.) I left the code factored in such a way so that if need be, someone who knew the Grease Pencil system better than me could add the unhandled case in with the right maths. Something an expert coder could do in a second, probably.

I submitted patch D5483 at at around 2:00am my time. Then I went to bed.

Getting the fix accepted

Now, submitting a patch doesn’t mean there was nothing for the coders to do, only that they had a code submission which fixes a bug. But was it readable code? Was it efficient code? Did it follow the appropriate formatting standards? Did the code change cover everything it needed to cover without introducing any regressions? For a module owner to accept code, it means they accept responsibility for what the code does and how it does it.

The next day, Grease Pencil module owner Antonio Vazquez had reviewed my patch. He thanked me for the code and encouraged me to handle the partially affected stroke case. I agreed it shouldn’t be left half done and did not make excuses that I was too tired to want to finish it all in one hit, and that it would be better for users if it didn’t just ignore certain cases (which were too hard for me to work out at two o’clock in the morning).

I spent a couple of extra hours on Friday reading other bits of Grease Pencil code to figure out the maths to convert stroke thickness to point pressure given a particular stroke thickness. After having no luck tracing through the code with Visual Studio for an answer, I did a brute force text search for where “thickness” and “pressure” occurred on the same line. It turned out to be simple algebra – target stroke thickness (from the modifier) divided by current stroke thickness results in the right pressure value.

Easy maths, right? Kind of.

Fun with numbers, C style

I knew enough about C to know it’s quite particular about the way it represents particular kinds of number. For instance, point pressure is a floating point (fractional) number and stroke thickness is an integer (whole number). If you divide two integers in C, you don’t get the remainder back. So if you want the remainder (which I did), you need to cast (convert) the integers to a floating point number instead. Then you can divide them to get a point pressure. (This converting may seem like a massive pain in the arse, and friendlier higher-level languages are happy to do those conversions under the hood, but the trade-off is that C runs at speeds which leave higher-level languages in the dust by comparison.)

I got the partial stroke normalisation case working on Friday evening and submitted an updated patch.

Antonio’s follow-up review on Saturday noted that Blender doesn’t do same-line comments, but that he was OK with the code of the patch. He added an extra line to clamp the width to a safe minimum – something an expert coder would know to do – and committed my updated patch to Blender’s master branch as a bugfix on Saturday.

My first Blender commit

The commit hash for my fix is a477c2e0e079 and I’m listed as the contributor. It’s not the first commit I’ve been named in (I helped fix a build bug a little while ago) but it’s the first commit where I’ve written actual code to fix something and been identified as a contributor. Yay!

Fixing that bug took me about six and a half hours, give or take. Much of that time was spent reading through unfamiliar code in a language I haven’t used before. And even if it was a small obscure bug, something very few people would notice or care about that much, it’s fun to see my name come up in Blender’s commit logs and nice to know I helped Blender work a little better than it did before.

I was a spider!

I recently did some voice acting work for animator Jeannot Landry (Blender Pirate). He wanted an Australian male voice for Roby, a cute peacock spider in his short “The Last Dance?”

In addition to voicing the character, I rewrote and extended Jeannot’s script to push the comedy some more and make the dialogue feel more authentically Aussie as requested. I was also a second set of eyes during animation blocking.

Hope you enjoy it! (A note to arachnophobes and people who are uneasy about spiders: Roby is a relatively naturalistic jumping spider in terms of the way he looks and moves. He also gets pretty close to the POV by the end of the movie. Hopefully the cute factor helps!)

Check out the Blender Pirate’s YouTube channel for more of Jeannot’s work!

December 2018 retro

December 2018! Western quolls at the Arid Recovery desert site appear to be doing well, and (as feared) all but one of the team-mates at work has resigned. Also I have a new-fangled block-based editor to play with for this blog. Gosh.

The sun and moments therein

I finished a cut of the AMITS: Hello! story reel at the beginning of the month. It’s just shy of 90 seconds which is a nice compact running time. And here it is! (Spoiler warning, obviously.)

After literally years of struggling to write a story with these two characters, this story reel is a quietly magnificent relief.

I modelled and rigged the Hellobot in the Blender 2.80 beta. It’s a simple rounded cylinder, with the eyes rigged to change colour and shape. It should be more than enough to get me through layout. Here is a short demo. (Very slight spoiler warning.)

There are now eight assets left to build, including scenery, a few props and two characters. Producing AMITS to any kind of deadline or schedule is completely unthinkable at the moment, unfortunately.

Blender 2.80 beta is coming along nicely but I haven’t made any updates to Keyframe Tools just yet. Hopefully the API to access keyframe data is not as convoluted as it is in the 2.7x series.


This month mainly I’ve mainly been studying Japanese. Or should I say Kongetsu ni watashi wa omoni nihongo wo benkyou shite-ita. Or should I say 今月に私は主に日本語を勉強しいた。I can do that now. 今は出来るよ。OK, I’ll stop.

I’ve shifted gear from five minutes a day farting around on Duolingo to at least an hour a day learning Japanese characters, vocabulary and grammar. It’s really worth a blog post of its own. IOU!

That’s about it for December. I’ve got a yearly recap blog pencilled in for New Year’s Day or thereabouts, so expect that soon!

November 2018 recap

That was November! California was on fire and Queensland is now also on fire. Also there was a giant cow called Knickers and Blender 2.80 finally went into beta.

In summary…

  • I’ve been recovering from having my gall bladder removed
  • I released some sleep-aiding whooshy noises on Bandcamp
  • AMITS: Hello! got a first pass of storyboards on index cards
  • The robot has not kicked the soccer ball yet.
  • I helped out with a compilation error in Blender
  • I’m learning Japanese!

Please read on for specifics…


I had my gall bladder out at the end of October and I’ve been in recovery mode since. Fronting up to work in tracksuit pants is fun.

The gall bladder recovery meant roughly a week of not being able to sit up without extreme discomfort – I was either lying in bed or standing up. I watched a lot of movies, including the restoration of Abel Gance’s epic 5 1/2 hour silent film “Napoleon”. Honestly I don’t remember a lot about those two weeks aside from that they were slow and full of nourishing home-made stew. I blame the anaesthetic.

My top tips for people about to have a laparoscopic cholecystectomy (keyhole gallbladder removal):

  • Stock up on oversized t-shirts and soft pants with drawstrings.
  • Work on your upper body strength and leg strength, especially squats. It will hurt like hell to bend over for a week or two.
  • Take a book to hospital which is capable of distracting you. I took “Fear and Loathing in Las Vegas” and it was a perfect companion for walking off the CO2 bubbles.
  • Don’t plan on sitting up at a table or desk for a while after surgery. For me it was about a week and a half before sitting at a desk for longer than a few minutes was comfortable. Even four weeks later I’m taking extra doses of painkillers to manage the discomfort.
  • It hurts to laugh for a week or so. Aim for viewing material which is fascinating enough to pass the time without being laugh-out-loud funny.

Noises to sleep to

I live near a main road so having a neutral sound playing helps me sleep. I’ve been using a white noise app for years but lately my Bluetooth has been cutting out. Even worse, when it cuts out it cheerfully announces that it’s in pairing mode. Bah.

Fortunately the speakers can take audio over cables too, but my phone’s headphone jack doesn’t really grip anymore. Double bah!

Not to be defeated, I’ve patched up my modular synth to function as a white noise machine. There’s a video on the way going through the patch for the curious. I’ll update the blog post with a link once I’ve cut it together and uploaded it.

If you find yourself needing whooshy noises yourself, you can grab a 36-minute recording of these whooshy noises for a whole fifty cents over at Bandcamp. I’d offer it free but frankly I need to pay for this modular synth somehow.

A moment in the sun

In short: it’s on again!

Back on 8 November I finished up the first pass of rough storyboards for AMITS: Hello!

There are over seventy index cards – I used actual physical index cards because I could hold them in my hand as I was drawing them without needing to sit down. Sitting down hurt a lot at the time because I was full of holes.

Gronky lays down the law

Pointy has a moan with his new cuter look

Working smarter, not harder

Today I scanned in the index cards three at a time with a different chunk of the storyboard running at the top, middle and bottom. The Blender video sequence editor lets me crop video elements, so the idea was to run the sequence of scanned images three times with a different crop for each repetition.

Start at the top, middle in the middle, end at the bottom..

You can watch the entire sequence of scans below. The index cards are even thick enough to maintain their registration – at least, it’s close enough for rough storyboarding purposes.

If you can follow this after it loads, you’re an alien.

Batching the images up this way makes digitisation super quick – after half an hour of scanning and getting the right crop values, I have individual images of my index cards. Now I can import the images back into the video sequence editor and time them out to my audio scratch to see what I’ve got. Yay!

But has the robot kicked the ball yet?

Not really. I loaded the file up one night with no intention but to mess around and got a nice twisting faceplant happening in blocking. (Note: the first part of this isn’t timed out properly yet.)

This is how I feel about this exercise now.

Time away from animating has helped me realise something hugely important about where I’m going wrong: I’ve been taking reference pretty much as gospel instead of using it as a leaping-off point for my own ideas. It’s been screwing my creative process up a lot and it’s a thinking pattern I really must fix…

Other stuff

I helped troubleshoot a Blender compilation bug. It’s not much but I’m pleased to have found a temporary workaround nonetheless. 🙂

Between following sumo and getting back into Japanese animation, I find myself with a mighty strong urge to learn Japanese again. I’m trying out the site WaniKani to boost my vocabulary. So far WK is both challenging, aggravating and rewarding enough that I’m hooked.

That’s all for this month!

There goes May 2018

Summary: I made an animation tools plug-in for Blender 2.8 and I’m still working through body mechanics and lip sync animation courses for now.

Hello from May 2018. This month, Blender Animation Studio packed up and moved to the new HQ in Amsterdam North and to my south Margaret River tragically became famous for something other than surfing. The Hawai’ian volcano Kilauea started tearing up its neighbours and there was some royal wedding that people made a fuss about. And oh that torrent of never-ending GDPR emails, many from companies we look forward to never hearing a peep out of again..

Personally I spent most of the month battling one illness or another as the cold started settling in here.

There was a little pear animation I made. It uses shape keys and the Laplacian Deform modifier. Here’s the .blend file if you want a closer look. It was made for Blender 2.79a but it’s munty in the current 2.8 preview.

Speaking of Blender 2.8, I set up a Windows build environment this month when Blender’s nightly builds stopped during their office move. If you’ve ever wanted to try out unbuilt branches (like greasepencil-object) or code changes as they get committed, this is not super difficult to do and absolutely worth it!

I even did a little coding myself. Now that armature-driven animation is possible in Blender 2.8 again, I wrote a little add-on to put back the old 2.7-series keyframing tools on the toolbar exactly how they were before.

And of course there’s the fun of loading up old files in the 2.8 preview to see how well they work. Here’s an abandoned animation test from A moment in the sun rendered in 2.8’s Eevee renderer (currently a work-in-progress). None of the materials have been tweaked to work in Eevee – it’s doing a pretty good job reproducing the Cycles materials, I reckon!


I kept going with the Animation Body Mechanics course. I submitted this polished jump for exercise 2. (Character rig is from CG Cookie.)


It only had to be a simple jump across a gap, but I got fancy – that’s how this four seconds of animation is the end result of nearly 26 hours of blocking, splining and polishing over an entire month.

I’ve been encouraged to stick closer to the assigned work in future without creating momentum-crippling challenges for myself. I think this is sound advice. 🙂

For something a little easier, I started the Demystifying Lip Sync Animation course too. My linguistics training helps me get good mouth shapes at speed. Here’s my submission for exercise 2 of the course. (Character and sound from CG Cookie.)


That’s it for now. Thanks for reading and I hope you have a great June. 🙂