bloboland

annotate sdr/bloboray.p.glsl @ 3:a39c301cdcce

terrain raytracing pretty much done
author John Tsiombikas <nuclear@member.fsf.org>
date Sun, 16 Dec 2012 14:24:16 +0200
parents
children 9021a906c5d3
rev   line source
nuclear@3 1 struct Ray {
nuclear@3 2 vec3 origin;
nuclear@3 3 vec3 dir;
nuclear@3 4 };
nuclear@3 5
nuclear@3 6 struct AABBox {
nuclear@3 7 vec3 vmin, vmax;
nuclear@3 8 };
nuclear@3 9
nuclear@3 10 struct HitPoint {
nuclear@3 11 bool hit;
nuclear@3 12 float t0, t1;
nuclear@3 13 vec3 pos, normal;
nuclear@3 14 vec4 color;
nuclear@3 15 };
nuclear@3 16
nuclear@3 17 vec3 shade(Ray ray, HitPoint hit);
nuclear@3 18 HitPoint intersect_voxels(Ray ray);
nuclear@3 19 HitPoint intersect_aabb(Ray ray, AABBox aabb);
nuclear@3 20 Ray get_primary_ray(float x, float y);
nuclear@3 21
nuclear@3 22 #define RAY_STEP 0.001
nuclear@3 23
nuclear@3 24 #define FOV camprop.x
nuclear@3 25 #define ASPECT camprop.y
nuclear@3 26 uniform vec4 camprop;
nuclear@3 27 uniform vec3 volsize;
nuclear@3 28 uniform sampler3D voltex;
nuclear@3 29
nuclear@3 30 //const vec3 worldsize = vec3(4.0, 4.0, 2.0);
nuclear@3 31 const vec3 worldsize = vec3(1.0, 1.0, 0.5);
nuclear@3 32
nuclear@3 33 void main()
nuclear@3 34 {
nuclear@3 35 Ray ray = get_primary_ray(gl_TexCoord[0].x, gl_TexCoord[0].y);
nuclear@3 36
nuclear@3 37 vec3 color = vec3(0.0, 0.0, 0.0);
nuclear@3 38 HitPoint hit = intersect_voxels(ray);
nuclear@3 39 if(hit.hit) {
nuclear@3 40 color = shade(ray, hit);
nuclear@3 41 }
nuclear@3 42
nuclear@3 43 gl_FragColor = vec4(color, 1.0);
nuclear@3 44 }
nuclear@3 45
nuclear@3 46 vec3 shade(Ray ray, HitPoint hit)
nuclear@3 47 {
nuclear@3 48 const vec3 light_pos = vec3(-2, 3, 2);
nuclear@3 49 vec3 ldir = normalize(light_pos - hit.pos);
nuclear@3 50
nuclear@3 51 vec3 vdir = normalize(-ray.dir);
nuclear@3 52 vec3 hvec = normalize(vdir + ldir);
nuclear@3 53
nuclear@3 54 float ndotl = max(dot(hit.normal, ldir), 0.0);
nuclear@3 55 float ndoth = max(dot(hit.normal, hvec), 0.0);
nuclear@3 56
nuclear@3 57 vec3 diffuse = hit.color.xyz * ndotl;
nuclear@3 58 vec3 specular = vec3(0.4, 0.4, 0.4) * pow(ndoth, 60.0);
nuclear@3 59
nuclear@3 60 return diffuse + specular;
nuclear@3 61 }
nuclear@3 62
nuclear@3 63 vec4 fetch_voxel(vec3 pt)
nuclear@3 64 {
nuclear@3 65 pt *= 1.0 / worldsize;
nuclear@3 66 return texture3D(voltex, pt * 0.5 + 0.5);
nuclear@3 67 }
nuclear@3 68
nuclear@3 69 vec3 calc_voxel_normal(vec3 pt)
nuclear@3 70 {
nuclear@3 71 vec3 offs = 1.8 / volsize;
nuclear@3 72 float dfdx = fetch_voxel(pt + vec3(offs.x, 0.0, 0.0)).w - fetch_voxel(pt - vec3(offs.x, 0.0, 0.0)).w;
nuclear@3 73 float dfdy = fetch_voxel(pt + vec3(0.0, offs.y, 0.0)).w - fetch_voxel(pt - vec3(0.0, offs.y, 0.0)).w;
nuclear@3 74 float dfdz = fetch_voxel(pt + vec3(0.0, 0.0, offs.z)).w - fetch_voxel(pt - vec3(0.0, 0.0, offs.z)).w;
nuclear@3 75
nuclear@3 76 return -normalize(vec3(dfdx, dfdy, dfdz));
nuclear@3 77 }
nuclear@3 78
nuclear@3 79 HitPoint intersect_voxels(Ray ray)
nuclear@3 80 {
nuclear@3 81 HitPoint hit;
nuclear@3 82 //AABBox aabb = AABBox(vec3(-1.0, -1.0, -1.0), vec3(1.0, 1.0, 1.0));
nuclear@3 83 AABBox aabb = AABBox(-worldsize.xzy, worldsize.xzy);
nuclear@3 84
nuclear@3 85
nuclear@3 86 hit = intersect_aabb(ray, aabb);
nuclear@3 87 if(!hit.hit) {
nuclear@3 88 return hit;
nuclear@3 89 }
nuclear@3 90
nuclear@3 91 /* start tracing from the first intersection, or if it's behind
nuclear@3 92 * the viewer, start from 0.
nuclear@3 93 */
nuclear@3 94 float dist = max(hit.t0, 0.0);
nuclear@3 95 float end_dist = hit.t1;
nuclear@3 96
nuclear@3 97 while(dist < end_dist) {
nuclear@3 98 vec3 pt = ray.origin + ray.dir * dist;
nuclear@3 99 vec4 voxel = fetch_voxel(pt.xzy);
nuclear@3 100
nuclear@3 101
nuclear@3 102 if(voxel.a > 0.5) {
nuclear@3 103 hit.t0 = dist;
nuclear@3 104 hit.pos = pt;
nuclear@3 105 hit.normal = calc_voxel_normal(pt.xzy).xzy;
nuclear@3 106 hit.color = voxel;
nuclear@3 107 return hit;
nuclear@3 108 }
nuclear@3 109
nuclear@3 110 dist += RAY_STEP;
nuclear@3 111 }
nuclear@3 112
nuclear@3 113 hit.hit = false;
nuclear@3 114 return hit;
nuclear@3 115 }
nuclear@3 116
nuclear@3 117 HitPoint intersect_aabb(Ray ray, AABBox aabb)
nuclear@3 118 {
nuclear@3 119 HitPoint res;
nuclear@3 120
nuclear@3 121 vec3 invR = 1.0 / ray.dir;
nuclear@3 122 vec3 tbot = invR * (aabb.vmin - ray.origin);
nuclear@3 123 vec3 ttop = invR * (aabb.vmax - ray.origin);
nuclear@3 124 vec3 tmin = min(ttop, tbot);
nuclear@3 125 vec3 tmax = max(ttop, tbot);
nuclear@3 126 vec2 t = max(tmin.xx, tmin.yz);
nuclear@3 127 float t0 = max(t.x, t.y);
nuclear@3 128 t = min(tmax.xx, tmax.yz);
nuclear@3 129 float t1 = min(t.x, t.y);
nuclear@3 130
nuclear@3 131 if(t0 <= t1) {
nuclear@3 132 res.hit = true;
nuclear@3 133 res.t0 = t0;
nuclear@3 134 res.t1 = t1;
nuclear@3 135 } else {
nuclear@3 136 res.hit = false;
nuclear@3 137 }
nuclear@3 138 return res;
nuclear@3 139 }
nuclear@3 140
nuclear@3 141 Ray get_primary_ray(float x, float y)
nuclear@3 142 {
nuclear@3 143 vec3 dir;
nuclear@3 144 dir.x = ASPECT * (2.0 * x - 1.0);
nuclear@3 145 dir.y = 2.0 * y - 1.0;
nuclear@3 146 dir.z = -1.0 / tan(FOV / 2.0);
nuclear@3 147
nuclear@3 148 Ray ray;
nuclear@3 149 ray.origin = (gl_ModelViewMatrix * vec4(0.0, 0.0, 0.0, 1.0)).xyz;
nuclear@3 150 ray.dir = gl_NormalMatrix * normalize(dir);
nuclear@3 151 return ray;
nuclear@3 152 }