gpuray_glsl

view sdr/rt.glsl @ 4:2ed3da7dc0bc

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