textures, overlay images, libimago
[demo_prior] / sdr / whitted.p.glsl
1 struct Material {
2         vec3 diffuse, specular;
3         float shin;
4 };
5
6 struct HitPoint {
7         float dist;
8         vec3 pos, norm;
9         vec2 surfpos;
10         Material mtl;
11 };
12
13 varying vec3 v_rorg, v_rdir;
14
15
16 vec3 shade(in vec3 ro, in vec3 rd, in HitPoint hit);
17 vec3 backdrop(in vec3 dir);
18
19 bool isect_scene(in vec3 ro, in vec3 rd, out HitPoint hit);
20
21 bool isect_floor(in vec3 ro, in vec3 rd, in vec2 sz, out HitPoint hit);
22 bool isect_plane(in vec3 ro, in vec3 rd, in vec4 plane, out HitPoint hit);
23 bool isect_sphere(in vec3 ro, in vec3 rd, in vec3 pos, float rad, out HitPoint hit);
24
25 vec3 tex_chess(in vec3 col1, in vec3 col2, in vec2 spos);
26
27 const Material mtl_sph = Material(vec3(1.0, 0.0, 0.0), vec3(1.0, 1.0, 1.0), 80.0);
28 const Material mtl_floor = Material(vec3(0.5, 0.5, 0.5), vec3(0.0, 0.0, 0.0), 1.0);
29
30 const vec3 light_pos = vec3(-10, 50, 30);
31
32 void main()
33 {
34         vec3 rdir = normalize(v_rdir);
35         gl_FragColor.rgb = backdrop(rdir);
36
37         HitPoint hit;
38         if(isect_scene(v_rorg, rdir, hit)) {
39                 gl_FragColor.rgb = shade(v_rorg, rdir, hit);
40         } else {
41                 gl_FragColor.rgb = backdrop(rdir);
42         }
43         gl_FragColor.a = 1.0;
44 }
45
46 vec3 shade(in vec3 ro, in vec3 rd, in HitPoint hit)
47 {
48         HitPoint shadow_hit;
49         vec3 ldir = light_pos - hit.pos;
50
51         vec3 col = vec3(0.03, 0.03, 0.03);      // ambient
52
53         if(!isect_scene(hit.pos + hit.norm * 0.01, ldir, shadow_hit) || shadow_hit.dist > 1.0) {
54                 vec3 l = normalize(ldir);
55                 vec3 v = normalize(-rd);
56                 vec3 h = normalize(v + l);
57                 float ndotl = max(dot(hit.norm, l), 0.0);
58                 float ndoth = max(dot(hit.norm, h), 0.0);
59
60                 col += hit.mtl.diffuse * ndotl + hit.mtl.specular * pow(ndoth, hit.mtl.shin);
61         }
62
63         return col;
64 }
65
66 #define M_PI    3.1415926
67 #define M_2PI   (M_PI * 2.0)
68
69 vec3 backdrop(in vec3 dir)
70 {
71         return mix(vec3(0.8, 0.3, 0.2), vec3(0.2, 0.3, 0.8), smoothstep(-0.1, 0.1, dir.y));
72 }
73
74 #define FLOOR_OFFS      vec3(3.0, 0.0, 0.0)
75 #define FLOOR_SIZE      vec2(5.5, 15.0)
76
77 bool isect_scene(in vec3 ro, in vec3 rd, out HitPoint hit_res)
78 {
79         HitPoint hit, nearest;
80
81         nearest.dist = 10000.0;
82
83         if(isect_sphere(ro, rd, vec3(1.0, 0.0, 0.0), 1.0, hit)) {
84                 nearest = hit;
85                 nearest.mtl = mtl_sph;
86         }
87
88         if(isect_floor(ro, rd, FLOOR_SIZE, hit) && hit.dist < nearest.dist) {
89                 nearest = hit;
90                 nearest.mtl = mtl_floor;
91                 nearest.mtl.diffuse = tex_chess(vec3(1.0, 0.0, 0.0), vec3(1.0, 1.0, 0.0), hit.surfpos);
92         }
93
94         if(nearest.dist >= 10000.0) {
95                 return false;
96         }
97
98         hit_res = nearest;
99         return true;
100 }
101
102 bool isect_floor(in vec3 ro, in vec3 rd, in vec2 sz, out HitPoint hit)
103 {
104         if(!isect_plane(ro - FLOOR_OFFS, rd, vec4(0.0, 1.0, 0.0, -1.8), hit)) {
105                 return false;
106         }
107
108         if(abs(hit.pos.x) >= sz.x || abs(hit.pos.z) >= sz.y) {
109                 return false;
110         }
111
112         hit.pos += FLOOR_OFFS;
113         hit.surfpos /= sz * 2.0;
114         return true;
115 }
116
117 bool isect_plane(in vec3 ro, in vec3 rd, in vec4 plane, out HitPoint hit)
118 {
119         float ndotrd = dot(rd, plane.xyz);
120
121         if(abs(ndotrd) < 1e-6) {
122                 return false;
123         }
124
125         vec3 pp = plane.xyz * plane.w;
126         vec3 pdir = pp - ro;
127         float t = dot(pdir, plane.xyz) / ndotrd;
128
129         if(t < 1e-6) {
130                 return false;
131         }
132
133         hit.dist = t;
134         hit.pos = ro + rd * t;
135         hit.norm = plane.xyz;
136         hit.surfpos = hit.pos.xz;       /* XXX */
137         return true;
138 }
139
140 bool isect_sphere(in vec3 ro, in vec3 rd, in vec3 pos, float rad, out HitPoint hit)
141 {
142         float a = dot(rd, rd);
143         float b = dot(rd * 2.0, (ro - pos));
144         float c = dot(ro, ro) + dot(pos, pos) - 2.0 * dot(ro, pos) - rad * rad;
145
146         float d = b * b - 4.0 * a * c;
147         if(d < 1e-6) {
148                 return false;
149         }
150
151         float t0 = (-b + sqrt(d)) / (2.0 * a);
152         float t1 = (-b - sqrt(d)) / (2.0 * a);
153
154         if(t0 < 0.0) t0 = t1;
155         if(t1 < 0.0) t1 = t0;
156         float t = min(t0, t1);
157
158         if(t < 1e-6) {
159                 return false;
160         }
161
162         hit.dist = t;
163         hit.pos = ro + rd * t;
164         hit.norm = normalize(hit.pos - pos);
165         hit.surfpos.x = atan(hit.norm.z, hit.norm.x);
166         hit.surfpos.y = acos(hit.norm.y);
167         return true;
168 }
169
170 vec3 tex_chess(in vec3 col1, in vec3 col2, in vec2 spos)
171 {
172         float foo = step(0.5, mod(spos.x * 8.0, 1.0)) * 2.0 - 1.0;
173         float bar = step(0.5, mod(spos.y * 24.0, 1.0)) * 2.0 - 1.0;
174
175         float xor = (foo * bar) * 0.5 + 0.5;
176
177         return mix(col1, col2, xor);
178 }