|
Blender
V2.59
|
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 * Contributors: Matt Ebb 00022 * 00023 * ***** END GPL LICENSE BLOCK ***** 00024 */ 00025 00031 #include <math.h> 00032 #include <stdlib.h> 00033 #include <stdio.h> 00034 00035 #include "MEM_guardedalloc.h" 00036 00037 #include "BLI_math.h" 00038 #include "BLI_blenlib.h" 00039 #include "BLI_kdopbvh.h" 00040 #include "BLI_utildefines.h" 00041 00042 #include "BKE_DerivedMesh.h" 00043 #include "BKE_global.h" 00044 #include "BKE_lattice.h" 00045 #include "BKE_main.h" 00046 #include "BKE_object.h" 00047 #include "BKE_particle.h" 00048 #include "BKE_scene.h" 00049 #include "BKE_texture.h" 00050 #include "BKE_colortools.h" 00051 00052 #include "DNA_meshdata_types.h" 00053 #include "DNA_texture_types.h" 00054 #include "DNA_particle_types.h" 00055 00056 #include "render_types.h" 00057 #include "renderdatabase.h" 00058 #include "texture.h" 00059 #include "pointdensity.h" 00060 00061 /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 00062 /* defined in pipeline.c, is hardcopy of active dynamic allocated Render */ 00063 /* only to be used here in this file, it's for speed */ 00064 extern struct Render R; 00065 /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ 00066 00067 00068 static int point_data_used(PointDensity *pd) 00069 { 00070 int pd_bitflag = 0; 00071 00072 if (pd->source == TEX_PD_PSYS) { 00073 if ((pd->noise_influence == TEX_PD_NOISE_VEL) || (pd->falloff_type == TEX_PD_FALLOFF_PARTICLE_VEL) || (pd->color_source == TEX_PD_COLOR_PARTVEL) || (pd->color_source == TEX_PD_COLOR_PARTSPEED)) 00074 pd_bitflag |= POINT_DATA_VEL; 00075 if ((pd->noise_influence == TEX_PD_NOISE_AGE) || (pd->color_source == TEX_PD_COLOR_PARTAGE) || (pd->falloff_type == TEX_PD_FALLOFF_PARTICLE_AGE)) 00076 pd_bitflag |= POINT_DATA_LIFE; 00077 } 00078 00079 return pd_bitflag; 00080 } 00081 00082 00083 /* additional data stored alongside the point density BVH, 00084 * accessible by point index number to retrieve other information 00085 * such as particle velocity or lifetime */ 00086 static void alloc_point_data(PointDensity *pd, int total_particles, int point_data_used) 00087 { 00088 int data_size = 0; 00089 00090 if (point_data_used & POINT_DATA_VEL) { 00091 /* store 3 channels of velocity data */ 00092 data_size += 3; 00093 } 00094 if (point_data_used & POINT_DATA_LIFE) { 00095 /* store 1 channel of lifetime data */ 00096 data_size += 1; 00097 } 00098 00099 if (data_size) 00100 pd->point_data = MEM_mallocN(sizeof(float)*data_size*total_particles, "particle point data"); 00101 } 00102 00103 static void pointdensity_cache_psys(Render *re, PointDensity *pd, Object *ob, ParticleSystem *psys) 00104 { 00105 DerivedMesh* dm; 00106 ParticleKey state; 00107 ParticleSimulationData sim= {0}; 00108 ParticleData *pa=NULL; 00109 float cfra = BKE_curframe(re->scene); 00110 int i, childexists; 00111 int total_particles, offset=0; 00112 int data_used = point_data_used(pd); 00113 float partco[3]; 00114 float obview[4][4]; 00115 00116 /* init everything */ 00117 if (!psys || !ob || !pd) return; 00118 00119 mul_m4_m4m4(obview, re->viewinv, ob->obmat); 00120 00121 /* Just to create a valid rendering context for particles */ 00122 psys_render_set(ob, psys, re->viewmat, re->winmat, re->winx, re->winy, 0); 00123 00124 dm = mesh_create_derived_render(re->scene, ob,CD_MASK_BAREMESH|CD_MASK_MTFACE|CD_MASK_MCOL); 00125 00126 if ( !psys_check_enabled(ob, psys)) { 00127 psys_render_restore(ob, psys); 00128 return; 00129 } 00130 00131 sim.scene= re->scene; 00132 sim.ob= ob; 00133 sim.psys= psys; 00134 00135 /* in case ob->imat isn't up-to-date */ 00136 invert_m4_m4(ob->imat, ob->obmat); 00137 00138 total_particles = psys->totpart+psys->totchild; 00139 psys->lattice=psys_get_lattice(&sim); 00140 00141 pd->point_tree = BLI_bvhtree_new(total_particles, 0.0, 4, 6); 00142 alloc_point_data(pd, total_particles, data_used); 00143 pd->totpoints = total_particles; 00144 if (data_used & POINT_DATA_VEL) offset = pd->totpoints*3; 00145 00146 if (psys->totchild > 0 && !(psys->part->draw & PART_DRAW_PARENT)) 00147 childexists = 1; 00148 00149 for (i=0, pa=psys->particles; i < total_particles; i++, pa++) { 00150 00151 state.time = cfra; 00152 if(psys_get_particle_state(&sim, i, &state, 0)) { 00153 00154 VECCOPY(partco, state.co); 00155 00156 if (pd->psys_cache_space == TEX_PD_OBJECTSPACE) 00157 mul_m4_v3(ob->imat, partco); 00158 else if (pd->psys_cache_space == TEX_PD_OBJECTLOC) { 00159 sub_v3_v3(partco, ob->loc); 00160 } else { 00161 /* TEX_PD_WORLDSPACE */ 00162 } 00163 00164 BLI_bvhtree_insert(pd->point_tree, i, partco, 1); 00165 00166 if (data_used & POINT_DATA_VEL) { 00167 pd->point_data[i*3 + 0] = state.vel[0]; 00168 pd->point_data[i*3 + 1] = state.vel[1]; 00169 pd->point_data[i*3 + 2] = state.vel[2]; 00170 } 00171 if (data_used & POINT_DATA_LIFE) { 00172 float pa_time; 00173 00174 if (i < psys->totpart) { 00175 pa_time = (cfra - pa->time)/pa->lifetime; 00176 } else { 00177 ChildParticle *cpa= (psys->child + i) - psys->totpart; 00178 float pa_birthtime, pa_dietime; 00179 00180 pa_time = psys_get_child_time(psys, cpa, cfra, &pa_birthtime, &pa_dietime); 00181 } 00182 00183 pd->point_data[offset + i] = pa_time; 00184 00185 } 00186 } 00187 } 00188 00189 BLI_bvhtree_balance(pd->point_tree); 00190 dm->release(dm); 00191 00192 if(psys->lattice){ 00193 end_latt_deform(psys->lattice); 00194 psys->lattice=0; 00195 } 00196 00197 psys_render_restore(ob, psys); 00198 } 00199 00200 00201 static void pointdensity_cache_object(Render *re, PointDensity *pd, Object *ob) 00202 { 00203 int i; 00204 DerivedMesh *dm; 00205 MVert *mvert = NULL; 00206 00207 dm = mesh_create_derived_render(re->scene, ob, CD_MASK_BAREMESH|CD_MASK_MTFACE|CD_MASK_MCOL); 00208 mvert= dm->getVertArray(dm); /* local object space */ 00209 00210 pd->totpoints= dm->getNumVerts(dm); 00211 if (pd->totpoints == 0) return; 00212 00213 pd->point_tree = BLI_bvhtree_new(pd->totpoints, 0.0, 4, 6); 00214 00215 for(i=0; i < pd->totpoints; i++, mvert++) { 00216 float co[3]; 00217 00218 VECCOPY(co, mvert->co); 00219 00220 switch(pd->ob_cache_space) { 00221 case TEX_PD_OBJECTSPACE: 00222 break; 00223 case TEX_PD_OBJECTLOC: 00224 mul_m4_v3(ob->obmat, co); 00225 sub_v3_v3(co, ob->loc); 00226 break; 00227 case TEX_PD_WORLDSPACE: 00228 default: 00229 mul_m4_v3(ob->obmat, co); 00230 break; 00231 } 00232 00233 BLI_bvhtree_insert(pd->point_tree, i, co, 1); 00234 } 00235 00236 BLI_bvhtree_balance(pd->point_tree); 00237 dm->release(dm); 00238 00239 } 00240 static void cache_pointdensity(Render *re, Tex *tex) 00241 { 00242 PointDensity *pd = tex->pd; 00243 00244 if(!pd) 00245 return; 00246 00247 if (pd->point_tree) { 00248 BLI_bvhtree_free(pd->point_tree); 00249 pd->point_tree = NULL; 00250 } 00251 00252 if (pd->source == TEX_PD_PSYS) { 00253 Object *ob = pd->object; 00254 ParticleSystem *psys; 00255 00256 if (!ob || !pd->psys) return; 00257 00258 psys= BLI_findlink(&ob->particlesystem, pd->psys-1); 00259 if (!psys) return; 00260 00261 pointdensity_cache_psys(re, pd, ob, psys); 00262 } 00263 else if (pd->source == TEX_PD_OBJECT) { 00264 Object *ob = pd->object; 00265 if (ob && ob->type == OB_MESH) 00266 pointdensity_cache_object(re, pd, ob); 00267 } 00268 } 00269 00270 static void free_pointdensity(Render *UNUSED(re), Tex *tex) 00271 { 00272 PointDensity *pd = tex->pd; 00273 00274 if (!pd) return; 00275 00276 if (pd->point_tree) { 00277 BLI_bvhtree_free(pd->point_tree); 00278 pd->point_tree = NULL; 00279 } 00280 00281 if (pd->point_data) { 00282 MEM_freeN(pd->point_data); 00283 pd->point_data = NULL; 00284 } 00285 pd->totpoints = 0; 00286 } 00287 00288 00289 00290 void make_pointdensities(Render *re) 00291 { 00292 Tex *tex; 00293 00294 if(re->scene->r.scemode & R_PREVIEWBUTS) 00295 return; 00296 00297 re->i.infostr= "Caching Point Densities"; 00298 re->stats_draw(re->sdh, &re->i); 00299 00300 for (tex= re->main->tex.first; tex; tex= tex->id.next) { 00301 if(tex->id.us && tex->type==TEX_POINTDENSITY) { 00302 cache_pointdensity(re, tex); 00303 } 00304 } 00305 00306 re->i.infostr= NULL; 00307 re->stats_draw(re->sdh, &re->i); 00308 } 00309 00310 void free_pointdensities(Render *re) 00311 { 00312 Tex *tex; 00313 00314 if(re->scene->r.scemode & R_PREVIEWBUTS) 00315 return; 00316 00317 for (tex= re->main->tex.first; tex; tex= tex->id.next) { 00318 if(tex->id.us && tex->type==TEX_POINTDENSITY) { 00319 free_pointdensity(re, tex); 00320 } 00321 } 00322 } 00323 00324 typedef struct PointDensityRangeData 00325 { 00326 float *density; 00327 float squared_radius; 00328 float *point_data; 00329 float *vec; 00330 float softness; 00331 short falloff_type; 00332 short noise_influence; 00333 float *age; 00334 int point_data_used; 00335 int offset; 00336 struct CurveMapping *density_curve; 00337 float velscale; 00338 } PointDensityRangeData; 00339 00340 static void accum_density(void *userdata, int index, float squared_dist) 00341 { 00342 PointDensityRangeData *pdr = (PointDensityRangeData *)userdata; 00343 const float dist = (pdr->squared_radius - squared_dist) / pdr->squared_radius * 0.5f; 00344 float density = 0.0f; 00345 00346 if (pdr->point_data_used & POINT_DATA_VEL) { 00347 pdr->vec[0] += pdr->point_data[index*3 + 0]; //* density; 00348 pdr->vec[1] += pdr->point_data[index*3 + 1]; //* density; 00349 pdr->vec[2] += pdr->point_data[index*3 + 2]; //* density; 00350 } 00351 if (pdr->point_data_used & POINT_DATA_LIFE) { 00352 *pdr->age += pdr->point_data[pdr->offset + index]; // * density; 00353 } 00354 00355 if (pdr->falloff_type == TEX_PD_FALLOFF_STD) 00356 density = dist; 00357 else if (pdr->falloff_type == TEX_PD_FALLOFF_SMOOTH) 00358 density = 3.0f*dist*dist - 2.0f*dist*dist*dist; 00359 else if (pdr->falloff_type == TEX_PD_FALLOFF_SOFT) 00360 density = pow(dist, pdr->softness); 00361 else if (pdr->falloff_type == TEX_PD_FALLOFF_CONSTANT) 00362 density = pdr->squared_radius; 00363 else if (pdr->falloff_type == TEX_PD_FALLOFF_ROOT) 00364 density = sqrt(dist); 00365 else if (pdr->falloff_type == TEX_PD_FALLOFF_PARTICLE_AGE) { 00366 if (pdr->point_data_used & POINT_DATA_LIFE) 00367 density = dist*MIN2(pdr->point_data[pdr->offset + index], 1.0f); 00368 else 00369 density = dist; 00370 } 00371 else if (pdr->falloff_type == TEX_PD_FALLOFF_PARTICLE_VEL) { 00372 if (pdr->point_data_used & POINT_DATA_VEL) 00373 density = dist*len_v3(pdr->point_data + index*3)*pdr->velscale; 00374 else 00375 density = dist; 00376 } 00377 00378 if (pdr->density_curve && dist != 0.0f) { 00379 density = curvemapping_evaluateF(pdr->density_curve, 0, density/dist)*dist; 00380 } 00381 00382 *pdr->density += density; 00383 } 00384 00385 00386 static void init_pointdensityrangedata(PointDensity *pd, PointDensityRangeData *pdr, 00387 float *density, float *vec, float *age, struct CurveMapping *density_curve, float velscale) 00388 { 00389 pdr->squared_radius = pd->radius*pd->radius; 00390 pdr->density = density; 00391 pdr->point_data = pd->point_data; 00392 pdr->falloff_type = pd->falloff_type; 00393 pdr->vec = vec; 00394 pdr->age = age; 00395 pdr->softness = pd->falloff_softness; 00396 pdr->noise_influence = pd->noise_influence; 00397 pdr->point_data_used = point_data_used(pd); 00398 pdr->offset = (pdr->point_data_used & POINT_DATA_VEL)?pd->totpoints*3:0; 00399 pdr->density_curve = density_curve; 00400 pdr->velscale = velscale; 00401 } 00402 00403 00404 int pointdensitytex(Tex *tex, float *texvec, TexResult *texres) 00405 { 00406 int retval = TEX_INT; 00407 PointDensity *pd = tex->pd; 00408 PointDensityRangeData pdr; 00409 float density=0.0f, age=0.0f, time=0.0f; 00410 float vec[3] = {0.0f, 0.0f, 0.0f}, co[3]; 00411 float col[4]; 00412 float turb, noise_fac; 00413 int num=0; 00414 00415 texres->tin = 0.0f; 00416 00417 if ((!pd) || (!pd->point_tree)) 00418 return 0; 00419 00420 init_pointdensityrangedata(pd, &pdr, &density, vec, &age, 00421 (pd->flag&TEX_PD_FALLOFF_CURVE ? pd->falloff_curve : NULL), pd->falloff_speed_scale*0.001f); 00422 noise_fac = pd->noise_fac * 0.5f; /* better default */ 00423 00424 VECCOPY(co, texvec); 00425 00426 if (point_data_used(pd)) { 00427 /* does a BVH lookup to find accumulated density and additional point data * 00428 * stores particle velocity vector in 'vec', and particle lifetime in 'time' */ 00429 num = BLI_bvhtree_range_query(pd->point_tree, co, pd->radius, accum_density, &pdr); 00430 if (num > 0) { 00431 age /= num; 00432 mul_v3_fl(vec, 1.0f/num); 00433 } 00434 00435 /* reset */ 00436 density = vec[0] = vec[1] = vec[2] = 0.0f; 00437 } 00438 00439 if (pd->flag & TEX_PD_TURBULENCE) { 00440 00441 if (pd->noise_influence == TEX_PD_NOISE_AGE) { 00442 turb = BLI_gTurbulence(pd->noise_size, texvec[0]+age, texvec[1]+age, texvec[2]+age, pd->noise_depth, 0, pd->noise_basis); 00443 } 00444 else if (pd->noise_influence == TEX_PD_NOISE_TIME) { 00445 time = R.cfra / (float)R.r.efra; 00446 turb = BLI_gTurbulence(pd->noise_size, texvec[0]+time, texvec[1]+time, texvec[2]+time, pd->noise_depth, 0, pd->noise_basis); 00447 //turb = BLI_turbulence(pd->noise_size, texvec[0]+time, texvec[1]+time, texvec[2]+time, pd->noise_depth); 00448 } 00449 else { 00450 turb = BLI_gTurbulence(pd->noise_size, texvec[0]+vec[0], texvec[1]+vec[1], texvec[2]+vec[2], pd->noise_depth, 0, pd->noise_basis); 00451 } 00452 00453 turb -= 0.5f; /* re-center 0.0-1.0 range around 0 to prevent offsetting result */ 00454 00455 /* now we have an offset coordinate to use for the density lookup */ 00456 co[0] = texvec[0] + noise_fac * turb; 00457 co[1] = texvec[1] + noise_fac * turb; 00458 co[2] = texvec[2] + noise_fac * turb; 00459 } 00460 00461 /* BVH query with the potentially perturbed coordinates */ 00462 num = BLI_bvhtree_range_query(pd->point_tree, co, pd->radius, accum_density, &pdr); 00463 if (num > 0) { 00464 age /= num; 00465 mul_v3_fl(vec, 1.0f/num); 00466 } 00467 00468 texres->tin = density; 00469 BRICONT; 00470 00471 if (pd->color_source == TEX_PD_COLOR_CONSTANT) 00472 return retval; 00473 00474 retval |= TEX_RGB; 00475 00476 switch (pd->color_source) { 00477 case TEX_PD_COLOR_PARTAGE: 00478 if (pd->coba) { 00479 if (do_colorband(pd->coba, age, col)) { 00480 texres->talpha= 1; 00481 VECCOPY(&texres->tr, col); 00482 texres->tin *= col[3]; 00483 texres->ta = texres->tin; 00484 } 00485 } 00486 break; 00487 case TEX_PD_COLOR_PARTSPEED: 00488 { 00489 float speed = len_v3(vec) * pd->speed_scale; 00490 00491 if (pd->coba) { 00492 if (do_colorband(pd->coba, speed, col)) { 00493 texres->talpha= 1; 00494 VECCOPY(&texres->tr, col); 00495 texres->tin *= col[3]; 00496 texres->ta = texres->tin; 00497 } 00498 } 00499 break; 00500 } 00501 case TEX_PD_COLOR_PARTVEL: 00502 texres->talpha= 1; 00503 mul_v3_fl(vec, pd->speed_scale); 00504 VECCOPY(&texres->tr, vec); 00505 texres->ta = texres->tin; 00506 break; 00507 case TEX_PD_COLOR_CONSTANT: 00508 default: 00509 texres->tr = texres->tg = texres->tb = texres->ta = 1.0f; 00510 break; 00511 } 00512 BRICONTRGB; 00513 00514 return retval; 00515 00516 /* 00517 if (texres->nor!=NULL) { 00518 texres->nor[0] = texres->nor[1] = texres->nor[2] = 0.0f; 00519 } 00520 */ 00521 }