Blender  V2.59
pointdensity.c
Go to the documentation of this file.
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 }