/* Traces a shadow through the object, * pretty much gets the transmission over a ray path */ void shade_volume_shadow(struct ShadeInput *shi, struct ShadeResult *shr, struct Isect *last_is) { float hitco[3]; float tr[3] = {1.0,1.0,1.0}; Isect is; float *startco, *endco; float density=0.f; memset(shr, 0, sizeof(ShadeResult)); /* if 1st hit normal is facing away from the camera, * then we're inside the volume already. */ if (shi->flippednor) { startco = last_is->start; endco = shi->co; } /* trace to find a backface, the other side bounds of the volume */ /* (ray intersect ignores front faces here) */ else if (vol_get_bounds(shi, shi->co, shi->view, hitco, &is, VOL_BOUNDS_DEPTH)) { startco = shi->co; endco = hitco; } else { shr->combined[0] = shr->combined[1] = shr->combined[2] = 0.f; shr->alpha = shr->combined[3] = 1.f; return; } density = vol_get_density(shi, startco); vol_get_transmittance(shi, tr, startco, endco); VecCopyf(shr->combined, tr); shr->combined[3] = 1.0f - luminance(tr); }
/* Traces a shadow through the object, * pretty much gets the transmission over a ray path */ void shade_volume_shadow(struct ShadeInput *shi, struct ShadeResult *shr, struct Isect *last_is) { float hitco[3]; float tr[3] = {1.0,1.0,1.0}; Isect is= {{0}}; float *startco, *endco; int intersect_type = VOL_BOUNDS_DEPTH; memset(shr, 0, sizeof(ShadeResult)); /* if 1st hit normal is facing away from the camera, * then we're inside the volume already. */ if (shi->flippednor) { startco = last_is->start; endco = shi->co; intersect_type = VOL_BOUNDS_SS; } /* trace to find a backface, the other side bounds of the volume */ /* (ray intersect ignores front faces here) */ else if (vol_get_bounds(shi, shi->co, shi->view, hitco, &is, intersect_type)) { startco = shi->co; endco = hitco; } else { shr->combined[0] = shr->combined[1] = shr->combined[2] = 0.f; shr->alpha = shr->combined[3] = 1.f; return; } vol_get_transmittance(shi, tr, startco, endco); /* if we hit another face in the same volume bounds */ /* shift raytrace coordinates to the hit point, to avoid shading volume twice */ /* due to idiosyncracy in ray_trace_shadow_tra() */ if (is.hit.ob == shi->obi) { copy_v3_v3(shi->co, hitco); last_is->dist -= is.dist; shi->vlr = (VlakRen *)is.hit.face; } copy_v3_v3(shr->combined, tr); shr->combined[3] = 1.0f - luminance(tr); shr->alpha = shr->combined[3]; }
/* the main entry point for volume shading */ static void volume_trace(struct ShadeInput *shi, struct ShadeResult *shr, int inside_volume) { float hitco[3], col[4] = {0.f, 0.f, 0.f, 0.f}; float *startco, *endco; int trace_behind = 1; const int ztransp = ((shi->depth == 0) && (shi->mat->mode & MA_TRANSP) && (shi->mat->mode & MA_ZTRANSP)); Isect is; /* check for shading an internal face a volume object directly */ if (inside_volume == VOL_SHADE_INSIDE) trace_behind = 0; else if (inside_volume == VOL_SHADE_OUTSIDE) { if (shi->flippednor) inside_volume = VOL_SHADE_INSIDE; } if (ztransp && inside_volume == VOL_SHADE_INSIDE) { MatInside *mi; int render_this = 0; /* don't render the backfaces of ztransp volume materials. * * volume shading renders the internal volume from between the * ' view intersection of the solid volume to the * intersection on the other side, as part of the shading of * the front face. * * Because ztransp renders both front and back faces independently * this will double up, so here we prevent rendering the backface as well, * which would otherwise render the volume in between the camera and the backface * --matt */ for (mi = R.render_volumes_inside.first; mi; mi = mi->next) { /* weak... */ if (mi->ma == shi->mat) render_this = 1; } if (!render_this) return; } if (inside_volume == VOL_SHADE_INSIDE) { startco = shi->camera_co; endco = shi->co; if (trace_behind) { if (!ztransp) /* trace behind the volume object */ vol_trace_behind(shi, shi->vlr, endco, col); } else { /* we're tracing through the volume between the camera * and a solid surface, so use that pre-shaded radiance */ copy_v4_v4(col, shr->combined); } /* shade volume from 'camera' to 1st hit point */ volumeintegrate(shi, col, startco, endco); } /* trace to find a backface, the other side bounds of the volume */ /* (ray intersect ignores front faces here) */ else if (vol_get_bounds(shi, shi->co, shi->view, hitco, &is, VOL_BOUNDS_DEPTH)) { VlakRen *vlr = (VlakRen *)is.hit.face; startco = shi->co; endco = hitco; if (!ztransp) { /* if it's another face in the same material */ if (vlr->mat == shi->mat) { /* trace behind the 2nd (raytrace) hit point */ vol_trace_behind(shi, (VlakRen *)is.hit.face, endco, col); } else { shade_intersection(shi, col, &is); } } /* shade volume from 1st hit point to 2nd hit point */ volumeintegrate(shi, col, startco, endco); } if (ztransp) col[3] = col[3] > 1.f ? 1.f : col[3]; else col[3] = 1.f; copy_v3_v3(shr->combined, col); shr->alpha = col[3]; copy_v3_v3(shr->diff, shr->combined); }
static void vol_shade_one_lamp(struct ShadeInput *shi, const float co[3], const float view[3], LampRen *lar, float lacol[3]) { float visifac, lv[3], lampdist; float tr[3] = {1.0, 1.0, 1.0}; float hitco[3], *atten_co; float p, ref_col[3]; if (lar->mode & LA_LAYER) if ((lar->lay & shi->obi->lay) == 0) return; if ((lar->lay & shi->lay) == 0) return; if (lar->energy == 0.0f) return; if ((visifac = lamp_get_visibility(lar, co, lv, &lampdist)) == 0.f) return; copy_v3_v3(lacol, &lar->r); if (lar->mode & LA_TEXTURE) { shi->osatex = 0; do_lamp_tex(lar, lv, shi, lacol, LA_TEXTURE); } mul_v3_fl(lacol, visifac); if (ELEM(lar->type, LA_SUN, LA_HEMI)) copy_v3_v3(lv, lar->vec); negate_v3(lv); if (shi->mat->vol.shade_type == MA_VOL_SHADE_SHADOWED) { mul_v3_fl(lacol, vol_get_shadow(shi, lar, co)); } else if (ELEM3(shi->mat->vol.shade_type, MA_VOL_SHADE_SHADED, MA_VOL_SHADE_MULTIPLE, MA_VOL_SHADE_SHADEDPLUSMULTIPLE)) { Isect is; if (shi->mat->vol.shadeflag & MA_VOL_RECV_EXT_SHADOW) { mul_v3_fl(lacol, vol_get_shadow(shi, lar, co)); if (rgb_to_luma_y(lacol) < 0.001f) return; } /* find minimum of volume bounds, or lamp coord */ if (vol_get_bounds(shi, co, lv, hitco, &is, VOL_BOUNDS_SS)) { float dist = len_v3v3(co, hitco); VlakRen *vlr = (VlakRen *)is.hit.face; /* simple internal shadowing */ if (vlr->mat->material_type == MA_TYPE_SURFACE) { lacol[0] = lacol[1] = lacol[2] = 0.0f; return; } if (ELEM(lar->type, LA_SUN, LA_HEMI)) /* infinite lights, can never be inside volume */ atten_co = hitco; else if (lampdist < dist) { atten_co = lar->co; } else atten_co = hitco; vol_get_transmittance(shi, tr, co, atten_co); mul_v3_v3v3(lacol, lacol, tr); } else { /* Point is on the outside edge of the volume, * therefore no attenuation, full transmission. * Radiance from lamp remains unchanged */ } } if (rgb_to_luma_y(lacol) < 0.001f) return; normalize_v3(lv); p = vol_get_phasefunc(shi, shi->mat->vol.asymmetry, view, lv); /* physically based scattering with non-physically based RGB gain */ vol_get_reflection_color(shi, ref_col, co); lacol[0] *= p * ref_col[0]; lacol[1] *= p * ref_col[1]; lacol[2] *= p * ref_col[2]; }