refactor the animation script a bit
[chaz/rasterize] / animate.lua
1 #!/usr/bin/env lua
2
3 --
4 -- CS5600 University of Utah
5 -- Charles McGarvey
6 -- mcgarvey@eng.utah.edu
7 --
8
9 -- This program automates the process of creating simple fly-by animations.
10 -- The rasters are saved in the `frames' directory, and if ffmpeg is
11 -- installed, the frames will also be combined into a video file. This script
12 -- must be called from the same directory where the rasterize program is.
13
14 -- Set the number of frames to be rendered for the animation.
15 local frames = 360
16
17 -- Define the code to calculate where the camera is, in world coordinates.
18 local eye = function(frame)
19 -- just rotate around the center of the scene on the XZ plane
20 local center = vec_new(0, 1, 0)
21 local distance = 4
22 local start = math.pi
23 local t = start + 2 * math.pi * frame / frames
24 local v = vec_new(math.cos(t), 0, math.sin(t))
25 return vec_add(vec_scale(v, distance), center)
26 end
27
28 -- Define the code to calculate where the focal point of the scene is.
29 local look = function(frame)
30 -- keep the camera focused on the buddha
31 return vec_new(2, 1, 2)
32 end
33
34 -- Define the actual objects of the scene that will be rendered, in the
35 -- extended u3d format.
36 local scene = [[
37 L 0 1000000 0 1 1 1 1 1 1
38 L 0 0 1000000 1 1 1 1 1 1
39 g ak47.obj
40 c 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1
41 M 0.9 0.9 0.9 128
42 g dragon.raw
43 M 0.3 0.3 0.3 5
44 c 0.7 0.3 0.2 0.8 0.2 0.1 0.9 0.2 0.2
45 t -2 -1 -2
46 s 2 2 2
47 g budda.raw
48 c 0.1 0.2 0.7 0.1 0.3 0.9 0.2 0.1 0.8
49 t 2 -1.5 2
50 s 10 10 10
51 g bunny.raw
52 M 0.2 0.2 0.2 1
53 c 0.9 0.8 0.9 0.8 0.7 0.9 0.9 0.8 0.7
54 t -2 -1 2
55 s 10 10 10
56 ]]
57
58 -- Set the number of samples for supersampling. If this is set to a value of
59 -- two or greater, each frame will be rendered larger by the factor specified.
60 -- ImageMagick is used to scale the frames back down to size; if ImageMagick
61 -- is not installed, the resulting frames will end up bigger than they should
62 -- be and the aliasing problem will not be fixed.
63 local supersample = 2
64
65 -- Set the width and height of the viewport.
66 local size = {w = 640, h = 480}
67
68 -- Set the number of concurrent renderings (for multi-core machines).
69 local jobs = 6
70
71 -- Set the options to be passed directly to ffmpeg.
72 local ffmpeg_opts = "-b 1024k"
73
74 -- end of configuration
75 ---------------------------------------------------------------------------
76
77 function vec_new(x, y, z)
78 return {x = x, y = y, z = z}
79 end
80
81 function vec_add(a, b)
82 return vec_new(a.x + b.x, a.y + b.y, a.z + b.z)
83 end
84
85 function vec_scale(v, s)
86 return vec_new(v.x * s, v.y * s, v.z * s)
87 end
88
89 local fmt = string.format
90 local write = function(...) io.write(fmt(...)) io.flush() end
91 local run = function(...) return os.execute(fmt(...)) end
92
93 function render(i)
94 while i do
95 local w, h = size.w, size.h
96 if 1 < supersample then
97 w = w * supersample
98 h = h * supersample
99 end
100 local filename = fmt("frames/anim%04d.bmp", i)
101 local command = fmt("./rasterize -o %s >/dev/null", filename)
102 local out = io.popen(command, "w")
103 local e = eye(i)
104 local l = look(i)
105 write("\27[80D\27[2Kframe\t %4d / %d", i, frames)
106 out:write(fmt([[
107 U3
108 %d %d
109 %f %f %f
110 %f %f %f
111 0 1 0
112 1.57 %f 0.1 1000
113 %s
114 X
115 ]], w, h, e.x, e.y, e.z, l.x, l.y, l.z, size.w/size.h, scene))
116 i = coroutine.yield()
117 out:close()
118 if 1 < supersample then
119 run("convert %s -scale %dx%d %s", filename, size.w, size.h, filename)
120 end
121 end
122 end
123
124 function renderings()
125 local t = {}
126 for i = 1,jobs do
127 table.insert(t, coroutine.wrap(render))
128 end
129 local iterations = frames + jobs
130 local frame = 0
131 return function()
132 frame = frame + 1
133 if frame <= iterations then
134 local i = frame
135 if frames < i then i = null end
136 return t[1 + frame % jobs], i
137 end
138 end
139 end
140
141 print("Animating scene...")
142
143 run("rm -rf frames && mkdir frames >/dev/null 2>&1")
144 for render,frame in renderings() do render(frame) end
145
146 print()
147
148 if run("ffmpeg -i frames/anim%%04d.bmp %s -y -an scene.avi", ffmpeg_opts) == 0 then
149 print("Animation written to scene.avi.")
150 end
151
This page took 0.047975 seconds and 4 git commands to generate.