]> Dogcows Code - chaz/rasterize/blobdiff - animate.lua
fixes for compiling with mingw32
[chaz/rasterize] / animate.lua
index d04f5df539a98bd00bbad77de0ee65c495d5bee3..616c717f4eb51ff396a343b5a2759ef90faf35d8 100755 (executable)
 -- mcgarvey@eng.utah.edu
 --
 
--- This program that draws a scene multiple times from different camera angles
--- and positions.  The rasters are saved in the `frames' directory, and if
--- ffmpeg is installed, they will also be combined into a video file.  The
--- camera will make a full rotation along the X and Z axes, around a specified
--- point (center), all the while looking at some other point (look).
--- This must be called from the same directory where the rasterize program is.
-
-local size      = {w = 640, h = 480}    -- width and height of the viewport
-local frames    = 512                   -- number of animation frames
-
-local look      = {x = 2, y = 1, z = 2} -- the point to look at
-local center    = {x = 0, y = 1, z = 0} -- center of rotation
-local distance  = 4                     -- the distance from the center
-local start     = math.pi               -- where is the first frame
+-- This program automates the process of creating simple fly-by animations.
+-- The rasters are saved in the `frames' directory, and if ffmpeg is
+-- installed, the frames will also be combined into a video file.  This script
+-- must be called from the same directory where the rasterize program is.
+-- The CACHE_GEOMETRY option is also recommended to improve performance.
+
+-- Set the number of frames to be rendered for the animation.
+local frames = 360
+
+-- Define the code to calculate where the camera is, in world coordinates.
+local eye = function(frame)
+    -- just rotate around the center of the scene on the XZ plane
+    local center    = vec_new(0, 0.4, 0)
+    local distance  = 0.7
+    local start     = math.pi
+    local t = start + 2 * math.pi * frame / frames
+    local v = vec_new(math.cos(t), 0, math.sin(t))
+    return vec_add(vec_scale(v, distance), center)
+end
 
-local jobs      = 6                     -- number of concurrent renderings
+-- Define the code to calculate where the focal point of the scene is.
+local look = function(frame)
+    -- keep the camera focused at the center
+    return vec_new(0, 0, 0)
+end
 
--- the actual objects of the scene that will be drawn:
+-- Define the actual objects of the scene that will be rendered, in the
+-- extended u3d format.
 local scene = [[
-L 0 1000000 0 1 1 1 1 1 1
-L 0 0 1000000 1 1 1 1 1 1
-g triangle.raw
-c 0.9 0.8 0.7 0.6 0.5 0.4 0.3 0.2 0.1
-t 2 0 -2
-s 1 1 1
-g dragon.raw
-c 0.7 0.3 0.2 0.8 0.2 0.1 0.9 0.2 0.2
-t -2 -1 -2
-s 2 2 2
-g budda.raw
-c 0.1 0.2 0.7 0.1 0.3 0.9 0.2 0.1 0.8
-t 2 -1.5 2
-s 10 10 10
-g bunny.raw
-c 0.9 0.8 0.9 0.8 0.7 0.9 0.9 0.8 0.7
-t -2 -1 2
-s 10 10 10
-g teapot2.raw
-c 0 1 0 0 1 0 0 1 0
-t 0 -1 0
-s 0.6 0.6 0.6
+l -14687.0 7986.0 8976.0 1.0 1.0 1.0
+g checker.obj
+c 1.0 0.6 0.6 0.6
+m checker.ppm
+r -1.57 1.0 0.0 0.0
+p 1.0 1.0 1.0 100.0
+g teapot.raw
+c 0.9 0.7 0.1 0.2
+p 1.0 1.0 1.0 60.0
+t 0.0 0.1 0.0
+s 0.004 0.004 0.004
 ]]
 
