When I am playing around with three.js I often like to use it to make simple looping animations, and it would be nice to have at least one or two ways to export these projects to a reliable, well supported video file format like the webm file format making it easy to share as a stand alone video file. Now there may be a great number of ways to go about doing this sort of thing actually on stack overflow I saw an example the makes use of some built in browser features as a way to go about capturing video from a canvas element on the fly. However what I have in mind is something where I can create a video on a frame by frame basis rather than recoding for an amount of time.
To help with this I have come across a project called whammy that seems to work okay for the sake of making a webm file on a frame by frame basis. In this post I will be outlining a simple example of doing just this using three.js, and whammy.
There is not just being mindful of the version of threejs that is being used, but also the version numbers of the web browsers that I am running code in, and also the version number of whammy. In late versions of chrome using whammy seems to no loner work, and it also looks like the whammy library is not being supported also to make matters worse. It would seem like the root cause of this has to do with code breaking changes that have been bade with respect to the URL.createObjectURL method. Thus far I have not found a way to fix what has happened using more modern means of doing so.
When I last edited this post I was using thee.js r127, and when I first wrote this post I was using three.js r91. Also it would seem that whammy is not being maintained, however I think that is not always such a bad thing with what it is that I intend to use if for, and as long as it still works I do not see any major problem. I am sure that there might be other options for this sort of thing, but I will always want to use something that works more or less the same way by passing frames one at a time, rather than recoding on the fly video.
For the sake of keeping this post simple and to the point I will just be using a simple rotating cube example for this post. This will help to take the focus away from the animation and place it more so with the process of exporting an three.js animation to webm with whammy. Using whammy is fairly simple, but there are a few pitfalls that I have ran into. Nothing major, but I will be going over them here.
Once I have both whammy, and three.js included in my html with script tags, I start off by setting some variables that I will be using to help with the movement of the animation. Using whammy starts off by just calling the Whammy.Video constructor passing the desired frame rate for the exported video. This will return an encoder that I can use to add frames one by one in a render loop, and then them I am done I just need to call a compile method from this encoder.
Next I have an animation method that will be used to update the scene, call the renderer, and use the whammy exporter. Here I am using the current values of my frame, and maxFrame variables to find a percentage value that I then use to set the status of the frame animation for the current frame. For this animation I am just moving the position of the camera, and having it look at a simple mesh of a cube with the lookAt method that is called off of the camera.
In the body of this method I request another animation frame for the method over and over again as long as the current frame index is lower than the maxFrame value that I set. Each time after rendering I add the current state of the canvas to the encoder with the encoder.add method, by creating a dataUrl of the image/webp type. The whammy documentation says that I can just add the canvas, but I run into an error when doing that.
Once the animation is over, and all the frames have been added using the encoder.add method, I then call the encoder.compile method that will output a blob than can then be used to create a data url which is what I do with the exportVid method.
When the encoder is finished compiling, a callback will fire with a blob passed as the first argument for that callback. I Can then use the URL.createObjectURL method to convert the blob to a data url. This data url can then be used as the src attribute when making a video element.
I make sure to set the controls attribute to true, so that I can play the video element. In addition in chrome there is a download option for the video as well.
So here I just set up the usual scene, camera, mesh, and renderer. Once I do that I call the animate method to get the ball running with this.
So far this seems like one of the best options for converting a simple three.js looping animation to a stand alone webm file, or at least it was until things broke with it. So then I will still want to look into other options for this sort of thing, but some of them are more complex then that need to be, or I could not find a way to build the file on a frame by frame basis which is what I want to do. Because of the code breaking changes that have happed as of thins writing I have been r3educed to having to use a solution that involves creating a collection of PNG files and then using the program ffmpeg to create a video file that way.
Still the use of whammy will allow me to create a webm file of an animation using three.js, from there it is just a question of what I do with that. With that said I have found that I like to use a program called Open Shot to create a finished video with audio. I could also use just about any video editing program with one or more webm files crated with whammy, and then do editing and any additional processing to create a finished product of some kind.
If you know of any other methods of getting this done, or have an questions or concerns please let me know in the comments, and thanks for reading.