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