-- 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.
+
+-- Set the width and height of the viewport.
+local size = {w = 640, h = 480}
+
+-- Set the number of frames to be rendered for the animation.
+local frames = 512
+
+-- 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 = {x = 0, y = 1, z = 0}
+ local distance = 4
+ local start = math.pi
+ local t = start + 2 * math.pi * frame / frames
+ local v = {
+ x = math.cos(t),
+ y = 0,
+ z = 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)
+ return {x = 2, y = 1, z = 2} -- keep focused on the buddha
+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
s 0.6 0.6 0.6
]]
+-- Set the number of concurrent renderings (for multi-core machines).
+local jobs = 6
+
+
+-- end of configuration
+---------------------------------------------------------------------------
+
+local fmt = string.format
+local write = function(...) io.write(fmt(...)) end
function vec_add(a, b)
return {x = a.x + b.x, y = a.y + b.y, z = a.z + b.z}
return {x = v.x * s, y = v.y * s, z = v.z * s}
end
-local fmt = string.format
-local write = function(...) io.write(fmt(...)) end
-
-function render(i, v)
- while i and v do
+function render(i)
+ while i do
local filename = fmt("frames/anim%04d.bmp", i)
local command = fmt("./rasterize -o %s >/dev/null", filename)
local out = io.popen(command, "w")
+ local e = eye(i)
+ local l = look(i)
write("\27[80D\27[2Kframe\t %4d / %d", i + 1, frames)
out:write(fmt([[
U3
1.57 %f 0.1 1000
%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()
+]], size.w, size.h, e.x, e.y, e.z, l.x, l.y, l.z, size.w/size.h, scene))
+ i = coroutine.yield()
out:close()
end
end
-
print("Animating scene...")
local threads = {}
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)
+ threads[1 + (i % jobs)](i)
end
for _,thread in ipairs(threads) do thread(null) end
print()