svn merge https://svn.blender.org/svnroot/bf-blender/trunk/blender -r22935:23022
[blender.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 Fernandez Hernandez (Farsthary)
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 #include "BLI_voxel.h"
40
41 #include "RE_shader_ext.h"
42 #include "RE_raytrace.h"
43
44 #include "DNA_material_types.h"
45 #include "DNA_group_types.h"
46 #include "DNA_lamp_types.h"
47
48 #include "BKE_global.h"
49
50 #include "render_types.h"
51 #include "pixelshading.h"
52 #include "shading.h"
53 #include "texture.h"
54 #include "volumetric.h"
55 #include "volume_precache.h"
56
57 #if defined( _MSC_VER ) && !defined( __cplusplus )
58 # define inline __inline
59 #endif // defined( _MSC_VER ) && !defined( __cplusplus )
60
61 /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
62 /* defined in pipeline.c, is hardcopy of active dynamic allocated Render */
63 /* only to be used here in this file, it's for speed */
64 extern struct Render R;
65 /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
66
67
68 /* tracing */
69
70 static int vol_get_bounds(ShadeInput *shi, float *co, float *vec, float *hitco, Isect *isect, int intersect_type)
71 {
72         float maxsize = RE_ray_tree_max_size(R.raytree);
73         
74         /* XXX TODO - get raytrace max distance from object instance's bounding box */
75         /* need to account for scaling only, but keep coords in camera space...
76          * below code is WIP and doesn't work!
77         VecSubf(bb_dim, shi->obi->obr->boundbox[1], shi->obi->obr->boundbox[2]);
78         Mat3MulVecfl(shi->obi->nmat, bb_dim);
79         maxsize = VecLength(bb_dim);
80         */
81         
82         VECCOPY(isect->start, co);
83         isect->end[0] = co[0] + vec[0] * maxsize;
84         isect->end[1] = co[1] + vec[1] * maxsize;
85         isect->end[2] = co[2] + vec[2] * maxsize;
86         
87         isect->mode= RE_RAY_MIRROR;
88         isect->oborig= RAY_OBJECT_SET(&R, shi->obi);
89         isect->face_last= NULL;
90         isect->ob_last= 0;
91         isect->lay= -1;
92         
93         if (intersect_type == VOL_BOUNDS_DEPTH) isect->faceorig= (RayFace*)shi->vlr;
94         else if (intersect_type == VOL_BOUNDS_SS) isect->faceorig= NULL;
95         
96         if(RE_ray_tree_intersect(R.raytree, isect))
97         {
98                 hitco[0] = isect->start[0] + isect->labda*isect->vec[0];
99                 hitco[1] = isect->start[1] + isect->labda*isect->vec[1];
100                 hitco[2] = isect->start[2] + isect->labda*isect->vec[2];
101                 return 1;
102         } else {
103                 return 0;
104         }
105 }
106
107 static void shade_intersection(ShadeInput *shi, float *col, Isect *is)
108 {
109         ShadeInput shi_new;
110         ShadeResult shr_new;
111         
112         memset(&shi_new, 0, sizeof(ShadeInput)); 
113         
114         shi_new.mask= shi->mask;
115         shi_new.osatex= shi->osatex;
116         shi_new.thread= shi->thread;
117         shi_new.depth = shi->depth + 1;
118         shi_new.volume_depth= shi->volume_depth + 1;
119         shi_new.xs= shi->xs;
120         shi_new.ys= shi->ys;
121         shi_new.lay= shi->lay;
122         shi_new.passflag= SCE_PASS_COMBINED; /* result of tracing needs no pass info */
123         shi_new.combinedflag= 0xFFFFFF;          /* ray trace does all options */
124         shi_new.light_override= shi->light_override;
125         shi_new.mat_override= shi->mat_override;
126         
127         VECCOPY(shi_new.camera_co, is->start);
128         
129         memset(&shr_new, 0, sizeof(ShadeResult));
130         
131         /* hardcoded limit of 100 for now - prevents problems in weird geometry */
132         if (shi->volume_depth < 100) {
133                 shade_ray(is, &shi_new, &shr_new);
134         }
135         
136         VecCopyf(col, shr_new.combined);
137         col[3] = shr_new.alpha;
138 }
139
140 static void vol_trace_behind(ShadeInput *shi, VlakRen *vlr, float *co, float *col)
141 {
142         Isect isect;
143         float maxsize = RE_ray_tree_max_size(R.raytree);
144         
145         VECCOPY(isect.start, co);
146         isect.end[0] = isect.start[0] + shi->view[0] * maxsize;
147         isect.end[1] = isect.start[1] + shi->view[1] * maxsize;
148         isect.end[2] = isect.start[2] + shi->view[2] * maxsize;
149         
150         isect.faceorig= (RayFace *)vlr;
151         
152         isect.mode= RE_RAY_MIRROR;
153         isect.oborig= RAY_OBJECT_SET(&R, shi->obi);
154         isect.face_last= NULL;
155         isect.ob_last= 0;
156         isect.lay= -1;
157         
158         /* check to see if there's anything behind the volume, otherwise shade the sky */
159         if(RE_ray_tree_intersect(R.raytree, &isect)) {
160                 shade_intersection(shi, col, &isect);
161         } else {
162                 shadeSkyView(col, co, shi->view, NULL, shi->thread);
163                 shadeSunView(col, shi->view);
164         }
165 }
166
167 /* input shader data */
168
169 float vol_get_stepsize(struct ShadeInput *shi, int context)
170 {
171         if (shi->mat->vol.stepsize_type == MA_VOL_STEP_RANDOMIZED) {
172                 /* range between 0.75 and 1.25 */
173                 const float rnd = 0.5f * BLI_thread_frand(shi->thread) + 0.75f;
174         
175                 if (context == STEPSIZE_VIEW)
176                         return shi->mat->vol.stepsize * rnd;
177                 else if (context == STEPSIZE_SHADE)
178                         return shi->mat->vol.shade_stepsize * rnd;
179         }
180         else {  // MA_VOL_STEP_CONSTANT
181                 
182                 if (context == STEPSIZE_VIEW)
183                         return shi->mat->vol.stepsize;
184                 else if (context == STEPSIZE_SHADE)
185                         return shi->mat->vol.shade_stepsize;
186         }
187         
188         return shi->mat->vol.stepsize;
189 }
190
191 /* trilinear interpolation */
192 static void vol_get_precached_scattering(ShadeInput *shi, float *scatter_col, float *co)
193 {
194         VolumePrecache *vp = shi->obi->volume_precache;
195         float bbmin[3], bbmax[3], dim[3];
196         float sample_co[3];
197         
198         if (!vp) return;
199         
200         /* convert input coords to 0.0, 1.0 */
201         VECCOPY(bbmin, shi->obi->obr->boundbox[0]);
202         VECCOPY(bbmax, shi->obi->obr->boundbox[1]);
203         VecSubf(dim, bbmax, bbmin);
204
205         sample_co[0] = ((co[0] - bbmin[0]) / dim[0]);
206         sample_co[1] = ((co[1] - bbmin[1]) / dim[1]);
207         sample_co[2] = ((co[2] - bbmin[2]) / dim[2]);
208
209         scatter_col[0] = voxel_sample_trilinear(vp->data_r, vp->res, sample_co);
210         scatter_col[1] = voxel_sample_trilinear(vp->data_g, vp->res, sample_co);
211         scatter_col[2] = voxel_sample_trilinear(vp->data_b, vp->res, sample_co);
212 }
213
214 float vol_get_density(struct ShadeInput *shi, float *co)
215 {
216         float density = shi->mat->vol.density;
217         float density_scale = shi->mat->vol.density_scale;
218         float col[3] = {0.0, 0.0, 0.0};
219         
220         do_volume_tex(shi, co, MAP_DENSITY, col, &density);
221         
222         return density * density_scale;
223 }
224
225 /* scattering multiplier, values above 1.0 are non-physical, 
226  * but can be useful to tweak lighting */
227 float vol_get_scattering_fac(ShadeInput *shi, float *co)
228 {
229         float scatter = shi->mat->vol.scattering;
230         float col[3] = {0.0, 0.0, 0.0};
231         
232         do_volume_tex(shi, co, MAP_SCATTERING, col, &scatter);
233         
234         return scatter;
235 }
236
237 /* compute emission component, amount of radiance to add per segment
238  * can be textured with 'emit' */
239 void vol_get_emission(ShadeInput *shi, float *emission_col, float *co, float density)
240 {
241         float emission = shi->mat->vol.emission;
242         VECCOPY(emission_col, shi->mat->vol.emission_col);
243         
244         do_volume_tex(shi, co, MAP_EMISSION+MAP_EMISSION_COL, emission_col, &emission);
245         
246         emission_col[0] = emission_col[0] * emission * density;
247         emission_col[1] = emission_col[1] * emission * density;
248         emission_col[2] = emission_col[2] * emission * density;
249 }
250
251 void vol_get_absorption(ShadeInput *shi, float *absorb_col, float *co)
252 {
253         float absorption = shi->mat->vol.absorption;
254         VECCOPY(absorb_col, shi->mat->vol.absorption_col);
255         
256         do_volume_tex(shi, co, MAP_ABSORPTION+MAP_ABSORPTION_COL, absorb_col, &absorption);
257         
258         absorb_col[0] = (1.0f - absorb_col[0]) * absorption;
259         absorb_col[1] = (1.0f - absorb_col[1]) * absorption;
260         absorb_col[2] = (1.0f - absorb_col[2]) * absorption;
261 }
262
263
264 /* phase function - determines in which directions the light 
265  * is scattered in the volume relative to incoming direction 
266  * and view direction */
267 float vol_get_phasefunc(ShadeInput *shi, short phasefunc_type, float g, float *w, float *wp)
268 {
269         const float costheta = Inpf(w, wp);
270         const float scale = M_PI;
271         
272         /*
273          * Scale constant is required, since Blender's shading system doesn't normalise for
274          * energy conservation - eg. scaling by 1/pi for a lambert shader.
275          * This makes volumes darker than other solid objects, for the same lighting intensity.
276          * To correct this, scale up the phase function values
277          * until Blender's shading system supports this better. --matt
278          */
279         
280         switch (phasefunc_type) {
281                 case MA_VOL_PH_MIEHAZY:
282                         return scale * (0.5f + 4.5f * powf(0.5 * (1.f + costheta), 8.f)) / (4.f*M_PI);
283                 case MA_VOL_PH_MIEMURKY:
284                         return scale * (0.5f + 16.5f * powf(0.5 * (1.f + costheta), 32.f)) / (4.f*M_PI);
285                 case MA_VOL_PH_RAYLEIGH:
286                         return scale * 3.f/(16.f*M_PI) * (1 + costheta * costheta);
287                 case MA_VOL_PH_HG:
288                         return scale * (1.f / (4.f * M_PI) * (1.f - g*g) / powf(1.f + g*g - 2.f * g * costheta, 1.5f));
289                 case MA_VOL_PH_SCHLICK:
290                 {
291                         const float k = 1.55f * g - .55f * g * g * g;
292                         const float kcostheta = k * costheta;
293                         return scale * (1.f / (4.f * M_PI) * (1.f - k*k) / ((1.f - kcostheta) * (1.f - kcostheta)));
294                 }
295                 case MA_VOL_PH_ISOTROPIC:
296                 default:
297                         return scale * (1.f / (4.f * M_PI));
298         }
299 }
300
301 /* Compute attenuation, otherwise known as 'optical thickness', extinction, or tau.
302  * Used in the relationship Transmittance = e^(-attenuation)
303  */
304 void vol_get_attenuation_seg(ShadeInput *shi, float *transmission, float stepsize, float *co, float density)
305 {
306         /* input density = density at co */
307         float tau[3] = {0.f, 0.f, 0.f};
308         float absorb_col[3];
309
310         vol_get_absorption(shi, absorb_col, co);
311         
312         /* homogenous volume within the sampled distance */
313         tau[0] = stepsize * density * absorb_col[0];
314         tau[1] = stepsize * density * absorb_col[1];
315         tau[2] = stepsize * density * absorb_col[2];
316         
317         transmission[0] *= exp(-tau[0]);
318         transmission[1] *= exp(-tau[1]);
319         transmission[2] *= exp(-tau[2]);
320 }
321
322 /* Compute attenuation, otherwise known as 'optical thickness', extinction, or tau.
323  * Used in the relationship Transmittance = e^(-attenuation)
324  */
325 void vol_get_attenuation(ShadeInput *shi, float *transmission, float *co, float *endco, float density, float stepsize)
326 {
327         /* input density = density at co */
328         float tau[3] = {0.f, 0.f, 0.f};
329         float absorb_col[3];
330         int s, nsteps;
331         float step_vec[3], step_sta[3], step_end[3];
332         const float dist = VecLenf(co, endco);
333
334         vol_get_absorption(shi, absorb_col, co);
335
336         nsteps = (int)((dist / stepsize) + 0.5);
337         
338         VecSubf(step_vec, endco, co);
339         VecMulf(step_vec, 1.0f / nsteps);
340         
341         VecCopyf(step_sta, co);
342         VecAddf(step_end, step_sta, step_vec);
343         
344         for (s = 0;  s < nsteps; s++) {
345                 if (s > 0)
346                         density = vol_get_density(shi, step_sta);
347                 
348                 tau[0] += stepsize * density;
349                 tau[1] += stepsize * density;
350                 tau[2] += stepsize * density;
351                 
352                 if (s < nsteps-1) {
353                         VecCopyf(step_sta, step_end);
354                         VecAddf(step_end, step_end, step_vec);
355                 }
356         }
357         VecMulVecf(tau, tau, absorb_col);
358         
359         transmission[0] *= exp(-tau[0]);
360         transmission[1] *= exp(-tau[1]);
361         transmission[2] *= exp(-tau[2]);
362 }
363
364 void vol_shade_one_lamp(struct ShadeInput *shi, float *co, LampRen *lar, float *lacol, float stepsize, float density)
365 {
366         float visifac, lv[3], lampdist;
367         float tr[3]={1.0,1.0,1.0};
368         float hitco[3], *atten_co;
369         float p;
370         float scatter_fac;
371         float shade_stepsize = vol_get_stepsize(shi, STEPSIZE_SHADE);
372         
373         if (lar->mode & LA_LAYER) if((lar->lay & shi->obi->lay)==0) return;
374         if ((lar->lay & shi->lay)==0) return;
375         if (lar->energy == 0.0) return;
376         
377         if ((visifac= lamp_get_visibility(lar, co, lv, &lampdist)) == 0.f) return;
378         
379         VecCopyf(lacol, &lar->r);
380         
381         if(lar->mode & LA_TEXTURE) {
382                 shi->osatex= 0;
383                 do_lamp_tex(lar, lv, shi, lacol, LA_TEXTURE);
384         }
385
386         VecMulf(lacol, visifac*lar->energy);
387
388         if (ELEM(lar->type, LA_SUN, LA_HEMI))
389                 VECCOPY(lv, lar->vec);
390         VecMulf(lv, -1.0f);
391         
392         if (shi->mat->vol.shade_type != MA_VOL_SHADE_NONE) {
393                 Isect is;
394                 
395                 /* find minimum of volume bounds, or lamp coord */
396                 if (vol_get_bounds(shi, co, lv, hitco, &is, VOL_BOUNDS_SS)) {
397                         float dist = VecLenf(co, hitco);
398                         VlakRen *vlr = (VlakRen *)is.face;
399                         
400                         /* simple internal shadowing */
401                         if (vlr->mat->material_type == MA_TYPE_SURFACE) {
402                                 lacol[0] = lacol[1] = lacol[2] = 0.0f;
403                                 return;
404                         }
405
406                         if (ELEM(lar->type, LA_SUN, LA_HEMI))
407                                 /* infinite lights, can never be inside volume */
408                                 atten_co = hitco;
409                         else if ( lampdist < dist ) {
410                                 atten_co = lar->co;
411                         } else
412                                 atten_co = hitco;
413                         
414                         vol_get_attenuation(shi, tr, co, atten_co, density, shade_stepsize);
415                         
416                         VecMulVecf(lacol, lacol, tr);
417                 }
418                 else {
419                         /* Point is on the outside edge of the volume,
420                          * therefore no attenuation, full transmission.
421                          * Radiance from lamp remains unchanged */
422                 }
423         }
424         
425         p = vol_get_phasefunc(shi, shi->mat->vol.phasefunc_type, shi->mat->vol.phasefunc_g, shi->view, lv);
426         VecMulf(lacol, p);
427         
428         scatter_fac = vol_get_scattering_fac(shi, co);
429         VecMulf(lacol, scatter_fac);
430 }
431
432 /* single scattering only for now */
433 void vol_get_scattering(ShadeInput *shi, float *scatter_col, float *co, float stepsize, float density)
434 {
435         ListBase *lights;
436         GroupObject *go;
437         LampRen *lar;
438         
439         scatter_col[0] = scatter_col[1] = scatter_col[2] = 0.f;
440         
441         lights= get_lights(shi);
442         for(go=lights->first; go; go= go->next)
443         {
444                 float lacol[3] = {0.f, 0.f, 0.f};
445                 lar= go->lampren;
446                 
447                 if (lar) {
448                         vol_shade_one_lamp(shi, co, lar, lacol, stepsize, density);
449                         VecAddf(scatter_col, scatter_col, lacol);
450                 }
451         }
452 }
453
454         
455 /*
456 The main volumetric integrator, using an emission/absorption/scattering model.
457
458 Incoming radiance = 
459
460 outgoing radiance from behind surface * beam transmittance/attenuation
461 + added radiance from all points along the ray due to participating media
462         --> radiance for each segment = 
463                 (radiance added by scattering + radiance added by emission) * beam transmittance/attenuation
464 */
465 static void volumeintegrate(struct ShadeInput *shi, float *col, float *co, float *endco)
466 {
467         float tr[3] = {1.0f, 1.0f, 1.0f};
468         float radiance[3] = {0.f, 0.f, 0.f}, d_radiance[3] = {0.f, 0.f, 0.f};
469         float stepsize = vol_get_stepsize(shi, STEPSIZE_VIEW);
470         int nsteps, s;
471         float emit_col[3], scatter_col[3] = {0.0, 0.0, 0.0};
472         float stepvec[3], step_sta[3], step_end[3], step_mid[3];
473         float density;
474         const float depth_cutoff = shi->mat->vol.depth_cutoff;
475
476         /* ray marching */
477         nsteps = (int)((VecLenf(co, endco) / stepsize) + 0.5);
478         
479         VecSubf(stepvec, endco, co);
480         VecMulf(stepvec, 1.0f / nsteps);
481         VecCopyf(step_sta, co);
482         VecAddf(step_end, step_sta, stepvec);
483         
484         /* get radiance from all points along the ray due to participating media */
485         for (s = 0; s < nsteps; s++) {
486
487                 density = vol_get_density(shi, step_sta);
488                 
489                 /* there's only any use in shading here if there's actually some density to shade! */
490                 if (density > 0.01f) {
491                 
492                         /* transmittance component (alpha) */
493                         vol_get_attenuation_seg(shi, tr, stepsize, co, density);
494
495                         step_mid[0] = step_sta[0] + (stepvec[0] * 0.5);
496                         step_mid[1] = step_sta[1] + (stepvec[1] * 0.5);
497                         step_mid[2] = step_sta[2] + (stepvec[2] * 0.5);
498                 
499                         /* incoming light via emission or scattering (additive) */
500                         vol_get_emission(shi, emit_col, step_mid, density);
501                         
502                         if (shi->obi->volume_precache)
503                                 vol_get_precached_scattering(shi, scatter_col, step_mid);
504                         else
505                                 vol_get_scattering(shi, scatter_col, step_mid, stepsize, density);
506                         
507                         VecMulf(scatter_col, density);
508                         VecAddf(d_radiance, emit_col, scatter_col);
509                         
510                         /*   Lv += Tr * (Lve() + Ld) */
511                         VecMulVecf(d_radiance, tr, d_radiance);
512                         VecMulf(d_radiance, stepsize);
513                         
514                         VecAddf(radiance, radiance, d_radiance);        
515                 }
516
517                 VecCopyf(step_sta, step_end);
518                 VecAddf(step_end, step_end, stepvec);
519                 
520                 /* luminance rec. 709 */
521                 if ((0.2126*tr[0] + 0.7152*tr[1] + 0.0722*tr[2]) < depth_cutoff) break; 
522         }
523         
524         /* multiply original color (behind volume) with beam transmittance over entire distance */
525         VecMulVecf(col, tr, col);       
526         VecAddf(col, col, radiance);
527         
528         /* alpha <-- transmission luminance */
529         col[3] = 1.0f -(0.2126*tr[0] + 0.7152*tr[1] + 0.0722*tr[2]);
530 }
531
532 /* the main entry point for volume shading */
533 static void volume_trace(struct ShadeInput *shi, struct ShadeResult *shr, int inside_volume)
534 {
535         float hitco[3], col[4] = {0.f,0.f,0.f,0.f};
536         float *startco, *endco;
537         int trace_behind = 1;
538         const int ztransp= ((shi->depth==0) && (shi->mat->mode & MA_TRANSP) && (shi->mat->mode & MA_ZTRANSP));
539         Isect is;
540
541         /* check for shading an internal face a volume object directly */
542         if (inside_volume == VOL_SHADE_INSIDE)
543                 trace_behind = 0;
544         else if (inside_volume == VOL_SHADE_OUTSIDE) {
545                 if (shi->flippednor)
546                         inside_volume = VOL_SHADE_INSIDE;
547         }
548         
549         if (ztransp && inside_volume == VOL_SHADE_INSIDE) {
550                 MatInside *mi;
551                 int render_this=0;
552                 
553                 /* don't render the backfaces of ztransp volume materials.
554                  
555                  * volume shading renders the internal volume from between the
556                  * near view intersection of the solid volume to the
557                  * intersection on the other side, as part of the shading of
558                  * the front face.
559                  
560                  * Because ztransp renders both front and back faces independently
561                  * this will double up, so here we prevent rendering the backface as well, 
562                  * which would otherwise render the volume in between the camera and the backface
563                  * --matt */
564                 
565                 for (mi=R.render_volumes_inside.first; mi; mi=mi->next) {
566                         /* weak... */
567                         if (mi->ma == shi->mat) render_this=1;
568                 }
569                 if (!render_this) return;
570         }
571         
572
573         if (inside_volume == VOL_SHADE_INSIDE)
574         {
575                 startco = shi->camera_co;
576                 endco = shi->co;
577                 
578                 if (trace_behind) {
579                         if (!ztransp)
580                                 /* trace behind the volume object */
581                                 vol_trace_behind(shi, shi->vlr, endco, col);
582                 } else {
583                         /* we're tracing through the volume between the camera 
584                          * and a solid surface, so use that pre-shaded radiance */
585                         QUATCOPY(col, shr->combined);
586                 }
587                 
588                 /* shade volume from 'camera' to 1st hit point */
589                 volumeintegrate(shi, col, startco, endco);
590         }
591         /* trace to find a backface, the other side bounds of the volume */
592         /* (ray intersect ignores front faces here) */
593         else if (vol_get_bounds(shi, shi->co, shi->view, hitco, &is, VOL_BOUNDS_DEPTH))
594         {
595                 VlakRen *vlr = (VlakRen *)is.face;
596                 
597                 startco = shi->co;
598                 endco = hitco;
599                 
600                 if (!ztransp) {
601                         /* if it's another face in the same material */
602                         if (vlr->mat == shi->mat) {
603                                 /* trace behind the 2nd (raytrace) hit point */
604                                 vol_trace_behind(shi, (VlakRen *)is.face, endco, col);
605                         } else {
606                                 shade_intersection(shi, col, &is);
607                         }
608                 }
609                 
610                 /* shade volume from 1st hit point to 2nd hit point */
611                 volumeintegrate(shi, col, startco, endco);
612         }
613         
614         if (ztransp)
615                 col[3] = col[3]>1.f?1.f:col[3];
616         else
617                 col[3] = 1.f;
618         
619         VecCopyf(shr->combined, col);
620         shr->alpha = col[3];
621         
622         VECCOPY(shr->diff, shr->combined);
623 }
624
625 /* Traces a shadow through the object, 
626  * pretty much gets the transmission over a ray path */
627 void shade_volume_shadow(struct ShadeInput *shi, struct ShadeResult *shr, struct Isect *last_is)
628 {
629         float hitco[3];
630         float tr[3] = {1.0,1.0,1.0};
631         Isect is;
632         float shade_stepsize = vol_get_stepsize(shi, STEPSIZE_SHADE);
633         float *startco, *endco;
634         float density=0.f;
635
636         memset(shr, 0, sizeof(ShadeResult));
637         
638         /* if 1st hit normal is facing away from the camera, 
639          * then we're inside the volume already. */
640         if (shi->flippednor) {
641                 startco = last_is->start;
642                 endco = shi->co;
643         }
644         /* trace to find a backface, the other side bounds of the volume */
645         /* (ray intersect ignores front faces here) */
646         else if (vol_get_bounds(shi, shi->co, shi->view, hitco, &is, VOL_BOUNDS_DEPTH)) {
647                 startco = shi->co;
648                 endco = hitco;
649         }
650         else {
651                 shr->combined[0] = shr->combined[1] = shr->combined[2] = 0.f;
652                 shr->alpha = shr->combined[3] = 1.f;
653                 return;
654         }
655         
656         density = vol_get_density(shi, startco);
657         vol_get_attenuation(shi, tr, startco, endco, density, shade_stepsize);
658         
659         VecCopyf(shr->combined, tr);
660         shr->combined[3] = 1.0f -(0.2126*tr[0] + 0.7152*tr[1] + 0.0722*tr[2]);
661         shr->alpha = shr->combined[3];
662 }
663
664
665 /* delivers a fully filled in ShadeResult, for all passes */
666 void shade_volume_outside(ShadeInput *shi, ShadeResult *shr)
667 {
668         memset(shr, 0, sizeof(ShadeResult));
669         volume_trace(shi, shr, VOL_SHADE_OUTSIDE);
670 }
671
672
673 void shade_volume_inside(ShadeInput *shi, ShadeResult *shr)
674 {
675         MatInside *m;
676         Material *mat_backup;
677         ObjectInstanceRen *obi_backup;
678         float prev_alpha = shr->alpha;
679         
680         //if (BLI_countlist(&R.render_volumes_inside) == 0) return;
681         
682         /* XXX: extend to multiple volumes perhaps later */
683         mat_backup = shi->mat;
684         obi_backup = shi->obi;
685         
686         m = R.render_volumes_inside.first;
687         shi->mat = m->ma;
688         shi->obi = m->obi;
689         shi->obr = m->obi->obr;
690         
691         volume_trace(shi, shr, VOL_SHADE_INSIDE);
692         shr->alpha += prev_alpha;
693         CLAMP(shr->alpha, 0.f, 1.f);
694         
695         shi->mat = mat_backup;
696         shi->obi = obi_backup;
697         shi->obr = obi_backup->obr;
698 }