gpuray_glsl

view sdr/rt.glsl @ 3:297dbc5080c4

cone intersection
author John Tsiombikas <nuclear@member.fsf.org>
date Sun, 09 Nov 2014 20:13:33 +0200
parents
children 2ed3da7dc0bc
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 Light {
50 vec3 pos, color;
51 };
53 vec3 shade(in Ray ray, in HitPoint hit);
54 bool find_intersection(in Ray ray, out HitPoint hit);
55 bool sphere_intersect(in Sphere sph, in Ray ray, out HitPoint pt);
56 bool plane_intersect(in Plane plane, in Ray ray, out HitPoint pt);
57 bool box_intersect(in Box box, in Ray ray, out HitPoint pt);
58 vec3 transform(in vec3 v, in mat4 inv_xform);
59 Ray transform(in Ray ray, in mat4 xform, in mat4 inv_xform);
60 Ray get_primary_ray();
62 Sphere read_sphere(in float idx);
63 Plane read_plane(in float idx);
64 Box read_box(in float idx);
65 Material read_material(in sampler2D tex, in float ty);
66 void read_xform(in float idx, out mat4 xform, out mat4 inv_xform);
68 uniform sampler2D tex_raydir;
69 uniform sampler2D tex_spheres, tex_planes, tex_boxes;
70 uniform sampler2D tex_megatex;
71 uniform sampler2D tex_xforms;
72 uniform samplerCube tex_env;
73 uniform vec2 fog;
75 uniform Light lights[8];
76 uniform int num_lights;
78 int num_spheres, num_planes, num_boxes;
79 float sph_tex_sz, plane_tex_sz, box_tex_sz, xform_tex_sz;
81 #ifdef INIT_EVERYTHING
82 Material default_material;
83 #endif
85 void main()
86 {
87 #ifdef INIT_EVERYTHING
88 default_material.diffuse = default_material.specular = vec3(0.0, 0.0, 0.0);
89 default_material.shininess = 1.0;
90 default_material.reflectivity = 0.0;
91 default_material.megatex_rect = vec4(0.0, 0.0, 0.0, 0.0);
92 #endif
94 Ray ray = get_primary_ray();
96 /* read the various descriptors specifying dimensions and counts for
97 * all the relevant data textures
98 */
99 vec4 desc = texture2D(tex_spheres, vec2(0.0, 0.0));
100 num_spheres = int(desc.x);
101 sph_tex_sz = desc.y;
103 desc = texture2D(tex_planes, vec2(0.0, 0.0));
104 num_planes = int(desc.x);
105 plane_tex_sz = desc.y;
107 desc = texture2D(tex_boxes, vec2(0.0, 0.0));
108 num_boxes = int(desc.x);
109 box_tex_sz = desc.y;
111 xform_tex_sz = texture2D(tex_xforms, vec2(0.0, 0.0)).x;
114 HitPoint hit;
115 #ifdef INIT_EVERYTHING
116 hit.dist = 0.0;
117 hit.pos = hit.normal = vec3(0.0, 0.0, 0.0);
118 #endif
120 vec3 color = vec3(0.0, 0.0, 0.0);
121 float energy = 1.0;
123 int iter = 0;
124 while(energy > 0.01 && iter++ < 4) {
125 vec3 envcol = textureCube(tex_env, ray.dir).xyz;
127 if(find_intersection(ray, hit)) {
128 float fog_t = clamp((hit.dist - fog.x) / (fog.y - fog.x), 0.0, 1.0);
129 color += mix(shade(ray, hit), envcol, fog_t) * energy;
130 energy *= hit.mat.reflectivity * (1.0 - fog_t);
131 ray.origin = hit.pos;
132 ray.dir = reflect(ray.dir, hit.normal);
133 } else {
134 color += envcol * energy;
135 energy = 0.0;
136 iter = 100;
137 }
138 }
140 gl_FragColor.xyz = color;
141 gl_FragColor.w = 1.0;
142 }
144 vec3 shade(in Ray ray, in HitPoint hit)
145 {
146 vec3 normal = faceforward(hit.normal, ray.dir, hit.normal);
148 vec3 vdir = normalize(ray.dir);
149 vec3 vref = reflect(vdir, normal);
151 /* if there's no texture rect.zw will be (0, 0, 0, 0) so this will map onto
152 * the top-left 1x1 null texture which is all white (having no effect)
153 */
154 vec2 tc = mod(hit.texcoord, vec2(1.0, 1.0)) * hit.mat.megatex_rect.zw + hit.mat.megatex_rect.xy;
156 vec3 diffuse_color = hit.mat.diffuse * texture2D(tex_megatex, tc).xyz;
158 vec3 color = vec3(0.0, 0.0, 0.0);
159 for(int i=0; i<num_lights; i++) {
160 Ray shadow_ray;
161 shadow_ray.origin = hit.pos;
162 shadow_ray.dir = lights[i].pos - hit.pos;
164 HitPoint shadow_hit;
165 if(!find_intersection(shadow_ray, shadow_hit) || shadow_hit.dist > 1.0) {
166 vec3 ldir = normalize(shadow_ray.dir);
168 float diffuse = max(dot(ldir, normal), 0.0);
169 float specular = pow(max(dot(ldir, vref), 0.0), hit.mat.shininess);
171 color += (diffuse_color * diffuse + hit.mat.specular * specular) * lights[i].color;
172 }
173 }
175 return color;
176 }
178 bool find_intersection(in Ray ray, out HitPoint hit)
179 {
180 hit.dist = 100000.0;
181 #ifdef INIT_EVERYTHING
182 hit.pos = hit.normal = vec3(0.0, 0.0, 0.0);
183 hit.mat = default_material;
184 hit.texcoord = vec2(0.0, 0.0);
185 #endif
186 bool found = false;
188 for(int i=0; i<num_spheres; i++) {
189 Sphere sph = read_sphere(i);
191 HitPoint tmphit;
192 if(sphere_intersect(sph, ray, tmphit) && tmphit.dist < hit.dist) {
193 hit = tmphit;
194 found = true;
195 }
196 }
198 for(int i=0; i<num_planes; i++) {
199 Plane plane = read_plane(i);
201 HitPoint tmphit;
202 if(plane_intersect(plane, ray, tmphit) && tmphit.dist < hit.dist) {
203 hit = tmphit;
204 found = true;
205 }
206 }
208 for(int i=0; i<num_boxes; i++) {
209 Box box = read_box(i);
211 HitPoint tmphit;
212 if(box_intersect(box, ray, tmphit) && tmphit.dist < hit.dist) {
213 hit = tmphit;
214 found = true;
215 }
216 }
218 return found;
219 }
221 #define EPSILON 1e-4
222 #define SQ(x) ((x) * (x))
224 bool sphere_intersect(in Sphere sph, in Ray inray, out HitPoint pt)
225 {
226 #ifdef USE_XFORM
227 mat4 xform, inv_xform;
228 read_xform(sph.index, xform, inv_xform);
230 Ray ray = transform(inray, inv_xform, xform);
231 #else
232 Ray ray = inray;
233 #endif
235 #ifdef INIT_EVERYTHING
236 pt.dist = 0.0;
237 pt.pos = pt.normal = vec3(0.0, 0.0, 0.0);
238 pt.mat = default_material;
239 pt.texcoord = vec2(0.0, 0.0);
240 #endif
242 float a = dot(ray.dir, ray.dir);
243 float b = dot(ray.dir, ray.origin - sph.pos) * 2.0;
244 float c = dot(ray.origin, ray.origin) + dot(sph.pos, sph.pos) -
245 2.0 * dot(ray.origin, sph.pos) - sph.radius * sph.radius;
247 float discr = b * b - 4.0 * a * c;
248 if(discr < EPSILON)
249 return false;
251 float sqrt_discr = sqrt(discr);
252 float t0 = (-b + sqrt_discr) / (2.0 * a);
253 float t1 = (-b - sqrt_discr) / (2.0 * a);
255 if(t0 < EPSILON)
256 t0 = t1;
257 if(t1 < EPSILON)
258 t1 = t0;
260 float t = min(t0, t1);
261 if(t < EPSILON)
262 return false;
264 // fill the HitPoint structure
265 pt.dist = t;
266 pt.pos = ray.origin + ray.dir * t;
267 pt.normal = (pt.pos - sph.pos) / sph.radius;
268 pt.mat = sph.mat;
270 pt.texcoord.x = 0.5 * atan(pt.normal.z, pt.normal.x) / M_PI + 0.5;
271 pt.texcoord.y = acos(pt.normal.y) / M_PI;
273 #ifdef USE_XFORM
274 pt.pos = (xform * vec4(pt.pos, 1.0)).xyz;
275 pt.normal = normalize(transform(pt.normal, xform));
276 #endif
277 return true;
278 }
280 bool plane_intersect(in Plane plane, in Ray inray, out HitPoint pt)
281 {
282 #ifdef USE_XFORM
283 mat4 xform, inv_xform;
284 read_xform(plane.index, xform, inv_xform);
286 Ray ray = transform(inray, inv_xform, xform);
287 #else
288 Ray ray = inray;
289 #endif
291 #ifdef INIT_EVERYTHING
292 pt.dist = 0.0;
293 pt.pos = pt.normal = vec3(0.0, 0.0, 0.0);
294 pt.mat = default_material;
295 pt.texcoord = vec2(0.0, 0.0);
296 #endif
298 float ndotdir = dot(plane.normal, ray.dir);
299 if(abs(ndotdir) < EPSILON) {
300 return false;
301 }
303 vec3 planept = plane.normal * plane.dist;
304 vec3 pptdir = planept - ray.origin;
306 float t = dot(plane.normal, pptdir) / ndotdir;
307 if(t < EPSILON) {
308 return false;
309 }
311 pt.dist = t;
312 pt.pos = ray.origin + ray.dir * t;
313 pt.normal = plane.normal;
314 pt.mat = plane.mat;
315 pt.texcoord.x = pt.pos.x;
316 pt.texcoord.y = pt.pos.z;
318 #ifdef USE_XFORM
319 pt.pos = (xform * vec4(pt.pos, 1.0)).xyz;
320 pt.normal = normalize(transform(pt.normal, xform));
321 #endif
322 return true;
323 }
325 bool box_intersect(in Box box, in Ray inray, out HitPoint pt)
326 {
327 #ifdef USE_XFORM
328 mat4 xform, inv_xform;
329 read_xform(box.index, xform, inv_xform);
331 Ray ray = transform(inray, inv_xform, xform);
332 #else
333 Ray ray = inray;
334 #endif
336 #ifdef INIT_EVERYTHING
337 pt.dist = 0.0;
338 pt.pos = pt.normal = vec3(0.0, 0.0, 0.0);
339 pt.mat = default_material;
340 pt.texcoord = vec2(0.0, 0.0);
341 #endif
343 vec3 param[2];
344 param[0] = box.min;
345 param[1] = box.max;
347 vec3 inv_dir = 1.0 / ray.dir;
348 int sgn[3];
349 sgn[0] = inv_dir.x < 0.0 ? 1 : 0;
350 sgn[1] = inv_dir.y < 0.0 ? 1 : 0;
351 sgn[2] = inv_dir.z < 0.0 ? 1 : 0;
353 float tmin = (param[sgn[0]].x - ray.origin.x) * inv_dir.x;
354 float tmax = (param[1 - sgn[0]].x - ray.origin.x) * inv_dir.x;
355 float tymin = (param[sgn[1]].y - ray.origin.y) * inv_dir.y;
356 float tymax = (param[1 - sgn[1]].y - ray.origin.y) * inv_dir.y;
358 pt.normal = vec3(ray.origin.x > 0.0 ? 1.0 : -1.0, 0.0, 0.0);
360 if(tmin > tymax || tymin > tmax) {
361 return false;
362 }
363 if(tymin > tmin) {
364 pt.normal = vec3(0.0, ray.origin.y > 0.0 ? 1.0 : -1.0, 0.0);
365 tmin = tymin;
366 }
367 if(tymax < tmax) {
368 tmax = tymax;
369 }
371 float tzmin = (param[sgn[2]].z - ray.origin.z) * inv_dir.z;
372 float tzmax = (param[1 - sgn[2]].z - ray.origin.z) * inv_dir.z;
374 if(tmin > tzmax || tzmin > tmax) {
375 return false;
376 }
377 if(tzmin > tmin) {
378 pt.normal = vec3(0.0, 0.0, ray.origin.z > 0.0 ? 1.0 : -1.0);
379 tmin = tzmin;
380 }
381 if(tzmax < tmax) {
382 tmax = tzmax;
383 }
385 float t = tmin < EPSILON ? tmax : tmin;
386 if(t >= 1e-4) {
387 pt.dist = t;
388 pt.pos = ray.origin + ray.dir * t;
389 pt.mat = box.mat;
391 float min_dist = 10000.0;
393 vec3 offs = box.min + (box.max - box.min) / 2.0;
394 vec3 local_pt = pt.pos - offs;
396 vec3 dist = abs((box.max - offs) - abs(local_pt));
397 if(dist.x < min_dist) {
398 min_dist = dist.x;
399 pt.normal = sign(local_pt.x) * vec3(1.0, 0.0, 0.0);
400 pt.texcoord = pt.pos.zy;
401 }
402 if(dist.y < min_dist) {
403 min_dist = dist.y;
404 pt.normal = sign(local_pt.y) * vec3(0.0, 1.0, 0.0);
405 pt.texcoord = pt.pos.xz;
406 }
407 if(dist.z < min_dist) {
408 pt.normal = sign(local_pt.y) * vec3(0.0, 0.0, 1.0);
409 pt.texcoord = pt.pos.xy;
410 }
413 #ifdef USE_XFORM
414 pt.pos = (xform * vec4(pt.pos, 1.0)).xyz;
415 pt.normal = normalize(transform(pt.normal, xform));
416 #endif
417 return true;
418 }
419 return false;
420 }
422 vec3 transform(in vec3 v, in mat4 xform)
423 {
424 return mat3(xform) * v;
425 }
427 Ray transform(in Ray ray, in mat4 xform, in mat4 inv_xform)
428 {
429 Ray res;
430 res.origin = (xform * vec4(ray.origin, 1.0)).xyz;
431 res.dir = transform(ray.dir, xform);
432 return res;
433 }
435 Ray get_primary_ray()
436 {
437 Ray ray;
438 ray.origin = (gl_ModelViewMatrix * vec4(0.0, 0.0, 0.0, 1.0)).xyz;
439 vec3 dir = texture2D(tex_raydir, gl_TexCoord[0].st).xyz;
440 ray.dir = normalize(gl_NormalMatrix * dir);
441 return ray;
442 }
444 #define ITEM(x) ((float(x) + 0.5) / OBJ_LINE_WIDTH)
446 Sphere read_sphere(in float idx)
447 {
448 Sphere sph;
449 // +1 because the first scanline is the descriptor
450 float ty = (idx + 1.0) / sph_tex_sz;
452 sph.index = texture2D(tex_spheres, vec2(ITEM(0), ty)).x;
454 vec4 texel = texture2D(tex_spheres, vec2(ITEM(1), ty));
455 sph.pos = texel.xyz;
456 sph.radius = texel.w;
458 sph.mat = read_material(tex_spheres, ty);
459 return sph;
460 }
462 Plane read_plane(in float idx)
463 {
464 Plane plane;
465 // +1 (see above)
466 float ty = (idx + 1.0) / plane_tex_sz;
468 plane.index = texture2D(tex_planes, vec2(ITEM(0), ty)).x;
470 vec4 texel = texture2D(tex_planes, vec2(ITEM(1), ty));
471 plane.normal = texel.xyz;
472 plane.dist = texel.w;
474 plane.mat = read_material(tex_planes, ty);
475 return plane;
476 }
478 Box read_box(in float idx)
479 {
480 Box box;
481 float ty = (idx + 1.0) / box_tex_sz;
483 box.index = texture2D(tex_boxes, vec2(ITEM(0), ty)).x;
485 box.min = texture2D(tex_boxes, vec2(ITEM(1), ty)).xyz;
486 box.max = texture2D(tex_boxes, vec2(ITEM(2), ty)).xyz;
488 box.mat = read_material(tex_boxes, ty);
489 return box;
490 }
492 void read_xform(in float idx, out mat4 xform, out mat4 inv_xform)
493 {
494 float ty = (idx + 1.0) / xform_tex_sz;
496 for(int i=0; i<4; i++) {
497 xform[i] = texture2D(tex_xforms, vec2(ITEM(i), ty));
498 }
499 inv_xform = inverse(xform);
500 /*for(int i=0; i<4; i++) {
501 inv_xform[i] = texture2D(tex_xforms, vec2(ITEM(float(i) + 4.0), ty));
502 }*/
503 }
505 #define MAT_START 4
506 Material read_material(in sampler2D tex, in float ty)
507 {
508 Material mat;
510 vec4 texel = texture2D(tex, vec2(ITEM(MAT_START), ty));
511 mat.diffuse = texel.xyz;
513 texel = texture2D(tex, vec2(ITEM(MAT_START + 1), ty));
514 mat.specular = texel.xyz;
515 mat.shininess = texel.w;
517 texel = texture2D(tex, vec2(ITEM(MAT_START + 2), ty));
518 mat.reflectivity = texel.x;
520 mat.megatex_rect = texture2D(tex, vec2(ITEM(MAT_START + 3), ty));
522 return mat;
523 }