+-- Set the number of samples for supersampling.  If this is set to a value
+-- of two or greater, each frame will be rendered larger by the factor
+-- specified.  ImageMagick is used to scale the frames back down to size;
+-- if ImageMagick is not installed, this script will exit with error 1.
+local supersample = 2
+
+-- Set the width and height of the viewport.
+local size = {w = 640, h = 480}
+
+-- Set the number of concurrent renderings (for multi-core machines).
+local jobs = 6
+
+-- Set the options to be passed directly to ffmpeg.
+local ffmpeg_opts = "-b 1024k"
+
+-- end of configuration
+---------------------------------------------------------------------------
+
+function vec_new(x, y, z)
+    return {x = x, y = y, z = z}
+end
 
 function vec_add(a, b)
-    return {x = a.x + b.x, y = a.y + b.y, z = a.z + b.z}
+    return vec_new(a.x + b.x, a.y + b.y, a.z + b.z)
 end
 
 function vec_scale(v, s)
-    return {x = v.x * s, y = v.y * s, z = v.z * s}
+    return vec_new(v.x * s, v.y * s, v.z * s)
 end
 
 local fmt   = string.format
-local write = function(...) io.write(fmt(...)) end
-
-function render(i, v)
-    while i and v do
+local write = function(...) io.write(fmt(...)) io.flush() end
+local run   = function(...) return os.execute(fmt(...)) end
+
+function render(i)
+    while i do
+        local w, h = size.w, size.h
+        if 1 < supersample then
+            w = w * supersample
+            h = h * supersample
+        end
         local filename  = fmt("frames/anim%04d.bmp", i)
         local command   = fmt("./rasterize -o %s >/dev/null", filename)
         local out = io.popen(command, "w")
-        write("\27[80D\27[2Kframe\t %4d / %d", i + 1, frames)
+        local e = eye(i)
+        local l = look(i)
+        write("\27[80D\27[2Kframe\t %4d / %d", i, frames)
         out:write(fmt([[
-U3
+U4
 %d %d
 %f %f %f
 %f %f %f
 0 1 0
 1.57 %f 0.1 1000
+1.0 1.0 1.0
 %s
 X
-]], size.w, size.h, v.x, v.y, v.z, look.x, look.y, look.z, size.w/size.h, scene))
-        i, v = coroutine.yield()
+]], w, h, e.x, e.y, e.z, l.x, l.y, l.z, size.w/size.h, scene))
+        i = coroutine.yield()
         out:close()
+        if 1 < supersample and
+                run("convert %s -scale %dx%d %s", filename, size.w, size.h, filename) ~= 0 then
+            print()
+            os.exit(1)
+        end
     end
 end
 
+function renderings()
+    local t = {}
+    for i = 1,jobs do
+        table.insert(t, coroutine.wrap(render))
+    end
+    local iterations = frames + jobs
+    local frame = 0
+    return function()
+        frame = frame + 1
+        if frame <= iterations then
+            local i = frame
+            if frames < i then i = null end
+            return t[1 + frame % jobs], i
+        end
+    end
+end
 
 print("Animating scene...")
 
-local threads = {}
-for i = 1,jobs do
-    table.insert(threads, coroutine.wrap(render))
-end
+run("rm -rf frames && mkdir frames >/dev/null 2>&1")
+for render,frame in renderings() do render(frame) end
 
-os.execute("rm -rf frames && mkdir frames >/dev/null 2>&1")
-for i = 0,(frames-1) do
-    local t = start + 2 * math.pi * i / frames
-    local v = {
-        x = math.cos(t),
-        y = 0,
-        z = math.sin(t),
-    }
-    v = vec_add(vec_scale(v, distance), center)
-    threads[1 + (i % jobs)](i, v)
-end
-for _,thread in ipairs(threads) do thread(null) end
 print()
 
-if os.execute("ffmpeg -i frames/anim%04d.bmp -b 1024k -y -an scene.avi") == 0 then
+if run("ffmpeg -i frames/anim%%04d.bmp %s -y -an scene.avi", ffmpeg_opts) == 0 then
     print("Animation written to scene.avi.")
+else
+    print("The animation could not be created. Is ffmpeg installed?")
+    os.exit(2)
 end
 
This page took 0.021384 seconds and 4 git commands to generate.