qvolray

annotate sdr/volray.p.glsl @ 37:450d4c50470f

- 16bit floating point textures halve gpu texture memory usage - slower transfer function change
author John Tsiombikas <nuclear@member.fsf.org>
date Wed, 01 Jan 2014 00:23:57 +0200
parents 437e1ba9cf39
children
rev   line source
nuclear@0 1 uniform sampler3D volume;
nuclear@0 2 uniform sampler2D ray_tex;
nuclear@4 3 uniform sampler1D xfer_tex;
nuclear@7 4 uniform float ray_step;
nuclear@7 5 uniform float zclip;
nuclear@0 6
nuclear@0 7 struct Ray {
nuclear@0 8 vec3 origin, dir;
nuclear@0 9 };
nuclear@0 10
nuclear@4 11 struct AABBox {
nuclear@4 12 vec3 min, max;
nuclear@4 13 };
nuclear@4 14
nuclear@0 15 struct ISect {
nuclear@0 16 bool hit;
nuclear@7 17 float t0, t1;
nuclear@0 18 vec3 pos;
nuclear@0 19 vec3 normal;
nuclear@0 20 };
nuclear@0 21
nuclear@1 22 vec3 sky(Ray ray);
nuclear@7 23 vec3 ray_march(Ray ray, float t0, float t1);
nuclear@26 24 vec3 shade(Ray ray, vec3 pos, vec3 norm, vec3 ldir);
nuclear@0 25 Ray get_primary_ray();
nuclear@5 26 ISect intersect_aabb(Ray ray, AABBox aabb);
nuclear@25 27 ISect intersect_sphere(Ray ray, float rad);
nuclear@25 28
nuclear@25 29 //#define USE_AABB
nuclear@0 30
nuclear@0 31 void main()
nuclear@0 32 {
nuclear@0 33 Ray ray = get_primary_ray();
nuclear@0 34
nuclear@4 35 vec3 color = vec3(0.0, 0.0, 0.0);
nuclear@4 36
nuclear@25 37 #ifdef USE_AABB
nuclear@25 38 const AABBox aabb = AABBox(vec3(-1.0, -1.0, -1.0), vec3(1.0, 1.0, 1.0));
nuclear@5 39 ISect res = intersect_aabb(ray, aabb);
nuclear@5 40 if(res.hit) {
nuclear@25 41 color += ray_march(ray, res.t0, res.t1);
nuclear@4 42 }
nuclear@25 43 #else
nuclear@25 44 ISect res = intersect_sphere(ray, 1.5);
nuclear@25 45 if(res.hit) {
nuclear@25 46 color += ray_march(ray, res.t0, res.t1);
nuclear@25 47 }
nuclear@25 48 #endif
nuclear@4 49
nuclear@4 50 gl_FragColor = vec4(color, 1.0);
nuclear@0 51 }
nuclear@0 52
nuclear@25 53 vec3 sky(Ray ray)
nuclear@25 54 {
nuclear@25 55 vec3 c0 = vec3(0.2, 0.5, 0.8);
nuclear@25 56 vec3 c1 = vec3(0.8, 0.5, 0.2);
nuclear@25 57 float t = smoothstep(-0.2, 0.2, ray.dir.z);
nuclear@25 58 return mix(c0, c1, t);
nuclear@25 59 }
nuclear@25 60
nuclear@20 61 float eval(vec3 pos, out vec3 grad)
nuclear@4 62 {
nuclear@5 63 vec3 tc = pos * 0.5 + 0.5;
nuclear@7 64
nuclear@7 65 if(tc.x < 0.0 || tc.y < 0.0 || tc.z < zclip || tc.x > 1.0 || tc.y > 1.0 || tc.z > 1.0) {
nuclear@20 66 grad = vec3(0.0, 0.0, 0.0);
nuclear@7 67 return 0.0;
nuclear@7 68 }
nuclear@7 69
nuclear@20 70 vec4 texel = texture3D(volume, tc);
nuclear@20 71 grad = texel.xyz;
nuclear@20 72
nuclear@20 73 return texture1D(xfer_tex, texel.a).x;
nuclear@4 74 }
nuclear@4 75
nuclear@7 76 vec3 ray_march(Ray ray, float t0, float t1)
nuclear@0 77 {
nuclear@0 78 float energy = 1.0;
nuclear@7 79 float t = t0;
nuclear@7 80 vec3 col = vec3(0.0, 0.0, 0.0);
nuclear@33 81 vec3 ldir = normalize(vec3(-1, 1, -4));
nuclear@0 82
nuclear@7 83
nuclear@7 84 while(t < t1) {
nuclear@7 85 vec3 pos = ray.origin + ray.dir * t;
nuclear@7 86 t += ray_step;
nuclear@7 87
nuclear@7 88 vec3 norm;
nuclear@20 89 float val = eval(pos, norm);
nuclear@7 90
nuclear@25 91 float energy_drop = exp(val * -ray_step); // * scatter_coeff ?
nuclear@25 92 energy *= energy_drop;
nuclear@25 93
nuclear@26 94 vec3 irrad = shade(ray, pos, normalize(norm), ldir);
nuclear@25 95
nuclear@25 96 col += (1.0 - energy_drop) * energy * irrad;
nuclear@1 97 if(energy < 0.001) {
nuclear@1 98 break;
nuclear@1 99 }
nuclear@0 100 }
nuclear@0 101
nuclear@7 102 return col;
nuclear@0 103 }
nuclear@0 104
nuclear@26 105 vec3 shade(Ray ray, vec3 pos, vec3 norm, vec3 ldir)
nuclear@0 106 {
nuclear@26 107 vec3 vdir = -normalize(ray.dir);
nuclear@26 108 vec3 hdir = normalize(ldir + vdir);
nuclear@0 109
nuclear@25 110 float ndotl = abs(dot(ldir, norm));
nuclear@25 111 float ndoth = abs(dot(hdir, norm));
nuclear@0 112
nuclear@8 113 vec3 dcol = vec3(0.9, 0.9, 0.9) * max(ndotl, 0.0);
nuclear@8 114 vec3 scol = vec3(0.5, 0.5, 0.5) * pow(max(ndoth, 0.0), 50.0);
nuclear@0 115
nuclear@25 116 return dcol + scol;
nuclear@0 117 }
nuclear@0 118
nuclear@0 119 Ray get_primary_ray()
nuclear@0 120 {
nuclear@0 121 Ray ray;
nuclear@0 122 vec2 tc = gl_TexCoord[0].xy;
nuclear@0 123 ray.dir = gl_NormalMatrix * normalize(texture2D(ray_tex, tc).xyz);
nuclear@0 124 ray.origin = (gl_ModelViewMatrix * vec4(0.0, 0.0, 0.0, 1.0)).xyz;
nuclear@0 125 return ray;
nuclear@0 126 }
nuclear@4 127
nuclear@35 128 #ifdef USE_AABB
nuclear@5 129 ISect intersect_aabb(Ray ray, AABBox aabb)
nuclear@4 130 {
nuclear@5 131 ISect res;
nuclear@5 132 res.hit = false;
nuclear@7 133 res.t0 = res.t1 = 0.0;
nuclear@5 134
nuclear@4 135 if(ray.origin.x >= aabb.min.x && ray.origin.y >= aabb.min.y && ray.origin.z >= aabb.min.z &&
nuclear@4 136 ray.origin.x < aabb.max.x && ray.origin.y < aabb.max.y && ray.origin.z < aabb.max.z) {
nuclear@5 137 res.hit = true;
nuclear@5 138 return res;
nuclear@4 139 }
nuclear@4 140
nuclear@4 141 vec4 bbox[2];
nuclear@4 142 bbox[0] = vec4(aabb.min.x, aabb.min.y, aabb.min.z, 0);
nuclear@4 143 bbox[1] = vec4(aabb.max.x, aabb.max.y, aabb.max.z, 0);
nuclear@4 144
nuclear@4 145 int xsign = int(ray.dir.x < 0.0);
nuclear@4 146 float invdirx = 1.0 / ray.dir.x;
nuclear@4 147 float tmin = (bbox[xsign].x - ray.origin.x) * invdirx;
nuclear@4 148 float tmax = (bbox[1 - xsign].x - ray.origin.x) * invdirx;
nuclear@4 149
nuclear@4 150 int ysign = int(ray.dir.y < 0.0);
nuclear@4 151 float invdiry = 1.0 / ray.dir.y;
nuclear@4 152 float tymin = (bbox[ysign].y - ray.origin.y) * invdiry;
nuclear@4 153 float tymax = (bbox[1 - ysign].y - ray.origin.y) * invdiry;
nuclear@4 154
nuclear@4 155 if(tmin > tymax || tymin > tmax) {
nuclear@5 156 return res;
nuclear@4 157 }
nuclear@4 158
nuclear@4 159 if(tymin > tmin) tmin = tymin;
nuclear@4 160 if(tymax < tmax) tmax = tymax;
nuclear@4 161
nuclear@4 162 int zsign = int(ray.dir.z < 0.0);
nuclear@4 163 float invdirz = 1.0 / ray.dir.z;
nuclear@4 164 float tzmin = (bbox[zsign].z - ray.origin.z) * invdirz;
nuclear@4 165 float tzmax = (bbox[1 - zsign].z - ray.origin.z) * invdirz;
nuclear@4 166
nuclear@4 167 if(tmin > tzmax || tzmin > tmax) {
nuclear@5 168 return res;
nuclear@4 169 }
nuclear@4 170
nuclear@7 171 res.t0 = tmin;
nuclear@7 172 res.t1 = tmax;
nuclear@5 173 res.hit = true;
nuclear@5 174 return res;
nuclear@4 175 }
nuclear@35 176 #else
nuclear@25 177
nuclear@25 178 ISect intersect_sphere(Ray ray, float rad)
nuclear@25 179 {
nuclear@25 180 ISect res;
nuclear@25 181 res.hit = false;
nuclear@25 182 res.t0 = res.t1 = 0.0;
nuclear@25 183
nuclear@25 184 float a = dot(ray.dir, ray.dir);
nuclear@25 185 float b = 2.0 * dot(ray.dir, ray.origin);
nuclear@25 186 float c = dot(ray.origin, ray.origin) - rad * rad;
nuclear@25 187 float d = b * b - 4.0 * a * c;
nuclear@25 188
nuclear@25 189 if(d < 0.0) {
nuclear@25 190 return res;
nuclear@25 191 }
nuclear@25 192
nuclear@25 193 float sqrt_d = sqrt(d);
nuclear@25 194 float t0 = (-b + sqrt_d) / (2.0 * a);
nuclear@25 195 float t1 = (-b - sqrt_d) / (2.0 * a);
nuclear@25 196
nuclear@35 197 res.t0 = max(min(t0, t1), 0.0);
nuclear@35 198 res.t1 = max(max(t0, t1), 0.0);
nuclear@25 199 res.hit = true;
nuclear@25 200
nuclear@25 201 /*res.pos = ray.origin + ray.dir * res.t0;
nuclear@25 202 res.normal = normalize(res.pos);*/
nuclear@25 203 return res;
nuclear@25 204 }
nuclear@35 205 #endif