svn merge -r 17201:17502 https://svn.blender.org/svnroot/bf-blender/trunk/blender
[blender-staging.git] / source / blender / render / intern / source / volumetric.c
1 /**
2  *
3  * ***** BEGIN GPL LICENSE BLOCK *****
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software Foundation,
17  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18  *
19  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
20  * All rights reserved.
21  *
22  * The Original Code is: all of this file.
23  *
24  * Contributor(s): Matt Ebb, Raul Hernandez.
25  *
26  * ***** END GPL LICENSE BLOCK *****
27  */
28
29 #include <math.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <float.h>
33
34 #include "MEM_guardedalloc.h"
35
36 #include "BLI_blenlib.h"
37 #include "BLI_arithb.h"
38 #include "BLI_rand.h"
39
40 #include "RE_shader_ext.h"
41 #include "RE_raytrace.h"
42
43 #include "DNA_material_types.h"
44 #include "DNA_group_types.h"
45 #include "DNA_lamp_types.h"
46
47 #include "BKE_global.h"
48
49 #include "render_types.h"
50 #include "pixelshading.h"
51 #include "shading.h"
52 #include "texture.h"
53 #include "volumetric.h"
54
55 #if defined( _MSC_VER ) && !defined( __cplusplus )
56 # define inline __inline
57 #endif // defined( _MSC_VER ) && !defined( __cplusplus )
58
59 /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
60 /* defined in pipeline.c, is hardcopy of active dynamic allocated Render */
61 /* only to be used here in this file, it's for speed */
62 extern struct Render R;
63 /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
64
65 static int vol_backface_intersect_check(Isect *is, int ob, RayFace *face)
66 {
67         VlakRen *vlr = (VlakRen *)face;
68         
69         /* only consider faces away, so overlapping layers
70          * of foward facing geometry don't cause the ray to stop */
71         return (INPR(is->vec, vlr->n) < 0.0f);
72 }
73
74 /* TODO: Box or sphere intersection types could speed things up */
75 static int vol_get_bounds(ShadeInput *shi, float *co, float *vec, float *hitco, Isect *isect, int intersect_type, int checkfunc)
76 {
77         float maxsize = RE_ray_tree_max_size(R.raytree);
78         int intersected=0;
79
80         /* TODO: use object's bounding box to calculate max size */
81         VECCOPY(isect->start, co);
82         isect->end[0] = co[0] + vec[0] * maxsize;
83         isect->end[1] = co[1] + vec[1] * maxsize;
84         isect->end[2] = co[2] + vec[2] * maxsize;
85         
86         isect->mode= RE_RAY_MIRROR;
87         isect->oborig= RAY_OBJECT_SET(&R, shi->obi);
88         isect->face_last= NULL;
89         isect->ob_last= 0;
90         isect->lay= -1;
91         
92         if (intersect_type == VOL_BOUNDS_DEPTH) isect->faceorig= (RayFace*)shi->vlr;
93         else if (intersect_type == VOL_BOUNDS_SS) isect->faceorig= NULL;
94         
95         if (checkfunc==VOL_IS_BACKFACE)
96                 intersected = RE_ray_tree_intersect_check(R.raytree, isect, vol_backface_intersect_check);
97         else
98                 intersected = RE_ray_tree_intersect(R.raytree, isect);
99         
100         if(intersected)
101         {
102                 float isvec[3];
103
104                 VECCOPY(isvec, isect->vec);
105                 hitco[0] = isect->start[0] + isect->labda*isvec[0];
106                 hitco[1] = isect->start[1] + isect->labda*isvec[1];
107                 hitco[2] = isect->start[2] + isect->labda*isvec[2];
108                 
109                 return 1;
110         } else {
111                 return 0;
112         }
113 }
114
115 float vol_get_stepsize(struct ShadeInput *shi, int context)
116 {
117         if (shi->mat->vol_stepsize_type == MA_VOL_STEP_RANDOMIZED) {
118                 /* range between 0.75 and 1.25 */
119                 const float rnd = 0.5f * BLI_thread_frand(shi->thread) + 0.75f;
120         
121                 if (context == STEPSIZE_VIEW)
122                         return shi->mat->vol_stepsize * rnd;
123                 else if (context == STEPSIZE_SHADE)
124                         return shi->mat->vol_shade_stepsize * rnd;
125         }
126         else {  // MA_VOL_STEP_CONSTANT
127                 
128                 if (context == STEPSIZE_VIEW)
129                         return shi->mat->vol_stepsize;
130                 else if (context == STEPSIZE_SHADE)
131                         return shi->mat->vol_shade_stepsize;
132         }
133         
134         return shi->mat->vol_stepsize;
135 }
136
137 /* SHADING */
138
139 static float D(ShadeInput *shi, int rgb, int x, int y, int z)
140 {
141         const int res = shi->mat->vol_precache_resolution;
142         CLAMP(x, 0, res-1);
143         CLAMP(y, 0, res-1);
144         CLAMP(z, 0, res-1);
145         return shi->obi->volume_precache[rgb*res*res*res + x*res*res + y*res + z];
146 }
147
148 inline float lerp(float t, float v1, float v2) {
149         return (1.f - t) * v1 + t * v2;
150 }
151
152 /* trilinear interpolation */
153 static void vol_get_precached_scattering(ShadeInput *shi, float *scatter_col, float *co)
154 {
155         const int res = shi->mat->vol_precache_resolution;
156         float voxx, voxy, voxz;
157         int vx, vy, vz;
158         float dx, dy, dz;
159         float d00, d10, d01, d11, d0, d1, d_final;
160         float bbmin[3], bbmax[3], dim[3];
161         int rgb;
162         
163         if (!shi->obi->volume_precache) return;
164         
165         VECCOPY(bbmin, shi->obi->obr->boundbox[0]);
166         VECCOPY(bbmax, shi->obi->obr->boundbox[1]);
167         VecSubf(dim, bbmax, bbmin);
168         
169         voxx = ((co[0] - bbmin[0]) / dim[0]) * res - 0.5f;
170         voxy = ((co[1] - bbmin[1]) / dim[1]) * res - 0.5f;
171         voxz = ((co[2] - bbmin[2]) / dim[2]) * res - 0.5f;
172         
173         vx = (int)voxx; vy = (int)voxy; vz = (int)voxz;
174         
175         dx = voxx - vx; dy = voxy - vy; dz = voxz - vz;
176         
177         for (rgb=0; rgb < 3; rgb++) {
178                 d00 = lerp(dx, D(shi, rgb, vx, vy, vz),                 D(shi, rgb, vx+1, vy, vz));
179                 d10 = lerp(dx, D(shi, rgb, vx, vy+1, vz),               D(shi, rgb, vx+1, vy+1, vz));
180                 d01 = lerp(dx, D(shi, rgb, vx, vy, vz+1),               D(shi, rgb, vx+1, vy, vz+1));
181                 d11 = lerp(dx, D(shi, rgb, vx, vy+1, vz+1),     D(shi, rgb, vx+1, vy+1, vz+1));
182                 d0 = lerp(dy, d00, d10);
183                 d1 = lerp(dy, d01, d11);
184                 d_final = lerp(dz, d0, d1);
185                 
186                 scatter_col[rgb] = d_final;
187         }
188 }
189
190 /* no interpolation */
191 static void vol_get_precached_scattering_nearest(ShadeInput *shi, float *scatter_col, float *co)
192 {
193         const int res = shi->mat->vol_precache_resolution;
194         int x,y,z;
195         float bbmin[3], bbmax[3], dim[3];
196
197         if (!shi->obi->volume_precache) return;
198         
199         VECCOPY(bbmin, shi->obi->obr->boundbox[0]);
200         VECCOPY(bbmax, shi->obi->obr->boundbox[1]);
201         VecSubf(dim, bbmax, bbmin);
202         
203         x = (int)(((co[0] - bbmin[0]) / dim[0]) * res);
204         y = (int)(((co[1] - bbmin[1]) / dim[1]) * res);
205         z = (int)(((co[2] - bbmin[2]) / dim[2]) * res);
206         
207         scatter_col[0] = shi->obi->volume_precache[0*res*res*res + x*res*res + y*res + z];
208         scatter_col[1] = shi->obi->volume_precache[1*res*res*res + x*res*res + y*res + z];
209         scatter_col[2] = shi->obi->volume_precache[2*res*res*res + x*res*res + y*res + z];
210 }
211
212 float vol_get_density(struct ShadeInput *shi, float *co)
213 {
214         float density = shi->mat->alpha;
215         float density_scale = shi->mat->vol_density_scale;
216         float col[3] = {0.0, 0.0, 0.0};
217         
218         if (shi->mat->flag & MA_IS_TEXTURED) {
219                 do_volume_tex(shi, co, MAP_ALPHA, col, &density);
220         }
221         
222         return density * density_scale;
223 }
224
225 /* compute emission component, amount of radiance to add per segment
226  * can be textured with 'emit' */
227 void vol_get_emission(ShadeInput *shi, float *em, float *co, float density)
228 {
229         float emission = shi->mat->emit;
230         float col[3] = {0.0, 0.0, 0.0};
231         
232         VECCOPY(col, &shi->mat->r);
233         
234         do_volume_tex(shi, co, MAP_EMIT+MAP_COL, col, &emission);
235         
236         em[0] = em[1] = em[2] = emission * density;
237         VecMulVecf(em, em, col);
238 }
239
240 /* scattering multiplier, values above 1.0 are non-physical, 
241  * but can be useful to tweak lighting */
242 void vol_get_scattering_fac(ShadeInput *shi, float *scatter_fac, float *co, float density)
243 {
244         *scatter_fac = shi->mat->vol_scattering;
245 }
246
247 /* phase function - determines in which directions the light 
248  * is scattered in the volume relative to incoming direction 
249  * and view direction */
250 float vol_get_phasefunc(ShadeInput *shi, short phasefunc_type, float g, float *w, float *wp)
251 {
252         const float costheta = Inpf(w, wp);
253         
254         if (phasefunc_type == MA_VOL_PH_ISOTROPIC) {
255                 return 1.f / (4.f * M_PI);
256         }
257         else if (phasefunc_type == MA_VOL_PH_MIEHAZY) {
258                 return (0.5f + 4.5f * powf(0.5 * (1.f + costheta), 8.f)) / (4.f*M_PI);
259         }
260         else if (phasefunc_type == MA_VOL_PH_MIEMURKY) {
261                 return (0.5f + 16.5f * powf(0.5 * (1.f + costheta), 32.f)) / (4.f*M_PI);
262         }
263         else if (phasefunc_type == MA_VOL_PH_RAYLEIGH) {
264                 return 3.f/(16.f*M_PI) * (1 + costheta * costheta);
265         }
266         else if (phasefunc_type == MA_VOL_PH_HG) {
267                 return 1.f / (4.f * M_PI) * (1.f - g*g) / powf(1.f + g*g - 2.f * g * costheta, 1.5f);
268         }
269         else if (phasefunc_type == MA_VOL_PH_SCHLICK) {
270                 const float k = 1.55f * g - .55f * g * g * g;
271                 const float kcostheta = k * costheta;
272                 return 1.f / (4.f * M_PI) * (1.f - k*k) / ((1.f - kcostheta) * (1.f - kcostheta));
273         } else {
274                 return 1.0f;
275         }
276 }
277
278 void vol_get_absorption(ShadeInput *shi, float *absorb_col, float *co)
279 {
280         float dummy = 1.0f;
281         float absorption = shi->mat->vol_absorption;
282         
283         VECCOPY(absorb_col, shi->mat->vol_absorption_col);
284         
285         if (shi->mat->flag & MA_IS_TEXTURED)
286                 do_volume_tex(shi, co, MAP_COLMIR, absorb_col, &dummy);
287         
288         absorb_col[0] = (1.0f - absorb_col[0]) * absorption;
289         absorb_col[1] = (1.0f - absorb_col[1]) * absorption;
290         absorb_col[2] = (1.0f - absorb_col[2]) * absorption;
291 }
292
293 /* Compute attenuation, otherwise known as 'optical thickness', extinction, or tau.
294  * Used in the relationship Transmittance = e^(-attenuation)
295  */
296 void vol_get_attenuation(ShadeInput *shi, float *tau, float *co, float *endco, float density, float stepsize)
297 {
298         /* input density = density at co */
299         float dist;
300         float absorb_col[3];
301         int s, nsteps;
302         float step_vec[3], step_sta[3], step_end[3];
303
304         vol_get_absorption(shi, absorb_col, co);
305
306         dist = VecLenf(co, endco);
307         nsteps = (int)((dist / stepsize) + 0.5);
308         
309         /* trigger for recalculating density */
310         if (density < -0.001f) density = vol_get_density(shi, co);
311         
312         if (nsteps == 1) {
313                 /* homogenous volume within the sampled distance */
314                 tau[0] = tau[1] = tau[2] = dist * density;
315                 
316                 VecMulVecf(tau, tau, absorb_col);
317                 return;
318         } else {
319                 tau[0] = tau[1] = tau[2] = 0.0;
320         }
321         
322         VecSubf(step_vec, endco, co);
323         VecMulf(step_vec, 1.0f / nsteps);
324         
325         VecCopyf(step_sta, co);
326         VecAddf(step_end, step_sta, step_vec);
327         
328         for (s = 0;  s < nsteps; s++) {
329                 if (s > 0)
330                         density = vol_get_density(shi, step_sta);
331                 
332                 tau[0] += stepsize * density;
333                 tau[1] += stepsize * density;
334                 tau[2] += stepsize * density;
335                 
336                 if (s < nsteps-1) {
337                         VECCOPY(step_sta, step_end);
338                         VecAddf(step_end, step_end, step_vec);
339                 }
340         }
341         VecMulVecf(tau, tau, absorb_col);
342 }
343
344 void vol_shade_one_lamp(struct ShadeInput *shi, float *co, LampRen *lar, float *lacol, float stepsize, float density)
345 {
346         float visifac, lv[3], lampdist;
347         float tau[3], tr[3]={1.0,1.0,1.0};
348         float hitco[3], *atten_co;
349         float p;
350         float scatter_fac;
351         float shade_stepsize = vol_get_stepsize(shi, STEPSIZE_SHADE);
352         
353         if (lar->mode & LA_LAYER) if((lar->lay & shi->obi->lay)==0) return;
354         if ((lar->lay & shi->lay)==0) return;
355         if (lar->energy == 0.0) return;
356         
357         visifac= lamp_get_visibility(lar, co, lv, &lampdist);
358         if(visifac==0.0f) return;
359
360         lacol[0] = lar->r;
361         lacol[1] = lar->g;
362         lacol[2] = lar->b;
363         
364         if(lar->mode & LA_TEXTURE) {
365                 shi->osatex= 0;
366                 do_lamp_tex(lar, lv, shi, lacol, LA_TEXTURE);
367         }
368
369         VecMulf(lacol, visifac*lar->energy);
370
371         if (ELEM(lar->type, LA_SUN, LA_HEMI))
372                 VECCOPY(lv, lar->vec);
373         VecMulf(lv, -1.0f);
374         
375         p = vol_get_phasefunc(shi, shi->mat->vol_phasefunc_type, shi->mat->vol_phasefunc_g, shi->view, lv);
376         VecMulf(lacol, p);
377         
378         if (shi->mat->vol_shadeflag & MA_VOL_ATTENUATED) {
379                 Isect is;
380                 
381                 /* find minimum of volume bounds, or lamp coord */
382                 if (vol_get_bounds(shi, co, lv, hitco, &is, VOL_BOUNDS_SS, 0)) {
383                         float dist = VecLenf(co, hitco);
384                         VlakRen *vlr = (VlakRen *)is.face;
385                         
386                         /* simple internal shadowing */
387                         if (vlr->mat->material_type == MA_SOLID) {
388                                 lacol[0] = lacol[1] = lacol[2] = 0.0f;
389                                 return;
390                         }
391
392                         if (ELEM(lar->type, LA_SUN, LA_HEMI))
393                                 atten_co = hitco;
394                         else if ( lampdist < dist ) {
395                                 atten_co = lar->co;
396                         } else
397                                 atten_co = hitco;
398                         
399                         vol_get_attenuation(shi, tau, co, atten_co, density, shade_stepsize);
400                         tr[0] = exp(-tau[0]);
401                         tr[1] = exp(-tau[1]);
402                         tr[2] = exp(-tau[2]);
403                         
404                         VecMulVecf(lacol, lacol, tr);
405                 }
406                 else {
407                         /* Point is on the outside edge of the volume,
408                          * therefore no attenuation, full transmission.
409                          * Radiance from lamp remains unchanged */
410                 }
411         }
412         
413         vol_get_scattering_fac(shi, &scatter_fac, co, density);
414         VecMulf(lacol, scatter_fac);
415 }
416
417 /* single scattering only for now */
418 void vol_get_scattering(ShadeInput *shi, float *scatter, float *co, float stepsize, float density)
419 {
420         GroupObject *go;
421         LampRen *lar;
422         float col[3] = {0.f, 0.f, 0.f};
423         int i=0;
424
425         for(go=R.lights.first; go; go= go->next)
426         {
427                 float lacol[3] = {0.f, 0.f, 0.f};
428         
429                 i++;
430         
431                 lar= go->lampren;
432                 if (lar) {
433                         vol_shade_one_lamp(shi, co, lar, lacol, stepsize, density);
434                         VecAddf(col, col, lacol);
435                 }
436         }
437         
438         VECCOPY(scatter, col);
439 }
440
441         
442 /*
443 The main volumetric integrator, using an emission/absorption/scattering model.
444
445 Incoming radiance = 
446
447 outgoing radiance from behind surface * beam transmittance/attenuation
448 + added radiance from all points along the ray due to participating media
449         --> radiance for each segment = 
450                 (radiance added by scattering + radiance added by emission) * beam transmittance/attenuation
451
452 -- To find transmittance:
453         compute optical thickness with tau (perhaps involving monte carlo integration)
454         transmittance = exp(-tau)
455         
456 -- To find radiance from segments along the way:
457         find radiance for one step: 
458         - loop over lights and weight by phase function
459 */
460 static void volumeintegrate(struct ShadeInput *shi, float *col, float *co, float *endco)
461 {
462         float tr[3] = {1.0f, 1.0f, 1.0f};
463         float radiance[3] = {0.f, 0.f, 0.f}, d_radiance[3] = {0.f, 0.f, 0.f};
464         float stepsize = vol_get_stepsize(shi, STEPSIZE_VIEW);
465         int nsteps, s;
466         float tau[3], emit_col[3], scatter_col[3] = {0.0, 0.0, 0.0};
467         float stepvec[3], step_sta[3], step_end[3], step_mid[3];
468         float density = vol_get_density(shi, co);
469         
470         /* multiply col_behind with beam transmittance over entire distance */
471         vol_get_attenuation(shi, tau, co, endco, density, stepsize);
472         tr[0] *= exp(-tau[0]);
473         tr[1] *= exp(-tau[1]);
474         tr[2] *= exp(-tau[2]);
475         VecMulVecf(radiance, tr, col);  
476         tr[0] = tr[1] = tr[2] = 1.0f;
477         
478         /* ray marching */
479         nsteps = (int)((VecLenf(co, endco) / stepsize) + 0.5);
480         
481         VecSubf(stepvec, endco, co);
482         VecMulf(stepvec, 1.0f / nsteps);
483         VecCopyf(step_sta, co);
484         VecAddf(step_end, step_sta, stepvec);
485         
486         /* get radiance from all points along the ray due to participating media */
487         for (s = 0; s < nsteps; s++) {
488
489                 if (s > 0) density = vol_get_density(shi, step_sta);
490                 
491                 /* there's only any use in shading here if there's actually some density to shade! */
492                 if (density > 0.01f) {
493                 
494                         /* transmittance component (alpha) */
495                         vol_get_attenuation(shi, tau, step_sta, step_end, density, stepsize);
496                         tr[0] *= exp(-tau[0]);
497                         tr[1] *= exp(-tau[1]);
498                         tr[2] *= exp(-tau[2]);
499                         
500                         step_mid[0] = step_sta[0] + (stepvec[0] * 0.5);
501                         step_mid[1] = step_sta[1] + (stepvec[1] * 0.5);
502                         step_mid[2] = step_sta[2] + (stepvec[2] * 0.5);
503                 
504                         /* incoming light via emission or scattering (additive) */
505                         vol_get_emission(shi, emit_col, step_mid, density);
506                         
507                         if ((shi->mat->vol_shadeflag & MA_VOL_PRECACHESHADING) &&
508                                 (shi->mat->vol_shadeflag & MA_VOL_ATTENUATED)) {
509                                 vol_get_precached_scattering(shi, scatter_col, step_mid);
510                         } else
511                                 vol_get_scattering(shi, scatter_col, step_mid, stepsize, density);
512                                                 
513                         VecMulf(scatter_col, density);
514                         VecAddf(d_radiance, emit_col, scatter_col);
515                         
516                         /*   Lv += Tr * (Lve() + Ld) */
517                         VecMulVecf(d_radiance, tr, d_radiance);
518                         VecMulf(d_radiance, stepsize);
519                         
520                         VecAddf(radiance, radiance, d_radiance);        
521                 }
522
523                 VecCopyf(step_sta, step_end);
524                 VecAddf(step_end, step_end, stepvec);
525         }
526         
527         VecCopyf(col, radiance);
528         col[3] = 1.0f -(tr[0] + tr[1] + tr[2]) * 0.333f;
529 }
530
531 static void shade_intersection(ShadeInput *shi, float *col, Isect *is)
532 {
533         ShadeInput shi_new;
534         ShadeResult shr_new;
535         
536         memset(&shi_new, 0, sizeof(ShadeInput)); 
537         
538         shi_new.mask= shi->mask;
539         shi_new.osatex= shi->osatex;
540         shi_new.thread= shi->thread;
541         shi_new.depth= 1;
542         shi_new.volume_depth= shi->volume_depth + 1;
543         shi_new.xs= shi->xs;
544         shi_new.ys= shi->ys;
545         shi_new.lay= shi->lay;
546         shi_new.passflag= SCE_PASS_COMBINED; /* result of tracing needs no pass info */
547         shi_new.combinedflag= 0xFFFFFF;          /* ray trace does all options */
548         shi_new.light_override= shi->light_override;
549         shi_new.mat_override= shi->mat_override;
550         
551         VECCOPY(shi_new.camera_co, is->start);
552         
553         memset(&shr_new, 0, sizeof(ShadeResult));
554
555         /* hardcoded limit of 100 for now - prevents problems in weird geometry */
556         if (shi->volume_depth < 100) {
557                 shade_ray(is, &shi_new, &shr_new);
558         }
559         
560         col[0] = shr_new.combined[0];
561         col[1] = shr_new.combined[1];
562         col[2] = shr_new.combined[2];
563         col[3] = shr_new.alpha;
564 }
565
566 static void vol_trace_behind(ShadeInput *shi, VlakRen *vlr, float *co, float *col)
567 {
568         Isect isect;
569         float maxsize = RE_ray_tree_max_size(R.raytree);
570
571         VECCOPY(isect.start, co);
572         isect.end[0] = isect.start[0] + shi->view[0] * maxsize;
573         isect.end[1] = isect.start[1] + shi->view[1] * maxsize;
574         isect.end[2] = isect.start[2] + shi->view[2] * maxsize;
575
576         isect.faceorig= (RayFace *)vlr;
577         
578         isect.mode= RE_RAY_MIRROR;
579         isect.oborig= RAY_OBJECT_SET(&R, shi->obi);
580         isect.face_last= NULL;
581         isect.ob_last= 0;
582         isect.lay= -1;
583         
584         /* check to see if there's anything behind the volume, otherwise shade the sky */
585         if(RE_ray_tree_intersect(R.raytree, &isect)) {
586                 shade_intersection(shi, col, &isect);
587         } else {
588                 shadeSkyView(col, co, shi->view, NULL, shi->thread);
589                 shadeSunView(col, shi->view);
590         }
591 }
592
593 /* the main entry point for volume shading */
594 void volume_trace(struct ShadeInput *shi, struct ShadeResult *shr)
595 {
596         float hitco[3], col[4] = {0.f,0.f,0.f,0.f};
597         Isect is;
598
599         memset(shr, 0, sizeof(ShadeResult));
600
601         /* if 1st hit normal is facing away from the camera, 
602          * then we're inside the volume already. */
603         if (shi->flippednor) {
604                 /* trace behind the 1st hit point */
605                 vol_trace_behind(shi, shi->vlr, shi->co, col);
606                 
607                 /* shade volume from 'camera' to 1st hit point */
608                 volumeintegrate(shi, col, shi->camera_co, shi->co);
609                 
610                 shr->combined[0] = col[0];
611                 shr->combined[1] = col[1];
612                 shr->combined[2] = col[2];
613                 
614                 if (shi->mat->vol_shadeflag & MA_VOL_USEALPHA) {
615                         if (col[3] > 1.0f)
616                                 col[3] = 1.0f;
617                 }
618                 else
619                         col[3] = 1.0f;
620                 shr->combined[3] = col[3];
621                 shr->alpha = col[3];
622                 
623                 VECCOPY(shr->diff, shr->combined);
624         }
625         /* trace to find a backface, the other side bounds of the volume */
626         /* (ray intersect ignores front faces here) */
627         else if (vol_get_bounds(shi, shi->co, shi->view, hitco, &is, VOL_BOUNDS_DEPTH, 0)) {
628                 VlakRen *vlr = (VlakRen *)is.face;
629                 
630                 /* if it's another face in the same material */
631                 if (vlr->mat == shi->mat) {
632                         /* trace behind the 2nd (raytrace) hit point */
633                         vol_trace_behind(shi, (VlakRen *)is.face, hitco, col);
634                 } else {
635                         shade_intersection(shi, col, &is);
636                 }
637         
638                 /* shade volume from 1st hit point to 2nd hit point */
639                 volumeintegrate(shi, col, shi->co, hitco);
640                 
641                 shr->combined[0] = col[0];
642                 shr->combined[1] = col[1];
643                 shr->combined[2] = col[2];
644                 
645                 if (shi->mat->vol_shadeflag & MA_VOL_USEALPHA) {
646                         if (col[3] > 1.0f)
647                                 col[3] = 1.0f;
648                 }
649                 else
650                         col[3] = 1.0f;
651                 shr->combined[3] = col[3];
652                 shr->alpha = col[3];
653                 
654                 VECCOPY(shr->diff, shr->combined);
655         }
656         else {
657                 shr->combined[0] = 0.0f;
658                 shr->combined[1] = 0.0f;
659                 shr->combined[2] = 0.0f;
660                 shr->combined[3] = shr->alpha =  1.0f;
661         }
662 }
663
664 /* Traces a shadow through the object, 
665  * pretty much gets the transmission over a ray path */
666 void volume_trace_shadow(struct ShadeInput *shi, struct ShadeResult *shr, struct Isect *last_is)
667 {
668         float hitco[3];
669         float tr[3] = {1.0,1.0,1.0};
670         float tau[3] = {0.0,0.0,0.0};
671         Isect is;
672         float shade_stepsize = vol_get_stepsize(shi, STEPSIZE_SHADE);
673
674         memset(shr, 0, sizeof(ShadeResult));
675         
676         /* if 1st hit normal is facing away from the camera, 
677          * then we're inside the volume already. */
678         if (shi->flippednor) {
679         
680                 vol_get_attenuation(shi, tau, last_is->start, shi->co, -1.0f, shade_stepsize);
681                 tr[0] = exp(-tau[0]);
682                 tr[1] = exp(-tau[1]);
683                 tr[2] = exp(-tau[2]);
684                 
685                 shr->combined[0] = tr[0];
686                 shr->combined[1] = tr[1];
687                 shr->combined[2] = tr[2];
688                 
689                 shr->combined[3] = 1.0f -(tr[0] + tr[1] + tr[2]) * 0.333f;
690                 shr->alpha = shr->combined[3];
691         }
692         /* trace to find a backface, the other side bounds of the volume */
693         /* (ray intersect ignores front faces here) */
694         else if (vol_get_bounds(shi, shi->co, shi->view, hitco, &is, VOL_BOUNDS_DEPTH, 0)) {
695                 
696                 vol_get_attenuation(shi, tau, shi->co, hitco, -1.0f, shade_stepsize);
697                 tr[0] = exp(-tau[0]);
698                 tr[1] = exp(-tau[1]);
699                 tr[2] = exp(-tau[2]);
700                 
701                 shr->combined[0] = tr[0];
702                 shr->combined[1] = tr[1];
703                 shr->combined[2] = tr[2];
704                 
705                 shr->combined[3] = 1.0f -(tr[0] + tr[1] + tr[2]) * 0.333f;
706                 shr->alpha = shr->combined[3];
707
708         }
709         else {
710                 shr->combined[0] = 0.0f;
711                 shr->combined[1] = 0.0f;
712                 shr->combined[2] = 0.0f;
713                 shr->combined[3] = shr->alpha =  0.0f;
714         }
715 }
716