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@5
|
128 ISect intersect_aabb(Ray ray, AABBox aabb)
|
nuclear@4
|
129 {
|
nuclear@5
|
130 ISect res;
|
nuclear@5
|
131 res.hit = false;
|
nuclear@7
|
132 res.t0 = res.t1 = 0.0;
|
nuclear@5
|
133
|
nuclear@4
|
134 if(ray.origin.x >= aabb.min.x && ray.origin.y >= aabb.min.y && ray.origin.z >= aabb.min.z &&
|
nuclear@4
|
135 ray.origin.x < aabb.max.x && ray.origin.y < aabb.max.y && ray.origin.z < aabb.max.z) {
|
nuclear@5
|
136 res.hit = true;
|
nuclear@5
|
137 return res;
|
nuclear@4
|
138 }
|
nuclear@4
|
139
|
nuclear@4
|
140 vec4 bbox[2];
|
nuclear@4
|
141 bbox[0] = vec4(aabb.min.x, aabb.min.y, aabb.min.z, 0);
|
nuclear@4
|
142 bbox[1] = vec4(aabb.max.x, aabb.max.y, aabb.max.z, 0);
|
nuclear@4
|
143
|
nuclear@4
|
144 int xsign = int(ray.dir.x < 0.0);
|
nuclear@4
|
145 float invdirx = 1.0 / ray.dir.x;
|
nuclear@4
|
146 float tmin = (bbox[xsign].x - ray.origin.x) * invdirx;
|
nuclear@4
|
147 float tmax = (bbox[1 - xsign].x - ray.origin.x) * invdirx;
|
nuclear@4
|
148
|
nuclear@4
|
149 int ysign = int(ray.dir.y < 0.0);
|
nuclear@4
|
150 float invdiry = 1.0 / ray.dir.y;
|
nuclear@4
|
151 float tymin = (bbox[ysign].y - ray.origin.y) * invdiry;
|
nuclear@4
|
152 float tymax = (bbox[1 - ysign].y - ray.origin.y) * invdiry;
|
nuclear@4
|
153
|
nuclear@4
|
154 if(tmin > tymax || tymin > tmax) {
|
nuclear@5
|
155 return res;
|
nuclear@4
|
156 }
|
nuclear@4
|
157
|
nuclear@4
|
158 if(tymin > tmin) tmin = tymin;
|
nuclear@4
|
159 if(tymax < tmax) tmax = tymax;
|
nuclear@4
|
160
|
nuclear@4
|
161 int zsign = int(ray.dir.z < 0.0);
|
nuclear@4
|
162 float invdirz = 1.0 / ray.dir.z;
|
nuclear@4
|
163 float tzmin = (bbox[zsign].z - ray.origin.z) * invdirz;
|
nuclear@4
|
164 float tzmax = (bbox[1 - zsign].z - ray.origin.z) * invdirz;
|
nuclear@4
|
165
|
nuclear@4
|
166 if(tmin > tzmax || tzmin > tmax) {
|
nuclear@5
|
167 return res;
|
nuclear@4
|
168 }
|
nuclear@4
|
169
|
nuclear@7
|
170 res.t0 = tmin;
|
nuclear@7
|
171 res.t1 = tmax;
|
nuclear@5
|
172 res.hit = true;
|
nuclear@5
|
173 return res;
|
nuclear@4
|
174 }
|
nuclear@4
|
175
|
nuclear@25
|
176
|
nuclear@25
|
177 ISect intersect_sphere(Ray ray, float rad)
|
nuclear@25
|
178 {
|
nuclear@25
|
179 ISect res;
|
nuclear@25
|
180 res.hit = false;
|
nuclear@25
|
181 res.t0 = res.t1 = 0.0;
|
nuclear@25
|
182
|
nuclear@25
|
183 float a = dot(ray.dir, ray.dir);
|
nuclear@25
|
184 float b = 2.0 * dot(ray.dir, ray.origin);
|
nuclear@25
|
185 float c = dot(ray.origin, ray.origin) - rad * rad;
|
nuclear@25
|
186 float d = b * b - 4.0 * a * c;
|
nuclear@25
|
187
|
nuclear@25
|
188 if(d < 0.0) {
|
nuclear@25
|
189 return res;
|
nuclear@25
|
190 }
|
nuclear@25
|
191
|
nuclear@25
|
192 float sqrt_d = sqrt(d);
|
nuclear@25
|
193 float t0 = (-b + sqrt_d) / (2.0 * a);
|
nuclear@25
|
194 float t1 = (-b - sqrt_d) / (2.0 * a);
|
nuclear@25
|
195
|
nuclear@25
|
196 res.t0 = min(t0, t1);
|
nuclear@25
|
197 res.t1 = max(t0, t1);
|
nuclear@25
|
198 res.hit = true;
|
nuclear@25
|
199
|
nuclear@25
|
200 /*res.pos = ray.origin + ray.dir * res.t0;
|
nuclear@25
|
201 res.normal = normalize(res.pos);*/
|
nuclear@25
|
202 return res;
|
nuclear@25
|
203 }
|