X-Git-Url: https://git.dogcows.com/gitweb?p=chaz%2Frasterize;a=blobdiff_plain;f=animate.lua;h=b9fb1be73c995bf31013172f8e2bcceac4e7e4bd;hp=d04f5df539a98bd00bbad77de0ee65c495d5bee3;hb=09dd89d10e65029f0be313dd463ba1f43cac2fbb;hpb=e16cf0578f4baaf879e4ab9d3528a765bfd29be0 diff --git a/animate.lua b/animate.lua index d04f5df..b9fb1be 100755 --- a/animate.lua +++ b/animate.lua @@ -6,32 +6,41 @@ -- 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 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, 1, 0) + local distance = 4 + 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 on the buddha + return vec_new(2, 1, 2) +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 ak47.obj +c 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 +M 0.9 0.9 0.9 128 g dragon.raw +M 0.3 0.3 0.3 5 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 @@ -40,32 +49,57 @@ 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 +M 0.2 0.2 0.2 1 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 ]] +-- 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, the resulting frames will end up bigger than they should +-- be and the aliasing problem will not be fixed. +local supersample = 4 + +-- 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 + + +-- end of configuration +--------------------------------------------------------------------------- + +local fmt = string.format +local write = function(...) return io.write(fmt(...)) end +local run = function(...) return os.execute(fmt(...)) end + +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 +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") + local e = eye(i) + local l = look(i) write("\27[80D\27[2Kframe\t %4d / %d", i + 1, frames) out:write(fmt([[ U3 @@ -76,13 +110,15 @@ 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() +]], 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 then + run("convert %s -scale %dx%d %s", filename, size.w, size.h, filename) + end end end - print("Animating scene...") local threads = {} @@ -90,21 +126,14 @@ for i = 1,jobs do table.insert(threads, coroutine.wrap(render)) end -os.execute("rm -rf frames && mkdir frames >/dev/null 2>&1") +run("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() -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 -b 1024k -y -an scene.avi") == 0 then print("Animation written to scene.avi.") end