diff --git a/README.md b/README.md index 5a6900a..e843ff0 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ A ray marching renderer in rust - `rlua` for lua scene building ## What currently works -- Simple shapes (half-spaces and spheres are the only tested ones so far) +- Simple shapes (half-spaces, spheres, cylinders and torus are the only tested ones so far) - Spectral simulation (currently using 4 color components) - Global illumination (with diffuse and reflective surfaces) - Punctual illumination @@ -28,6 +28,7 @@ A ray marching renderer in rust ![1st test scene](prod/1.png) ![2nd test scene](prod/2.png) ![randomly generated spheres](prod/randomspheres.png) +![randomly generated objects](prod/smolgalaxy.png) ## License -MIT \ No newline at end of file +MIT diff --git a/prod/smolgalaxy.png b/prod/smolgalaxy.png new file mode 100644 index 0000000..03bfbb5 Binary files /dev/null and b/prod/smolgalaxy.png differ diff --git a/scenes/smolgalaxy.lua b/scenes/smolgalaxy.lua new file mode 100644 index 0000000..23dfec3 --- /dev/null +++ b/scenes/smolgalaxy.lua @@ -0,0 +1,128 @@ +local unpack = table.unpack or _G.unpack +math.randomseed(os.time()) + +local SCALE = 0.3 +local N_EACH = 25 + +local function randab(a, b) + return math.random() * (b-a) + a +end + +local function randtable(n, a, b) + local t = {} + for i=1, n do + t[i] = randab(a, b) + end + return t +end + +local function choice(list) + return list[math.random(1, #list)] +end + +local MATERIALS = {surfacetype.DIFFUSE, surfacetype.REFLECTIVE, surfacetype.STOP} +local function randommaterial() + local emission = colorvec.new(unpack(randtable(4, 0, 1))) + local reflection = colormat.new(unpack(randtable(16, 0, 1))) + local surfacetype = choice(MATERIALS) + + return material.new(emission, reflection, surfacetype) +end + +local ORIENTATIONS = { + mat3.new( + 1, 0, 0, + 0, 1, 0, + 0, 0, 1 + ), + mat3.new( + 1, 0, 0, + 0, 0, 1, + 0, 1, 0 + ), + mat3.new( + 0, 1, 0, + 1, 0, 0, + 0, 0, 1 + ), + mat3.new( + 0, 1, 0, + 0, 0, 1, + 1, 0, 0 + ), + mat3.new( + 0, 0, 1, + 0, 1, 0, + 1, 0, 0 + ), + mat3.new( + 0, 0, 1, + 1, 0, 0, + 0, 1, 0 + ) +} +local function randomorientation() + return choice(ORIENTATIONS) +end + +local function randomsphere() + local pos = vec3.new(unpack(randtable(3, -2, 2))) + local radius = randab(0, SCALE) + + return obj.sphere(pos, radius) +end + +local function randomtorus() + local pos = vec3.new(unpack(randtable(3, -2, 2))) + local radius = randab(0, SCALE) + local thickness = randab(radius/4, radius) + local orientation = randomorientation() + + return obj.affinetransform(obj.torus(pos, radius, thickness), orientation, vec3.O) +end + +local function randomcuboid() + local pos = vec3.new(unpack(randtable(3, -2, 2))) + local radius = randab(0, SCALE) + + return obj.cuboid(pos, vec3.new(radius, radius, radius)) +end + +local function randomcylinder() + local pos = vec3.new(unpack(randtable(3, -2, 2))) + local radius = randab(0, SCALE) + local height = randab(0, SCALE) + local orientation = randomorientation() + + return obj.affinetransform( + obj.intersection( + obj.cylinder(pos, radius), + obj.cuboid(pos, vec3.new(radius, height, radius)) + ), + orientation, + vec3.O + ) +end + +local function union(objs) + local n = #objs + if n == 1 then return objs[1] end + + local mid = n//2 + local left, right = {}, {} + for i=1, mid do + left[i] = objs[i] + end + for i=mid+1, n do + right[i-mid] = objs[i] + end + return obj.union(union(left), union(right)) +end + +local objects = {} +for i=1, N_EACH do table.insert(objects, randomsphere()) end +for i=1, N_EACH do table.insert(objects, randomtorus()) end +for i=1, N_EACH do table.insert(objects, randomcuboid()) end +for i=1, N_EACH do table.insert(objects, randomcylinder()) end +for i, object in ipairs(objects) do objects[i] = obj.withmaterial(object, randommaterial()) end +return union(objects) \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 1d63a76..9ff326a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -86,7 +86,7 @@ fn default_scene3() -> Scene { fn main() { // get scene and camera - let scene = scene_from_file("scenes/randomspheres.lua".to_owned()).unwrap(); + let scene = scene_from_file("scenes/smolgalaxy.lua".to_owned()).unwrap(); let cam = default_cam(); // get stats on the scene we're about to render diff --git a/src/object/cylinder.rs b/src/object/cylinder.rs index d179421..239a030 100644 --- a/src/object/cylinder.rs +++ b/src/object/cylinder.rs @@ -15,9 +15,9 @@ impl Cylinder { impl Obj for Cylinder { fn distance_to(&self, point: Vec3) -> f64 { - Vec3::new(self.center.x(), 0., self.center.z()).distance_to(point) - self.radius + Vec3::new(self.center.x(), point.y(), self.center.z()).distance_to(point) - self.radius } fn normal_at(&self, point: Vec3) -> Vec3 { - point - Vec3::new(self.center.x(), 0.,self.center.z()) + point - Vec3::new(self.center.x(), point.y(),self.center.z()) } }