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 }
|