rev |
line source |
nuclear@0
|
1 /* vi:set filetype=glsl ts=4 sw=4: */
|
nuclear@0
|
2 #version 120
|
nuclear@0
|
3 #extension GL_ARB_gpu_shader5 : enable
|
nuclear@0
|
4
|
nuclear@0
|
5 #define M_PI 3.1415926
|
nuclear@0
|
6
|
nuclear@0
|
7 #define INIT_EVERYTHING
|
nuclear@0
|
8 #define USE_XFORM
|
nuclear@0
|
9 #define OBJ_LINE_WIDTH 16.0
|
nuclear@0
|
10
|
nuclear@0
|
11 struct Ray {
|
nuclear@0
|
12 vec3 origin, dir;
|
nuclear@0
|
13 };
|
nuclear@0
|
14
|
nuclear@0
|
15 struct Material {
|
nuclear@0
|
16 vec3 diffuse, specular;
|
nuclear@0
|
17 float shininess;
|
nuclear@0
|
18 vec4 megatex_rect;
|
nuclear@0
|
19 float reflectivity;
|
nuclear@0
|
20 };
|
nuclear@0
|
21
|
nuclear@0
|
22 struct HitPoint {
|
nuclear@0
|
23 float dist;
|
nuclear@0
|
24 vec3 pos, normal;
|
nuclear@0
|
25 vec2 texcoord;
|
nuclear@0
|
26 struct Material mat;
|
nuclear@0
|
27 };
|
nuclear@0
|
28
|
nuclear@0
|
29 struct Sphere {
|
nuclear@0
|
30 float index;
|
nuclear@0
|
31 vec3 pos;
|
nuclear@0
|
32 float radius;
|
nuclear@0
|
33 struct Material mat;
|
nuclear@0
|
34 };
|
nuclear@0
|
35
|
nuclear@0
|
36 struct Plane {
|
nuclear@0
|
37 float index;
|
nuclear@0
|
38 vec3 normal;
|
nuclear@0
|
39 float dist;
|
nuclear@0
|
40 struct Material mat;
|
nuclear@0
|
41 };
|
nuclear@0
|
42
|
nuclear@0
|
43 struct Box {
|
nuclear@0
|
44 float index;
|
nuclear@0
|
45 vec3 min, max;
|
nuclear@0
|
46 struct Material mat;
|
nuclear@0
|
47 };
|
nuclear@0
|
48
|
nuclear@4
|
49 struct Cone {
|
nuclear@4
|
50 float index;
|
nuclear@4
|
51 float angle;
|
nuclear@4
|
52 float start, end;
|
nuclear@4
|
53 struct Material mat;
|
nuclear@4
|
54 };
|
nuclear@4
|
55
|
nuclear@0
|
56 struct Light {
|
nuclear@0
|
57 vec3 pos, color;
|
nuclear@0
|
58 };
|
nuclear@0
|
59
|
nuclear@0
|
60 vec3 shade(in Ray ray, in HitPoint hit);
|
nuclear@0
|
61 bool find_intersection(in Ray ray, out HitPoint hit);
|
nuclear@0
|
62 bool sphere_intersect(in Sphere sph, in Ray ray, out HitPoint pt);
|
nuclear@0
|
63 bool plane_intersect(in Plane plane, in Ray ray, out HitPoint pt);
|
nuclear@0
|
64 bool box_intersect(in Box box, in Ray ray, out HitPoint pt);
|
nuclear@4
|
65 bool cone_intersect(in Cone cone, in Ray ray, out HitPoint pt);
|
nuclear@0
|
66 vec3 transform(in vec3 v, in mat4 inv_xform);
|
nuclear@0
|
67 Ray transform(in Ray ray, in mat4 xform, in mat4 inv_xform);
|
nuclear@0
|
68 Ray get_primary_ray();
|
nuclear@0
|
69
|
nuclear@0
|
70 Sphere read_sphere(in float idx);
|
nuclear@0
|
71 Plane read_plane(in float idx);
|
nuclear@0
|
72 Box read_box(in float idx);
|
nuclear@4
|
73 Cone read_cone(in float idx);
|
nuclear@0
|
74 Material read_material(in sampler2D tex, in float ty);
|
nuclear@0
|
75 void read_xform(in float idx, out mat4 xform, out mat4 inv_xform);
|
nuclear@0
|
76
|
nuclear@0
|
77 uniform sampler2D tex_raydir;
|
nuclear@4
|
78 uniform sampler2D tex_spheres, tex_planes, tex_boxes, tex_cones;
|
nuclear@0
|
79 uniform sampler2D tex_megatex;
|
nuclear@0
|
80 uniform sampler2D tex_xforms;
|
nuclear@0
|
81 uniform samplerCube tex_env;
|
nuclear@0
|
82 uniform vec2 fog;
|
nuclear@0
|
83
|
nuclear@0
|
84 uniform Light lights[8];
|
nuclear@0
|
85 uniform int num_lights;
|
nuclear@0
|
86
|
nuclear@4
|
87 int num_spheres, num_planes, num_boxes, num_cones;
|
nuclear@4
|
88 float sph_tex_sz, plane_tex_sz, box_tex_sz, cone_tex_sz, xform_tex_sz;
|
nuclear@0
|
89
|
nuclear@0
|
90 #ifdef INIT_EVERYTHING
|
nuclear@0
|
91 Material default_material;
|
nuclear@0
|
92 #endif
|
nuclear@0
|
93
|
nuclear@0
|
94 void main()
|
nuclear@0
|
95 {
|
nuclear@0
|
96 #ifdef INIT_EVERYTHING
|
nuclear@0
|
97 default_material.diffuse = default_material.specular = vec3(0.0, 0.0, 0.0);
|
nuclear@0
|
98 default_material.shininess = 1.0;
|
nuclear@0
|
99 default_material.reflectivity = 0.0;
|
nuclear@0
|
100 default_material.megatex_rect = vec4(0.0, 0.0, 0.0, 0.0);
|
nuclear@0
|
101 #endif
|
nuclear@0
|
102
|
nuclear@0
|
103 Ray ray = get_primary_ray();
|
nuclear@0
|
104
|
nuclear@0
|
105 /* read the various descriptors specifying dimensions and counts for
|
nuclear@0
|
106 * all the relevant data textures
|
nuclear@0
|
107 */
|
nuclear@0
|
108 vec4 desc = texture2D(tex_spheres, vec2(0.0, 0.0));
|
nuclear@0
|
109 num_spheres = int(desc.x);
|
nuclear@0
|
110 sph_tex_sz = desc.y;
|
nuclear@0
|
111
|
nuclear@0
|
112 desc = texture2D(tex_planes, vec2(0.0, 0.0));
|
nuclear@0
|
113 num_planes = int(desc.x);
|
nuclear@0
|
114 plane_tex_sz = desc.y;
|
nuclear@0
|
115
|
nuclear@0
|
116 desc = texture2D(tex_boxes, vec2(0.0, 0.0));
|
nuclear@0
|
117 num_boxes = int(desc.x);
|
nuclear@0
|
118 box_tex_sz = desc.y;
|
nuclear@0
|
119
|
nuclear@4
|
120 desc = texture2D(tex_cones, vec2(0.0, 0.0));
|
nuclear@4
|
121 num_cones = int(desc.x);
|
nuclear@4
|
122 cone_tex_sz = desc.y;
|
nuclear@4
|
123
|
nuclear@0
|
124 xform_tex_sz = texture2D(tex_xforms, vec2(0.0, 0.0)).x;
|
nuclear@0
|
125
|
nuclear@0
|
126
|
nuclear@0
|
127 HitPoint hit;
|
nuclear@0
|
128 #ifdef INIT_EVERYTHING
|
nuclear@0
|
129 hit.dist = 0.0;
|
nuclear@0
|
130 hit.pos = hit.normal = vec3(0.0, 0.0, 0.0);
|
nuclear@0
|
131 #endif
|
nuclear@0
|
132
|
nuclear@0
|
133 vec3 color = vec3(0.0, 0.0, 0.0);
|
nuclear@0
|
134 float energy = 1.0;
|
nuclear@0
|
135
|
nuclear@0
|
136 int iter = 0;
|
nuclear@0
|
137 while(energy > 0.01 && iter++ < 4) {
|
nuclear@0
|
138 vec3 envcol = textureCube(tex_env, ray.dir).xyz;
|
nuclear@0
|
139
|
nuclear@0
|
140 if(find_intersection(ray, hit)) {
|
nuclear@0
|
141 float fog_t = clamp((hit.dist - fog.x) / (fog.y - fog.x), 0.0, 1.0);
|
nuclear@0
|
142 color += mix(shade(ray, hit), envcol, fog_t) * energy;
|
nuclear@0
|
143 energy *= hit.mat.reflectivity * (1.0 - fog_t);
|
nuclear@0
|
144 ray.origin = hit.pos;
|
nuclear@0
|
145 ray.dir = reflect(ray.dir, hit.normal);
|
nuclear@0
|
146 } else {
|
nuclear@0
|
147 color += envcol * energy;
|
nuclear@0
|
148 energy = 0.0;
|
nuclear@0
|
149 iter = 100;
|
nuclear@0
|
150 }
|
nuclear@0
|
151 }
|
nuclear@0
|
152
|
nuclear@0
|
153 gl_FragColor.xyz = color;
|
nuclear@0
|
154 gl_FragColor.w = 1.0;
|
nuclear@0
|
155 }
|
nuclear@0
|
156
|
nuclear@0
|
157 vec3 shade(in Ray ray, in HitPoint hit)
|
nuclear@0
|
158 {
|
nuclear@0
|
159 vec3 normal = faceforward(hit.normal, ray.dir, hit.normal);
|
nuclear@0
|
160
|
nuclear@0
|
161 vec3 vdir = normalize(ray.dir);
|
nuclear@0
|
162 vec3 vref = reflect(vdir, normal);
|
nuclear@0
|
163
|
nuclear@0
|
164 /* if there's no texture rect.zw will be (0, 0, 0, 0) so this will map onto
|
nuclear@0
|
165 * the top-left 1x1 null texture which is all white (having no effect)
|
nuclear@0
|
166 */
|
nuclear@0
|
167 vec2 tc = mod(hit.texcoord, vec2(1.0, 1.0)) * hit.mat.megatex_rect.zw + hit.mat.megatex_rect.xy;
|
nuclear@0
|
168
|
nuclear@0
|
169 vec3 diffuse_color = hit.mat.diffuse * texture2D(tex_megatex, tc).xyz;
|
nuclear@0
|
170
|
nuclear@0
|
171 vec3 color = vec3(0.0, 0.0, 0.0);
|
nuclear@0
|
172 for(int i=0; i<num_lights; i++) {
|
nuclear@0
|
173 Ray shadow_ray;
|
nuclear@0
|
174 shadow_ray.origin = hit.pos;
|
nuclear@0
|
175 shadow_ray.dir = lights[i].pos - hit.pos;
|
nuclear@0
|
176
|
nuclear@0
|
177 HitPoint shadow_hit;
|
nuclear@0
|
178 if(!find_intersection(shadow_ray, shadow_hit) || shadow_hit.dist > 1.0) {
|
nuclear@0
|
179 vec3 ldir = normalize(shadow_ray.dir);
|
nuclear@0
|
180
|
nuclear@0
|
181 float diffuse = max(dot(ldir, normal), 0.0);
|
nuclear@0
|
182 float specular = pow(max(dot(ldir, vref), 0.0), hit.mat.shininess);
|
nuclear@0
|
183
|
nuclear@0
|
184 color += (diffuse_color * diffuse + hit.mat.specular * specular) * lights[i].color;
|
nuclear@0
|
185 }
|
nuclear@0
|
186 }
|
nuclear@0
|
187
|
nuclear@0
|
188 return color;
|
nuclear@0
|
189 }
|
nuclear@0
|
190
|
nuclear@0
|
191 bool find_intersection(in Ray ray, out HitPoint hit)
|
nuclear@0
|
192 {
|
nuclear@0
|
193 hit.dist = 100000.0;
|
nuclear@0
|
194 #ifdef INIT_EVERYTHING
|
nuclear@0
|
195 hit.pos = hit.normal = vec3(0.0, 0.0, 0.0);
|
nuclear@0
|
196 hit.mat = default_material;
|
nuclear@0
|
197 hit.texcoord = vec2(0.0, 0.0);
|
nuclear@0
|
198 #endif
|
nuclear@0
|
199 bool found = false;
|
nuclear@0
|
200
|
nuclear@0
|
201 for(int i=0; i<num_spheres; i++) {
|
nuclear@0
|
202 Sphere sph = read_sphere(i);
|
nuclear@0
|
203
|
nuclear@0
|
204 HitPoint tmphit;
|
nuclear@0
|
205 if(sphere_intersect(sph, ray, tmphit) && tmphit.dist < hit.dist) {
|
nuclear@0
|
206 hit = tmphit;
|
nuclear@0
|
207 found = true;
|
nuclear@0
|
208 }
|
nuclear@0
|
209 }
|
nuclear@0
|
210
|
nuclear@0
|
211 for(int i=0; i<num_planes; i++) {
|
nuclear@0
|
212 Plane plane = read_plane(i);
|
nuclear@0
|
213
|
nuclear@0
|
214 HitPoint tmphit;
|
nuclear@0
|
215 if(plane_intersect(plane, ray, tmphit) && tmphit.dist < hit.dist) {
|
nuclear@0
|
216 hit = tmphit;
|
nuclear@0
|
217 found = true;
|
nuclear@0
|
218 }
|
nuclear@0
|
219 }
|
nuclear@0
|
220
|
nuclear@0
|
221 for(int i=0; i<num_boxes; i++) {
|
nuclear@0
|
222 Box box = read_box(i);
|
nuclear@0
|
223
|
nuclear@0
|
224 HitPoint tmphit;
|
nuclear@0
|
225 if(box_intersect(box, ray, tmphit) && tmphit.dist < hit.dist) {
|
nuclear@0
|
226 hit = tmphit;
|
nuclear@0
|
227 found = true;
|
nuclear@0
|
228 }
|
nuclear@0
|
229 }
|
nuclear@0
|
230
|
nuclear@4
|
231 for(int i=0; i<num_cones; i++) {
|
nuclear@4
|
232 Cone cone = read_cone(i);
|
nuclear@4
|
233
|
nuclear@4
|
234 HitPoint tmphit;
|
nuclear@4
|
235 if(cone_intersect(cone, ray, tmphit) && tmphit.dist < hit.dist) {
|
nuclear@4
|
236 hit = tmphit;
|
nuclear@4
|
237 found = true;
|
nuclear@4
|
238 }
|
nuclear@4
|
239 }
|
nuclear@4
|
240
|
nuclear@0
|
241 return found;
|
nuclear@0
|
242 }
|
nuclear@0
|
243
|
nuclear@0
|
244 #define EPSILON 1e-4
|
nuclear@0
|
245 #define SQ(x) ((x) * (x))
|
nuclear@0
|
246
|
nuclear@0
|
247 bool sphere_intersect(in Sphere sph, in Ray inray, out HitPoint pt)
|
nuclear@0
|
248 {
|
nuclear@0
|
249 #ifdef USE_XFORM
|
nuclear@0
|
250 mat4 xform, inv_xform;
|
nuclear@0
|
251 read_xform(sph.index, xform, inv_xform);
|
nuclear@0
|
252
|
nuclear@0
|
253 Ray ray = transform(inray, inv_xform, xform);
|
nuclear@0
|
254 #else
|
nuclear@0
|
255 Ray ray = inray;
|
nuclear@0
|
256 #endif
|
nuclear@0
|
257
|
nuclear@0
|
258 #ifdef INIT_EVERYTHING
|
nuclear@0
|
259 pt.dist = 0.0;
|
nuclear@0
|
260 pt.pos = pt.normal = vec3(0.0, 0.0, 0.0);
|
nuclear@0
|
261 pt.mat = default_material;
|
nuclear@0
|
262 pt.texcoord = vec2(0.0, 0.0);
|
nuclear@0
|
263 #endif
|
nuclear@0
|
264
|
nuclear@0
|
265 float a = dot(ray.dir, ray.dir);
|
nuclear@0
|
266 float b = dot(ray.dir, ray.origin - sph.pos) * 2.0;
|
nuclear@0
|
267 float c = dot(ray.origin, ray.origin) + dot(sph.pos, sph.pos) -
|
nuclear@0
|
268 2.0 * dot(ray.origin, sph.pos) - sph.radius * sph.radius;
|
nuclear@0
|
269
|
nuclear@0
|
270 float discr = b * b - 4.0 * a * c;
|
nuclear@0
|
271 if(discr < EPSILON)
|
nuclear@0
|
272 return false;
|
nuclear@0
|
273
|
nuclear@0
|
274 float sqrt_discr = sqrt(discr);
|
nuclear@0
|
275 float t0 = (-b + sqrt_discr) / (2.0 * a);
|
nuclear@0
|
276 float t1 = (-b - sqrt_discr) / (2.0 * a);
|
nuclear@0
|
277
|
nuclear@0
|
278 if(t0 < EPSILON)
|
nuclear@0
|
279 t0 = t1;
|
nuclear@0
|
280 if(t1 < EPSILON)
|
nuclear@0
|
281 t1 = t0;
|
nuclear@0
|
282
|
nuclear@0
|
283 float t = min(t0, t1);
|
nuclear@0
|
284 if(t < EPSILON)
|
nuclear@0
|
285 return false;
|
nuclear@0
|
286
|
nuclear@0
|
287 // fill the HitPoint structure
|
nuclear@0
|
288 pt.dist = t;
|
nuclear@0
|
289 pt.pos = ray.origin + ray.dir * t;
|
nuclear@0
|
290 pt.normal = (pt.pos - sph.pos) / sph.radius;
|
nuclear@0
|
291 pt.mat = sph.mat;
|
nuclear@0
|
292
|
nuclear@0
|
293 pt.texcoord.x = 0.5 * atan(pt.normal.z, pt.normal.x) / M_PI + 0.5;
|
nuclear@0
|
294 pt.texcoord.y = acos(pt.normal.y) / M_PI;
|
nuclear@0
|
295
|
nuclear@0
|
296 #ifdef USE_XFORM
|
nuclear@0
|
297 pt.pos = (xform * vec4(pt.pos, 1.0)).xyz;
|
nuclear@0
|
298 pt.normal = normalize(transform(pt.normal, xform));
|
nuclear@0
|
299 #endif
|
nuclear@0
|
300 return true;
|
nuclear@0
|
301 }
|
nuclear@0
|
302
|
nuclear@0
|
303 bool plane_intersect(in Plane plane, in Ray inray, out HitPoint pt)
|
nuclear@0
|
304 {
|
nuclear@0
|
305 #ifdef USE_XFORM
|
nuclear@0
|
306 mat4 xform, inv_xform;
|
nuclear@0
|
307 read_xform(plane.index, xform, inv_xform);
|
nuclear@0
|
308
|
nuclear@0
|
309 Ray ray = transform(inray, inv_xform, xform);
|
nuclear@0
|
310 #else
|
nuclear@0
|
311 Ray ray = inray;
|
nuclear@0
|
312 #endif
|
nuclear@0
|
313
|
nuclear@0
|
314 #ifdef INIT_EVERYTHING
|
nuclear@0
|
315 pt.dist = 0.0;
|
nuclear@0
|
316 pt.pos = pt.normal = vec3(0.0, 0.0, 0.0);
|
nuclear@0
|
317 pt.mat = default_material;
|
nuclear@0
|
318 pt.texcoord = vec2(0.0, 0.0);
|
nuclear@0
|
319 #endif
|
nuclear@0
|
320
|
nuclear@0
|
321 float ndotdir = dot(plane.normal, ray.dir);
|
nuclear@0
|
322 if(abs(ndotdir) < EPSILON) {
|
nuclear@0
|
323 return false;
|
nuclear@0
|
324 }
|
nuclear@0
|
325
|
nuclear@0
|
326 vec3 planept = plane.normal * plane.dist;
|
nuclear@0
|
327 vec3 pptdir = planept - ray.origin;
|
nuclear@0
|
328
|
nuclear@0
|
329 float t = dot(plane.normal, pptdir) / ndotdir;
|
nuclear@0
|
330 if(t < EPSILON) {
|
nuclear@0
|
331 return false;
|
nuclear@0
|
332 }
|
nuclear@0
|
333
|
nuclear@0
|
334 pt.dist = t;
|
nuclear@0
|
335 pt.pos = ray.origin + ray.dir * t;
|
nuclear@0
|
336 pt.normal = plane.normal;
|
nuclear@0
|
337 pt.mat = plane.mat;
|
nuclear@0
|
338 pt.texcoord.x = pt.pos.x;
|
nuclear@0
|
339 pt.texcoord.y = pt.pos.z;
|
nuclear@0
|
340
|
nuclear@0
|
341 #ifdef USE_XFORM
|
nuclear@0
|
342 pt.pos = (xform * vec4(pt.pos, 1.0)).xyz;
|
nuclear@0
|
343 pt.normal = normalize(transform(pt.normal, xform));
|
nuclear@0
|
344 #endif
|
nuclear@0
|
345 return true;
|
nuclear@0
|
346 }
|
nuclear@0
|
347
|
nuclear@0
|
348 bool box_intersect(in Box box, in Ray inray, out HitPoint pt)
|
nuclear@0
|
349 {
|
nuclear@0
|
350 #ifdef USE_XFORM
|
nuclear@0
|
351 mat4 xform, inv_xform;
|
nuclear@0
|
352 read_xform(box.index, xform, inv_xform);
|
nuclear@0
|
353
|
nuclear@0
|
354 Ray ray = transform(inray, inv_xform, xform);
|
nuclear@0
|
355 #else
|
nuclear@0
|
356 Ray ray = inray;
|
nuclear@0
|
357 #endif
|
nuclear@0
|
358
|
nuclear@0
|
359 #ifdef INIT_EVERYTHING
|
nuclear@0
|
360 pt.dist = 0.0;
|
nuclear@0
|
361 pt.pos = pt.normal = vec3(0.0, 0.0, 0.0);
|
nuclear@0
|
362 pt.mat = default_material;
|
nuclear@0
|
363 pt.texcoord = vec2(0.0, 0.0);
|
nuclear@0
|
364 #endif
|
nuclear@0
|
365
|
nuclear@0
|
366 vec3 param[2];
|
nuclear@0
|
367 param[0] = box.min;
|
nuclear@0
|
368 param[1] = box.max;
|
nuclear@0
|
369
|
nuclear@0
|
370 vec3 inv_dir = 1.0 / ray.dir;
|
nuclear@0
|
371 int sgn[3];
|
nuclear@0
|
372 sgn[0] = inv_dir.x < 0.0 ? 1 : 0;
|
nuclear@0
|
373 sgn[1] = inv_dir.y < 0.0 ? 1 : 0;
|
nuclear@0
|
374 sgn[2] = inv_dir.z < 0.0 ? 1 : 0;
|
nuclear@0
|
375
|
nuclear@0
|
376 float tmin = (param[sgn[0]].x - ray.origin.x) * inv_dir.x;
|
nuclear@0
|
377 float tmax = (param[1 - sgn[0]].x - ray.origin.x) * inv_dir.x;
|
nuclear@0
|
378 float tymin = (param[sgn[1]].y - ray.origin.y) * inv_dir.y;
|
nuclear@0
|
379 float tymax = (param[1 - sgn[1]].y - ray.origin.y) * inv_dir.y;
|
nuclear@0
|
380
|
nuclear@0
|
381 pt.normal = vec3(ray.origin.x > 0.0 ? 1.0 : -1.0, 0.0, 0.0);
|
nuclear@0
|
382
|
nuclear@0
|
383 if(tmin > tymax || tymin > tmax) {
|
nuclear@0
|
384 return false;
|
nuclear@0
|
385 }
|
nuclear@0
|
386 if(tymin > tmin) {
|
nuclear@0
|
387 pt.normal = vec3(0.0, ray.origin.y > 0.0 ? 1.0 : -1.0, 0.0);
|
nuclear@0
|
388 tmin = tymin;
|
nuclear@0
|
389 }
|
nuclear@0
|
390 if(tymax < tmax) {
|
nuclear@0
|
391 tmax = tymax;
|
nuclear@0
|
392 }
|
nuclear@0
|
393
|
nuclear@0
|
394 float tzmin = (param[sgn[2]].z - ray.origin.z) * inv_dir.z;
|
nuclear@0
|
395 float tzmax = (param[1 - sgn[2]].z - ray.origin.z) * inv_dir.z;
|
nuclear@0
|
396
|
nuclear@0
|
397 if(tmin > tzmax || tzmin > tmax) {
|
nuclear@0
|
398 return false;
|
nuclear@0
|
399 }
|
nuclear@0
|
400 if(tzmin > tmin) {
|
nuclear@0
|
401 pt.normal = vec3(0.0, 0.0, ray.origin.z > 0.0 ? 1.0 : -1.0);
|
nuclear@0
|
402 tmin = tzmin;
|
nuclear@0
|
403 }
|
nuclear@0
|
404 if(tzmax < tmax) {
|
nuclear@0
|
405 tmax = tzmax;
|
nuclear@0
|
406 }
|
nuclear@0
|
407
|
nuclear@0
|
408 float t = tmin < EPSILON ? tmax : tmin;
|
nuclear@0
|
409 if(t >= 1e-4) {
|
nuclear@0
|
410 pt.dist = t;
|
nuclear@0
|
411 pt.pos = ray.origin + ray.dir * t;
|
nuclear@0
|
412 pt.mat = box.mat;
|
nuclear@0
|
413
|
nuclear@0
|
414 float min_dist = 10000.0;
|
nuclear@0
|
415
|
nuclear@0
|
416 vec3 offs = box.min + (box.max - box.min) / 2.0;
|
nuclear@0
|
417 vec3 local_pt = pt.pos - offs;
|
nuclear@0
|
418
|
nuclear@0
|
419 vec3 dist = abs((box.max - offs) - abs(local_pt));
|
nuclear@0
|
420 if(dist.x < min_dist) {
|
nuclear@0
|
421 min_dist = dist.x;
|
nuclear@0
|
422 pt.normal = sign(local_pt.x) * vec3(1.0, 0.0, 0.0);
|
nuclear@0
|
423 pt.texcoord = pt.pos.zy;
|
nuclear@0
|
424 }
|
nuclear@0
|
425 if(dist.y < min_dist) {
|
nuclear@0
|
426 min_dist = dist.y;
|
nuclear@0
|
427 pt.normal = sign(local_pt.y) * vec3(0.0, 1.0, 0.0);
|
nuclear@0
|
428 pt.texcoord = pt.pos.xz;
|
nuclear@0
|
429 }
|
nuclear@0
|
430 if(dist.z < min_dist) {
|
nuclear@0
|
431 pt.normal = sign(local_pt.y) * vec3(0.0, 0.0, 1.0);
|
nuclear@0
|
432 pt.texcoord = pt.pos.xy;
|
nuclear@0
|
433 }
|
nuclear@0
|
434
|
nuclear@0
|
435
|
nuclear@0
|
436 #ifdef USE_XFORM
|
nuclear@0
|
437 pt.pos = (xform * vec4(pt.pos, 1.0)).xyz;
|
nuclear@0
|
438 pt.normal = normalize(transform(pt.normal, xform));
|
nuclear@0
|
439 #endif
|
nuclear@0
|
440 return true;
|
nuclear@0
|
441 }
|
nuclear@0
|
442 return false;
|
nuclear@0
|
443 }
|
nuclear@0
|
444
|
nuclear@4
|
445 bool cone_intersect(in Cone cone, in Ray inray, out HitPoint pt)
|
nuclear@4
|
446 {
|
nuclear@4
|
447 #ifdef USE_XFORM
|
nuclear@4
|
448 mat4 xform, inv_xform;
|
nuclear@4
|
449 read_xform(cone.index, xform, inv_xform);
|
nuclear@4
|
450
|
nuclear@4
|
451 Ray ray = transform(inray, inv_xform, xform);
|
nuclear@4
|
452 #else
|
nuclear@4
|
453 Ray ray = inray;
|
nuclear@4
|
454 #endif
|
nuclear@4
|
455
|
nuclear@4
|
456 #ifdef INIT_EVERYTHING
|
nuclear@4
|
457 pt.dist = 0.0;
|
nuclear@4
|
458 pt.pos = pt.normal = vec3(0.0, 0.0, 0.0);
|
nuclear@4
|
459 pt.mat = default_material;
|
nuclear@4
|
460 pt.texcoord = vec2(0.0, 0.0);
|
nuclear@4
|
461 #endif
|
nuclear@4
|
462
|
nuclear@4
|
463 float slope = 2.0 * cone.angle / M_PI;
|
nuclear@4
|
464
|
nuclear@4
|
465 float a = SQ(ray.dir.x) - SQ(slope * ray.dir.y) + SQ(ray.dir.z);
|
nuclear@4
|
466 float b = 2.0 * ray.origin.x * ray.dir.x - 2.0 * SQ(slope) * ray.origin.y * ray.dir.y +
|
nuclear@4
|
467 2.0 * ray.origin.z * ray.dir.z;
|
nuclear@4
|
468 float c = SQ(ray.origin.x) - SQ(slope * ray.origin.y) + SQ(ray.origin.z);
|
nuclear@4
|
469
|
nuclear@4
|
470 float discr = b * b - 4.0 * a * c;
|
nuclear@4
|
471 if(discr < EPSILON)
|
nuclear@4
|
472 return false;
|
nuclear@4
|
473
|
nuclear@4
|
474 float sqrt_discr = sqrt(discr);
|
nuclear@4
|
475 float t0 = (-b + sqrt_discr) / (2.0 * a);
|
nuclear@4
|
476 float t1 = (-b - sqrt_discr) / (2.0 * a);
|
nuclear@4
|
477
|
nuclear@4
|
478 if(t0 < EPSILON)
|
nuclear@4
|
479 t0 = t1;
|
nuclear@4
|
480 if(t1 < EPSILON)
|
nuclear@4
|
481 t1 = t0;
|
nuclear@4
|
482
|
nuclear@4
|
483 float t = min(t0, t1);
|
nuclear@4
|
484 if(t < EPSILON)
|
nuclear@4
|
485 return false;
|
nuclear@4
|
486
|
nuclear@4
|
487 // fill the HitPoint structure
|
nuclear@4
|
488 pt.dist = t;
|
nuclear@4
|
489 pt.pos = ray.origin + ray.dir * t;
|
nuclear@4
|
490
|
nuclear@4
|
491 if(pt.pos.y < cone.start || pt.pos.y >= cone.end) {
|
nuclear@4
|
492 return false;
|
nuclear@4
|
493 }
|
nuclear@4
|
494
|
nuclear@4
|
495 float radius = pt.pos.y * slope;
|
nuclear@4
|
496 pt.normal = vec3(pt.pos.x, 0.0, pt.pos.z) / radius;
|
nuclear@4
|
497
|
nuclear@4
|
498 float ny = sin(cone.angle);
|
nuclear@4
|
499 float xzlen = sqrt(1.0 - ny * ny);
|
nuclear@4
|
500 pt.normal.x *= xzlen;
|
nuclear@4
|
501 pt.normal.y = ny;
|
nuclear@4
|
502 pt.normal.z *= xzlen;
|
nuclear@4
|
503
|
nuclear@4
|
504 pt.mat = cone.mat;
|
nuclear@4
|
505
|
nuclear@4
|
506 pt.texcoord.x = 0.5 * atan(pt.normal.z, pt.normal.x) / M_PI + 0.5;
|
nuclear@4
|
507 pt.texcoord.y = (pt.pos.y - cone.start) / (cone.end - cone.start);
|
nuclear@4
|
508
|
nuclear@4
|
509 #ifdef USE_XFORM
|
nuclear@4
|
510 pt.pos = (xform * vec4(pt.pos, 1.0)).xyz;
|
nuclear@4
|
511 pt.normal = normalize(transform(pt.normal, xform));
|
nuclear@4
|
512 #endif
|
nuclear@4
|
513 return true;
|
nuclear@4
|
514 }
|
nuclear@4
|
515
|
nuclear@0
|
516 vec3 transform(in vec3 v, in mat4 xform)
|
nuclear@0
|
517 {
|
nuclear@0
|
518 return mat3(xform) * v;
|
nuclear@0
|
519 }
|
nuclear@0
|
520
|
nuclear@0
|
521 Ray transform(in Ray ray, in mat4 xform, in mat4 inv_xform)
|
nuclear@0
|
522 {
|
nuclear@0
|
523 Ray res;
|
nuclear@0
|
524 res.origin = (xform * vec4(ray.origin, 1.0)).xyz;
|
nuclear@0
|
525 res.dir = transform(ray.dir, xform);
|
nuclear@0
|
526 return res;
|
nuclear@0
|
527 }
|
nuclear@0
|
528
|
nuclear@0
|
529 Ray get_primary_ray()
|
nuclear@0
|
530 {
|
nuclear@0
|
531 Ray ray;
|
nuclear@0
|
532 ray.origin = (gl_ModelViewMatrix * vec4(0.0, 0.0, 0.0, 1.0)).xyz;
|
nuclear@0
|
533 vec3 dir = texture2D(tex_raydir, gl_TexCoord[0].st).xyz;
|
nuclear@0
|
534 ray.dir = normalize(gl_NormalMatrix * dir);
|
nuclear@0
|
535 return ray;
|
nuclear@0
|
536 }
|
nuclear@0
|
537
|
nuclear@0
|
538 #define ITEM(x) ((float(x) + 0.5) / OBJ_LINE_WIDTH)
|
nuclear@0
|
539
|
nuclear@0
|
540 Sphere read_sphere(in float idx)
|
nuclear@0
|
541 {
|
nuclear@0
|
542 Sphere sph;
|
nuclear@0
|
543 // +1 because the first scanline is the descriptor
|
nuclear@0
|
544 float ty = (idx + 1.0) / sph_tex_sz;
|
nuclear@0
|
545
|
nuclear@0
|
546 sph.index = texture2D(tex_spheres, vec2(ITEM(0), ty)).x;
|
nuclear@0
|
547
|
nuclear@0
|
548 vec4 texel = texture2D(tex_spheres, vec2(ITEM(1), ty));
|
nuclear@0
|
549 sph.pos = texel.xyz;
|
nuclear@0
|
550 sph.radius = texel.w;
|
nuclear@0
|
551
|
nuclear@0
|
552 sph.mat = read_material(tex_spheres, ty);
|
nuclear@0
|
553 return sph;
|
nuclear@0
|
554 }
|
nuclear@0
|
555
|
nuclear@0
|
556 Plane read_plane(in float idx)
|
nuclear@0
|
557 {
|
nuclear@0
|
558 Plane plane;
|
nuclear@0
|
559 // +1 (see above)
|
nuclear@0
|
560 float ty = (idx + 1.0) / plane_tex_sz;
|
nuclear@0
|
561
|
nuclear@0
|
562 plane.index = texture2D(tex_planes, vec2(ITEM(0), ty)).x;
|
nuclear@0
|
563
|
nuclear@0
|
564 vec4 texel = texture2D(tex_planes, vec2(ITEM(1), ty));
|
nuclear@0
|
565 plane.normal = texel.xyz;
|
nuclear@0
|
566 plane.dist = texel.w;
|
nuclear@0
|
567
|
nuclear@0
|
568 plane.mat = read_material(tex_planes, ty);
|
nuclear@0
|
569 return plane;
|
nuclear@0
|
570 }
|
nuclear@0
|
571
|
nuclear@0
|
572 Box read_box(in float idx)
|
nuclear@0
|
573 {
|
nuclear@0
|
574 Box box;
|
nuclear@0
|
575 float ty = (idx + 1.0) / box_tex_sz;
|
nuclear@0
|
576
|
nuclear@0
|
577 box.index = texture2D(tex_boxes, vec2(ITEM(0), ty)).x;
|
nuclear@0
|
578
|
nuclear@0
|
579 box.min = texture2D(tex_boxes, vec2(ITEM(1), ty)).xyz;
|
nuclear@0
|
580 box.max = texture2D(tex_boxes, vec2(ITEM(2), ty)).xyz;
|
nuclear@0
|
581
|
nuclear@0
|
582 box.mat = read_material(tex_boxes, ty);
|
nuclear@0
|
583 return box;
|
nuclear@0
|
584 }
|
nuclear@0
|
585
|
nuclear@4
|
586 Cone read_cone(in float idx)
|
nuclear@4
|
587 {
|
nuclear@4
|
588 Cone cone;
|
nuclear@4
|
589 float ty = (idx + 1.0) / cone_tex_sz;
|
nuclear@4
|
590
|
nuclear@4
|
591 cone.index = texture2D(tex_cones, vec2(ITEM(0), ty)).x;
|
nuclear@4
|
592
|
nuclear@4
|
593 vec4 texel = texture2D(tex_cones, vec2(ITEM(1), ty));
|
nuclear@4
|
594 cone.angle = texel.x;
|
nuclear@4
|
595 cone.start = texel.y;
|
nuclear@4
|
596 cone.end = texel.z;
|
nuclear@4
|
597
|
nuclear@4
|
598 cone.mat = read_material(tex_cones, ty);
|
nuclear@4
|
599 return cone;
|
nuclear@4
|
600 }
|
nuclear@4
|
601
|
nuclear@0
|
602 void read_xform(in float idx, out mat4 xform, out mat4 inv_xform)
|
nuclear@0
|
603 {
|
nuclear@0
|
604 float ty = (idx + 1.0) / xform_tex_sz;
|
nuclear@0
|
605
|
nuclear@0
|
606 for(int i=0; i<4; i++) {
|
nuclear@0
|
607 xform[i] = texture2D(tex_xforms, vec2(ITEM(i), ty));
|
nuclear@0
|
608 }
|
nuclear@0
|
609 inv_xform = inverse(xform);
|
nuclear@0
|
610 /*for(int i=0; i<4; i++) {
|
nuclear@0
|
611 inv_xform[i] = texture2D(tex_xforms, vec2(ITEM(float(i) + 4.0), ty));
|
nuclear@0
|
612 }*/
|
nuclear@0
|
613 }
|
nuclear@0
|
614
|
nuclear@0
|
615 #define MAT_START 4
|
nuclear@0
|
616 Material read_material(in sampler2D tex, in float ty)
|
nuclear@0
|
617 {
|
nuclear@0
|
618 Material mat;
|
nuclear@0
|
619
|
nuclear@0
|
620 vec4 texel = texture2D(tex, vec2(ITEM(MAT_START), ty));
|
nuclear@0
|
621 mat.diffuse = texel.xyz;
|
nuclear@0
|
622
|
nuclear@0
|
623 texel = texture2D(tex, vec2(ITEM(MAT_START + 1), ty));
|
nuclear@0
|
624 mat.specular = texel.xyz;
|
nuclear@0
|
625 mat.shininess = texel.w;
|
nuclear@0
|
626
|
nuclear@0
|
627 texel = texture2D(tex, vec2(ITEM(MAT_START + 2), ty));
|
nuclear@0
|
628 mat.reflectivity = texel.x;
|
nuclear@0
|
629
|
nuclear@0
|
630 mat.megatex_rect = texture2D(tex, vec2(ITEM(MAT_START + 3), ty));
|
nuclear@0
|
631
|
nuclear@0
|
632 return mat;
|
nuclear@0
|
633 }
|