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_dist = 50 local bg_col = {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(location, ray_dir, sdf, count) local p = sdf(location) if p.dist < eps then return p.texture(location, ray_dir, calculate_normal(sdf, location-(ray_dir*eps)), count) elseif p.dist > max_dist then return bg_col else return march(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; 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*((y/height - 0.5)*c.fov*aspect) for x=1,width do local ray_dir = V.normalize(rayy + right*((x/width - 0.5)*c.fov)) local col = march(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 scene = { sdf = O.union(P.make_sphere(V.new{0,0,0}, 1, -- T.make_count_texture()), T.make_phong({V.new{2,-1,2}}, {0,1,0}, 1.0, 0.5, 100)), P.make_sphere(V.new{1.5,0,1.0}, 0.5, T.make_phong({V.new{2,-1,2}}, {0,0,1}, 1.0, 0.5, 100))), camera = {location = V.new{0,-5,0}, point_at = V.new{0,0,0}, right = V.new{1,0,0}, fov = 1}} render(scene, 640, 480, "test.ppm")