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@4
|
15 vec3 refl;
|
nuclear@3
|
16 };
|
nuclear@3
|
17
|
nuclear@3
|
18 vec3 shade(Ray ray, HitPoint hit);
|
nuclear@4
|
19 vec3 sky(Ray ray);
|
nuclear@4
|
20 HitPoint ray_march(Ray ray);
|
nuclear@4
|
21 float eval_blobs(vec3 pt);
|
nuclear@4
|
22 vec3 calc_blob_normal(vec3 pt);
|
nuclear@3
|
23 HitPoint intersect_aabb(Ray ray, AABBox aabb);
|
nuclear@3
|
24 Ray get_primary_ray(float x, float y);
|
nuclear@4
|
25 float luminance(vec3 col);
|
nuclear@4
|
26 float fresnel(float r, float cosa);
|
nuclear@4
|
27 vec3 get_blob(int i);
|
nuclear@3
|
28
|
nuclear@4
|
29 #define BLOB_THRESHOLD 0.5
|
nuclear@4
|
30 #define BLOB_SCALE (1.0 / 4.0)
|
nuclear@4
|
31 #define MAX_ITER 1
|
nuclear@4
|
32
|
nuclear@4
|
33 #define RAY_STEP (0.75 / volsize.z)
|
nuclear@3
|
34
|
nuclear@3
|
35 #define FOV camprop.x
|
nuclear@3
|
36 #define ASPECT camprop.y
|
nuclear@3
|
37 uniform vec4 camprop;
|
nuclear@3
|
38 uniform vec3 volsize;
|
nuclear@3
|
39 uniform sampler3D voltex;
|
nuclear@4
|
40 uniform vec3 worldsize;
|
nuclear@3
|
41
|
nuclear@4
|
42 uniform sampler1D blobtex;
|
nuclear@4
|
43 uniform int num_blobs;
|
nuclear@3
|
44
|
nuclear@3
|
45 void main()
|
nuclear@3
|
46 {
|
nuclear@3
|
47 Ray ray = get_primary_ray(gl_TexCoord[0].x, gl_TexCoord[0].y);
|
nuclear@3
|
48
|
nuclear@4
|
49 HitPoint hit;
|
nuclear@3
|
50 vec3 color = vec3(0.0, 0.0, 0.0);
|
nuclear@4
|
51 vec3 power = vec3(1.0, 1.0, 1.0);
|
nuclear@4
|
52
|
nuclear@4
|
53 for(int i=0; i<=MAX_ITER; i++) {
|
nuclear@4
|
54 hit = ray_march(ray);
|
nuclear@4
|
55 if(hit.hit) {
|
nuclear@4
|
56 color += shade(ray, hit) * power;
|
nuclear@4
|
57 } else {
|
nuclear@4
|
58 color += sky(ray) * power;
|
nuclear@4
|
59 break;
|
nuclear@4
|
60 }
|
nuclear@4
|
61
|
nuclear@4
|
62 ray.origin = hit.pos + hit.normal * RAY_STEP;
|
nuclear@4
|
63 ray.dir = reflect(ray.dir, hit.normal);
|
nuclear@4
|
64 power *= hit.refl;
|
nuclear@4
|
65
|
nuclear@4
|
66 if(luminance(power) < 0.075) {
|
nuclear@4
|
67 break;
|
nuclear@4
|
68 }
|
nuclear@3
|
69 }
|
nuclear@3
|
70
|
nuclear@3
|
71 gl_FragColor = vec4(color, 1.0);
|
nuclear@3
|
72 }
|
nuclear@3
|
73
|
nuclear@3
|
74 vec3 shade(Ray ray, HitPoint hit)
|
nuclear@3
|
75 {
|
nuclear@3
|
76 const vec3 light_pos = vec3(-2, 3, 2);
|
nuclear@3
|
77 vec3 ldir = normalize(light_pos - hit.pos);
|
nuclear@3
|
78
|
nuclear@3
|
79 vec3 vdir = normalize(-ray.dir);
|
nuclear@3
|
80 vec3 hvec = normalize(vdir + ldir);
|
nuclear@3
|
81
|
nuclear@3
|
82 float ndotl = max(dot(hit.normal, ldir), 0.0);
|
nuclear@3
|
83 float ndoth = max(dot(hit.normal, hvec), 0.0);
|
nuclear@3
|
84
|
nuclear@3
|
85 vec3 diffuse = hit.color.xyz * ndotl;
|
nuclear@4
|
86 vec3 specular = hit.refl * pow(ndoth, 60.0);
|
nuclear@3
|
87
|
nuclear@4
|
88 vec3 color = diffuse + specular;
|
nuclear@4
|
89
|
nuclear@4
|
90 float fog = 0.0;//smoothstep(4.0, 8.0, hit.t0);
|
nuclear@4
|
91
|
nuclear@4
|
92 //const float fog_density = 0.18;
|
nuclear@4
|
93 //float fog = exp(-fog_density * fog_density * hit.t0 * hit.t0);
|
nuclear@4
|
94 //fog = clamp(fog, 0.0, 1.0);
|
nuclear@4
|
95
|
nuclear@4
|
96 return mix(color, sky(ray), fog);
|
nuclear@4
|
97 }
|
nuclear@4
|
98
|
nuclear@4
|
99 #define M_PI 3.141592653
|
nuclear@4
|
100
|
nuclear@4
|
101 vec3 sky(Ray ray)
|
nuclear@4
|
102 {
|
nuclear@4
|
103 const vec3 horiz = vec3(0.64, 0.70, 0.76);
|
nuclear@4
|
104 const vec3 zenith = vec3(0.65, 0.82, 0.94);
|
nuclear@4
|
105
|
nuclear@4
|
106 float angle = acos(ray.dir.y);
|
nuclear@4
|
107 float t = 1.0 - angle / (M_PI / 2.0);
|
nuclear@4
|
108
|
nuclear@4
|
109 return mix(horiz, zenith, smoothstep(-0.2, 0.2, t));
|
nuclear@3
|
110 }
|
nuclear@3
|
111
|
nuclear@3
|
112 vec4 fetch_voxel(vec3 pt)
|
nuclear@3
|
113 {
|
nuclear@3
|
114 pt *= 1.0 / worldsize;
|
nuclear@3
|
115 return texture3D(voltex, pt * 0.5 + 0.5);
|
nuclear@3
|
116 }
|
nuclear@3
|
117
|
nuclear@3
|
118 vec3 calc_voxel_normal(vec3 pt)
|
nuclear@3
|
119 {
|
nuclear@4
|
120 vec3 offs = 6.0 / volsize;
|
nuclear@3
|
121 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
|
122 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
|
123 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
|
124
|
nuclear@3
|
125 return -normalize(vec3(dfdx, dfdy, dfdz));
|
nuclear@3
|
126 }
|
nuclear@3
|
127
|
nuclear@4
|
128 HitPoint ray_march(Ray ray)
|
nuclear@3
|
129 {
|
nuclear@3
|
130 HitPoint hit;
|
nuclear@3
|
131 //AABBox aabb = AABBox(vec3(-1.0, -1.0, -1.0), vec3(1.0, 1.0, 1.0));
|
nuclear@3
|
132 AABBox aabb = AABBox(-worldsize.xzy, worldsize.xzy);
|
nuclear@3
|
133
|
nuclear@4
|
134 hit.hit = false;
|
nuclear@4
|
135 hit.t0 = hit.t1 = 0.0;
|
nuclear@4
|
136 hit.pos = hit.normal = vec3(0.0, 0.0, 0.0);
|
nuclear@4
|
137 hit.color = vec4(1.0, 1.0, 1.0, 1.0);
|
nuclear@4
|
138
|
nuclear@3
|
139
|
nuclear@3
|
140 hit = intersect_aabb(ray, aabb);
|
nuclear@3
|
141 if(!hit.hit) {
|
nuclear@3
|
142 return hit;
|
nuclear@3
|
143 }
|
nuclear@3
|
144
|
nuclear@3
|
145 /* start tracing from the first intersection, or if it's behind
|
nuclear@3
|
146 * the viewer, start from 0.
|
nuclear@3
|
147 */
|
nuclear@3
|
148 float dist = max(hit.t0, 0.0);
|
nuclear@3
|
149 float end_dist = hit.t1;
|
nuclear@3
|
150
|
nuclear@3
|
151 while(dist < end_dist) {
|
nuclear@3
|
152 vec3 pt = ray.origin + ray.dir * dist;
|
nuclear@4
|
153
|
nuclear@4
|
154 // first try evaluating the blob field at this point
|
nuclear@4
|
155 float blob = eval_blobs(pt);
|
nuclear@4
|
156 if(blob >= BLOB_THRESHOLD) {
|
nuclear@4
|
157 hit.t0 = dist;
|
nuclear@4
|
158 hit.pos = pt;
|
nuclear@4
|
159 hit.normal = calc_blob_normal(pt);
|
nuclear@4
|
160 hit.color = vec4(0.0, 0.0, 0.0, 1.0);
|
nuclear@4
|
161 hit.refl = vec3(1.0, 0.9, 0.75);
|
nuclear@4
|
162 return hit;
|
nuclear@4
|
163 }
|
nuclear@4
|
164
|
nuclear@3
|
165 vec4 voxel = fetch_voxel(pt.xzy);
|
nuclear@3
|
166 if(voxel.a > 0.5) {
|
nuclear@3
|
167 hit.t0 = dist;
|
nuclear@3
|
168 hit.pos = pt;
|
nuclear@3
|
169 hit.normal = calc_voxel_normal(pt.xzy).xzy;
|
nuclear@3
|
170 hit.color = voxel;
|
nuclear@4
|
171 hit.refl = vec3(0.0, 0.0, 0.0);
|
nuclear@3
|
172 return hit;
|
nuclear@3
|
173 }
|
nuclear@3
|
174
|
nuclear@3
|
175 dist += RAY_STEP;
|
nuclear@3
|
176 }
|
nuclear@3
|
177
|
nuclear@3
|
178 hit.hit = false;
|
nuclear@3
|
179 return hit;
|
nuclear@3
|
180 }
|
nuclear@3
|
181
|
nuclear@4
|
182 float eval_blobs(vec3 pt)
|
nuclear@4
|
183 {
|
nuclear@4
|
184 float val = 0.0;
|
nuclear@4
|
185
|
nuclear@4
|
186 for(int i=0; i<num_blobs; i++) {
|
nuclear@4
|
187 float dist = length(pt - get_blob(i));
|
nuclear@4
|
188 val += (dist * dist * (3.0 - 2.0 * dist));
|
nuclear@4
|
189 }
|
nuclear@4
|
190 return val;
|
nuclear@4
|
191 }
|
nuclear@4
|
192
|
nuclear@4
|
193 vec3 calc_blob_normal(vec3 pt)
|
nuclear@4
|
194 {
|
nuclear@4
|
195 const float offs = 0.01;
|
nuclear@4
|
196 vec3 grad;
|
nuclear@4
|
197 grad.x = eval_blobs(pt + vec3(offs, 0.0, 0.0)) - eval_blobs(pt - vec3(offs, 0.0, 0.0));
|
nuclear@4
|
198 grad.y = eval_blobs(pt + vec3(0.0, offs, 0.0)) - eval_blobs(pt - vec3(0.0, offs, 0.0));
|
nuclear@4
|
199 grad.z = eval_blobs(pt + vec3(0.0, 0.0, offs)) - eval_blobs(pt - vec3(0.0, 0.0, offs));
|
nuclear@4
|
200
|
nuclear@4
|
201 return -normalize(grad);
|
nuclear@4
|
202 }
|
nuclear@4
|
203
|
nuclear@3
|
204 HitPoint intersect_aabb(Ray ray, AABBox aabb)
|
nuclear@3
|
205 {
|
nuclear@3
|
206 HitPoint res;
|
nuclear@3
|
207
|
nuclear@4
|
208 res.pos = res.normal = vec3(0.0, 0.0, 0.0);
|
nuclear@4
|
209 res.color = vec4(1.0, 1.0, 1.0, 1.0);
|
nuclear@4
|
210 res.refl = vec3(0.0, 0.0, 0.0);
|
nuclear@4
|
211
|
nuclear@3
|
212 vec3 invR = 1.0 / ray.dir;
|
nuclear@4
|
213 vec3 tbot = invR * (aabb.vmin - ray.origin);
|
nuclear@4
|
214 vec3 ttop = invR * (aabb.vmax - ray.origin);
|
nuclear@4
|
215 vec3 tmin = min(ttop, tbot);
|
nuclear@4
|
216 vec3 tmax = max(ttop, tbot);
|
nuclear@4
|
217 vec2 t = max(tmin.xx, tmin.yz);
|
nuclear@4
|
218 res.t0 = max(t.x, t.y);
|
nuclear@4
|
219 t = min(tmax.xx, tmax.yz);
|
nuclear@4
|
220 res.t1 = min(t.x, t.y);
|
nuclear@3
|
221
|
nuclear@4
|
222 if(res.t0 <= res.t1) {
|
nuclear@3
|
223 res.hit = true;
|
nuclear@3
|
224 } else {
|
nuclear@3
|
225 res.hit = false;
|
nuclear@3
|
226 }
|
nuclear@3
|
227 return res;
|
nuclear@3
|
228 }
|
nuclear@3
|
229
|
nuclear@3
|
230 Ray get_primary_ray(float x, float y)
|
nuclear@3
|
231 {
|
nuclear@3
|
232 vec3 dir;
|
nuclear@3
|
233 dir.x = ASPECT * (2.0 * x - 1.0);
|
nuclear@3
|
234 dir.y = 2.0 * y - 1.0;
|
nuclear@3
|
235 dir.z = -1.0 / tan(FOV / 2.0);
|
nuclear@3
|
236
|
nuclear@3
|
237 Ray ray;
|
nuclear@3
|
238 ray.origin = (gl_ModelViewMatrix * vec4(0.0, 0.0, 0.0, 1.0)).xyz;
|
nuclear@3
|
239 ray.dir = gl_NormalMatrix * normalize(dir);
|
nuclear@3
|
240 return ray;
|
nuclear@3
|
241 }
|
nuclear@4
|
242
|
nuclear@4
|
243 float luminance(vec3 col)
|
nuclear@4
|
244 {
|
nuclear@4
|
245 //const vec3 fact = vec3(0.2126, 0.7152, 0.0722);
|
nuclear@4
|
246 //return dot(col, fact);
|
nuclear@4
|
247 return (col.x + col.y + col.z) / 3.0;
|
nuclear@4
|
248 }
|
nuclear@4
|
249
|
nuclear@4
|
250 float fresnel(float r, float cosa)
|
nuclear@4
|
251 {
|
nuclear@4
|
252 float inv_cosa = 1.0 - cosa;
|
nuclear@4
|
253 float inv_cosa_sq = inv_cosa * inv_cosa;
|
nuclear@4
|
254
|
nuclear@4
|
255 return r + (1.0 - r) * inv_cosa_sq * inv_cosa_sq * inv_cosa;
|
nuclear@4
|
256 }
|
nuclear@4
|
257
|
nuclear@4
|
258 vec3 get_blob(int i)
|
nuclear@4
|
259 {
|
nuclear@4
|
260 float tc = float(i) / float(num_blobs);
|
nuclear@4
|
261 return texture1D(blobtex, tc).xyz;
|
nuclear@4
|
262 }
|