nuclear@3: struct Ray { nuclear@3: vec3 origin; nuclear@3: vec3 dir; nuclear@3: }; nuclear@3: nuclear@3: struct AABBox { nuclear@3: vec3 vmin, vmax; nuclear@3: }; nuclear@3: nuclear@3: struct HitPoint { nuclear@3: bool hit; nuclear@3: float t0, t1; nuclear@3: vec3 pos, normal; nuclear@3: vec4 color; nuclear@3: }; nuclear@3: nuclear@3: vec3 shade(Ray ray, HitPoint hit); nuclear@3: HitPoint intersect_voxels(Ray ray); nuclear@3: HitPoint intersect_aabb(Ray ray, AABBox aabb); nuclear@3: Ray get_primary_ray(float x, float y); nuclear@3: nuclear@3: #define RAY_STEP 0.001 nuclear@3: nuclear@3: #define FOV camprop.x nuclear@3: #define ASPECT camprop.y nuclear@3: uniform vec4 camprop; nuclear@3: uniform vec3 volsize; nuclear@3: uniform sampler3D voltex; nuclear@3: nuclear@3: //const vec3 worldsize = vec3(4.0, 4.0, 2.0); nuclear@3: const vec3 worldsize = vec3(1.0, 1.0, 0.5); nuclear@3: nuclear@3: void main() nuclear@3: { nuclear@3: Ray ray = get_primary_ray(gl_TexCoord[0].x, gl_TexCoord[0].y); nuclear@3: nuclear@3: vec3 color = vec3(0.0, 0.0, 0.0); nuclear@3: HitPoint hit = intersect_voxels(ray); nuclear@3: if(hit.hit) { nuclear@3: color = shade(ray, hit); nuclear@3: } nuclear@3: nuclear@3: gl_FragColor = vec4(color, 1.0); nuclear@3: } nuclear@3: nuclear@3: vec3 shade(Ray ray, HitPoint hit) nuclear@3: { nuclear@3: const vec3 light_pos = vec3(-2, 3, 2); nuclear@3: vec3 ldir = normalize(light_pos - hit.pos); nuclear@3: nuclear@3: vec3 vdir = normalize(-ray.dir); nuclear@3: vec3 hvec = normalize(vdir + ldir); nuclear@3: nuclear@3: float ndotl = max(dot(hit.normal, ldir), 0.0); nuclear@3: float ndoth = max(dot(hit.normal, hvec), 0.0); nuclear@3: nuclear@3: vec3 diffuse = hit.color.xyz * ndotl; nuclear@3: vec3 specular = vec3(0.4, 0.4, 0.4) * pow(ndoth, 60.0); nuclear@3: nuclear@3: return diffuse + specular; nuclear@3: } nuclear@3: nuclear@3: vec4 fetch_voxel(vec3 pt) nuclear@3: { nuclear@3: pt *= 1.0 / worldsize; nuclear@3: return texture3D(voltex, pt * 0.5 + 0.5); nuclear@3: } nuclear@3: nuclear@3: vec3 calc_voxel_normal(vec3 pt) nuclear@3: { nuclear@3: vec3 offs = 1.8 / volsize; nuclear@3: 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: 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: 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: nuclear@3: return -normalize(vec3(dfdx, dfdy, dfdz)); nuclear@3: } nuclear@3: nuclear@3: HitPoint intersect_voxels(Ray ray) nuclear@3: { nuclear@3: HitPoint hit; nuclear@3: //AABBox aabb = AABBox(vec3(-1.0, -1.0, -1.0), vec3(1.0, 1.0, 1.0)); nuclear@3: AABBox aabb = AABBox(-worldsize.xzy, worldsize.xzy); nuclear@3: nuclear@3: nuclear@3: hit = intersect_aabb(ray, aabb); nuclear@3: if(!hit.hit) { nuclear@3: return hit; nuclear@3: } nuclear@3: nuclear@3: /* start tracing from the first intersection, or if it's behind nuclear@3: * the viewer, start from 0. nuclear@3: */ nuclear@3: float dist = max(hit.t0, 0.0); nuclear@3: float end_dist = hit.t1; nuclear@3: nuclear@3: while(dist < end_dist) { nuclear@3: vec3 pt = ray.origin + ray.dir * dist; nuclear@3: vec4 voxel = fetch_voxel(pt.xzy); nuclear@3: nuclear@3: nuclear@3: if(voxel.a > 0.5) { nuclear@3: hit.t0 = dist; nuclear@3: hit.pos = pt; nuclear@3: hit.normal = calc_voxel_normal(pt.xzy).xzy; nuclear@3: hit.color = voxel; nuclear@3: return hit; nuclear@3: } nuclear@3: nuclear@3: dist += RAY_STEP; nuclear@3: } nuclear@3: nuclear@3: hit.hit = false; nuclear@3: return hit; nuclear@3: } nuclear@3: nuclear@3: HitPoint intersect_aabb(Ray ray, AABBox aabb) nuclear@3: { nuclear@3: HitPoint res; nuclear@3: nuclear@3: vec3 invR = 1.0 / ray.dir; nuclear@3: vec3 tbot = invR * (aabb.vmin - ray.origin); nuclear@3: vec3 ttop = invR * (aabb.vmax - ray.origin); nuclear@3: vec3 tmin = min(ttop, tbot); nuclear@3: vec3 tmax = max(ttop, tbot); nuclear@3: vec2 t = max(tmin.xx, tmin.yz); nuclear@3: float t0 = max(t.x, t.y); nuclear@3: t = min(tmax.xx, tmax.yz); nuclear@3: float t1 = min(t.x, t.y); nuclear@3: nuclear@3: if(t0 <= t1) { nuclear@3: res.hit = true; nuclear@3: res.t0 = t0; nuclear@3: res.t1 = t1; nuclear@3: } else { nuclear@3: res.hit = false; nuclear@3: } nuclear@3: return res; nuclear@3: } nuclear@3: nuclear@3: Ray get_primary_ray(float x, float y) nuclear@3: { nuclear@3: vec3 dir; nuclear@3: dir.x = ASPECT * (2.0 * x - 1.0); nuclear@3: dir.y = 2.0 * y - 1.0; nuclear@3: dir.z = -1.0 / tan(FOV / 2.0); nuclear@3: nuclear@3: Ray ray; nuclear@3: ray.origin = (gl_ModelViewMatrix * vec4(0.0, 0.0, 0.0, 1.0)).xyz; nuclear@3: ray.dir = gl_NormalMatrix * normalize(dir); nuclear@3: return ray; nuclear@3: }