3 * ***** BEGIN GPL LICENSE BLOCK *****
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.
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.
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
20 * All rights reserved.
22 * The Original Code is: all of this file.
24 * Contributor(s): Matt Ebb, Raul Fernandez Hernandez (Farsthary)
26 * ***** END GPL LICENSE BLOCK *****
34 #include "MEM_guardedalloc.h"
36 #include "BLI_blenlib.h"
39 #include "BLI_voxel.h"
41 #include "RE_shader_ext.h"
42 #include "RE_raytrace.h"
44 #include "DNA_material_types.h"
45 #include "DNA_group_types.h"
46 #include "DNA_lamp_types.h"
47 #include "DNA_meta_types.h"
49 #include "BKE_global.h"
51 #include "render_types.h"
52 #include "pixelshading.h"
56 #include "volumetric.h"
57 #include "volume_precache.h"
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 /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
65 /* luminance rec. 709 */
66 BM_INLINE float luminance(float* col)
68 return (0.212671f*col[0] + 0.71516f*col[1] + 0.072169f*col[2]);
72 static float vol_get_shadow(ShadeInput *shi, LampRen *lar, float *co)
74 float visibility = 1.f;
77 float dxco[3]={0.f, 0.f, 0.f}, dyco[3]={0.f, 0.f, 0.f};
79 visibility = testshadowbuf(&R, lar->shb, co, dxco, dyco, 1.0, 0.0);
80 } else if (lar->mode & LA_SHAD_RAY) {
81 /* trace shadow manually, no good lamp api atm */
84 copy_v3_v3(is.start, co);
85 if(lar->type==LA_SUN || lar->type==LA_HEMI) {
86 is.vec[0] = -lar->vec[0];
87 is.vec[1] = -lar->vec[1];
88 is.vec[2] = -lar->vec[2];
91 VECSUB( is.vec, lar->co, is.start );
92 is.labda = len_v3( is.vec );
95 is.mode = RE_RAY_MIRROR;
96 is.skip = RE_SKIP_VLR_RENDER_CHECK | RE_SKIP_VLR_NON_SOLID_MATERIAL;
98 if(lar->mode & (LA_LAYER|LA_LAYER_SHADOW))
105 is.last_hit = lar->last_hit[shi->thread];
107 if(RE_rayobject_raycast(R.raytree,&is)) {
111 lar->last_hit[shi->thread]= is.last_hit;
116 static int vol_get_bounds(ShadeInput *shi, float *co, float *vec, float *hitco, Isect *isect, int intersect_type)
118 /* XXX TODO - get raytrace max distance from object instance's bounding box */
119 /* need to account for scaling only, but keep coords in camera space...
120 * below code is WIP and doesn't work!
121 sub_v3_v3v3(bb_dim, shi->obi->obr->boundbox[1], shi->obi->obr->boundbox[2]);
122 mul_m3_v3(shi->obi->nmat, bb_dim);
123 maxsize = len_v3(bb_dim);
126 VECCOPY(isect->start, co);
127 VECCOPY(isect->vec, vec );
128 isect->labda = FLT_MAX;
129 isect->mode= RE_RAY_MIRROR;
130 isect->last_hit = NULL;
133 if (intersect_type == VOL_BOUNDS_DEPTH) {
134 isect->skip = RE_SKIP_VLR_NEIGHBOUR;
135 isect->orig.face = (void*)shi->vlr;
136 isect->orig.ob = (void*)shi->obi;
137 } else { // if (intersect_type == VOL_BOUNDS_SS) {
139 isect->orig.face= NULL;
140 isect->orig.ob = NULL;
143 if(RE_rayobject_raycast(R.raytree, isect))
145 hitco[0] = isect->start[0] + isect->labda*isect->vec[0];
146 hitco[1] = isect->start[1] + isect->labda*isect->vec[1];
147 hitco[2] = isect->start[2] + isect->labda*isect->vec[2];
154 static void shade_intersection(ShadeInput *shi, float *col, Isect *is)
159 memset(&shi_new, 0, sizeof(ShadeInput));
161 shi_new.mask= shi->mask;
162 shi_new.osatex= shi->osatex;
163 shi_new.thread= shi->thread;
164 shi_new.depth = shi->depth + 1;
165 shi_new.volume_depth= shi->volume_depth + 1;
168 shi_new.lay= shi->lay;
169 shi_new.passflag= SCE_PASS_COMBINED; /* result of tracing needs no pass info */
170 shi_new.combinedflag= 0xFFFFFF; /* ray trace does all options */
171 shi_new.light_override= shi->light_override;
172 shi_new.mat_override= shi->mat_override;
174 VECCOPY(shi_new.camera_co, is->start);
176 memset(&shr_new, 0, sizeof(ShadeResult));
178 /* hardcoded limit of 100 for now - prevents problems in weird geometry */
179 if (shi->volume_depth < 100) {
180 shade_ray(is, &shi_new, &shr_new);
183 copy_v3_v3(col, shr_new.combined);
184 col[3] = shr_new.alpha;
187 static void vol_trace_behind(ShadeInput *shi, VlakRen *vlr, float *co, float *col)
191 VECCOPY(isect.start, co);
192 VECCOPY(isect.vec, shi->view);
193 isect.labda = FLT_MAX;
195 isect.mode= RE_RAY_MIRROR;
196 isect.skip = RE_SKIP_VLR_NEIGHBOUR | RE_SKIP_VLR_RENDER_CHECK;
197 isect.orig.ob = (void*) shi->obi;
198 isect.orig.face = (void*)vlr;
199 isect.last_hit = NULL;
202 /* check to see if there's anything behind the volume, otherwise shade the sky */
203 if(RE_rayobject_raycast(R.raytree, &isect)) {
204 shade_intersection(shi, col, &isect);
206 shadeSkyView(col, co, shi->view, NULL, shi->thread);
207 shadeSunView(col, shi->view);
212 /* trilinear interpolation */
213 static void vol_get_precached_scattering(ShadeInput *shi, float *scatter_col, float *co)
215 VolumePrecache *vp = shi->obi->volume_precache;
216 float bbmin[3], bbmax[3], dim[3];
217 float world_co[3], sample_co[3];
221 /* find sample point in global space bounding box 0.0-1.0 */
222 global_bounds_obi(re, shi->obi, bbmin, bbmax);
223 sub_v3_v3v3(dim, bbmax, bbmin);
224 mul_v3_m4v3(world_co, re->viewinv, co);
226 /* sample_co in 0.0-1.0 */
227 sample_co[0] = (world_co[0] - bbmin[0]) / dim[0];
228 sample_co[1] = (world_co[1] - bbmin[1]) / dim[1];
229 sample_co[2] = (world_co[2] - bbmin[2]) / dim[2];
231 scatter_col[0] = voxel_sample_triquadratic(vp->data_r, vp->res, sample_co);
232 scatter_col[1] = voxel_sample_triquadratic(vp->data_g, vp->res, sample_co);
233 scatter_col[2] = voxel_sample_triquadratic(vp->data_b, vp->res, sample_co);
236 /* Meta object density, brute force for now
237 * (might be good enough anyway, don't need huge number of metaobs to model volumetric objects */
238 static float metadensity(Object* ob, float* co)
240 float mat[4][4], imat[4][4], dens = 0.f;
241 MetaBall* mb = (MetaBall*)ob->data;
244 /* transform co to meta-element */
245 float tco[3] = {co[0], co[1], co[2]};
246 mul_m4_m4m4(mat, ob->obmat, R.viewmat);
247 invert_m4_m4(imat, mat);
248 mul_m4_v3(imat, tco);
250 for (ml = mb->elems.first; ml; ml=ml->next) {
251 float bmat[3][3], dist2;
253 /* element rotation transform */
254 float tp[3] = {ml->x - tco[0], ml->y - tco[1], ml->z - tco[2]};
255 quat_to_mat3( bmat,ml->quat);
256 transpose_m3(bmat); // rot.only, so inverse == transpose
259 /* MB_BALL default */
262 tp[0] /= ml->expx, tp[1] /= ml->expy, tp[2] /= ml->expz;
265 tp[2] = (tp[2] > ml->expz) ? (tp[2] - ml->expz) : ((tp[2] < -ml->expz) ? (tp[2] + ml->expz) : 0.f);
266 // no break, xy as plane
268 tp[1] = (tp[1] > ml->expy) ? (tp[1] - ml->expy) : ((tp[1] < -ml->expy) ? (tp[1] + ml->expy) : 0.f);
269 // no break, x as tube
271 tp[0] = (tp[0] > ml->expx) ? (tp[0] - ml->expx) : ((tp[0] < -ml->expx) ? (tp[0] + ml->expx) : 0.f);
274 /* ml->rad2 is not set */
275 dist2 = 1.f - ((tp[0]*tp[0] + tp[1]*tp[1] + tp[2]*tp[2]) / (ml->rad*ml->rad));
277 dens += (ml->flag & MB_NEGATIVE) ? -ml->s*dist2*dist2*dist2 : ml->s*dist2*dist2*dist2;
281 return (dens < 0.f) ? 0.f : dens;
284 float vol_get_density(struct ShadeInput *shi, float *co)
286 float density = shi->mat->vol.density;
287 float density_scale = shi->mat->vol.density_scale;
289 if (shi->mat->mapto_textured & MAP_DENSITY)
290 do_volume_tex(shi, co, MAP_DENSITY, NULL, &density);
292 // if meta-object, modulate by metadensity without increasing it
293 if (shi->obi->obr->ob->type == OB_MBALL) {
294 const float md = metadensity(shi->obi->obr->ob, co);
295 if (md < 1.f) density *= md;
298 return density * density_scale;
302 /* Color of light that gets scattered out by the volume */
303 /* Uses same physically based scattering parameter as in transmission calculations,
304 * along with artificial reflection scale/reflection color tint */
305 void vol_get_reflection_color(ShadeInput *shi, float *ref_col, float *co)
307 float scatter = shi->mat->vol.scattering;
308 float reflection= shi->mat->vol.reflection;
309 VECCOPY(ref_col, shi->mat->vol.reflection_col);
311 if (shi->mat->mapto_textured & (MAP_SCATTERING+MAP_REFLECTION_COL))
312 do_volume_tex(shi, co, MAP_SCATTERING+MAP_REFLECTION_COL, ref_col, &scatter);
314 /* only one single float parameter at a time... :s */
315 if (shi->mat->mapto_textured & (MAP_REFLECTION))
316 do_volume_tex(shi, co, MAP_REFLECTION, NULL, &reflection);
318 ref_col[0] = reflection * ref_col[0] * scatter;
319 ref_col[1] = reflection * ref_col[1] * scatter;
320 ref_col[2] = reflection * ref_col[2] * scatter;
323 /* compute emission component, amount of radiance to add per segment
324 * can be textured with 'emit' */
325 void vol_get_emission(ShadeInput *shi, float *emission_col, float *co)
327 float emission = shi->mat->vol.emission;
328 VECCOPY(emission_col, shi->mat->vol.emission_col);
330 if (shi->mat->mapto_textured & (MAP_EMISSION+MAP_EMISSION_COL))
331 do_volume_tex(shi, co, MAP_EMISSION+MAP_EMISSION_COL, emission_col, &emission);
333 emission_col[0] = emission_col[0] * emission;
334 emission_col[1] = emission_col[1] * emission;
335 emission_col[2] = emission_col[2] * emission;
339 /* A combination of scattering and absorption -> known as sigma T.
340 * This can possibly use a specific scattering colour,
341 * and absorption multiplier factor too, but these parameters are left out for simplicity.
342 * It's easy enough to get a good wide range of results with just these two parameters. */
343 void vol_get_sigma_t(ShadeInput *shi, float *sigma_t, float *co)
345 /* technically absorption, but named transmission color
346 * since it describes the effect of the coloring *after* absorption */
347 float transmission_col[3] = {shi->mat->vol.transmission_col[0], shi->mat->vol.transmission_col[1], shi->mat->vol.transmission_col[2]};
348 float scattering = shi->mat->vol.scattering;
350 if (shi->mat->mapto_textured & (MAP_SCATTERING+MAP_TRANSMISSION_COL))
351 do_volume_tex(shi, co, MAP_SCATTERING+MAP_TRANSMISSION_COL, transmission_col, &scattering);
353 sigma_t[0] = (1.0f - transmission_col[0]) + scattering;
354 sigma_t[1] = (1.0f - transmission_col[1]) + scattering;
355 sigma_t[2] = (1.0f - transmission_col[2]) + scattering;
358 /* phase function - determines in which directions the light
359 * is scattered in the volume relative to incoming direction
360 * and view direction */
361 float vol_get_phasefunc(ShadeInput *shi, float g, float *w, float *wp)
363 const float normalize = 0.25f; // = 1.f/4.f = M_PI/(4.f*M_PI)
365 /* normalization constant is 1/4 rather than 1/4pi, since
366 * Blender's shading system doesn't normalise for
367 * energy conservation - eg. multiplying by pdf ( 1/pi for a lambert brdf ).
368 * This means that lambert surfaces in Blender are pi times brighter than they 'should be'
369 * and therefore, with correct energy conservation, volumes will darker than other solid objects,
370 * for the same lighting intensity.
371 * To correct this, scale up the phase function values by pi
372 * until Blender's shading system supports this better. --matt
375 if (g == 0.f) { /* isotropic */
376 return normalize * 1.f;
377 } else { /* schlick */
378 const float k = 1.55f * g - .55f * g * g * g;
379 const float kcostheta = k * dot_v3v3(w, wp);
380 return normalize * (1.f - k*k) / ((1.f - kcostheta) * (1.f - kcostheta));
384 * not used, but here for reference:
385 switch (phasefunc_type) {
386 case MA_VOL_PH_MIEHAZY:
387 return normalize * (0.5f + 4.5f * powf(0.5 * (1.f + costheta), 8.f));
388 case MA_VOL_PH_MIEMURKY:
389 return normalize * (0.5f + 16.5f * powf(0.5 * (1.f + costheta), 32.f));
390 case MA_VOL_PH_RAYLEIGH:
391 return normalize * 3.f/4.f * (1 + costheta * costheta);
393 return normalize * (1.f - g*g) / powf(1.f + g*g - 2.f * g * costheta, 1.5f));
394 case MA_VOL_PH_SCHLICK:
396 const float k = 1.55f * g - .55f * g * g * g;
397 const float kcostheta = k * costheta;
398 return normalize * (1.f - k*k) / ((1.f - kcostheta) * (1.f - kcostheta));
400 case MA_VOL_PH_ISOTROPIC:
402 return normalize * 1.f;
407 /* Compute transmittance = e^(-attenuation) */
408 void vol_get_transmittance_seg(ShadeInput *shi, float *tr, float stepsize, float *co, float density)
410 /* input density = density at co */
411 float tau[3] = {0.f, 0.f, 0.f};
412 const float stepd = density * stepsize;
415 vol_get_sigma_t(shi, sigma_t, co);
417 /* homogenous volume within the sampled distance */
418 tau[0] += stepd * sigma_t[0];
419 tau[1] += stepd * sigma_t[1];
420 tau[2] += stepd * sigma_t[2];
422 tr[0] *= exp(-tau[0]);
423 tr[1] *= exp(-tau[1]);
424 tr[2] *= exp(-tau[2]);
427 /* Compute transmittance = e^(-attenuation) */
428 static void vol_get_transmittance(ShadeInput *shi, float *tr, float *co, float *endco)
430 float p[3] = {co[0], co[1], co[2]};
431 float step_vec[3] = {endco[0] - co[0], endco[1] - co[1], endco[2] - co[2]};
432 float tau[3] = {0.f, 0.f, 0.f};
435 float t1 = normalize_v3(step_vec);
438 t0 += shi->mat->vol.stepsize * ((shi->mat->vol.stepsize_type == MA_VOL_STEP_CONSTANT) ? 0.5f : BLI_thread_frand(shi->thread));
439 p[0] += t0 * step_vec[0];
440 p[1] += t0 * step_vec[1];
441 p[2] += t0 * step_vec[2];
442 mul_v3_fl(step_vec, shi->mat->vol.stepsize);
444 for (; t0 < t1; pt0 = t0, t0 += shi->mat->vol.stepsize) {
445 const float d = vol_get_density(shi, p);
446 const float stepd = (t0 - pt0) * d;
449 vol_get_sigma_t(shi, sigma_t, co);
451 tau[0] += stepd * sigma_t[0];
452 tau[1] += stepd * sigma_t[1];
453 tau[2] += stepd * sigma_t[2];
455 add_v3_v3(p, step_vec);
458 /* return transmittance */
459 tr[0] = expf(-tau[0]);
460 tr[1] = expf(-tau[1]);
461 tr[2] = expf(-tau[2]);
464 void vol_shade_one_lamp(struct ShadeInput *shi, float *co, LampRen *lar, float *lacol)
466 float visifac, lv[3], lampdist;
467 float tr[3]={1.0,1.0,1.0};
468 float hitco[3], *atten_co;
471 if (lar->mode & LA_LAYER) if((lar->lay & shi->obi->lay)==0) return;
472 if ((lar->lay & shi->lay)==0) return;
473 if (lar->energy == 0.0) return;
475 if ((visifac= lamp_get_visibility(lar, co, lv, &lampdist)) == 0.f) return;
477 copy_v3_v3(lacol, &lar->r);
479 if(lar->mode & LA_TEXTURE) {
481 do_lamp_tex(lar, lv, shi, lacol, LA_TEXTURE);
484 mul_v3_fl(lacol, visifac);
486 if (ELEM(lar->type, LA_SUN, LA_HEMI))
487 VECCOPY(lv, lar->vec);
490 if (shi->mat->vol.shade_type == MA_VOL_SHADE_SHADOWED) {
491 mul_v3_fl(lacol, vol_get_shadow(shi, lar, co));
493 else if (ELEM3(shi->mat->vol.shade_type, MA_VOL_SHADE_SHADED, MA_VOL_SHADE_MULTIPLE, MA_VOL_SHADE_SHADEDPLUSMULTIPLE))
497 if (shi->mat->vol.shadeflag & MA_VOL_RECV_EXT_SHADOW) {
498 mul_v3_fl(lacol, vol_get_shadow(shi, lar, co));
499 if (luminance(lacol) < 0.001f) return;
502 /* find minimum of volume bounds, or lamp coord */
503 if (vol_get_bounds(shi, co, lv, hitco, &is, VOL_BOUNDS_SS)) {
504 float dist = len_v3v3(co, hitco);
505 VlakRen *vlr = (VlakRen *)is.hit.face;
507 /* simple internal shadowing */
508 if (vlr->mat->material_type == MA_TYPE_SURFACE) {
509 lacol[0] = lacol[1] = lacol[2] = 0.0f;
513 if (ELEM(lar->type, LA_SUN, LA_HEMI))
514 /* infinite lights, can never be inside volume */
516 else if ( lampdist < dist ) {
521 vol_get_transmittance(shi, tr, co, atten_co);
523 mul_v3_v3v3(lacol, lacol, tr);
526 /* Point is on the outside edge of the volume,
527 * therefore no attenuation, full transmission.
528 * Radiance from lamp remains unchanged */
532 if (luminance(lacol) < 0.001f) return;
534 p = vol_get_phasefunc(shi, shi->mat->vol.asymmetry, shi->view, lv);
536 /* physically based scattering with non-physically based RGB gain */
537 vol_get_reflection_color(shi, ref_col, co);
539 lacol[0] *= p * ref_col[0];
540 lacol[1] *= p * ref_col[1];
541 lacol[2] *= p * ref_col[2];
544 /* single scattering only for now */
545 void vol_get_scattering(ShadeInput *shi, float *scatter_col, float *co)
551 scatter_col[0] = scatter_col[1] = scatter_col[2] = 0.f;
553 lights= get_lights(shi);
554 for(go=lights->first; go; go= go->next)
556 float lacol[3] = {0.f, 0.f, 0.f};
560 vol_shade_one_lamp(shi, co, lar, lacol);
561 add_v3_v3(scatter_col, lacol);
568 The main volumetric integrator, using an emission/absorption/scattering model.
572 outgoing radiance from behind surface * beam transmittance/attenuation
573 + added radiance from all points along the ray due to participating media
574 --> radiance for each segment =
575 (radiance added by scattering + radiance added by emission) * beam transmittance/attenuation
578 /* For ease of use, I've also introduced a 'reflection' and 'reflection color' parameter, which isn't
579 * physically correct. This works as an RGB tint/gain on out-scattered light, but doesn't affect the light
580 * that is transmitted through the volume. While having wavelength dependent absorption/scattering is more correct,
581 * it also makes it harder to control the overall look of the volume since colouring the outscattered light results
582 * in the inverse colour being transmitted through the rest of the volume.
584 static void volumeintegrate(struct ShadeInput *shi, float *col, float *co, float *endco)
586 float radiance[3] = {0.f, 0.f, 0.f};
587 float tr[3] = {1.f, 1.f, 1.f};
588 float p[3] = {co[0], co[1], co[2]};
589 float step_vec[3] = {endco[0] - co[0], endco[1] - co[1], endco[2] - co[2]};
590 const float stepsize = shi->mat->vol.stepsize;
594 float t1 = normalize_v3(step_vec); /* returns vector length */
596 t0 += stepsize * ((shi->mat->vol.stepsize_type == MA_VOL_STEP_CONSTANT) ? 0.5f : BLI_thread_frand(shi->thread));
597 p[0] += t0 * step_vec[0];
598 p[1] += t0 * step_vec[1];
599 p[2] += t0 * step_vec[2];
600 mul_v3_fl(step_vec, stepsize);
602 for (; t0 < t1; pt0 = t0, t0 += stepsize) {
603 const float density = vol_get_density(shi, p);
605 if (density > 0.01f) {
606 float scatter_col[3] = {0.f, 0.f, 0.f}, emit_col[3];
607 const float stepd = (t0 - pt0) * density;
609 /* transmittance component (alpha) */
610 vol_get_transmittance_seg(shi, tr, stepsize, co, density);
612 if (luminance(tr) < shi->mat->vol.depth_cutoff) break;
614 vol_get_emission(shi, emit_col, p);
616 if (shi->obi->volume_precache) {
619 p2[0] = p[0] + (step_vec[0] * 0.5);
620 p2[1] = p[1] + (step_vec[1] * 0.5);
621 p2[2] = p[2] + (step_vec[2] * 0.5);
623 vol_get_precached_scattering(&R, shi, scatter_col, p2);
625 vol_get_scattering(shi, scatter_col, p);
627 radiance[0] += stepd * tr[0] * (emit_col[0] + scatter_col[0]);
628 radiance[1] += stepd * tr[1] * (emit_col[1] + scatter_col[1]);
629 radiance[2] += stepd * tr[2] * (emit_col[2] + scatter_col[2]);
631 add_v3_v3(p, step_vec);
634 /* multiply original color (from behind volume) with transmittance over entire distance */
635 mul_v3_v3v3(col, tr, col);
636 add_v3_v3(col, radiance);
638 /* alpha <-- transmission luminance */
639 col[3] = 1.0f - luminance(tr);
642 /* the main entry point for volume shading */
643 static void volume_trace(struct ShadeInput *shi, struct ShadeResult *shr, int inside_volume)
645 float hitco[3], col[4] = {0.f,0.f,0.f,0.f};
646 float *startco, *endco;
647 int trace_behind = 1;
648 const int ztransp= ((shi->depth==0) && (shi->mat->mode & MA_TRANSP) && (shi->mat->mode & MA_ZTRANSP));
651 /* check for shading an internal face a volume object directly */
652 if (inside_volume == VOL_SHADE_INSIDE)
654 else if (inside_volume == VOL_SHADE_OUTSIDE) {
656 inside_volume = VOL_SHADE_INSIDE;
659 if (ztransp && inside_volume == VOL_SHADE_INSIDE) {
663 /* don't render the backfaces of ztransp volume materials.
665 * volume shading renders the internal volume from between the
666 * ' view intersection of the solid volume to the
667 * intersection on the other side, as part of the shading of
670 * Because ztransp renders both front and back faces independently
671 * this will double up, so here we prevent rendering the backface as well,
672 * which would otherwise render the volume in between the camera and the backface
675 for (mi=R.render_volumes_inside.first; mi; mi=mi->next) {
677 if (mi->ma == shi->mat) render_this=1;
679 if (!render_this) return;
683 if (inside_volume == VOL_SHADE_INSIDE)
685 startco = shi->camera_co;
690 /* trace behind the volume object */
691 vol_trace_behind(shi, shi->vlr, endco, col);
693 /* we're tracing through the volume between the camera
694 * and a solid surface, so use that pre-shaded radiance */
695 QUATCOPY(col, shr->combined);
698 /* shade volume from 'camera' to 1st hit point */
699 volumeintegrate(shi, col, startco, endco);
701 /* trace to find a backface, the other side bounds of the volume */
702 /* (ray intersect ignores front faces here) */
703 else if (vol_get_bounds(shi, shi->co, shi->view, hitco, &is, VOL_BOUNDS_DEPTH))
705 VlakRen *vlr = (VlakRen *)is.hit.face;
711 /* if it's another face in the same material */
712 if (vlr->mat == shi->mat) {
713 /* trace behind the 2nd (raytrace) hit point */
714 vol_trace_behind(shi, (VlakRen *)is.hit.face, endco, col);
716 shade_intersection(shi, col, &is);
720 /* shade volume from 1st hit point to 2nd hit point */
721 volumeintegrate(shi, col, startco, endco);
725 col[3] = col[3]>1.f?1.f:col[3];
729 copy_v3_v3(shr->combined, col);
732 VECCOPY(shr->diff, shr->combined);
735 /* Traces a shadow through the object,
736 * pretty much gets the transmission over a ray path */
737 void shade_volume_shadow(struct ShadeInput *shi, struct ShadeResult *shr, struct Isect *last_is)
740 float tr[3] = {1.0,1.0,1.0};
742 float *startco, *endco;
745 memset(shr, 0, sizeof(ShadeResult));
747 /* if 1st hit normal is facing away from the camera,
748 * then we're inside the volume already. */
749 if (shi->flippednor) {
750 startco = last_is->start;
753 /* trace to find a backface, the other side bounds of the volume */
754 /* (ray intersect ignores front faces here) */
755 else if (vol_get_bounds(shi, shi->co, shi->view, hitco, &is, VOL_BOUNDS_DEPTH)) {
760 shr->combined[0] = shr->combined[1] = shr->combined[2] = 0.f;
761 shr->alpha = shr->combined[3] = 1.f;
765 density = vol_get_density(shi, startco);
766 vol_get_transmittance(shi, tr, startco, endco);
768 copy_v3_v3(shr->combined, tr);
769 shr->combined[3] = 1.0f - luminance(tr);
773 /* delivers a fully filled in ShadeResult, for all passes */
774 void shade_volume_outside(ShadeInput *shi, ShadeResult *shr)
776 memset(shr, 0, sizeof(ShadeResult));
777 volume_trace(shi, shr, VOL_SHADE_OUTSIDE);
781 void shade_volume_inside(ShadeInput *shi, ShadeResult *shr)
784 Material *mat_backup;
785 ObjectInstanceRen *obi_backup;
786 float prev_alpha = shr->alpha;
788 //if (BLI_countlist(&R.render_volumes_inside) == 0) return;
790 /* XXX: extend to multiple volumes perhaps later */
791 mat_backup = shi->mat;
792 obi_backup = shi->obi;
794 m = R.render_volumes_inside.first;
797 shi->obr = m->obi->obr;
799 volume_trace(shi, shr, VOL_SHADE_INSIDE);
800 shr->alpha += prev_alpha;
801 CLAMP(shr->alpha, 0.f, 1.f);
803 shi->mat = mat_backup;
804 shi->obi = obi_backup;
805 shi->obr = obi_backup->obr;