Blender V2.61 - r43446
|
00001 /* 00002 * ***** BEGIN GPL LICENSE BLOCK ***** 00003 * 00004 * This program is free software; you can redistribute it and/or 00005 * modify it under the terms of the GNU General Public License 00006 * as published by the Free Software Foundation; either version 2 00007 * of the License, or (at your option) any later version. 00008 * 00009 * This program is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 * GNU General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU General Public License 00015 * along with this program; if not, write to the Free Software Foundation, 00016 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00017 * 00018 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. 00019 * All rights reserved. 00020 * 00021 * The Original Code is: all of this file. 00022 * 00023 * Contributor(s): Matt Ebb, Raul Fernandez Hernandez (Farsthary) 00024 * 00025 * ***** END GPL LICENSE BLOCK ***** 00026 */ 00027 00033 #include <math.h> 00034 #include <stdlib.h> 00035 #include <string.h> 00036 #include <float.h> 00037 00038 #include "MEM_guardedalloc.h" 00039 00040 #include "BLI_blenlib.h" 00041 #include "BLI_math.h" 00042 #include "BLI_rand.h" 00043 #include "BLI_voxel.h" 00044 #include "BLI_utildefines.h" 00045 00046 #include "RE_shader_ext.h" 00047 00048 #include "DNA_material_types.h" 00049 #include "DNA_group_types.h" 00050 #include "DNA_lamp_types.h" 00051 #include "DNA_meta_types.h" 00052 00053 #include "BKE_global.h" 00054 00055 #include "render_types.h" 00056 #include "pixelshading.h" 00057 #include "rayintersection.h" 00058 #include "rayobject.h" 00059 #include "shading.h" 00060 #include "shadbuf.h" 00061 #include "texture.h" 00062 #include "volumetric.h" 00063 #include "volume_precache.h" 00064 00065 /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 00066 /* defined in pipeline.c, is hardcopy of active dynamic allocated Render */ 00067 /* only to be used here in this file, it's for speed */ 00068 extern struct Render R; 00069 /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 00070 00071 /* luminance rec. 709 */ 00072 BM_INLINE float luminance(const float col[3]) 00073 { 00074 return (0.212671f*col[0] + 0.71516f*col[1] + 0.072169f*col[2]); 00075 } 00076 00077 /* tracing */ 00078 static float vol_get_shadow(ShadeInput *shi, LampRen *lar, const float co[3]) 00079 { 00080 float visibility = 1.f; 00081 00082 if(lar->shb) { 00083 float dxco[3]={0.f, 0.f, 0.f}, dyco[3]={0.f, 0.f, 0.f}; 00084 00085 visibility = testshadowbuf(&R, lar->shb, co, dxco, dyco, 1.0, 0.0); 00086 } else if (lar->mode & LA_SHAD_RAY) { 00087 /* trace shadow manually, no good lamp api atm */ 00088 Isect is; 00089 00090 copy_v3_v3(is.start, co); 00091 if(lar->type==LA_SUN || lar->type==LA_HEMI) { 00092 is.dir[0] = -lar->vec[0]; 00093 is.dir[1] = -lar->vec[1]; 00094 is.dir[2] = -lar->vec[2]; 00095 is.dist = R.maxdist; 00096 } else { 00097 sub_v3_v3v3(is.dir, lar->co, is.start); 00098 is.dist = normalize_v3( is.dir ); 00099 } 00100 00101 is.mode = RE_RAY_MIRROR; 00102 is.check = RE_CHECK_VLR_NON_SOLID_MATERIAL; 00103 is.skip = 0; 00104 00105 if(lar->mode & (LA_LAYER|LA_LAYER_SHADOW)) 00106 is.lay= lar->lay; 00107 else 00108 is.lay= -1; 00109 00110 is.orig.ob = NULL; 00111 is.orig.face = NULL; 00112 is.last_hit = lar->last_hit[shi->thread]; 00113 00114 if(RE_rayobject_raycast(R.raytree,&is)) { 00115 visibility = 0.f; 00116 } 00117 00118 lar->last_hit[shi->thread]= is.last_hit; 00119 } 00120 return visibility; 00121 } 00122 00123 static int vol_get_bounds(ShadeInput *shi, const float co[3], const float vec[3], float hitco[3], Isect *isect, int intersect_type) 00124 { 00125 00126 copy_v3_v3(isect->start, co); 00127 copy_v3_v3(isect->dir, vec); 00128 isect->dist = FLT_MAX; 00129 isect->mode= RE_RAY_MIRROR; 00130 isect->last_hit = NULL; 00131 isect->lay= -1; 00132 isect->check= RE_CHECK_VLR_NONE; 00133 00134 if (intersect_type == VOL_BOUNDS_DEPTH) { 00135 isect->skip = RE_SKIP_VLR_NEIGHBOUR; 00136 isect->orig.face = (void*)shi->vlr; 00137 isect->orig.ob = (void*)shi->obi; 00138 } else { // if (intersect_type == VOL_BOUNDS_SS) { 00139 isect->skip= 0; 00140 isect->orig.face= NULL; 00141 isect->orig.ob = NULL; 00142 } 00143 00144 if(RE_rayobject_raycast(R.raytree, isect)) 00145 { 00146 hitco[0] = isect->start[0] + isect->dist*isect->dir[0]; 00147 hitco[1] = isect->start[1] + isect->dist*isect->dir[1]; 00148 hitco[2] = isect->start[2] + isect->dist*isect->dir[2]; 00149 return 1; 00150 } else { 00151 return 0; 00152 } 00153 } 00154 00155 static void shade_intersection(ShadeInput *shi, float col_r[4], Isect *is) 00156 { 00157 ShadeInput shi_new; 00158 ShadeResult shr_new; 00159 00160 memset(&shi_new, 0, sizeof(ShadeInput)); 00161 00162 shi_new.mask= shi->mask; 00163 shi_new.osatex= shi->osatex; 00164 shi_new.thread= shi->thread; 00165 shi_new.depth = shi->depth + 1; 00166 shi_new.volume_depth= shi->volume_depth + 1; 00167 shi_new.xs= shi->xs; 00168 shi_new.ys= shi->ys; 00169 shi_new.lay= shi->lay; 00170 shi_new.passflag= SCE_PASS_COMBINED; /* result of tracing needs no pass info */ 00171 shi_new.combinedflag= 0xFFFFFF; /* ray trace does all options */ 00172 shi_new.light_override= shi->light_override; 00173 shi_new.mat_override= shi->mat_override; 00174 00175 copy_v3_v3(shi_new.camera_co, is->start); 00176 00177 memset(&shr_new, 0, sizeof(ShadeResult)); 00178 00179 /* hardcoded limit of 100 for now - prevents problems in weird geometry */ 00180 if (shi->volume_depth < 100) { 00181 shade_ray(is, &shi_new, &shr_new); 00182 } 00183 00184 copy_v3_v3(col_r, shr_new.combined); 00185 col_r[3] = shr_new.alpha; 00186 } 00187 00188 static void vol_trace_behind(ShadeInput *shi, VlakRen *vlr, const float co[3], float col_r[4]) 00189 { 00190 Isect isect; 00191 00192 copy_v3_v3(isect.start, co); 00193 copy_v3_v3(isect.dir, shi->view); 00194 isect.dist = FLT_MAX; 00195 00196 isect.mode= RE_RAY_MIRROR; 00197 isect.check = RE_CHECK_VLR_NONE; 00198 isect.skip = RE_SKIP_VLR_NEIGHBOUR; 00199 isect.orig.ob = (void*) shi->obi; 00200 isect.orig.face = (void*)vlr; 00201 isect.last_hit = NULL; 00202 isect.lay= -1; 00203 00204 /* check to see if there's anything behind the volume, otherwise shade the sky */ 00205 if(RE_rayobject_raycast(R.raytree, &isect)) { 00206 shade_intersection(shi, col_r, &isect); 00207 } else { 00208 shadeSkyView(col_r, co, shi->view, NULL, shi->thread); 00209 shadeSunView(col_r, shi->view); 00210 } 00211 } 00212 00213 00214 /* trilinear interpolation */ 00215 static void vol_get_precached_scattering(Render *re, ShadeInput *shi, float scatter_col[3], const float co[3]) 00216 { 00217 VolumePrecache *vp = shi->obi->volume_precache; 00218 float bbmin[3], bbmax[3], dim[3]; 00219 float world_co[3], sample_co[3]; 00220 00221 if (!vp) return; 00222 00223 /* find sample point in global space bounding box 0.0-1.0 */ 00224 global_bounds_obi(re, shi->obi, bbmin, bbmax); 00225 sub_v3_v3v3(dim, bbmax, bbmin); 00226 mul_v3_m4v3(world_co, re->viewinv, co); 00227 00228 /* sample_co in 0.0-1.0 */ 00229 sample_co[0] = (world_co[0] - bbmin[0]) / dim[0]; 00230 sample_co[1] = (world_co[1] - bbmin[1]) / dim[1]; 00231 sample_co[2] = (world_co[2] - bbmin[2]) / dim[2]; 00232 00233 scatter_col[0] = voxel_sample_triquadratic(vp->data_r, vp->res, sample_co); 00234 scatter_col[1] = voxel_sample_triquadratic(vp->data_g, vp->res, sample_co); 00235 scatter_col[2] = voxel_sample_triquadratic(vp->data_b, vp->res, sample_co); 00236 } 00237 00238 /* Meta object density, brute force for now 00239 * (might be good enough anyway, don't need huge number of metaobs to model volumetric objects */ 00240 static float metadensity(Object* ob, const float co[3]) 00241 { 00242 float mat[4][4], imat[4][4], dens = 0.f; 00243 MetaBall* mb = (MetaBall*)ob->data; 00244 MetaElem* ml; 00245 00246 /* transform co to meta-element */ 00247 float tco[3] = {co[0], co[1], co[2]}; 00248 mult_m4_m4m4(mat, R.viewmat, ob->obmat); 00249 invert_m4_m4(imat, mat); 00250 mul_m4_v3(imat, tco); 00251 00252 for (ml = mb->elems.first; ml; ml=ml->next) { 00253 float bmat[3][3], dist2; 00254 00255 /* element rotation transform */ 00256 float tp[3] = {ml->x - tco[0], ml->y - tco[1], ml->z - tco[2]}; 00257 quat_to_mat3( bmat,ml->quat); 00258 transpose_m3(bmat); // rot.only, so inverse == transpose 00259 mul_m3_v3(bmat, tp); 00260 00261 /* MB_BALL default */ 00262 switch (ml->type) { 00263 case MB_ELIPSOID: 00264 tp[0] /= ml->expx, tp[1] /= ml->expy, tp[2] /= ml->expz; 00265 break; 00266 case MB_CUBE: 00267 tp[2] = (tp[2] > ml->expz) ? (tp[2] - ml->expz) : ((tp[2] < -ml->expz) ? (tp[2] + ml->expz) : 0.f); 00268 // no break, xy as plane 00269 case MB_PLANE: 00270 tp[1] = (tp[1] > ml->expy) ? (tp[1] - ml->expy) : ((tp[1] < -ml->expy) ? (tp[1] + ml->expy) : 0.f); 00271 // no break, x as tube 00272 case MB_TUBE: 00273 tp[0] = (tp[0] > ml->expx) ? (tp[0] - ml->expx) : ((tp[0] < -ml->expx) ? (tp[0] + ml->expx) : 0.f); 00274 } 00275 00276 /* ml->rad2 is not set */ 00277 dist2 = 1.f - ((tp[0]*tp[0] + tp[1]*tp[1] + tp[2]*tp[2]) / (ml->rad*ml->rad)); 00278 if (dist2 > 0.f) 00279 dens += (ml->flag & MB_NEGATIVE) ? -ml->s*dist2*dist2*dist2 : ml->s*dist2*dist2*dist2; 00280 } 00281 00282 dens -= mb->thresh; 00283 return (dens < 0.f) ? 0.f : dens; 00284 } 00285 00286 float vol_get_density(struct ShadeInput *shi, const float co[3]) 00287 { 00288 float density = shi->mat->vol.density; 00289 float density_scale = shi->mat->vol.density_scale; 00290 00291 if (shi->mat->mapto_textured & MAP_DENSITY) 00292 do_volume_tex(shi, co, MAP_DENSITY, NULL, &density, &R); 00293 00294 // if meta-object, modulate by metadensity without increasing it 00295 if (shi->obi->obr->ob->type == OB_MBALL) { 00296 const float md = metadensity(shi->obi->obr->ob, co); 00297 if (md < 1.f) density *= md; 00298 } 00299 00300 return density * density_scale; 00301 } 00302 00303 00304 /* Color of light that gets scattered out by the volume */ 00305 /* Uses same physically based scattering parameter as in transmission calculations, 00306 * along with artificial reflection scale/reflection color tint */ 00307 static void vol_get_reflection_color(ShadeInput *shi, float ref_col[3], const float co[3]) 00308 { 00309 float scatter = shi->mat->vol.scattering; 00310 float reflection= shi->mat->vol.reflection; 00311 copy_v3_v3(ref_col, shi->mat->vol.reflection_col); 00312 00313 if (shi->mat->mapto_textured & (MAP_SCATTERING+MAP_REFLECTION_COL)) 00314 do_volume_tex(shi, co, MAP_SCATTERING+MAP_REFLECTION_COL, ref_col, &scatter, &R); 00315 00316 /* only one single float parameter at a time... :s */ 00317 if (shi->mat->mapto_textured & (MAP_REFLECTION)) 00318 do_volume_tex(shi, co, MAP_REFLECTION, NULL, &reflection, &R); 00319 00320 ref_col[0] = reflection * ref_col[0] * scatter; 00321 ref_col[1] = reflection * ref_col[1] * scatter; 00322 ref_col[2] = reflection * ref_col[2] * scatter; 00323 } 00324 00325 /* compute emission component, amount of radiance to add per segment 00326 * can be textured with 'emit' */ 00327 static void vol_get_emission(ShadeInput *shi, float emission_col[3], const float co[3]) 00328 { 00329 float emission = shi->mat->vol.emission; 00330 copy_v3_v3(emission_col, shi->mat->vol.emission_col); 00331 00332 if (shi->mat->mapto_textured & (MAP_EMISSION+MAP_EMISSION_COL)) 00333 do_volume_tex(shi, co, MAP_EMISSION+MAP_EMISSION_COL, emission_col, &emission, &R); 00334 00335 emission_col[0] = emission_col[0] * emission; 00336 emission_col[1] = emission_col[1] * emission; 00337 emission_col[2] = emission_col[2] * emission; 00338 } 00339 00340 00341 /* A combination of scattering and absorption -> known as sigma T. 00342 * This can possibly use a specific scattering color, 00343 * and absorption multiplier factor too, but these parameters are left out for simplicity. 00344 * It's easy enough to get a good wide range of results with just these two parameters. */ 00345 static void vol_get_sigma_t(ShadeInput *shi, float sigma_t[3], const float co[3]) 00346 { 00347 /* technically absorption, but named transmission color 00348 * since it describes the effect of the coloring *after* absorption */ 00349 float transmission_col[3] = {shi->mat->vol.transmission_col[0], shi->mat->vol.transmission_col[1], shi->mat->vol.transmission_col[2]}; 00350 float scattering = shi->mat->vol.scattering; 00351 00352 if (shi->mat->mapto_textured & (MAP_SCATTERING+MAP_TRANSMISSION_COL)) 00353 do_volume_tex(shi, co, MAP_SCATTERING+MAP_TRANSMISSION_COL, transmission_col, &scattering, &R); 00354 00355 sigma_t[0] = (1.0f - transmission_col[0]) + scattering; 00356 sigma_t[1] = (1.0f - transmission_col[1]) + scattering; 00357 sigma_t[2] = (1.0f - transmission_col[2]) + scattering; 00358 } 00359 00360 /* phase function - determines in which directions the light 00361 * is scattered in the volume relative to incoming direction 00362 * and view direction */ 00363 static float vol_get_phasefunc(ShadeInput *UNUSED(shi), float g, const float w[3], const float wp[3]) 00364 { 00365 const float normalize = 0.25f; // = 1.f/4.f = M_PI/(4.f*M_PI) 00366 00367 /* normalization constant is 1/4 rather than 1/4pi, since 00368 * Blender's shading system doesn't normalise for 00369 * energy conservation - eg. multiplying by pdf ( 1/pi for a lambert brdf ). 00370 * This means that lambert surfaces in Blender are pi times brighter than they 'should be' 00371 * and therefore, with correct energy conservation, volumes will darker than other solid objects, 00372 * for the same lighting intensity. 00373 * To correct this, scale up the phase function values by pi 00374 * until Blender's shading system supports this better. --matt 00375 */ 00376 00377 if (g == 0.f) { /* isotropic */ 00378 return normalize * 1.f; 00379 } else { /* schlick */ 00380 const float k = 1.55f * g - .55f * g * g * g; 00381 const float kcostheta = k * dot_v3v3(w, wp); 00382 return normalize * (1.f - k*k) / ((1.f - kcostheta) * (1.f - kcostheta)); 00383 } 00384 00385 /* 00386 * not used, but here for reference: 00387 switch (phasefunc_type) { 00388 case MA_VOL_PH_MIEHAZY: 00389 return normalize * (0.5f + 4.5f * powf(0.5 * (1.f + costheta), 8.f)); 00390 case MA_VOL_PH_MIEMURKY: 00391 return normalize * (0.5f + 16.5f * powf(0.5 * (1.f + costheta), 32.f)); 00392 case MA_VOL_PH_RAYLEIGH: 00393 return normalize * 3.f/4.f * (1 + costheta * costheta); 00394 case MA_VOL_PH_HG: 00395 return normalize * (1.f - g*g) / powf(1.f + g*g - 2.f * g * costheta, 1.5f)); 00396 case MA_VOL_PH_SCHLICK: 00397 { 00398 const float k = 1.55f * g - .55f * g * g * g; 00399 const float kcostheta = k * costheta; 00400 return normalize * (1.f - k*k) / ((1.f - kcostheta) * (1.f - kcostheta)); 00401 } 00402 case MA_VOL_PH_ISOTROPIC: 00403 default: 00404 return normalize * 1.f; 00405 } 00406 */ 00407 } 00408 00409 /* Compute transmittance = e^(-attenuation) */ 00410 static void vol_get_transmittance_seg(ShadeInput *shi, float tr[3], float stepsize, const float co[3], float density) 00411 { 00412 /* input density = density at co */ 00413 float tau[3] = {0.f, 0.f, 0.f}; 00414 const float stepd = density * stepsize; 00415 float sigma_t[3]; 00416 00417 vol_get_sigma_t(shi, sigma_t, co); 00418 00419 /* homogenous volume within the sampled distance */ 00420 tau[0] += stepd * sigma_t[0]; 00421 tau[1] += stepd * sigma_t[1]; 00422 tau[2] += stepd * sigma_t[2]; 00423 00424 tr[0] *= expf(-tau[0]); 00425 tr[1] *= expf(-tau[1]); 00426 tr[2] *= expf(-tau[2]); 00427 } 00428 00429 /* Compute transmittance = e^(-attenuation) */ 00430 static void vol_get_transmittance(ShadeInput *shi, float tr[3], const float co[3], const float endco[3]) 00431 { 00432 float p[3] = {co[0], co[1], co[2]}; 00433 float step_vec[3] = {endco[0] - co[0], endco[1] - co[1], endco[2] - co[2]}; 00434 float tau[3] = {0.f, 0.f, 0.f}; 00435 00436 float t0 = 0.f; 00437 float t1 = normalize_v3(step_vec); 00438 float pt0 = t0; 00439 00440 t0 += shi->mat->vol.stepsize * ((shi->mat->vol.stepsize_type == MA_VOL_STEP_CONSTANT) ? 0.5f : BLI_thread_frand(shi->thread)); 00441 p[0] += t0 * step_vec[0]; 00442 p[1] += t0 * step_vec[1]; 00443 p[2] += t0 * step_vec[2]; 00444 mul_v3_fl(step_vec, shi->mat->vol.stepsize); 00445 00446 for (; t0 < t1; pt0 = t0, t0 += shi->mat->vol.stepsize) { 00447 const float d = vol_get_density(shi, p); 00448 const float stepd = (t0 - pt0) * d; 00449 float sigma_t[3]; 00450 00451 vol_get_sigma_t(shi, sigma_t, p); 00452 00453 tau[0] += stepd * sigma_t[0]; 00454 tau[1] += stepd * sigma_t[1]; 00455 tau[2] += stepd * sigma_t[2]; 00456 00457 add_v3_v3(p, step_vec); 00458 } 00459 00460 /* return transmittance */ 00461 tr[0] = expf(-tau[0]); 00462 tr[1] = expf(-tau[1]); 00463 tr[2] = expf(-tau[2]); 00464 } 00465 00466 static void vol_shade_one_lamp(struct ShadeInput *shi, const float co[3], const float view[3], LampRen *lar, float lacol[3]) 00467 { 00468 float visifac, lv[3], lampdist; 00469 float tr[3]={1.0,1.0,1.0}; 00470 float hitco[3], *atten_co; 00471 float p, ref_col[3]; 00472 00473 if (lar->mode & LA_LAYER) if((lar->lay & shi->obi->lay)==0) return; 00474 if ((lar->lay & shi->lay)==0) return; 00475 if (lar->energy == 0.0f) return; 00476 00477 if ((visifac= lamp_get_visibility(lar, co, lv, &lampdist)) == 0.f) return; 00478 00479 copy_v3_v3(lacol, &lar->r); 00480 00481 if(lar->mode & LA_TEXTURE) { 00482 shi->osatex= 0; 00483 do_lamp_tex(lar, lv, shi, lacol, LA_TEXTURE); 00484 } 00485 00486 mul_v3_fl(lacol, visifac); 00487 00488 if (ELEM(lar->type, LA_SUN, LA_HEMI)) 00489 copy_v3_v3(lv, lar->vec); 00490 negate_v3(lv); 00491 00492 if (shi->mat->vol.shade_type == MA_VOL_SHADE_SHADOWED) { 00493 mul_v3_fl(lacol, vol_get_shadow(shi, lar, co)); 00494 } 00495 else if (ELEM3(shi->mat->vol.shade_type, MA_VOL_SHADE_SHADED, MA_VOL_SHADE_MULTIPLE, MA_VOL_SHADE_SHADEDPLUSMULTIPLE)) 00496 { 00497 Isect is; 00498 00499 if (shi->mat->vol.shadeflag & MA_VOL_RECV_EXT_SHADOW) { 00500 mul_v3_fl(lacol, vol_get_shadow(shi, lar, co)); 00501 if (luminance(lacol) < 0.001f) return; 00502 } 00503 00504 /* find minimum of volume bounds, or lamp coord */ 00505 if (vol_get_bounds(shi, co, lv, hitco, &is, VOL_BOUNDS_SS)) { 00506 float dist = len_v3v3(co, hitco); 00507 VlakRen *vlr = (VlakRen *)is.hit.face; 00508 00509 /* simple internal shadowing */ 00510 if (vlr->mat->material_type == MA_TYPE_SURFACE) { 00511 lacol[0] = lacol[1] = lacol[2] = 0.0f; 00512 return; 00513 } 00514 00515 if (ELEM(lar->type, LA_SUN, LA_HEMI)) 00516 /* infinite lights, can never be inside volume */ 00517 atten_co = hitco; 00518 else if ( lampdist < dist ) { 00519 atten_co = lar->co; 00520 } else 00521 atten_co = hitco; 00522 00523 vol_get_transmittance(shi, tr, co, atten_co); 00524 00525 mul_v3_v3v3(lacol, lacol, tr); 00526 } 00527 else { 00528 /* Point is on the outside edge of the volume, 00529 * therefore no attenuation, full transmission. 00530 * Radiance from lamp remains unchanged */ 00531 } 00532 } 00533 00534 if (luminance(lacol) < 0.001f) return; 00535 00536 normalize_v3(lv); 00537 p = vol_get_phasefunc(shi, shi->mat->vol.asymmetry, view, lv); 00538 00539 /* physically based scattering with non-physically based RGB gain */ 00540 vol_get_reflection_color(shi, ref_col, co); 00541 00542 lacol[0] *= p * ref_col[0]; 00543 lacol[1] *= p * ref_col[1]; 00544 lacol[2] *= p * ref_col[2]; 00545 } 00546 00547 /* single scattering only for now */ 00548 void vol_get_scattering(ShadeInput *shi, float scatter_col[3], const float co[3], const float view[3]) 00549 { 00550 ListBase *lights; 00551 GroupObject *go; 00552 LampRen *lar; 00553 00554 zero_v3(scatter_col); 00555 00556 lights= get_lights(shi); 00557 for(go=lights->first; go; go= go->next) 00558 { 00559 float lacol[3] = {0.f, 0.f, 0.f}; 00560 lar= go->lampren; 00561 00562 if (lar) { 00563 vol_shade_one_lamp(shi, co, view, lar, lacol); 00564 add_v3_v3(scatter_col, lacol); 00565 } 00566 } 00567 } 00568 00569 00570 /* 00571 The main volumetric integrator, using an emission/absorption/scattering model. 00572 00573 Incoming radiance = 00574 00575 outgoing radiance from behind surface * beam transmittance/attenuation 00576 + added radiance from all points along the ray due to participating media 00577 --> radiance for each segment = 00578 (radiance added by scattering + radiance added by emission) * beam transmittance/attenuation 00579 */ 00580 00581 /* For ease of use, I've also introduced a 'reflection' and 'reflection color' parameter, which isn't 00582 * physically correct. This works as an RGB tint/gain on out-scattered light, but doesn't affect the light 00583 * that is transmitted through the volume. While having wavelength dependent absorption/scattering is more correct, 00584 * it also makes it harder to control the overall look of the volume since coloring the outscattered light results 00585 * in the inverse color being transmitted through the rest of the volume. 00586 */ 00587 static void volumeintegrate(struct ShadeInput *shi, float col[4], const float co[3], const float endco[3]) 00588 { 00589 float radiance[3] = {0.f, 0.f, 0.f}; 00590 float tr[3] = {1.f, 1.f, 1.f}; 00591 float p[3] = {co[0], co[1], co[2]}; 00592 float step_vec[3] = {endco[0] - co[0], endco[1] - co[1], endco[2] - co[2]}; 00593 const float stepsize = shi->mat->vol.stepsize; 00594 00595 float t0 = 0.f; 00596 float pt0 = t0; 00597 float t1 = normalize_v3(step_vec); /* returns vector length */ 00598 00599 t0 += stepsize * ((shi->mat->vol.stepsize_type == MA_VOL_STEP_CONSTANT) ? 0.5f : BLI_thread_frand(shi->thread)); 00600 p[0] += t0 * step_vec[0]; 00601 p[1] += t0 * step_vec[1]; 00602 p[2] += t0 * step_vec[2]; 00603 mul_v3_fl(step_vec, stepsize); 00604 00605 for (; t0 < t1; pt0 = t0, t0 += stepsize) { 00606 const float density = vol_get_density(shi, p); 00607 00608 if (density > 0.00001f) { 00609 float scatter_col[3] = {0.f, 0.f, 0.f}, emit_col[3]; 00610 const float stepd = (t0 - pt0) * density; 00611 00612 /* transmittance component (alpha) */ 00613 vol_get_transmittance_seg(shi, tr, stepsize, co, density); 00614 00615 if (t0 > t1 * 0.25f) { 00616 /* only use depth cutoff after we've traced a little way into the volume */ 00617 if (luminance(tr) < shi->mat->vol.depth_cutoff) break; 00618 } 00619 00620 vol_get_emission(shi, emit_col, p); 00621 00622 if (shi->obi->volume_precache) { 00623 float p2[3]; 00624 00625 p2[0] = p[0] + (step_vec[0] * 0.5f); 00626 p2[1] = p[1] + (step_vec[1] * 0.5f); 00627 p2[2] = p[2] + (step_vec[2] * 0.5f); 00628 00629 vol_get_precached_scattering(&R, shi, scatter_col, p2); 00630 } else 00631 vol_get_scattering(shi, scatter_col, p, shi->view); 00632 00633 radiance[0] += stepd * tr[0] * (emit_col[0] + scatter_col[0]); 00634 radiance[1] += stepd * tr[1] * (emit_col[1] + scatter_col[1]); 00635 radiance[2] += stepd * tr[2] * (emit_col[2] + scatter_col[2]); 00636 } 00637 add_v3_v3(p, step_vec); 00638 } 00639 00640 /* multiply original color (from behind volume) with transmittance over entire distance */ 00641 mul_v3_v3v3(col, tr, col); 00642 add_v3_v3(col, radiance); 00643 00644 /* alpha <-- transmission luminance */ 00645 col[3] = 1.0f - luminance(tr); 00646 } 00647 00648 /* the main entry point for volume shading */ 00649 static void volume_trace(struct ShadeInput *shi, struct ShadeResult *shr, int inside_volume) 00650 { 00651 float hitco[3], col[4] = {0.f,0.f,0.f,0.f}; 00652 float *startco, *endco; 00653 int trace_behind = 1; 00654 const int ztransp= ((shi->depth==0) && (shi->mat->mode & MA_TRANSP) && (shi->mat->mode & MA_ZTRANSP)); 00655 Isect is; 00656 00657 /* check for shading an internal face a volume object directly */ 00658 if (inside_volume == VOL_SHADE_INSIDE) 00659 trace_behind = 0; 00660 else if (inside_volume == VOL_SHADE_OUTSIDE) { 00661 if (shi->flippednor) 00662 inside_volume = VOL_SHADE_INSIDE; 00663 } 00664 00665 if (ztransp && inside_volume == VOL_SHADE_INSIDE) { 00666 MatInside *mi; 00667 int render_this=0; 00668 00669 /* don't render the backfaces of ztransp volume materials. 00670 00671 * volume shading renders the internal volume from between the 00672 * ' view intersection of the solid volume to the 00673 * intersection on the other side, as part of the shading of 00674 * the front face. 00675 00676 * Because ztransp renders both front and back faces independently 00677 * this will double up, so here we prevent rendering the backface as well, 00678 * which would otherwise render the volume in between the camera and the backface 00679 * --matt */ 00680 00681 for (mi=R.render_volumes_inside.first; mi; mi=mi->next) { 00682 /* weak... */ 00683 if (mi->ma == shi->mat) render_this=1; 00684 } 00685 if (!render_this) return; 00686 } 00687 00688 00689 if (inside_volume == VOL_SHADE_INSIDE) 00690 { 00691 startco = shi->camera_co; 00692 endco = shi->co; 00693 00694 if (trace_behind) { 00695 if (!ztransp) 00696 /* trace behind the volume object */ 00697 vol_trace_behind(shi, shi->vlr, endco, col); 00698 } else { 00699 /* we're tracing through the volume between the camera 00700 * and a solid surface, so use that pre-shaded radiance */ 00701 copy_v4_v4(col, shr->combined); 00702 } 00703 00704 /* shade volume from 'camera' to 1st hit point */ 00705 volumeintegrate(shi, col, startco, endco); 00706 } 00707 /* trace to find a backface, the other side bounds of the volume */ 00708 /* (ray intersect ignores front faces here) */ 00709 else if (vol_get_bounds(shi, shi->co, shi->view, hitco, &is, VOL_BOUNDS_DEPTH)) 00710 { 00711 VlakRen *vlr = (VlakRen *)is.hit.face; 00712 00713 startco = shi->co; 00714 endco = hitco; 00715 00716 if (!ztransp) { 00717 /* if it's another face in the same material */ 00718 if (vlr->mat == shi->mat) { 00719 /* trace behind the 2nd (raytrace) hit point */ 00720 vol_trace_behind(shi, (VlakRen *)is.hit.face, endco, col); 00721 } else { 00722 shade_intersection(shi, col, &is); 00723 } 00724 } 00725 00726 /* shade volume from 1st hit point to 2nd hit point */ 00727 volumeintegrate(shi, col, startco, endco); 00728 } 00729 00730 if (ztransp) 00731 col[3] = col[3]>1.f?1.f:col[3]; 00732 else 00733 col[3] = 1.f; 00734 00735 copy_v3_v3(shr->combined, col); 00736 shr->alpha = col[3]; 00737 00738 copy_v3_v3(shr->diff, shr->combined); 00739 } 00740 00741 /* Traces a shadow through the object, 00742 * pretty much gets the transmission over a ray path */ 00743 void shade_volume_shadow(struct ShadeInput *shi, struct ShadeResult *shr, struct Isect *last_is) 00744 { 00745 float hitco[3]; 00746 float tr[3] = {1.0,1.0,1.0}; 00747 Isect is= {{0}}; 00748 float *startco, *endco; 00749 00750 memset(shr, 0, sizeof(ShadeResult)); 00751 00752 /* if 1st hit normal is facing away from the camera, 00753 * then we're inside the volume already. */ 00754 if (shi->flippednor) { 00755 startco = last_is->start; 00756 endco = shi->co; 00757 } 00758 00759 /* trace to find a backface, the other side bounds of the volume */ 00760 /* (ray intersect ignores front faces here) */ 00761 else if (vol_get_bounds(shi, shi->co, shi->view, hitco, &is, VOL_BOUNDS_DEPTH)) { 00762 startco = shi->co; 00763 endco = hitco; 00764 } 00765 else { 00766 shr->combined[0] = shr->combined[1] = shr->combined[2] = 0.f; 00767 shr->alpha = shr->combined[3] = 1.f; 00768 return; 00769 } 00770 00771 vol_get_transmittance(shi, tr, startco, endco); 00772 00773 00774 /* if we hit another face in the same volume bounds */ 00775 /* shift raytrace coordinates to the hit point, to avoid shading volume twice */ 00776 /* due to idiosyncracy in ray_trace_shadow_tra() */ 00777 if (is.hit.ob == shi->obi) { 00778 copy_v3_v3(shi->co, hitco); 00779 last_is->dist -= is.dist; 00780 shi->vlr = (VlakRen *)is.hit.face; 00781 } 00782 00783 00784 copy_v3_v3(shr->combined, tr); 00785 shr->combined[3] = 1.0f - luminance(tr); 00786 shr->alpha = shr->combined[3]; 00787 } 00788 00789 00790 /* delivers a fully filled in ShadeResult, for all passes */ 00791 void shade_volume_outside(ShadeInput *shi, ShadeResult *shr) 00792 { 00793 memset(shr, 0, sizeof(ShadeResult)); 00794 volume_trace(shi, shr, VOL_SHADE_OUTSIDE); 00795 } 00796 00797 00798 void shade_volume_inside(ShadeInput *shi, ShadeResult *shr) 00799 { 00800 MatInside *m; 00801 Material *mat_backup; 00802 ObjectInstanceRen *obi_backup; 00803 float prev_alpha = shr->alpha; 00804 00805 /* XXX: extend to multiple volumes perhaps later */ 00806 mat_backup = shi->mat; 00807 obi_backup = shi->obi; 00808 00809 m = R.render_volumes_inside.first; 00810 shi->mat = m->ma; 00811 shi->obi = m->obi; 00812 shi->obr = m->obi->obr; 00813 00814 volume_trace(shi, shr, VOL_SHADE_INSIDE); 00815 00816 shr->alpha = shr->alpha + prev_alpha; 00817 CLAMP(shr->alpha, 0.0f, 1.0f); 00818 00819 shi->mat = mat_backup; 00820 shi->obi = obi_backup; 00821 shi->obr = obi_backup->obr; 00822 } 00823 00824