Aug 29, 2016
Animate MagicaVoxel

I've been playing around in @ephtracy's MagicaVoxel for a few months now, and love it - its a great example of a program that is doing some pretty complex things, but in a intuitive UI thats easy to manage. With recent additions like emmisive voxels and volumetric fog, the rendering engine has gotten pretty slick, to the point that some neat artwork can be made fairly easily. With as cool as these screenshots turn out, I wanted to see how hard it would be to render animations of scenes. I've done some work with applescript scripts for timelapses, and thought I might be able to do something similar with MagicaVoxel

Disclaimer: I'm using OSX El Capitan, MagicaVoxel 0.97, and a program called "QuicKeys" v 4.0.7 to create the animations - your milage may vary with different versions.

Disclaimer 2: This method is janky as hell. I'm working on improving it, but please take note that this workflow is a work in progress.

To begin, I needed a way to have the MagicaVoxel camera move between renders. I tried for quite some time to do this using the built in WSAD camera controls, sending keystrokes to MagicaVoxel using AppleScript. The problem, I quickly discovered was that Applescript seems to have a bug where it sends a "A" keystroke if you try to send a key down command - no matter what input I sent to MagicaVoxel, the camera would only pan left as though the "A" key was pressed. Crap.

The workaround that I found was to bring in another app, one with a little better keyboard/mouse scripting - QuicKeys. The program has a 30-day free trial, and I've been pleased with it so far. Its available here, or you can just do what I did and google "osx automate mouse" and follow stackoverflow to the program. As a sidenote, I generally hate using third party programs like this, especially for one-off processes, so if anyone has a better way to script mouse movements, I'd love to hear about it - hit me up on twitter.

Step 1: Set up camera movement macros

With QuickKeys downloaded and installed, I needed to create a few macros to move the MagicaVoxel camera around. I opted for the simplest setup I could - my macro would run when the "f1" key was pressed and would drag the mouse from a point on my monitor to 1 pixel to the left.

Obviously you'll need to adjust the starting and ending coordinates from my example depending on your monitor size - I'd suggest using the "Set Location" button for the Click Location, then copying and adjusting by 1px for the Release Location. This setup is dependent on your MagicaVoxel window position, so I maximized my MagicaVoxel app to give me the most working room.

Once done, save your macro and test. Bring up MagicaVoxel and press your f1 key - the view should move just slightly. You can use these macros to orbit in any direction or pan up/down/left/right.

I ended up making two macros - one to orbit, which I bound to (f1) and one to pan which I bound to (f2) - panning was accomplished by adding a "press spacebar" command before the mouse click in QuicKeys

Step 2: Set up the Applescript

Next, I created a AppleScript using OSX's "Script Editor" app. It took some trial and error, but the end result was something like this:

#Auto scroll and render a MagicalVoxel scene
set i to 1 #keep track of which render we are on

repeat 300 times #number of renders we are creating
	tell application "MagicaVoxel" to activate #focus MagicaVoxel
	delay 1
	tell application "System Events" to key code 122 #keycode for f1 is 122
	delay 1
	tell application "System Events" to key code 120 #keycode for f2 is 120

	delay 90 #render time

	tell application "System Events"
		key code 97 #keycode for f6 to save screenshot
		keystroke i as string #set file name as 1.png, 2.png etc...
		keystroke return #save file
	end tell

	delay 1

	set i to i + 1 #increment render count
end repeat

Breaking it down, the script loops through a set of actions a bunch of times: 1) move the camera 2) render the scene, and 3) save a screenshot. I just had the system press our "f1" and "f2" hotkeys to run the camera macros to accomplish the move, rendering is done automatically by MagicaVoxel - it just needs time to complete, and applescript is sufficient to save a new file screenshot. Feel free to grab/use/improve the script - you can adjust the number of renders and render times for different results.

Step 3: Final Setup

Ok, almost ready to run. Now I set up my MagicaVoxel scene: I set MagicaVoxel to render mode and set up my scene sky color, fog, emissive voxel colors etc. Once that was done I did a test render, and set my save folder using f6 - I would suggest using an empty folder to save your files in, to make creating a gif easier later. Once that was done, I set my initial camera angle and ran the applescript!

My first run was 500 frames at ~40seconds rendering time per frame. I had to let it run overnight to finish. The results were good, but only the first 200 frames were usable - a good 300 frames the subject was no longer in frame. My second run I did 300 frames at 90seconds per frame. I also doubled the rendered screenshot size from 400px to 800px to get a clearer image.

Step 4: Putting it all together

With the rendering done, I now had a set of 200-300 images that needed to be stitched together into a animated gif. There are a ton of great ways to do this - I used the imagemagick library available here, though you might prefer something else if you're not comfortable using OSX's terminal.

For anyone interested, the terminal workflow I used was:

for a in [0-9]*.png; do     mv $a `printf %03d.%s ${a%.*} ${a##*.}`; done
-to convert the filenames from 1.png to 001.png (this insures the "convert" command gets all images in the correct order

convert -delay 0 -loop 0 *.png -resize 40% animated.gif
to create the actual gif.

And that's it! I hope this writeup was helpful to at least a few of you - I'll continue to improve it as I refine the process. If you have suggestions to that end, or just want to show off the sweet images you make, tweet me at @drinkdecaf - I'd love to hear from you!