Blender V2.61 - r43446

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= {NULL};
00108     ParticleData *pa=NULL;
00109     float cfra = BKE_curframe(re->scene);
00110     int i /*, childexists*/ /* UNUSED */;
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     mult_m4_m4m4(obview, ob->obmat, re->viewinv);
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 0 /* UNUSED */
00147     if (psys->totchild > 0 && !(psys->part->draw & PART_DRAW_PARENT))
00148         childexists = 1;
00149 #endif
00150 
00151     for (i=0, pa=psys->particles; i < total_particles; i++, pa++) {
00152 
00153         state.time = cfra;
00154         if(psys_get_particle_state(&sim, i, &state, 0)) {
00155             
00156             copy_v3_v3(partco, state.co);
00157             
00158             if (pd->psys_cache_space == TEX_PD_OBJECTSPACE)
00159                 mul_m4_v3(ob->imat, partco);
00160             else if (pd->psys_cache_space == TEX_PD_OBJECTLOC) {
00161                 sub_v3_v3(partco, ob->loc);
00162             } else {
00163                 /* TEX_PD_WORLDSPACE */
00164             }
00165             
00166             BLI_bvhtree_insert(pd->point_tree, i, partco, 1);
00167             
00168             if (data_used & POINT_DATA_VEL) {
00169                 pd->point_data[i*3 + 0] = state.vel[0];
00170                 pd->point_data[i*3 + 1] = state.vel[1];
00171                 pd->point_data[i*3 + 2] = state.vel[2];
00172             } 
00173             if (data_used & POINT_DATA_LIFE) {
00174                 float pa_time;
00175                 
00176                 if (i < psys->totpart) {
00177                     pa_time = (cfra - pa->time)/pa->lifetime;
00178                 } else {
00179                     ChildParticle *cpa= (psys->child + i) - psys->totpart;
00180                     float pa_birthtime, pa_dietime;
00181                     
00182                     pa_time = psys_get_child_time(psys, cpa, cfra, &pa_birthtime, &pa_dietime);
00183                 }
00184                 
00185                 pd->point_data[offset + i] = pa_time;
00186                 
00187             }
00188         }
00189     }
00190     
00191     BLI_bvhtree_balance(pd->point_tree);
00192     dm->release(dm);
00193     
00194     if(psys->lattice){
00195         end_latt_deform(psys->lattice);
00196         psys->lattice=0;
00197     }
00198     
00199     psys_render_restore(ob, psys);
00200 }
00201 
00202 
00203 static void pointdensity_cache_object(Render *re, PointDensity *pd, Object *ob)
00204 {
00205     int i;
00206     DerivedMesh *dm;
00207     MVert *mvert = NULL;
00208     
00209     dm = mesh_create_derived_render(re->scene, ob,  CD_MASK_BAREMESH|CD_MASK_MTFACE|CD_MASK_MCOL);
00210     mvert= dm->getVertArray(dm);    /* local object space */
00211     
00212     pd->totpoints= dm->getNumVerts(dm);
00213     if (pd->totpoints == 0) return;
00214 
00215     pd->point_tree = BLI_bvhtree_new(pd->totpoints, 0.0, 4, 6);
00216     
00217     for(i=0; i < pd->totpoints; i++, mvert++) {
00218         float co[3];
00219         
00220         copy_v3_v3(co, mvert->co);
00221 
00222         switch(pd->ob_cache_space) {
00223             case TEX_PD_OBJECTSPACE:
00224                 break;
00225             case TEX_PD_OBJECTLOC:
00226                 mul_m4_v3(ob->obmat, co);
00227                 sub_v3_v3(co, ob->loc);
00228                 break;
00229             case TEX_PD_WORLDSPACE:
00230             default:
00231                 mul_m4_v3(ob->obmat, co);
00232                 break;
00233         }
00234 
00235         BLI_bvhtree_insert(pd->point_tree, i, co, 1);
00236     }
00237     
00238     BLI_bvhtree_balance(pd->point_tree);
00239     dm->release(dm);
00240 
00241 }
00242 void cache_pointdensity(Render *re, Tex *tex)
00243 {
00244     PointDensity *pd = tex->pd;
00245     
00246     if(!pd)
00247         return;
00248 
00249     if (pd->point_tree) {
00250         BLI_bvhtree_free(pd->point_tree);
00251         pd->point_tree = NULL;
00252     }
00253     
00254     if (pd->source == TEX_PD_PSYS) {
00255         Object *ob = pd->object;
00256         ParticleSystem *psys;
00257 
00258         if (!ob || !pd->psys) return;
00259 
00260         psys= BLI_findlink(&ob->particlesystem, pd->psys-1);
00261         if (!psys) return;
00262         
00263         pointdensity_cache_psys(re, pd, ob, psys);
00264     }
00265     else if (pd->source == TEX_PD_OBJECT) {
00266         Object *ob = pd->object;
00267         if (ob && ob->type == OB_MESH)
00268             pointdensity_cache_object(re, pd, ob);
00269     }
00270 }
00271 
00272 static void free_pointdensity(Render *UNUSED(re), Tex *tex)
00273 {
00274     PointDensity *pd = tex->pd;
00275 
00276     if (!pd) return;
00277     
00278     if (pd->point_tree) {
00279         BLI_bvhtree_free(pd->point_tree);
00280         pd->point_tree = NULL;
00281     }
00282 
00283     if (pd->point_data) {
00284         MEM_freeN(pd->point_data);
00285         pd->point_data = NULL;
00286     }
00287     pd->totpoints = 0;
00288 }
00289 
00290 
00291 
00292 void make_pointdensities(Render *re)
00293 {
00294     Tex *tex;
00295     
00296     if(re->scene->r.scemode & R_PREVIEWBUTS)
00297         return;
00298     
00299     re->i.infostr= "Caching Point Densities";
00300     re->stats_draw(re->sdh, &re->i);
00301 
00302     for (tex= re->main->tex.first; tex; tex= tex->id.next) {
00303         if(tex->id.us && tex->type==TEX_POINTDENSITY) {
00304             cache_pointdensity(re, tex);
00305         }
00306     }
00307     
00308     re->i.infostr= NULL;
00309     re->stats_draw(re->sdh, &re->i);
00310 }
00311 
00312 void free_pointdensities(Render *re)
00313 {
00314     Tex *tex;
00315     
00316     if(re->scene->r.scemode & R_PREVIEWBUTS)
00317         return;
00318     
00319     for (tex= re->main->tex.first; tex; tex= tex->id.next) {
00320         if(tex->id.us && tex->type==TEX_POINTDENSITY) {
00321             free_pointdensity(re, tex);
00322         }
00323     }
00324 }
00325 
00326 typedef struct PointDensityRangeData
00327 {
00328     float *density;
00329     float squared_radius;
00330     float *point_data;
00331     float *vec;
00332     float softness;
00333     short falloff_type;
00334     short noise_influence;
00335     float *age;
00336     int point_data_used;
00337     int offset;
00338     struct CurveMapping *density_curve;
00339     float velscale;
00340 } PointDensityRangeData;
00341 
00342 static void accum_density(void *userdata, int index, float squared_dist)
00343 {
00344     PointDensityRangeData *pdr = (PointDensityRangeData *)userdata;
00345     const float dist = (pdr->squared_radius - squared_dist) / pdr->squared_radius * 0.5f;
00346     float density = 0.0f;
00347     
00348     if (pdr->point_data_used & POINT_DATA_VEL) {
00349         pdr->vec[0] += pdr->point_data[index*3 + 0]; //* density;
00350         pdr->vec[1] += pdr->point_data[index*3 + 1]; //* density;
00351         pdr->vec[2] += pdr->point_data[index*3 + 2]; //* density;
00352     }
00353     if (pdr->point_data_used & POINT_DATA_LIFE) {
00354         *pdr->age += pdr->point_data[pdr->offset + index]; // * density;
00355     }
00356     
00357     if (pdr->falloff_type == TEX_PD_FALLOFF_STD)
00358         density = dist;
00359     else if (pdr->falloff_type == TEX_PD_FALLOFF_SMOOTH)
00360         density = 3.0f*dist*dist - 2.0f*dist*dist*dist;
00361     else if (pdr->falloff_type == TEX_PD_FALLOFF_SOFT)
00362         density = pow(dist, pdr->softness);
00363     else if (pdr->falloff_type == TEX_PD_FALLOFF_CONSTANT)
00364         density = pdr->squared_radius;
00365     else if (pdr->falloff_type == TEX_PD_FALLOFF_ROOT)
00366         density = sqrt(dist);
00367     else if (pdr->falloff_type == TEX_PD_FALLOFF_PARTICLE_AGE) {
00368         if (pdr->point_data_used & POINT_DATA_LIFE)
00369             density = dist*MIN2(pdr->point_data[pdr->offset + index], 1.0f);
00370         else
00371             density = dist;
00372     }
00373     else if (pdr->falloff_type == TEX_PD_FALLOFF_PARTICLE_VEL) {
00374         if (pdr->point_data_used & POINT_DATA_VEL)
00375             density = dist*len_v3(pdr->point_data + index*3)*pdr->velscale;
00376         else
00377             density = dist;
00378     }
00379     
00380     if (pdr->density_curve && dist != 0.0f) {
00381         density = curvemapping_evaluateF(pdr->density_curve, 0, density/dist)*dist;
00382     }
00383     
00384     *pdr->density += density;
00385 }
00386 
00387 
00388 static void init_pointdensityrangedata(PointDensity *pd, PointDensityRangeData *pdr, 
00389     float *density, float *vec, float *age, struct CurveMapping *density_curve, float velscale)
00390 {
00391     pdr->squared_radius = pd->radius*pd->radius;
00392     pdr->density = density;
00393     pdr->point_data = pd->point_data;
00394     pdr->falloff_type = pd->falloff_type;
00395     pdr->vec = vec;
00396     pdr->age = age;
00397     pdr->softness = pd->falloff_softness;
00398     pdr->noise_influence = pd->noise_influence;
00399     pdr->point_data_used = point_data_used(pd);
00400     pdr->offset = (pdr->point_data_used & POINT_DATA_VEL)?pd->totpoints*3:0;
00401     pdr->density_curve = density_curve;
00402     pdr->velscale = velscale;
00403 }
00404 
00405 
00406 int pointdensitytex(Tex *tex, float *texvec, TexResult *texres)
00407 {
00408     int retval = TEX_INT;
00409     PointDensity *pd = tex->pd;
00410     PointDensityRangeData pdr;
00411     float density=0.0f, age=0.0f, time=0.0f;
00412     float vec[3] = {0.0f, 0.0f, 0.0f}, co[3];
00413     float col[4];
00414     float turb, noise_fac;
00415     int num=0;
00416     
00417     texres->tin = 0.0f;
00418     
00419     if ((!pd) || (!pd->point_tree))     
00420         return 0;
00421         
00422     init_pointdensityrangedata(pd, &pdr, &density, vec, &age, 
00423         (pd->flag&TEX_PD_FALLOFF_CURVE ? pd->falloff_curve : NULL), pd->falloff_speed_scale*0.001f);
00424     noise_fac = pd->noise_fac * 0.5f;   /* better default */
00425     
00426     copy_v3_v3(co, texvec);
00427     
00428     if (point_data_used(pd)) {
00429         /* does a BVH lookup to find accumulated density and additional point data *
00430          * stores particle velocity vector in 'vec', and particle lifetime in 'time' */
00431         num = BLI_bvhtree_range_query(pd->point_tree, co, pd->radius, accum_density, &pdr);
00432         if (num > 0) {
00433             age /= num;
00434             mul_v3_fl(vec, 1.0f/num);
00435         }
00436         
00437         /* reset */
00438         density = vec[0] = vec[1] = vec[2] = 0.0f;
00439     }
00440     
00441     if (pd->flag & TEX_PD_TURBULENCE) {
00442     
00443         if (pd->noise_influence == TEX_PD_NOISE_AGE) {
00444             turb = BLI_gTurbulence(pd->noise_size, texvec[0]+age, texvec[1]+age, texvec[2]+age, pd->noise_depth, 0, pd->noise_basis);
00445         }
00446         else if (pd->noise_influence == TEX_PD_NOISE_TIME) {
00447             time = R.cfra / (float)R.r.efra;
00448             turb = BLI_gTurbulence(pd->noise_size, texvec[0]+time, texvec[1]+time, texvec[2]+time, pd->noise_depth, 0, pd->noise_basis);
00449             //turb = BLI_turbulence(pd->noise_size, texvec[0]+time, texvec[1]+time, texvec[2]+time, pd->noise_depth);
00450         }
00451         else {
00452             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);
00453         }
00454 
00455         turb -= 0.5f;   /* re-center 0.0-1.0 range around 0 to prevent offsetting result */
00456         
00457         /* now we have an offset coordinate to use for the density lookup */
00458         co[0] = texvec[0] + noise_fac * turb;
00459         co[1] = texvec[1] + noise_fac * turb;
00460         co[2] = texvec[2] + noise_fac * turb;
00461     }
00462 
00463     /* BVH query with the potentially perturbed coordinates */
00464     num = BLI_bvhtree_range_query(pd->point_tree, co, pd->radius, accum_density, &pdr);
00465     if (num > 0) {
00466         age /= num;
00467         mul_v3_fl(vec, 1.0f/num);
00468     }
00469     
00470     texres->tin = density;
00471     BRICONT;
00472     
00473     if (pd->color_source == TEX_PD_COLOR_CONSTANT)
00474         return retval;
00475     
00476     retval |= TEX_RGB;
00477     
00478     switch (pd->color_source) {
00479         case TEX_PD_COLOR_PARTAGE:
00480             if (pd->coba) {
00481                 if (do_colorband(pd->coba, age, col)) {
00482                     texres->talpha= 1;
00483                     copy_v3_v3(&texres->tr, col);
00484                     texres->tin *= col[3];
00485                     texres->ta = texres->tin;
00486                 }
00487             }
00488             break;
00489         case TEX_PD_COLOR_PARTSPEED:
00490         {
00491             float speed = len_v3(vec) * pd->speed_scale;
00492             
00493             if (pd->coba) {
00494                 if (do_colorband(pd->coba, speed, col)) {
00495                     texres->talpha= 1;  
00496                     copy_v3_v3(&texres->tr, col);
00497                     texres->tin *= col[3];
00498                     texres->ta = texres->tin;
00499                 }
00500             }
00501             break;
00502         }
00503         case TEX_PD_COLOR_PARTVEL:
00504             texres->talpha= 1;
00505             mul_v3_fl(vec, pd->speed_scale);
00506             copy_v3_v3(&texres->tr, vec);
00507             texres->ta = texres->tin;
00508             break;
00509         case TEX_PD_COLOR_CONSTANT:
00510         default:
00511             texres->tr = texres->tg = texres->tb = texres->ta = 1.0f;
00512             break;
00513     }
00514     BRICONTRGB;
00515     
00516     return retval;
00517     
00518     /*
00519     if (texres->nor!=NULL) {
00520         texres->nor[0] = texres->nor[1] = texres->nor[2] = 0.0f;
00521     }
00522     */
00523 }