Textures now take "mapped" pigments as arguments.
[raymarcher.git] / Textures.lua
1 -- Textures for raymarcher
2
3 require "Vector"
4 local V = Vector
5
6 local function make_phong_texture(lights, mapped_pigment, amb, diff, spec, shiny)
7    local normalize = V.normalize
8
9    local eps = 0.0001
10    local function light_visibility(location, light_dir, pos, dest, res, sdf)
11       local p = sdf(location)
12       if pos + p.dist > dest then
13          return res
14       elseif p.dist < eps then
15          return 0.0
16       else
17          return light_visibility(location + light_dir*p.dist, light_dir, pos+p.dist,
18                                  dest, math.min(res, 30*p.dist/(pos+p.dist)), sdf)
19       end
20    end
21    
22    return function (location, ray_dir, normal, count, sdf)
23       local colour = mapped_pigment(location)
24       local thiscol = {colour[1]*amb, colour[2]*amb, colour[3]*amb}
25
26       local reflected_ray = ray_dir - normal*(ray_dir*normal*2)
27       for _,light in ipairs(lights) do
28          local light_dist = V.norm(light-location)
29          local light_dir = (light-location)/light_dist
30
31          local vis = light_visibility(location + light_dir*eps, light_dir, eps, light_dist, 1, sdf)
32
33          local Idiff = math.max(normal*light_dir, 0)
34          local Ispec = math.pow(math.max(light_dir*reflected_ray,0),shiny)
35             
36          thiscol[1] = thiscol[1] + vis*(colour[1]*Idiff*diff + Ispec*spec)
37          thiscol[2] = thiscol[2] + vis*(colour[2]*Idiff*diff + Ispec*spec)
38          thiscol[3] = thiscol[3] + vis*(colour[3]*Idiff*diff + Ispec*spec)
39       end
40
41       return thiscol
42    end
43 end
44
45 local function make_count_texture(scale)
46    return function (location, ray_dir, normal, count, sdf)
47       return {count*scale, count*scale, count*scale}
48    end
49 end
50
51 local function make_flat_texture(mapped_pigment)
52    return function (location, ray_dir, normal, count, sdf)
53       return mapped_pigment(location)
54    end
55 end
56
57
58 -- Pigments
59
60 local function make_solid_pigment(colour)
61    return function(x,y)
62       return colour
63    end
64 end
65
66 local function make_checkered_pigment(colour1, colour2)
67    return function(x,y)
68       if (x%1 < 0.5 and y%1 < 0.5) or (x%1 > 0.5 and y%1 > 0.5) then
69          return colour1
70       else
71          return colour2
72       end
73    end
74 end
75
76 local function make_mandelbrot_pigment(set_pigment, nonset_pigment, max_iter)
77
78    local function get_col(x,y,cx,cy,iter)
79       if iter == 0 then
80          return set_pigment(cx, cy)
81       elseif x^2 + y^2 > 4 then
82          return nonset_pigment(cx, cy)
83       else
84          return get_col(x^2 - y^2 + cx,
85                         2*x*y + cy,
86                         cx, cy, iter-1)
87       end
88    end
89
90    return function (x,y)
91       return get_col(0,0,x,y,max_iter)
92    end
93 end
94
95 -- Mapping functions
96
97 -- These functions define mappings from 3D world coordinates to 2D
98 -- texture/pigment coordinates
99
100 local function map_rectangular(pigment, xvec, yvec)
101    return function(location)
102       return pigment(location*xvec, location*yvec)
103    end
104 end
105
106 local function map_spherical(pigment, centre, scale_theta, scale_phi)
107    return function(location)
108       local r = location-centre
109       local rnorm = V.norm(r)
110       
111       local phi = math.acos((V.z*r)/rnorm)
112       local theta = math.acos((V.x*r)/V.norm(V.cross(V.z,r)))
113
114       return pigment(theta*scale_theta/math.pi, phi*scale_phi/math.pi)
115    end
116 end
117    
118 Textures = {
119    make_phong_texture = make_phong_texture,
120    make_flat_texture = make_flat_texture,
121    make_count_texture = make_count_texture,
122    make_solid_pigment = make_solid_pigment,
123    make_checkered_pigment = make_checkered_pigment,
124    make_mandelbrot_pigment = make_mandelbrot_pigment,
125    map_rectangular = map_rectangular,
126    map_spherical = map_spherical
127 }
128
129 return Textures