From: Tim Vaughan Date: Tue, 21 Feb 2023 11:37:09 +0000 (+0100) Subject: Soft shadows. X-Git-Url: https://thelambdalab.xyz/gitweb/index.cgi?p=raymarcher.git;a=commitdiff_plain;h=46c0ad2326b3d4edae71c00b6f4fcecb5eff4e07 Soft shadows. --- diff --git a/Operations.lua b/Operations.lua index d606d39..617916d 100644 --- a/Operations.lua +++ b/Operations.lua @@ -13,8 +13,20 @@ local function union(s1, s2) end end +local function diff(s1, s2) + return function (location) + local p1 = s1(location) + local p2 = s2(location) + + return {dist = math.max(p1.dist, -p2.dist), + texture = p1.texture} + end +end + + Operations = { - union = union + union = union, + diff = diff } return Operations diff --git a/Primitives.lua b/Primitives.lua index aafa7cb..c13966b 100644 --- a/Primitives.lua +++ b/Primitives.lua @@ -17,9 +17,18 @@ local function make_plane(centre, normal, 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 + + Primitives = { make_sphere = make_sphere, - make_plane = make_plane + make_plane = make_plane, + make_pipe = make_pipe } return Primitives diff --git a/Textures.lua b/Textures.lua index cee3dd9..1e919c7 100644 --- a/Textures.lua +++ b/Textures.lua @@ -4,19 +4,37 @@ local V = Vector local function make_phong_texture(lights, pigment, amb, diff, spec, shiny) local normalize = V.normalize - return function (location, ray_dir, normal, count) - local colour = pigment(location[1],location[3]) + + local eps = 0.0001 + local function light_visibility(location, light_dir, pos, dest, res, sdf) + local p = sdf(location) + if pos + p.dist > dest then + return res + elseif p.dist < eps then + return 0.0 + else + return light_visibility(location + light_dir*p.dist, light_dir, pos+p.dist, + dest, math.min(res, 30*p.dist/(pos+p.dist)), sdf) + end + end + + return function (location, ray_dir, normal, count, sdf) + local colour = pigment(location[1],location[2]) local thiscol = {colour[1]*amb, colour[2]*amb, colour[3]*amb} local reflected_ray = ray_dir - normal*(ray_dir*normal*2) for _,light in ipairs(lights) do - local light_dir = V.normalize(light-location) + local light_dist = V.norm(light-location) + local light_dir = (light-location)/light_dist + + local vis = light_visibility(location + light_dir*eps, light_dir, eps, light_dist, 1, sdf) + local Idiff = math.max(normal*light_dir, 0) local Ispec = math.pow(math.max(light_dir*reflected_ray,0),shiny) - thiscol[1] = thiscol[1] + colour[1]*Idiff*diff + Ispec*spec - thiscol[2] = thiscol[2] + colour[2]*Idiff*diff + Ispec*spec - thiscol[3] = thiscol[3] + colour[3]*Idiff*diff + Ispec*spec + thiscol[1] = thiscol[1] + vis*(colour[1]*Idiff*diff + Ispec*spec) + thiscol[2] = thiscol[2] + vis*(colour[2]*Idiff*diff + Ispec*spec) + thiscol[3] = thiscol[3] + vis*(colour[3]*Idiff*diff + Ispec*spec) end return thiscol @@ -24,13 +42,13 @@ local function make_phong_texture(lights, pigment, amb, diff, spec, shiny) end local function make_count_texture(scale) - return function (location, ray_dir, normal, count) + return function (location, ray_dir, normal, count, sdf) return {count*scale, count*scale, count*scale} end end local function make_flat_texture(pigment) - return function (location, ray_dir, normal, count) + return function (location, ray_dir, normal, count, sdf) return pigment(location[1], location[2]) end end diff --git a/Vector.lua b/Vector.lua index 3f35b64..db39ce8 100644 --- a/Vector.lua +++ b/Vector.lua @@ -101,7 +101,8 @@ Vector = { normalize = normalize, x = new{1,0,0}, y = new{0,1,0}, - z = new{0,0,1} + z = new{0,0,1}, + origin = new{0,0,0} } return Vector diff --git a/raymarch.lua b/raymarch.lua index 5bace40..594645e 100644 --- a/raymarch.lua +++ b/raymarch.lua @@ -11,7 +11,7 @@ require "Textures" local T = Textures local eps = 0.01 -local max_dist2 = 20^2 +local max_dist2 = 30^2 local bg_col = {0.1,0.1,0.1} local function calculate_normal(sdf, l) @@ -28,7 +28,9 @@ local function march(start, 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) + return p.texture(location, ray_dir, + calculate_normal(sdf, location-(ray_dir*eps)), + count, sdf) else return march(start, location + ray_dir*p.dist, ray_dir, sdf, count+1) @@ -76,20 +78,32 @@ local function render(scene, width, height, filename) end +local lights = {V.new{3,-3,1}} local scene = { sdf = O.union( - P.make_sphere(V.new{0,0,0}, 1, - T.make_phong_texture({V.new{2,-3,1}}, - T.make_solid_pigment({0,1,0}), - 0.2, 0.7, 1.0, 100)), - P.make_plane(V.new{0,0,-3.0}, V.new{0,0,1}, - T.make_flat_texture(T.make_checkered_pigment({0,0,1}, {1,1,1})))), + O.diff( + O.diff( + O.diff( + P.make_sphere(V.new{0,0,0}, 1, + T.make_phong_texture(lights, + T.make_solid_pigment({0,1,0}), + 0.2, 0.7, 1.0, 100)), + P.make_sphere(V.new{0,0,0}, 0.8)), + P.make_pipe(V.new{0,0,0}, 0.5, V.new{0,1,0})), + P.make_pipe(V.new{0,0,0}, 0.5, V.new{1,0,0})), + + P.make_plane(V.new{0,0,-1.0}, V.new{0,0,1}, + T.make_phong_texture(lights, + T.make_checkered_pigment({0.5,0,0.2}, {1,1,1}), + 0.2, 1.0, 0, 1))), + -- T.make_flat_texture(T.make_checkered_pigment({0,0,1}, {1,1,1})))), - camera = {location = V.new{0,-5,0}, + camera = {location = V.new{2,-5,1}, point_at = V.new{0,0,0}, - right = V.new{1,0,0}, + right = V.x, fov = 1}} +-- render(scene, 320, 200, "test.ppm") render(scene, 640, 480, "test.ppm")