diff --git a/prod/tsm.png b/prod/tsm.png
new file mode 100644
index 0000000..51f802e
Binary files /dev/null and b/prod/tsm.png differ
diff --git a/scenes/smolgalaxy.lua b/scenes/smolgalaxy.lua
index 845a84d..57b644c 100644
--- a/scenes/smolgalaxy.lua
+++ b/scenes/smolgalaxy.lua
@@ -70,7 +70,7 @@ local function randomtorus()
local thickness = util.randab(radius/4, radius)
local orientation = randomorientation()
- return obj.affinetransform(obj.torus(pos, radius, thickness), orientation, vec3.O)
+ return util.transform(obj.torus(pos, radius, thickness), orientation)
end
local function randomcuboid()
@@ -86,13 +86,12 @@ local function randomcylinder()
local height = util.randab(0, SCALE)
local orientation = randomorientation()
- return obj.affinetransform(
+ return util.transform(
obj.intersection(
obj.cylinder(pos, radius),
obj.cuboid(pos, vec3.new(radius, height, radius))
),
- orientation,
- vec3.O
+ orientation
)
end
diff --git a/scenes/tsm.lua b/scenes/tsm.lua
new file mode 100644
index 0000000..5c51a8e
--- /dev/null
+++ b/scenes/tsm.lua
@@ -0,0 +1,157 @@
+-- Scene developed by TSM71
+-- Also this took 30 hours to render
+
+local COLOR_BLACK = colorvec.new(0, 0, 0, 0)
+
+local GRAY = material.newfromdiagonal(
+ COLOR_BLACK,
+ colorvec.new(0.5, 0.5, 0.5, 0.5),
+ surfacetype.DIFFUSE
+)
+local CYAN = material.newfromdiagonal(
+ COLOR_BLACK,
+ colorvec.new(0, 1, 1, 0),
+ surfacetype.DIFFUSE
+)
+local PINK = material.newfromdiagonal(
+ COLOR_BLACK,
+ colorvec.new(1, .5, .5, 0),
+ surfacetype.DIFFUSE
+)
+local RED = material.newfromdiagonal(
+ COLOR_BLACK,
+ colorvec.new(1, 0, 0, 0),
+ surfacetype.DIFFUSE
+)
+local MAGENTA = material.newfromdiagonal(
+ COLOR_BLACK,
+ colorvec.new(1, 0, 1, 0),
+ surfacetype.DIFFUSE
+)
+local MIRROR = material.newfromdiagonal(
+ COLOR_BLACK,
+ colorvec.new(1, 1, 1, 1),
+ surfacetype.REFLECTIVE
+)
+local FLUORESCENT = material.new(
+ COLOR_BLACK,
+ colormat.new(
+ .25, 0, 0, .25,
+ 0, .25, 0, .75,
+ 0, 0, .25, 0,
+ 0, 0, 0, 0
+ ),
+ surfacetype.DIFFUSE
+)
+
+--[[
+obj.transformaround = function(a, b, c)
+ return util.translate(
+ util.transform(
+ util.translate(
+ a,
+ -c
+ ),
+ b
+ ),
+ c
+ )
+end
+--]]
+--obj.transformaround = function(a, _b, _c) return a end
+--obj.affinetransform = function(a, _b, _c) return a end
+--obj.smoothunion = function(a, b, _r) return obj.union(a, b) end
+---[[
+util.stacktransforms = function(list)
+ --do return list[1] end
+ --do return list[#list] end
+ local n = #list
+ local a = mat3.I
+ --for i=n, 1, -1 do
+ for i=1, n do
+ a = list[i] * a
+ --a = a * list[i]
+ end
+ return a
+end
+--]]
+
+return obj.withlights(
+ obj.transformaround(
+ obj.withlights(
+ util.union({
+ util.intersection({
+ util.union({
+ obj.withmaterial(
+ obj.negation(
+ util.union({
+ obj.cuboid(vec3.new(0, 0, 0), vec3.new(.5, 1, 4)),
+ obj.cuboid(vec3.new(0, 0, 0), vec3.new(4, 1, .5))
+ })
+ ),
+ GRAY
+ ),
+ obj.withmaterial(
+ util.intersection({
+ util.union({
+ obj.cuboid(vec3.new(0, 1, 0), vec3.new(.4, .1, 3.9)),
+ obj.cuboid(vec3.new(0, 1, 0), vec3.new(3.9, .1, .4))
+ }),
+ obj.negation(
+ util.union({
+ obj.cuboid(vec3.new(0, 1, 0), vec3.new(.3, 1, 3.8)),
+ obj.cuboid(vec3.new(0, 1, 0), vec3.new(3.8, 1, .3))
+ })
+ )
+ }),
+ FLUORESCENT
+ ),
+ obj.smoothunion(
+ obj.withmaterial(
+ obj.sphere(vec3.new(0, .75, 0), .25),
+ CYAN
+ ),
+ obj.withmaterial( -- withdynamicmaterial
+ obj.sphere(vec3.new(-.5, .5, 0), .25),
+ MAGENTA --dynamicmaterial.missingtexture(vec3.new(-.5, .5, 0))
+ ),
+ .5
+ )
+ }),
+ obj.withmaterial(
+ obj.negation(
+ obj.cuboid(vec3.new(0, 0, 0), vec3.new(2, .25, 2))
+ ),
+ PINK
+ )
+ }),
+ obj.withmaterial(
+ obj.cylinder(vec3.new(1, 0, 0), .375),
+ RED
+ ),
+ util.transform(
+ obj.withmaterial(
+ obj.torus(vec3.new(0, 0, -1), .375, .125),
+ MIRROR
+ ),
+ transform.SWAPYZ
+ )
+ }),
+ {
+ light.new(vec3.new(.45, 1-.2, -.45), colorvec.new(0, 0, 0, .1)),
+ --light.new(vec3.new(.45, 1-.2, -.45), colorvec.new(0, 0, 0, 1)),
+ }
+ ),
+ util.stacktransforms({
+ transform.scalexyz(1, -1, 1),
+ transform.rotatez(10*math.pi/180),
+ }),
+ vec3.new(0, 0, -1.5)
+ ),
+ {
+ light.new(vec3.new(0, .9375, 0), colorvec.new(.5, .25, 0, 0)),
+ light.new(vec3.new(0, .9375, -.625), colorvec.new(0, 0, 1, 0)),
+ --light.new(vec3.new(0, .9375, 0), colorvec.new(5, 2.5, 0, 0)),
+ --light.new(vec3.new(0, .9375, -.625), colorvec.new(0, 0, 10, 0)),
+ }
+)
\ No newline at end of file
diff --git a/src/consts.rs b/src/consts.rs
index 082641a..0c6baed 100644
--- a/src/consts.rs
+++ b/src/consts.rs
@@ -20,21 +20,21 @@ pub const ANGLE_POWER: f64 = 2.;
//pub const IMG_WIDTH: usize = 480;
//pub const IMG_WIDTH: usize = 1280;
//pub const IMG_WIDTH: usize = 1080;
-//pub const IMG_WIDTH: usize = 1920;
-pub const IMG_WIDTH: usize = 4961;
+pub const IMG_WIDTH: usize = 1920;
+//pub const IMG_WIDTH: usize = 4961;
//pub const IMG_HEIGHT: usize = 480;
//pub const IMG_HEIGHT: usize = 720;
-//pub const IMG_HEIGHT: usize = 1080;
-pub const IMG_HEIGHT: usize = 3508;
+pub const IMG_HEIGHT: usize = 1080;
+//pub const IMG_HEIGHT: usize = 3508;
pub const IMG_DIM: usize = if IMG_HEIGHT > IMG_WIDTH { IMG_HEIGHT } else { IMG_WIDTH };
pub const IMG_SIZE: usize = IMG_WIDTH * IMG_HEIGHT;
pub const IMG_BYTE_SIZE: usize = IMG_SIZE * 3;
-pub const SUPERSAMPLING: usize = 1;
-//pub const SUPERSAMPLING: usize = 2;
-pub const RAYS_PER_PIXEL: usize = 1;
+//pub const SUPERSAMPLING: usize = 1;
+pub const SUPERSAMPLING: usize = 2;
+//pub const RAYS_PER_PIXEL: usize = 1;
//pub const RAYS_PER_PIXEL: usize = 50;
-//pub const RAYS_PER_PIXEL: usize = 500;
+pub const RAYS_PER_PIXEL: usize = 500;
//pub const MAX_BOUNCES: u32 = 1;
//pub const MAX_BOUNCES: u32 = 4;
//pub const MAX_BOUNCES: u32 = 8;
diff --git a/src/lua/mat3.rs b/src/lua/mat3.rs
index cb763ba..10d11d7 100644
--- a/src/lua/mat3.rs
+++ b/src/lua/mat3.rs
@@ -7,7 +7,7 @@ impl UserData for Mat3 {
methods.add_meta_method(MetaMethod::Sub, |ctx, a: &Self, b: Self| Ok(*a-b));
methods.add_meta_method(MetaMethod::Mul, |ctx, a: &Self, b: Self| Ok(*a*b));
methods.add_meta_method(MetaMethod::Unm, |ctx, a: &Self, b: ()| Ok(-*a));
- methods.add_meta_method(MetaMethod::Mul, |ctx, a: &Self, b: f64| Ok(*a*b));
+ //methods.add_meta_method(MetaMethod::Mul, |ctx, a: &Self, b: f64| Ok(*a*b)); //TODO find a way to make it cohabit
methods.add_meta_method(MetaMethod::Div, |ctx, a: &Self, b: f64| Ok(*a/b));
methods.add_method("a", |ctx, x, ()| Ok(x.a()));
diff --git a/src/lua/obj.rs b/src/lua/obj.rs
index f3eb2dc..b74369a 100644
--- a/src/lua/obj.rs
+++ b/src/lua/obj.rs
@@ -54,6 +54,10 @@ pub fn obj<'lua>(ctx: Context<'lua>, _env: Table<'lua>) -> rlua::Result
(ctx: Context<'lua>, _env: Table<'lua>) -> rlua::Result(ctx: Context<'lua>, _env: Table<'lua>) -> rlua::Result> {
@@ -26,11 +26,25 @@ pub fn transform<'lua>(ctx: Context<'lua>, _env: Table<'lua>) -> rlua::Result| {
let mut acc = I3;
for trans in transforms.iter().rev().cloned() {
- acc = trans * I3;
+ acc = acc * trans;
}
Ok(acc)
}
diff --git a/src/lua/util.lua b/src/lua/util.lua
index e1b4730..a3505d6 100644
--- a/src/lua/util.lua
+++ b/src/lua/util.lua
@@ -65,7 +65,7 @@ function M.transform(object, mat)
return obj.affinetransform(object, mat, vec3.O)
end
function M.translate(object, vec)
- return obj.affinetransform(object, mat3.O, vec)
+ return obj.affinetransform(object, mat3.I, vec)
end
return M
\ No newline at end of file
diff --git a/src/main.rs b/src/main.rs
index c271ce3..a8ab5c5 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -85,9 +85,10 @@ 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/tsm.lua".to_owned()).unwrap();
//let scene = default_scene3();
- let cam = default_cam();
+ let cam = Cam::new(Z * -1.5, Z, f64::sqrt(2.));
+ //let cam = default_cam();
// get stats on the scene we're about to render
let total_rpp = (RAYS_PER_PIXEL * SUPERSAMPLING * SUPERSAMPLING) as u64;
diff --git a/src/object/mod.rs b/src/object/mod.rs
index 10c082f..d89c77c 100644
--- a/src/object/mod.rs
+++ b/src/object/mod.rs
@@ -8,6 +8,7 @@ use std::vec::Vec;
mod sphere;
mod plane;
mod union;
+mod smoothunion;
mod intersection;
mod exclusion;
mod negation;
@@ -64,6 +65,7 @@ impl ObjClone for T {
pub use sphere::Sphere;
pub use plane::Plane;
pub use union::Union;
+pub use smoothunion::SmoothUnion;
pub use intersection::Intersection;
pub use exclusion::Exclusion;
pub use negation::Negation;
diff --git a/src/object/smoothunion.rs b/src/object/smoothunion.rs
new file mode 100644
index 0000000..e4971e5
--- /dev/null
+++ b/src/object/smoothunion.rs
@@ -0,0 +1,42 @@
+use crate::object::Obj;
+use crate::light::Light;
+use crate::structs::Vec3;
+use std::vec;
+use crate::material::Material;
+
+#[derive(Debug, Copy, Clone, PartialEq)]
+pub struct SmoothUnion {
+ a: A,
+ b: B,
+ r: f64
+}
+
+impl SmoothUnion {
+ pub fn new(a: A, b: B, r: f64) -> SmoothUnion {
+ SmoothUnion { a, b, r }
+ }
+}
+
+impl Obj for SmoothUnion {
+ fn distance_to(&self, point: Vec3) -> f64 {
+ let d1 = self.a.distance_to(point);
+ let d2 = self.b.distance_to(point);
+ let h = f64::max(self.r - f64::abs(d1-d2),0.);
+ d1.min(d2) - h*h*0.25 / self.r
+ }
+ fn material_at(&self, point: Vec3) -> Material {
+ if self.a.distance_to(point) < self.b.distance_to(point) {
+ self.a.material_at(point)
+ } else {
+ self.b.material_at(point)
+ }
+ }
+ fn get_lights(&self) -> vec::Vec {
+ let mut l = self.a.get_lights();
+ l.extend(self.b.get_lights());
+ l
+ }
+ fn node_count(&self) -> u32 {
+ self.a.node_count() + self.b.node_count() + 1
+ }
+}
diff --git a/src/object/transform.rs b/src/object/transform.rs
index 499f962..9221902 100644
--- a/src/object/transform.rs
+++ b/src/object/transform.rs
@@ -14,10 +14,10 @@ pub struct AffineTransform {
impl AffineTransform {
pub fn new(obj: T, transform: Mat3, translate: Vec3) -> AffineTransform {
- AffineTransform { obj, transform, transform_inv: transform.invert(), translate, scale: transform.det().cbrt() }
+ AffineTransform { obj, transform, transform_inv: transform.invert(), translate, scale: transform.det().abs().cbrt() }
}
pub fn new_linear(obj: T, transform: Mat3) -> AffineTransform {
- AffineTransform { obj, transform, transform_inv: transform.invert(), translate: O, scale: transform.det().cbrt() }
+ AffineTransform { obj, transform, transform_inv: transform.invert(), translate: O, scale: transform.det().abs().cbrt() }
}
pub fn new_translate(obj: T, translate: Vec3) -> AffineTransform {
AffineTransform { obj, transform: I3, transform_inv: I3, translate, scale: 1. }
@@ -59,6 +59,37 @@ pub const fn scale_x(k: f64) -> Mat3 { scale_xyz(k, 1., 1.) }
pub const fn scale_y(k: f64) -> Mat3 { scale_xyz(1., k, 1.) }
pub const fn scale_z(k: f64) -> Mat3 { scale_xyz(1., 1., k) }
+pub fn rotate_x(a: f64) -> Mat3 {
+ let c = a.cos();
+ let s = a.sin();
+ Mat3::new(
+ 1., 0., 0.,
+ 0., c, -s,
+ 0., s, c
+ )
+}
+pub fn rotate_y(a: f64) -> Mat3 {
+ let c = a.cos();
+ let s = a.sin();
+ Mat3::new(
+ c, 0., s,
+ 0., 1., 0.,
+ -s, 0., c
+ )
+}
+pub fn rotate_z(a: f64) -> Mat3 {
+ let c = a.cos();
+ let s = a.sin();
+ Mat3::new(
+ c, -s, 0.,
+ s, c, 0.,
+ 0., 0., 1.
+ )
+}
+pub fn rotate_xyz(x: f64, y: f64, z: f64) -> Mat3 {
+ rotate_z(z) * rotate_y(y) * rotate_x(x)
+}
+
impl Obj for AffineTransform {
fn distance_to(&self, point: Vec3) -> f64 {
self.obj.distance_to(self.apply_rev(point)) * self.scale
@@ -81,4 +112,50 @@ impl Obj for AffineTransform {
fn node_count(&self) -> u32 {
self.obj.node_count() + 1
}
-}
\ No newline at end of file
+}
+
+#[derive(Debug, Copy, Clone, PartialEq)]
+pub struct TransformAround {
+ obj: T,
+ transform: Mat3,
+ transform_inv: Mat3,
+ center: Vec3,
+ scale: f64
+}
+
+impl TransformAround {
+ pub fn new(obj: T, transform: Mat3, center: Vec3) -> TransformAround {
+ TransformAround { obj, transform, transform_inv: transform.invert(), center, scale: transform.det().abs().cbrt() }
+ }
+
+ fn apply_rev(&self, point: Vec3) -> Vec3 {
+ self.transform_inv * (point + self.center) - self.center
+ }
+ fn apply_fwd(&self, point: Vec3) -> Vec3 {
+ self.transform * (point - self.center) + self.center
+ }
+}
+
+impl Obj for TransformAround {
+ fn distance_to(&self, point: Vec3) -> f64 {
+ self.obj.distance_to(self.apply_rev(point)) * self.scale
+ }
+ fn normal_at(&self, point: Vec3) -> Vec3 {
+ self.apply_fwd(self.obj.normal_at(self.apply_rev(point))).unit()
+ }
+ fn material_at(&self, point: Vec3) -> Material {
+ self.obj.material_at(self.apply_rev(point))
+ }
+ fn get_lights(&self) -> Vec {
+ self.obj
+ .get_lights()
+ .into_iter()
+ .map(|light| {
+ Light::new(self.apply_fwd(light.pos()), light.color())
+ })
+ .collect()
+ }
+ fn node_count(&self) -> u32 {
+ self.obj.node_count() + 1
+ }
+}
diff --git a/src/structs/mat3.rs b/src/structs/mat3.rs
index aa3af00..6ea1e0f 100644
--- a/src/structs/mat3.rs
+++ b/src/structs/mat3.rs
@@ -137,7 +137,7 @@ impl Mul for Mat3 {
d: self.d*other.a + self.e*other.d + self.f*other.g,
e: self.d*other.b + self.e*other.e + self.f*other.h,
- f: self.d*other.c + self.e*other.f + self.e*other.i,
+ f: self.d*other.c + self.e*other.f + self.f*other.i,
g: self.g*other.a + self.h*other.d + self.i*other.g,
h: self.g*other.b + self.h*other.e + self.i*other.h,
diff --git a/test b/test
index 05bc9e0..bbe9dfb 100755
--- a/test
+++ b/test
@@ -1,7 +1,8 @@
#!/bin/bash
+[ -z "$SEED" ] && export SEED=0
clear
cargo build --release && \
clear && \
- time SEED=0 target/release/rmarcher && \
+ time target/release/rmarcher && \
printf '\n' && \
kitty +kitten icat --align=left a.png