-- Geometric primitives for raymarching require "Vector" local V = Vector local function make_sphere(centre, radius, texture) local norm = V.norm return function(p) return {dist = V.norm(p-centre) - radius, texture = texture} end end local function make_plane(centre, normal, texture) return function(p) return {dist = normal*(p-centre), texture = texture} end end local function make_pipe(centre, radius, axis, texture) return function(p) return {dist = V.norm(V.cross(p-centre, axis)) - radius, texture = texture} end end local function make_mandelbulb(centre, max_iter, power, texture) return function(p) local z = p - centre local dr = 1.0 local r = 0.0 for i=1,max_iter do r = V.norm(z) if r>2.0 then break end -- convert to polar coordinates theta = math.acos(z[3]/r) phi = math.atan(z[2],z[1]) dr = math.pow(r, power-1.0)*power*dr + 1.0 -- scale and rotate the point zr = math.pow(r, power) theta = theta*power phi = phi*power -- convert back to cartesian coordinates z = V.new{math.sin(theta)*math.cos(phi), math.sin(phi)*math.sin(theta), math.cos(theta)} * zr z = z + p end return {dist = 0.5*math.log(r)*r/dr, texture = texture} end end Primitives = { make_sphere = make_sphere, make_plane = make_plane, make_pipe = make_pipe, make_mandelbulb = make_mandelbulb } return Primitives