1+ #version 430
2+
3+ layout (binding = 1) uniform sampler3D TexVolume;
4+ layout (binding = 2) uniform sampler1D TexTransferFunc;
5+ layout (binding = 3) uniform sampler3D TexVolumeGradient;
6+ layout (binding = 4) uniform sampler3D TexVolumeLightCache;
7+
8+ uniform vec3 VolumeScaledSizes;
9+
10+ uniform vec3 CameraEye;
11+
12+ uniform mat4 ViewMatrix;
13+ uniform mat4 ProjectionMatrix;
14+
15+ uniform float fov_y_tangent;
16+ uniform float aspect_ratio;
17+
18+ uniform float StepSize;
19+
20+ uniform vec3 VolumeScales;
21+
22+ uniform int ApplyPhongShading;
23+
24+ uniform float Kambient;
25+ uniform float Kdiffuse;
26+ uniform float Kspecular;
27+ uniform float Nshininess;
28+
29+ uniform vec3 Ispecular;
30+
31+ uniform vec3 WorldEyePos;
32+ uniform vec3 WorldLightingPos;
33+
34+ uniform int ApplyOcclusion;
35+ uniform int ApplyShadow;
36+
37+ // size of each work group
38+ layout (local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
39+ layout (rgba16f, binding = 0) uniform image2D OutputFrag;
40+
41+ struct Ray {
42+ vec3 Origin;
43+ vec3 Dir;
44+ };
45+
46+ // Intersect ray with a box
47+ // http://www.siggraph.org/education/materials/HyperGraph/raytrace/rtinter3.htm
48+ bool IntersectBox (Ray r, vec3 boxmin, vec3 boxmax, out float tnear, out float tfar)
49+ {
50+ vec3 invR = vec3(1.0) / r.Dir;
51+
52+ vec3 tbbmin = invR * (boxmin - r.Origin);
53+ vec3 tbbmax = invR * (boxmax - r.Origin);
54+
55+ vec3 tmin = min(tbbmin, tbbmax);
56+ vec3 tmax = max(tbbmin, tbbmax);
57+
58+ tnear = max(max(tmin.x, tmin.y), tmin.z);
59+ tfar = min(min(tmax.x, tmax.y), tmax.z);
60+
61+ return tfar > tnear;
62+ }
63+
64+ bool RayAABBIntersection (vec3 vert_eye, vec3 vert_dir, out Ray r, out float rtnear, out float rtfar)
65+ {
66+ vec3 aabbmin = -VolumeScaledSizes * 0.5;
67+ vec3 aabbmax = VolumeScaledSizes * 0.5;
68+
69+ r.Origin = vert_eye;
70+ r.Dir = normalize(vert_dir);
71+
72+ float tnear, tfar;
73+ bool hit = IntersectBox(r, aabbmin, aabbmax, tnear, tfar);
74+
75+ tnear = max(tnear, 0.0);
76+
77+ rtnear = tnear;
78+ rtfar = tfar;
79+
80+ return hit;
81+ }
82+
83+ #if 0
84+ bool Shade = ApplyOcclusion == 1 || ApplyShadow == 1;
85+ vec4 ShadeSample (vec4 clr, vec3 tx_pos)
86+ {
87+ vec4 L = clr;
88+ float ka = 0.0, kd = 0.0, ks = 0.0;
89+
90+ if (Shade)
91+ {
92+ vec2 IaIs = texture(TexVolumeLightCache, tx_pos / VolumeScaledSizes).rg;
93+
94+ // Directional Cone Occlusion
95+ float IOcclusion = 0.0;
96+ if (ApplyOcclusion == 1)
97+ {
98+ ka = Kambient;
99+ IOcclusion = IaIs.r;
100+ }
101+
102+ // Directional Cone Shadow
103+ float IShadow = 0.0;
104+ if (ApplyShadow == 1)
105+ {
106+ kd = Kdiffuse;
107+ ks = Kspecular;
108+ IShadow = IaIs.g;
109+ }
110+
111+ if (ApplyPhongShading == 1)
112+ {
113+ vec3 Wpos = tx_pos - (VolumeScaledSizes * 0.5);
114+ vec3 gradient_normal = texture(TexVolumeGradient, tx_pos / VolumeScaledSizes).xyz;
115+
116+ if (gradient_normal != vec3(0, 0, 0))
117+ {
118+ gradient_normal = normalize(gradient_normal);
119+
120+ vec3 light_direction = normalize(WorldLightingPos - Wpos);
121+ vec3 eye_direction = normalize(CameraEye - Wpos);
122+ vec3 halfway_vector = normalize(eye_direction + light_direction);
123+
124+ float dot_diff = max(0, dot(gradient_normal, light_direction));
125+ float dot_spec = max(0, dot(halfway_vector, gradient_normal));
126+
127+ L.rgb = (1.0 / (ka + kd)) * (L.rgb * IOcclusion * ka + IShadow * (L.rgb * kd * dot_diff))
128+ + IShadow * (ks * Ispecular * pow(dot_spec, Nshininess));
129+ }
130+ }
131+ else
132+ {
133+ L.rgb = (1.0 / (ka + kd)) * (L.rgb * IOcclusion * ka + L.rgb * IShadow * kd);
134+ }
135+ }
136+
137+ return L;
138+ }
139+
140+ void main ()
141+ {
142+ ivec2 storePos = ivec2(gl_GlobalInvocationID.xy);
143+
144+ ivec2 size = imageSize(OutputFrag);
145+ if (storePos.x < size.x && storePos.y < size.y)
146+ {
147+ vec2 fpos = vec2(storePos) + 0.5;
148+
149+ // Transform from [0, 1] to [-1, 1]
150+ vec3 VerPos = (vec3(fpos.x / float(size.x), fpos.y / float(size.y), 0.0) * 2.0) - 1.0;
151+ // Camera direction
152+ vec3 camera_dir = vec3(VerPos.x * fov_y_tangent * aspect_ratio, VerPos.y * fov_y_tangent, -1.0) * mat3(ViewMatrix);
153+ camera_dir = normalize(camera_dir);
154+
155+ Ray r; float tnear, tfar;
156+ bool inbox = RayAABBIntersection(CameraEye, camera_dir, r, tnear, tfar);
157+
158+ if(inbox)
159+ {
160+ // Distance to be evaluated
161+ float D = abs(tfar - tnear);
162+
163+ // Initialize Transparency and Radiance color
164+ vec4 dst = vec4(0.0);
165+
166+ // World position at tnear, translating the volume to [0, VolumeAABB]
167+ vec3 wd_pos = r.Origin + r.Dir * tnear;
168+ wd_pos = wd_pos + (VolumeScaledSizes * 0.5);
169+ vec3 InvVolumeScaledSizes = 1.0 / VolumeScaledSizes;
170+
171+ // Evaluate from 0 to D...
172+ for (float s = 0.0; s < D;)
173+ {
174+ // Get the current step or the remaining interval
175+ float h = min(StepSize, D - s);
176+
177+ // Texture position at tnear + (s + h/2)
178+ vec3 tx_pos = wd_pos + r.Dir * (s + h * 0.5);
179+
180+ // Get normalized density from volume
181+ float density = texture(TexVolume, tx_pos * InvVolumeScaledSizes).r;
182+
183+ // Get color from transfer function given the normalized density
184+ vec4 src = texture(TexTransferFunc, density);
185+
186+ // Shade sample
187+ if (src.a > 0.0)
188+ {
189+ src = ShadeSample(src, tx_pos);
190+
191+ // Evaluate the current opacity
192+ src.a = 1.0 - exp(-src.a * h);
193+
194+ // Front-to-back composition
195+ src.rgb = src.rgb * src.a;
196+ dst = dst + (1.0 - dst.a) * src;
197+
198+ // early termination
199+ if (dst.a > 0.99) break;
200+ }
201+
202+ // Go to the next interval
203+ s = s + h;
204+ }
205+ imageStore(OutputFrag, storePos, dst);
206+ }
207+ }
208+ }
209+
210+ #else
211+ vec4 ShadeSample (vec4 clr, vec3 tx_pos)
212+ {
213+ vec4 L = clr;
214+
215+ vec2 IaIs = texture(TexVolumeLightCache, tx_pos / VolumeScaledSizes).rg;
216+
217+ float ka = 0.0, kd = 0.0, ks = 0.0;
218+
219+ // Directional Cone Occlusion
220+ float IOcclusion = 0.0;
221+ if (ApplyOcclusion == 1)
222+ {
223+ ka = Kambient;
224+ IOcclusion = IaIs.r;
225+ }
226+
227+ // Directional Cone Shadow
228+ float IShadow = 0.0;
229+ if (ApplyShadow == 1)
230+ {
231+ kd = Kdiffuse;
232+ ks = Kspecular;
233+ IShadow = IaIs.g;
234+ }
235+
236+ if (ApplyPhongShading == 1)
237+ {
238+ vec3 Wpos = tx_pos - (VolumeScaledSizes * 0.5);
239+ vec3 gradient_normal = texture(TexVolumeGradient, tx_pos / VolumeScaledSizes).xyz;
240+
241+ if (gradient_normal != vec3(0, 0, 0))
242+ {
243+ gradient_normal = normalize(gradient_normal);
244+
245+ vec3 light_direction = normalize(WorldLightingPos - Wpos);
246+ vec3 eye_direction = normalize(CameraEye - Wpos);
247+ vec3 halfway_vector = normalize(eye_direction + light_direction);
248+
249+ float dot_diff = max(0, dot(gradient_normal, light_direction));
250+ float dot_spec = max(0, dot(halfway_vector, gradient_normal));
251+
252+ L.rgb = (1.0 / (ka + kd)) * (L.rgb * IOcclusion * ka + IShadow * (L.rgb * kd * dot_diff))
253+ + IShadow * (ks * Ispecular * pow(dot_spec, Nshininess));
254+ }
255+ }
256+ else
257+ {
258+ L.rgb = (1.0 / (ka + kd)) * (L.rgb * IOcclusion * ka + L.rgb * IShadow * kd);
259+ }
260+
261+ return L;
262+ }
263+
264+ void main ()
265+ {
266+ ivec2 storePos = ivec2(gl_GlobalInvocationID.xy);
267+
268+ ivec2 size = imageSize(OutputFrag);
269+ if (storePos.x < size.x && storePos.y < size.y)
270+ {
271+ vec2 fpos = vec2(storePos) + 0.5;
272+
273+ // Transform from [0, 1] to [-1, 1]
274+ vec3 VerPos = (vec3(fpos.x / float(size.x), fpos.y / float(size.y), 0.0f) * 2.0f) - 1.0f;
275+ // Camera direction
276+ vec3 camera_dir = vec3(VerPos.x * fov_y_tangent * aspect_ratio, VerPos.y * fov_y_tangent, -1.0f) * mat3(ViewMatrix);
277+ camera_dir = normalize(camera_dir);
278+
279+ Ray r; float tnear, tfar;
280+ bool inbox = RayAABBIntersection(CameraEye, camera_dir, r, tnear, tfar);
281+
282+ if(inbox)
283+ {
284+ // Distance to be evaluated
285+ float D = abs(tfar - tnear);
286+
287+ // Initialize Transparency and Radiance color
288+ vec4 color = vec4(0.0f);
289+
290+ // World position at tnear, translating the volume to [0, VolumeAABB]
291+ vec3 wd_pos = r.Origin + r.Dir * tnear;
292+ wd_pos = wd_pos + (VolumeScaledSizes * 0.5f);
293+ vec3 InvVolumeScaledSizes = 1.0f / VolumeScaledSizes;
294+ bool Shade = ApplyOcclusion == 1 || ApplyShadow == 1;
295+
296+ // Evaluate from 0 to D...
297+ for (float s = 0.0f; s < D;)
298+ {
299+ // Get the current step or the remaining interval
300+ float h = min(StepSize, D - s);
301+
302+ // Texture position at tnear + (s + h/2)
303+ vec3 tx_pos = wd_pos + r.Dir * (s + h * 0.5f);
304+
305+ // Get normalized density from volume
306+ float density = texture(TexVolume, tx_pos * InvVolumeScaledSizes).r;
307+
308+ // Get color from transfer function given the normalized density
309+ vec4 src = texture(TexTransferFunc, density);
310+
311+ // Shade sample
312+ if (src.a > 0.0 && Shade)
313+ {
314+ src = ShadeSample(src, tx_pos);
315+
316+ // Evaluate the current opacity
317+ src.a = 1.0f - exp(-src.a * h);
318+
319+ // Front-to-back composition
320+ src.rgb = src.rgb * src.a;
321+ color = color + (1.0f - color.a) * src;
322+
323+ // Opacity threshold: a > 0.95
324+ if (color.a > 0.99f) break ;
325+ }
326+
327+ // Go to the next interval
328+ s = s + h;
329+ }
330+ imageStore(OutputFrag, storePos, color);
331+ }
332+ }
333+ }
334+ #endif
0 commit comments