nuclear@0: uniform sampler3D volume; nuclear@0: uniform sampler2D ray_tex; nuclear@4: uniform sampler1D xfer_tex; nuclear@7: uniform float ray_step; nuclear@7: uniform float zclip; nuclear@0: nuclear@0: struct Ray { nuclear@0: vec3 origin, dir; nuclear@0: }; nuclear@0: nuclear@4: struct AABBox { nuclear@4: vec3 min, max; nuclear@4: }; nuclear@4: nuclear@0: struct ISect { nuclear@0: bool hit; nuclear@7: float t0, t1; nuclear@0: vec3 pos; nuclear@0: vec3 normal; nuclear@0: }; nuclear@0: nuclear@1: vec3 sky(Ray ray); nuclear@7: vec3 ray_march(Ray ray, float t0, float t1); nuclear@7: vec3 shade(Ray ray, vec3 pos, vec3 norm); nuclear@0: Ray get_primary_ray(); nuclear@5: ISect intersect_aabb(Ray ray, AABBox aabb); nuclear@0: nuclear@0: void main() nuclear@0: { nuclear@5: const AABBox aabb = AABBox(vec3(-1.0, -1.0, -1.0), vec3(1.0, 1.0, 1.0)); nuclear@0: Ray ray = get_primary_ray(); nuclear@0: nuclear@4: vec3 color = vec3(0.0, 0.0, 0.0); nuclear@4: nuclear@5: ISect res = intersect_aabb(ray, aabb); nuclear@5: if(res.hit) { nuclear@7: color = ray_march(ray, res.t0, res.t1); nuclear@4: } nuclear@4: nuclear@4: gl_FragColor = vec4(color, 1.0); nuclear@0: } nuclear@0: nuclear@4: float eval(vec3 pos) nuclear@4: { nuclear@5: vec3 tc = pos * 0.5 + 0.5; nuclear@7: nuclear@7: 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@7: return 0.0; nuclear@7: } nuclear@7: nuclear@5: return texture1D(xfer_tex, texture3D(volume, tc).x).x; nuclear@4: } nuclear@4: nuclear@7: #define OFFS 0.01 nuclear@7: vec3 ray_march(Ray ray, float t0, float t1) nuclear@0: { nuclear@0: float energy = 1.0; nuclear@7: float t = t0; nuclear@7: vec3 col = vec3(0.0, 0.0, 0.0); nuclear@0: nuclear@7: nuclear@7: while(t < t1) { nuclear@7: vec3 pos = ray.origin + ray.dir * t; nuclear@7: t += ray_step; nuclear@7: nuclear@8: float val = eval(pos); nuclear@7: vec3 norm; nuclear@7: nuclear@7: norm.x = eval(pos + vec3(OFFS, 0.0, 0.0)) - val; nuclear@7: norm.y = eval(pos + vec3(0.0, OFFS, 0.0)) - val; nuclear@7: norm.z = eval(pos + vec3(0.0, 0.0, OFFS)) - val; nuclear@7: nuclear@8: col += shade(ray, pos, normalize(norm)) * val * energy; nuclear@1: energy -= val; nuclear@1: if(energy < 0.001) { nuclear@1: break; nuclear@1: } nuclear@0: pos += ray.dir * ray_step; nuclear@0: } nuclear@0: nuclear@7: return col; nuclear@0: } nuclear@0: nuclear@7: vec3 shade(Ray ray, vec3 pos, vec3 norm) nuclear@0: { nuclear@8: vec3 ldir = -pos;//normalize(vec3(10.0, 10.0, -10.0) - pos); nuclear@0: vec3 vdir = -ray.dir; nuclear@0: vec3 hdir = normalize(ldir + vdir); nuclear@0: nuclear@7: float ndotl = dot(ldir, norm); nuclear@7: float ndoth = dot(hdir, norm); nuclear@0: nuclear@8: vec3 dcol = vec3(0.9, 0.9, 0.9) * max(ndotl, 0.0); nuclear@8: vec3 scol = vec3(0.5, 0.5, 0.5) * pow(max(ndoth, 0.0), 50.0); nuclear@0: nuclear@0: return vec3(0.01, 0.01, 0.01) + dcol + scol; nuclear@0: } nuclear@0: nuclear@0: Ray get_primary_ray() nuclear@0: { nuclear@0: Ray ray; nuclear@0: vec2 tc = gl_TexCoord[0].xy; nuclear@0: ray.dir = gl_NormalMatrix * normalize(texture2D(ray_tex, tc).xyz); nuclear@0: ray.origin = (gl_ModelViewMatrix * vec4(0.0, 0.0, 0.0, 1.0)).xyz; nuclear@0: return ray; nuclear@0: } nuclear@4: nuclear@5: ISect intersect_aabb(Ray ray, AABBox aabb) nuclear@4: { nuclear@5: ISect res; nuclear@5: res.hit = false; nuclear@7: res.t0 = res.t1 = 0.0; nuclear@5: nuclear@4: if(ray.origin.x >= aabb.min.x && ray.origin.y >= aabb.min.y && ray.origin.z >= aabb.min.z && nuclear@4: ray.origin.x < aabb.max.x && ray.origin.y < aabb.max.y && ray.origin.z < aabb.max.z) { nuclear@5: res.hit = true; nuclear@5: return res; nuclear@4: } nuclear@4: nuclear@4: vec4 bbox[2]; nuclear@4: bbox[0] = vec4(aabb.min.x, aabb.min.y, aabb.min.z, 0); nuclear@4: bbox[1] = vec4(aabb.max.x, aabb.max.y, aabb.max.z, 0); nuclear@4: nuclear@4: int xsign = int(ray.dir.x < 0.0); nuclear@4: float invdirx = 1.0 / ray.dir.x; nuclear@4: float tmin = (bbox[xsign].x - ray.origin.x) * invdirx; nuclear@4: float tmax = (bbox[1 - xsign].x - ray.origin.x) * invdirx; nuclear@4: nuclear@4: int ysign = int(ray.dir.y < 0.0); nuclear@4: float invdiry = 1.0 / ray.dir.y; nuclear@4: float tymin = (bbox[ysign].y - ray.origin.y) * invdiry; nuclear@4: float tymax = (bbox[1 - ysign].y - ray.origin.y) * invdiry; nuclear@4: nuclear@4: if(tmin > tymax || tymin > tmax) { nuclear@5: return res; nuclear@4: } nuclear@4: nuclear@4: if(tymin > tmin) tmin = tymin; nuclear@4: if(tymax < tmax) tmax = tymax; nuclear@4: nuclear@4: int zsign = int(ray.dir.z < 0.0); nuclear@4: float invdirz = 1.0 / ray.dir.z; nuclear@4: float tzmin = (bbox[zsign].z - ray.origin.z) * invdirz; nuclear@4: float tzmax = (bbox[1 - zsign].z - ray.origin.z) * invdirz; nuclear@4: nuclear@4: if(tmin > tzmax || tzmin > tmax) { nuclear@5: return res; nuclear@4: } nuclear@4: nuclear@7: res.t0 = tmin; nuclear@7: res.t1 = tmax; nuclear@5: res.hit = true; nuclear@5: return res; nuclear@4: } nuclear@4: