require "Vector" local V = Vector require "Primitives" local P = Primitives require "Operations" local O = Operations require "Textures" local T = Textures local eps = 0.01 local max_dist2 = 30^2 local bg_col = {0.1,0.1,0.1} local function calculate_normal(sdf, l) local delta = 1e-3; return V.new{sdf(l+V.x*delta).dist-sdf(l-V.x*delta).dist, sdf(l+V.y*delta).dist-sdf(l-V.y*delta).dist, sdf(l+V.z*delta).dist-sdf(l-V.z*delta).dist}/(2*delta) end local function march(start, location, ray_dir, sdf, count) if V.norm2(location-start) > max_dist2 then return bg_col end local p = sdf(location) if p.dist < eps then return p.texture(location, ray_dir, calculate_normal(sdf, location-(ray_dir*eps)), count, sdf) else return march(start, location + ray_dir*p.dist, ray_dir, sdf, count+1) end end local function render(scene, width, height, filename) print("Rendering to file " .. filename .. "...") local f = io.open(filename, "w") f:write("P3 ", width, " ", height, " 255\n") local c = scene.camera local cam_dir = V.normalize(c.point_at - c.location) local right = V.normalize(c.right) local up = V.cross(right,cam_dir) local aspect = height/width; local normalize = V.normalize -- optimization for y=1,height do if y % math.floor(height/10) == 0 then print(y/math.floor(height/10) * 10 .. "%") end local rayy = cam_dir + up*((0.5 - y/height)*c.fov*aspect) for x=1,width do local ray_dir = normalize(rayy + right*((x/width - 0.5)*c.fov)) local col = march(c.location, c.location, ray_dir, scene.sdf, 0) col = {math.min(col[1]*255, 255), math.min(col[2]*255, 255), math.min(col[3]*255, 255)} f:write(math.floor(col[1]), " ", math.floor(col[2]), " ", math.floor(col[3]), " ") end f:write("\n") end f:write("\n") f:close() print("done") end local lights = {V.new{3,-3,1}} local scene = { sdf = O.union( O.diff( O.diff( O.diff( P.make_sphere(V.new{0,0,0}, 1, T.make_phong_texture(lights, T.make_solid_pigment({0,1,0}), 0.2, 0.7, 1.0, 100)), P.make_sphere(V.new{0,0,0}, 0.8)), P.make_pipe(V.new{0,0,0}, 0.5, V.new{0,1,0})), P.make_pipe(V.new{0,0,0}, 0.5, V.new{1,0,0})), P.make_plane(V.new{0,0,-1.0}, V.new{0,0,1}, T.make_phong_texture(lights, T.make_checkered_pigment({0.5,0,0.2}, {1,1,1}), 0.2, 1.0, 0, 1))), -- T.make_flat_texture(T.make_checkered_pigment({0,0,1}, {1,1,1})))), camera = {location = V.new{2,-5,1}, point_at = V.new{0,0,0}, right = V.x, fov = 1}} -- render(scene, 320, 200, "test.ppm") render(scene, 640, 480, "test.ppm")