more lua support, fixed scene 3
This commit is contained in:
@@ -19,7 +19,6 @@ A ray marching renderer in rust
|
||||
|
||||
## What is planned
|
||||
- Testing of more shapes
|
||||
- Support for a lua-based scene representation DSL
|
||||
- Support for controlling the whole application from lua
|
||||
- Support for linking against a `scene.so` exporting a scene
|
||||
- Support for using as a library
|
||||
@@ -27,6 +26,7 @@ A ray marching renderer in rust
|
||||
## Examples
|
||||

|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
|
||||
BIN
Binary file not shown.
|
After Width: | Height: | Size: 1.0 MiB |
@@ -1,28 +1,20 @@
|
||||
local unpack = table.unpack or _G.unpack
|
||||
math.randomseed(os.time())
|
||||
|
||||
local function randab(a, b)
|
||||
return math.random() * (b-a) + a
|
||||
end
|
||||
util.seed()
|
||||
|
||||
local function randtable(n, a, b)
|
||||
local t = {}
|
||||
for i=1, n do
|
||||
t[i] = randab(a, b)
|
||||
t[i] = util.randab(a, b)
|
||||
end
|
||||
return t
|
||||
end
|
||||
|
||||
local function choice(list)
|
||||
return list[math.random(1, #list)]
|
||||
end
|
||||
|
||||
local function randomsphere()
|
||||
local pos = vec3.new(unpack(randtable(3, -2, 2)))
|
||||
local radius = randab(0, 0.5)
|
||||
local radius = util.randab(0, 0.5)
|
||||
local emission = colorvec.new(unpack(randtable(4, 0, 1)))
|
||||
local reflection = colormat.new(unpack(randtable(16, 0, 1)))
|
||||
local surfacetype = choice({surfacetype.DIFFUSE, surfacetype.REFLECTIVE, surfacetype.STOP})
|
||||
local surfacetype = util.choice({surfacetype.DIFFUSE, surfacetype.REFLECTIVE, surfacetype.STOP})
|
||||
|
||||
return obj.withmaterial(
|
||||
obj.sphere(pos, radius),
|
||||
@@ -30,23 +22,8 @@ local function randomsphere()
|
||||
)
|
||||
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 spheres = {}
|
||||
for i=1, 100 do
|
||||
spheres[i] = randomsphere()
|
||||
end
|
||||
return union(spheres)
|
||||
return util.union(spheres)
|
||||
+11
-34
@@ -1,30 +1,22 @@
|
||||
local unpack = table.unpack or _G.unpack
|
||||
math.randomseed(os.time())
|
||||
util.seed()
|
||||
|
||||
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)
|
||||
t[i] = util.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)
|
||||
local surfacetype = util.choice(MATERIALS)
|
||||
|
||||
return material.new(emission, reflection, surfacetype)
|
||||
end
|
||||
@@ -62,20 +54,20 @@ local ORIENTATIONS = {
|
||||
)
|
||||
}
|
||||
local function randomorientation()
|
||||
return choice(ORIENTATIONS)
|
||||
return util.choice(ORIENTATIONS)
|
||||
end
|
||||
|
||||
local function randomsphere()
|
||||
local pos = vec3.new(unpack(randtable(3, -2, 2)))
|
||||
local radius = randab(0, SCALE)
|
||||
local radius = util.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 radius = util.randab(0, SCALE)
|
||||
local thickness = util.randab(radius/4, radius)
|
||||
local orientation = randomorientation()
|
||||
|
||||
return obj.affinetransform(obj.torus(pos, radius, thickness), orientation, vec3.O)
|
||||
@@ -83,15 +75,15 @@ end
|
||||
|
||||
local function randomcuboid()
|
||||
local pos = vec3.new(unpack(randtable(3, -2, 2)))
|
||||
local radius = randab(0, SCALE)
|
||||
local radius = util.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 radius = util.randab(0, SCALE)
|
||||
local height = util.randab(0, SCALE)
|
||||
local orientation = randomorientation()
|
||||
|
||||
return obj.affinetransform(
|
||||
@@ -104,25 +96,10 @@ local function randomcylinder()
|
||||
)
|
||||
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)
|
||||
return util.union(objects)
|
||||
+2
-2
@@ -4,7 +4,7 @@ use rlua::{UserData, Context, Table};
|
||||
impl UserData for ColorVec {}
|
||||
impl UserData for ColorMat {}
|
||||
|
||||
pub fn color_vec(ctx: Context, _: ()) -> rlua::Result<Table> {
|
||||
pub fn color_vec<'lua>(ctx: Context<'lua>, _env: Table<'lua>) -> rlua::Result<Table<'lua>> {
|
||||
let module = ctx.create_table()?;
|
||||
|
||||
module.set("new", ctx.create_function(
|
||||
@@ -16,7 +16,7 @@ pub fn color_vec(ctx: Context, _: ()) -> rlua::Result<Table> {
|
||||
Ok(module)
|
||||
}
|
||||
|
||||
pub fn color_mat(ctx: Context, _: ()) -> rlua::Result<Table> {
|
||||
pub fn color_mat<'lua>(ctx: Context<'lua>, _env: Table<'lua>) -> rlua::Result<Table<'lua>> {
|
||||
let module = ctx.create_table()?;
|
||||
|
||||
module.set("new", ctx.create_function(
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@ use rlua::{UserData, Context, Table};
|
||||
|
||||
impl UserData for Light {}
|
||||
|
||||
pub fn light(ctx: Context, _: ()) -> rlua::Result<Table> {
|
||||
pub fn light<'lua>(ctx: Context<'lua>, _env: Table<'lua>) -> rlua::Result<Table<'lua>> {
|
||||
let module = ctx.create_table()?;
|
||||
|
||||
module.set("new", ctx.create_function(
|
||||
|
||||
+1
-1
@@ -29,7 +29,7 @@ impl UserData for Mat3 {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mat3(ctx: Context, _: ()) -> rlua::Result<Table> {
|
||||
pub fn mat3<'lua>(ctx: Context<'lua>, _env: Table<'lua>) -> rlua::Result<Table<'lua>> {
|
||||
let module = ctx.create_table()?;
|
||||
|
||||
module.set("new", ctx.create_function(
|
||||
|
||||
+2
-2
@@ -4,7 +4,7 @@ use rlua::{UserData, Context, Table};
|
||||
impl UserData for SurfaceType {}
|
||||
impl UserData for Material {}
|
||||
|
||||
pub fn surface_type(ctx: Context, _: ()) -> rlua::Result<Table> {
|
||||
pub fn surface_type<'lua>(ctx: Context<'lua>, _env: Table<'lua>) -> rlua::Result<Table<'lua>> {
|
||||
let module = ctx.create_table()?;
|
||||
|
||||
module.set("DIFFUSE", SurfaceType::Diffuse)?;
|
||||
@@ -14,7 +14,7 @@ pub fn surface_type(ctx: Context, _: ()) -> rlua::Result<Table> {
|
||||
Ok(module)
|
||||
}
|
||||
|
||||
pub fn material(ctx: Context, _: ()) -> rlua::Result<Table> {
|
||||
pub fn material<'lua>(ctx: Context<'lua>, _env: Table<'lua>) -> rlua::Result<Table<'lua>> {
|
||||
let module = ctx.create_table()?;
|
||||
|
||||
module.set("new", ctx.create_function(
|
||||
|
||||
+18
-13
@@ -6,6 +6,8 @@ mod mat3;
|
||||
mod color;
|
||||
mod material;
|
||||
mod light;
|
||||
mod transform;
|
||||
mod util;
|
||||
|
||||
pub use obj::{LuaObject, obj};
|
||||
pub use vec3::vec3;
|
||||
@@ -13,25 +15,28 @@ pub use mat3::mat3;
|
||||
pub use color::{color_vec, color_mat};
|
||||
pub use material::{surface_type, material};
|
||||
pub use light::light;
|
||||
pub use transform::transform;
|
||||
pub use util::util;
|
||||
|
||||
pub fn env(ctx: Context, _: ()) -> rlua::Result<Table> {
|
||||
let module = ctx.create_table()?;
|
||||
pub fn add_scene_env<'lua>(ctx: Context<'lua>, env: Table<'lua>) -> rlua::Result<Table<'lua>> {
|
||||
env.set("obj", obj(ctx, env.clone())?)?;
|
||||
env.set("vec3", vec3(ctx, env.clone())?)?;
|
||||
env.set("mat3", mat3(ctx, env.clone())?)?;
|
||||
env.set("colorvec", color_vec(ctx, env.clone())?)?;
|
||||
env.set("colormat", color_mat(ctx, env.clone())?)?;
|
||||
env.set("surfacetype", surface_type(ctx, env.clone())?)?;
|
||||
env.set("material", material(ctx, env.clone())?)?;
|
||||
env.set("light", light(ctx, env.clone())?)?;
|
||||
env.set("transform", transform(ctx, env.clone())?)?;
|
||||
env.set("util", util(ctx, env.clone())?)?;
|
||||
|
||||
module.set("obj", obj(ctx, ())?)?;
|
||||
module.set("vec3", vec3(ctx, ())?)?;
|
||||
module.set("mat3", mat3(ctx, ())?)?;
|
||||
module.set("colorvec", color_vec(ctx, ())?)?;
|
||||
module.set("colormat", color_mat(ctx, ())?)?;
|
||||
module.set("surfacetype", surface_type(ctx, ())?)?;
|
||||
module.set("material", material(ctx, ())?)?;
|
||||
module.set("light", light(ctx, ())?)?;
|
||||
|
||||
Ok(module)
|
||||
Ok(env)
|
||||
}
|
||||
|
||||
pub fn scene_from_file(file: String) -> rlua::Result<LuaObject> {
|
||||
Lua::new().context(|ctx| {
|
||||
let env = env(ctx, ())?;
|
||||
let env = ctx.create_table()?;
|
||||
add_scene_env(ctx, env.clone())?;
|
||||
let meta = ctx.create_table()?;
|
||||
meta.set("__index", ctx.globals())?;
|
||||
env.set_metatable(Some(meta));
|
||||
|
||||
+6
-2
@@ -27,7 +27,7 @@ impl Obj for LuaObject {
|
||||
|
||||
impl UserData for LuaObject {}
|
||||
|
||||
pub fn obj(ctx: Context, _: ()) -> rlua::Result<Table> {
|
||||
pub fn obj<'lua>(ctx: Context<'lua>, _env: Table<'lua>) -> rlua::Result<Table<'lua>> {
|
||||
let module = ctx.create_table()?;
|
||||
|
||||
module.set("cuboid", ctx.create_function(
|
||||
@@ -70,10 +70,14 @@ pub fn obj(ctx: Context, _: ()) -> rlua::Result<Table> {
|
||||
|ctx, ()| LuaObject::new(Waves::new())
|
||||
)?)?;
|
||||
|
||||
module.set("withlights", ctx.create_function(
|
||||
module.set("withlight", ctx.create_function(
|
||||
|ctx, (obj, light): (LuaObject, Light)| LuaObject::new(WithLights::new_one(obj.get(), light))
|
||||
)?)?;
|
||||
|
||||
module.set("withlights", ctx.create_function(
|
||||
|ctx, (obj, lights): (LuaObject, Vec<Light>)| LuaObject::new(WithAnyLights::new(obj.get(), lights))
|
||||
)?)?;
|
||||
|
||||
module.set("withmaterial", ctx.create_function(
|
||||
|ctx, (obj, material): (LuaObject, Material)| LuaObject::new(WithMaterial::new(obj.get(), material))
|
||||
)?)?;
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
use rlua::{Context, Table, Error};
|
||||
use crate::object::{SWAP_XY, SWAP_YZ, SWAP_XZ, scale_xyz, scale, scale_x, scale_y, scale_z};
|
||||
use crate::structs::{Mat3, I3};
|
||||
|
||||
pub fn transform<'lua>(ctx: Context<'lua>, _env: Table<'lua>) -> rlua::Result<Table<'lua>> {
|
||||
let module = ctx.create_table()?;
|
||||
|
||||
module.set("SWAPXY", SWAP_XY)?;
|
||||
module.set("SWAPXZ", SWAP_XZ)?;
|
||||
module.set("SWAPYZ", SWAP_YZ)?;
|
||||
|
||||
module.set("scalexyz", ctx.create_function(
|
||||
|ctx, (x, y, z)| Ok(scale_xyz(x, y, z))
|
||||
)?)?;
|
||||
module.set("scale", ctx.create_function(
|
||||
|ctx, k| Ok(scale(k))
|
||||
)?)?;
|
||||
|
||||
module.set("scalex", ctx.create_function(
|
||||
|ctx, k| Ok(scale_x(k))
|
||||
)?)?;
|
||||
module.set("scaley", ctx.create_function(
|
||||
|ctx, k| Ok(scale_y(k))
|
||||
)?)?;
|
||||
module.set("scalez", ctx.create_function(
|
||||
|ctx, k| Ok(scale_z(k))
|
||||
)?)?;
|
||||
|
||||
module.set("stack", ctx.create_function(
|
||||
|ctx, transforms: Vec<Mat3>| {
|
||||
let mut acc = I3;
|
||||
for trans in transforms.iter().rev().cloned() {
|
||||
acc = trans * I3;
|
||||
}
|
||||
Ok(acc)
|
||||
}
|
||||
)?)?;
|
||||
|
||||
Ok(module)
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
local env = ...
|
||||
local obj = env.obj
|
||||
local vec3 = env.vec3
|
||||
local mat3 = env.mat3
|
||||
local transform = env.transform
|
||||
|
||||
local M = {}
|
||||
|
||||
-- technically a binary fold
|
||||
local function binstack(objs, fn)
|
||||
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 fn(binstack(left, fn), binstack(right, fn))
|
||||
end
|
||||
|
||||
-- technically a fold
|
||||
local function linstack(objs, fn)
|
||||
local head = objs[1]
|
||||
for i=2, #objs do
|
||||
head = fn(head, objs[i])
|
||||
end
|
||||
return head
|
||||
end
|
||||
|
||||
-- random functions
|
||||
local SEED = os.getenv "SEED" or os.time()
|
||||
function M.seed()
|
||||
math.randomseed(SEED)
|
||||
end
|
||||
function M.randab(a, b)
|
||||
return math.random() * (b-a) + a
|
||||
end
|
||||
function M.choice(list)
|
||||
return list[math.random(1, #list)]
|
||||
end
|
||||
|
||||
-- multiple object composition
|
||||
function M.union(objs)
|
||||
return binstack(objs, obj.union)
|
||||
end
|
||||
function M.intersection(objs)
|
||||
return binstack(objs, obj.intersection)
|
||||
end
|
||||
function M.smoothunion(objs, k)
|
||||
return linstack(objs, function(a, b) return obj.smoothunion(a, b, k) end)
|
||||
end
|
||||
function M.smoothintersection(objs, k)
|
||||
return linstack(objs, function(a, b) return obj.smoothintersection(a, b, k) end)
|
||||
end
|
||||
|
||||
-- simpler transformations
|
||||
function M.scale(object, k)
|
||||
return obj.affinetransform(object, transform.scale(k), vec3.O)
|
||||
end
|
||||
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)
|
||||
end
|
||||
|
||||
return M
|
||||
@@ -0,0 +1,5 @@
|
||||
use rlua::{Context, Table};
|
||||
|
||||
pub fn util<'lua>(ctx: Context<'lua>, env: Table<'lua>) -> rlua::Result<Table<'lua>> {
|
||||
ctx.load(include_str!("util.lua")).call(env)
|
||||
}
|
||||
+1
-1
@@ -24,7 +24,7 @@ impl UserData for Vec3 {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn vec3(ctx: Context, _: ()) -> rlua::Result<Table> {
|
||||
pub fn vec3<'lua>(ctx: Context<'lua>, _env: Table<'lua>) -> rlua::Result<Table<'lua>> {
|
||||
let module = ctx.create_table()?;
|
||||
|
||||
module.set("new", ctx.create_function(
|
||||
|
||||
+3
-3
@@ -68,8 +68,7 @@ fn default_scene2() -> Scene {
|
||||
}
|
||||
|
||||
fn default_scene3() -> Scene {
|
||||
//TODO fix this scene
|
||||
let s1 = WithMaterial::new(Sphere::new_xyz(4., 0., 0., 1.), WHITE);
|
||||
let s1 = WithMaterial::new(Sphere::new_xyz(4., 0., 0., 1.), MIRROR);
|
||||
let s2 = WithMaterial::new(Sphere::new_xyz(3., 1., 1., 0.5), GREEN);
|
||||
let navion = WithMaterial::new(Plane::new_xyz(0., 1., -1., 3.), BLUE);
|
||||
let backwall = WithMaterial::new(Plane::new_xyz(-1., -1., -0.5, 8.), RED);
|
||||
@@ -86,7 +85,8 @@ fn default_scene3() -> Scene {
|
||||
|
||||
fn main() {
|
||||
// get scene and camera
|
||||
let scene = scene_from_file("scenes/smolgalaxy.lua".to_owned()).unwrap();
|
||||
//let scene = scene_from_file("scenes/randomspheres.lua".to_owned()).unwrap();
|
||||
let scene = default_scene3();
|
||||
let cam = default_cam();
|
||||
|
||||
// get stats on the scene we're about to render
|
||||
|
||||
+1
-1
@@ -70,6 +70,6 @@ pub use cylinder::Cylinder;
|
||||
pub use torus::Torus;
|
||||
pub use waves::Waves;
|
||||
pub use with_material::{WithMaterial, WithDynamicMaterial};
|
||||
pub use with_lights::{WithLights, WithLight};
|
||||
pub use with_lights::{WithLights, WithLight, WithAnyLights};
|
||||
pub use transform::*;
|
||||
pub use scene::Scene;
|
||||
@@ -8,18 +8,19 @@ pub struct AffineTransform<T: Obj + Clone> {
|
||||
obj: T,
|
||||
transform: Mat3,
|
||||
transform_inv: Mat3,
|
||||
translate: Vec3
|
||||
translate: Vec3,
|
||||
scale: f64
|
||||
}
|
||||
|
||||
impl<T: Obj + Clone> AffineTransform<T> {
|
||||
pub fn new(obj: T, transform: Mat3, translate: Vec3) -> AffineTransform<T> {
|
||||
AffineTransform { obj, transform, transform_inv: transform.invert(), translate }
|
||||
AffineTransform { obj, transform, transform_inv: transform.invert(), translate, scale: transform.det().cbrt() }
|
||||
}
|
||||
pub fn new_linear(obj: T, transform: Mat3) -> AffineTransform<T> {
|
||||
AffineTransform { obj, transform, transform_inv: transform.invert(), translate: O }
|
||||
AffineTransform { obj, transform, transform_inv: transform.invert(), translate: O, scale: transform.det().cbrt() }
|
||||
}
|
||||
pub fn new_translate(obj: T, translate: Vec3) -> AffineTransform<T> {
|
||||
AffineTransform { obj, transform: I3, transform_inv: I3, translate }
|
||||
AffineTransform { obj, transform: I3, transform_inv: I3, translate, scale: 1. }
|
||||
}
|
||||
|
||||
fn apply_rev(&self, point: Vec3) -> Vec3 {
|
||||
@@ -60,7 +61,7 @@ pub const fn scale_z(k: f64) -> Mat3 { scale_xyz(1., 1., k) }
|
||||
|
||||
impl<T: Obj + Clone> Obj for AffineTransform<T> {
|
||||
fn distance_to(&self, point: Vec3) -> f64 {
|
||||
self.obj.distance_to(self.apply_rev(point))
|
||||
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()
|
||||
|
||||
@@ -41,4 +41,40 @@ impl<T: Obj> WithLight<T> {
|
||||
pub fn new_one(obj: T, light: Light) -> WithLight<T> {
|
||||
WithLight { obj, lights: [light; 1] }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct WithAnyLights<T: Obj> {
|
||||
obj: T,
|
||||
lights: Vec<Light>
|
||||
}
|
||||
|
||||
impl<T: Obj> WithAnyLights<T> {
|
||||
pub fn new(obj: T, lights: Vec<Light>) -> WithAnyLights<T> {
|
||||
WithAnyLights { obj, lights }
|
||||
}
|
||||
|
||||
pub fn add_light(&mut self, light: Light) {
|
||||
self.lights.push(light)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Obj> Obj for WithAnyLights<T> {
|
||||
fn distance_to(&self, point: Vec3) -> f64 {
|
||||
self.obj.distance_to(point)
|
||||
}
|
||||
fn normal_at(&self, point: Vec3) -> Vec3 {
|
||||
self.obj.normal_at(point)
|
||||
}
|
||||
fn material_at(&self, point: Vec3) -> Material {
|
||||
self.obj.material_at(point)
|
||||
}
|
||||
fn get_lights(&self) -> Vec<Light> {
|
||||
let mut l = self.obj.get_lights();
|
||||
l.extend(&self.lights);
|
||||
l
|
||||
}
|
||||
fn node_count(&self) -> u32 {
|
||||
self.obj.node_count() + 1
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user