2 * ***** BEGIN GPL LICENSE BLOCK *****
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software Foundation,
16 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
19 * All rights reserved.
21 * Contributors: Matt Ebb
23 * ***** END GPL LICENSE BLOCK *****
26 /** \file blender/render/intern/source/pointdensity.c
35 #include "MEM_guardedalloc.h"
38 #include "BLI_blenlib.h"
39 #include "BLI_noise.h"
40 #include "BLI_kdopbvh.h"
41 #include "BLI_utildefines.h"
43 #include "BLT_translation.h"
45 #include "BKE_DerivedMesh.h"
46 #include "BKE_lattice.h"
48 #include "BKE_object.h"
49 #include "BKE_particle.h"
50 #include "BKE_scene.h"
51 #include "BKE_texture.h"
52 #include "BKE_colortools.h"
54 #include "DNA_meshdata_types.h"
55 #include "DNA_texture_types.h"
56 #include "DNA_particle_types.h"
58 #include "render_types.h"
60 #include "pointdensity.h"
62 #include "RE_render_ext.h"
64 /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
65 /* defined in pipeline.c, is hardcopy of active dynamic allocated Render */
66 /* only to be used here in this file, it's for speed */
67 extern struct Render R;
68 /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
70 static ThreadMutex sample_mutex = PTHREAD_MUTEX_INITIALIZER;
72 static int point_data_used(PointDensity *pd)
76 if (pd->source == TEX_PD_PSYS) {
77 if ((pd->noise_influence == TEX_PD_NOISE_VEL) ||
78 (pd->falloff_type == TEX_PD_FALLOFF_PARTICLE_VEL) ||
79 (pd->color_source == TEX_PD_COLOR_PARTVEL) ||
80 (pd->color_source == TEX_PD_COLOR_PARTSPEED))
82 pd_bitflag |= POINT_DATA_VEL;
84 if ((pd->noise_influence == TEX_PD_NOISE_AGE) ||
85 (pd->color_source == TEX_PD_COLOR_PARTAGE) ||
86 (pd->falloff_type == TEX_PD_FALLOFF_PARTICLE_AGE))
88 pd_bitflag |= POINT_DATA_LIFE;
96 /* additional data stored alongside the point density BVH,
97 * accessible by point index number to retrieve other information
98 * such as particle velocity or lifetime */
99 static void alloc_point_data(PointDensity *pd, int total_particles, int point_data_used)
103 if (point_data_used & POINT_DATA_VEL) {
104 /* store 3 channels of velocity data */
107 if (point_data_used & POINT_DATA_LIFE) {
108 /* store 1 channel of lifetime data */
113 pd->point_data = MEM_mallocN(sizeof(float) * data_size * total_particles,
114 "particle point data");
118 static void pointdensity_cache_psys(Scene *scene,
121 ParticleSystem *psys,
125 const bool use_render_params)
129 ParticleCacheKey *cache;
130 ParticleSimulationData sim = {NULL};
131 ParticleData *pa = NULL;
132 float cfra = BKE_scene_frame_get(scene);
133 int i /*, childexists*/ /* UNUSED */;
134 int total_particles, offset = 0;
135 int data_used = point_data_used(pd);
138 /* init everything */
139 if (!psys || !ob || !pd) {
143 /* Just to create a valid rendering context for particles */
144 if (use_render_params) {
145 psys_render_set(ob, psys, viewmat, winmat, winx, winy, 0);
148 if (use_render_params) {
149 dm = mesh_create_derived_render(scene,
151 CD_MASK_BAREMESH | CD_MASK_MTFACE | CD_MASK_MCOL);
154 dm = mesh_get_derived_final(scene,
156 CD_MASK_BAREMESH | CD_MASK_MTFACE | CD_MASK_MCOL);
159 if ( !psys_check_enabled(ob, psys)) {
160 psys_render_restore(scene, ob, psys);
167 sim.psmd = psys_get_modifier(ob, psys);
169 /* in case ob->imat isn't up-to-date */
170 invert_m4_m4(ob->imat, ob->obmat);
172 total_particles = psys->totpart + psys->totchild;
173 psys->lattice_deform_data = psys_create_lattice_deform_data(&sim);
175 pd->point_tree = BLI_bvhtree_new(total_particles, 0.0, 4, 6);
176 alloc_point_data(pd, total_particles, data_used);
177 pd->totpoints = total_particles;
178 if (data_used & POINT_DATA_VEL) {
179 offset = pd->totpoints * 3;
183 if (psys->totchild > 0 && !(psys->part->draw & PART_DRAW_PARENT))
187 for (i = 0, pa = psys->particles; i < total_particles; i++, pa++) {
189 if (psys->part->type == PART_HAIR) {
191 if (i < psys->totpart && psys->pathcache)
192 cache = psys->pathcache[i];
193 else if (i >= psys->totpart && psys->childcache)
194 cache = psys->childcache[i - psys->totpart];
198 cache += cache->segments; /* use endpoint */
200 copy_v3_v3(state.co, cache->co);
205 /* emitter particles */
208 if (!psys_get_particle_state(&sim, i, &state, 0))
211 if (data_used & POINT_DATA_LIFE) {
212 if (i < psys->totpart) {
213 state.time = (cfra - pa->time) / pa->lifetime;
216 ChildParticle *cpa = (psys->child + i) - psys->totpart;
217 float pa_birthtime, pa_dietime;
219 state.time = psys_get_child_time(psys, cpa, cfra, &pa_birthtime, &pa_dietime);
224 copy_v3_v3(partco, state.co);
226 if (pd->psys_cache_space == TEX_PD_OBJECTSPACE)
227 mul_m4_v3(ob->imat, partco);
228 else if (pd->psys_cache_space == TEX_PD_OBJECTLOC) {
229 sub_v3_v3(partco, ob->loc);
232 /* TEX_PD_WORLDSPACE */
235 BLI_bvhtree_insert(pd->point_tree, i, partco, 1);
237 if (data_used & POINT_DATA_VEL) {
238 pd->point_data[i * 3 + 0] = state.vel[0];
239 pd->point_data[i * 3 + 1] = state.vel[1];
240 pd->point_data[i * 3 + 2] = state.vel[2];
242 if (data_used & POINT_DATA_LIFE) {
243 pd->point_data[offset + i] = state.time;
247 BLI_bvhtree_balance(pd->point_tree);
250 if (psys->lattice_deform_data) {
251 end_latt_deform(psys->lattice_deform_data);
252 psys->lattice_deform_data = NULL;
255 if (use_render_params) {
256 psys_render_restore(scene, ob, psys);
261 static void pointdensity_cache_object(Scene *scene,
264 const bool use_render_params)
270 if (use_render_params) {
271 dm = mesh_create_derived_render(scene,
273 CD_MASK_BAREMESH | CD_MASK_MTFACE | CD_MASK_MCOL);
276 dm = mesh_get_derived_final(scene,
278 CD_MASK_BAREMESH | CD_MASK_MTFACE | CD_MASK_MCOL);
281 mvert = dm->getVertArray(dm); /* local object space */
283 pd->totpoints = dm->getNumVerts(dm);
284 if (pd->totpoints == 0) {
288 pd->point_tree = BLI_bvhtree_new(pd->totpoints, 0.0, 4, 6);
290 for (i = 0; i < pd->totpoints; i++, mvert++) {
293 copy_v3_v3(co, mvert->co);
295 switch (pd->ob_cache_space) {
296 case TEX_PD_OBJECTSPACE:
298 case TEX_PD_OBJECTLOC:
299 mul_m4_v3(ob->obmat, co);
300 sub_v3_v3(co, ob->loc);
302 case TEX_PD_WORLDSPACE:
304 mul_m4_v3(ob->obmat, co);
308 BLI_bvhtree_insert(pd->point_tree, i, co, 1);
311 BLI_bvhtree_balance(pd->point_tree);
316 static void cache_pointdensity_ex(Scene *scene,
321 const bool use_render_params)
327 if (pd->point_tree) {
328 BLI_bvhtree_free(pd->point_tree);
329 pd->point_tree = NULL;
332 if (pd->source == TEX_PD_PSYS) {
333 Object *ob = pd->object;
334 ParticleSystem *psys;
336 if (!ob || !pd->psys) {
340 psys = BLI_findlink(&ob->particlesystem, pd->psys - 1);
345 pointdensity_cache_psys(scene,
353 else if (pd->source == TEX_PD_OBJECT) {
354 Object *ob = pd->object;
355 if (ob && ob->type == OB_MESH)
356 pointdensity_cache_object(scene, pd, ob, use_render_params);
360 void cache_pointdensity(Render *re, PointDensity *pd)
362 cache_pointdensity_ex(re->scene,
364 re->viewmat, re->winmat,
369 void free_pointdensity(PointDensity *pd)
375 if (pd->point_tree) {
376 BLI_bvhtree_free(pd->point_tree);
377 pd->point_tree = NULL;
380 if (pd->point_data) {
381 MEM_freeN(pd->point_data);
382 pd->point_data = NULL;
387 void make_pointdensities(Render *re)
391 if (re->scene->r.scemode & R_BUTS_PREVIEW) {
395 re->i.infostr = IFACE_("Caching Point Densities");
396 re->stats_draw(re->sdh, &re->i);
398 for (tex = re->main->tex.first; tex != NULL; tex = tex->id.next) {
399 if (tex->id.us && tex->type == TEX_POINTDENSITY) {
400 cache_pointdensity(re, tex->pd);
404 re->i.infostr = NULL;
405 re->stats_draw(re->sdh, &re->i);
408 void free_pointdensities(Render *re)
412 if (re->scene->r.scemode & R_BUTS_PREVIEW)
415 for (tex = re->main->tex.first; tex != NULL; tex = tex->id.next) {
416 if (tex->id.us && tex->type == TEX_POINTDENSITY) {
417 free_pointdensity(tex->pd);
422 typedef struct PointDensityRangeData {
424 float squared_radius;
425 const float *point_data;
429 short noise_influence;
433 struct CurveMapping *density_curve;
435 } PointDensityRangeData;
437 static void accum_density(void *userdata, int index, float squared_dist)
439 PointDensityRangeData *pdr = (PointDensityRangeData *)userdata;
440 const float dist = (pdr->squared_radius - squared_dist) / pdr->squared_radius * 0.5f;
441 float density = 0.0f;
443 if (pdr->point_data_used & POINT_DATA_VEL) {
444 pdr->vec[0] += pdr->point_data[index * 3 + 0]; // * density;
445 pdr->vec[1] += pdr->point_data[index * 3 + 1]; // * density;
446 pdr->vec[2] += pdr->point_data[index * 3 + 2]; // * density;
448 if (pdr->point_data_used & POINT_DATA_LIFE) {
449 *pdr->age += pdr->point_data[pdr->offset + index]; // * density;
452 if (pdr->falloff_type == TEX_PD_FALLOFF_STD)
454 else if (pdr->falloff_type == TEX_PD_FALLOFF_SMOOTH)
455 density = 3.0f * dist * dist - 2.0f * dist * dist * dist;
456 else if (pdr->falloff_type == TEX_PD_FALLOFF_SOFT)
457 density = pow(dist, pdr->softness);
458 else if (pdr->falloff_type == TEX_PD_FALLOFF_CONSTANT)
459 density = pdr->squared_radius;
460 else if (pdr->falloff_type == TEX_PD_FALLOFF_ROOT)
461 density = sqrtf(dist);
462 else if (pdr->falloff_type == TEX_PD_FALLOFF_PARTICLE_AGE) {
463 if (pdr->point_data_used & POINT_DATA_LIFE)
464 density = dist * MIN2(pdr->point_data[pdr->offset + index], 1.0f);
468 else if (pdr->falloff_type == TEX_PD_FALLOFF_PARTICLE_VEL) {
469 if (pdr->point_data_used & POINT_DATA_VEL)
470 density = dist * len_v3(pdr->point_data + index * 3) * pdr->velscale;
475 if (pdr->density_curve && dist != 0.0f) {
476 curvemapping_initialize(pdr->density_curve);
477 density = curvemapping_evaluateF(pdr->density_curve, 0, density / dist) * dist;
480 *pdr->density += density;
484 static void init_pointdensityrangedata(PointDensity *pd, PointDensityRangeData *pdr,
485 float *density, float *vec, float *age, struct CurveMapping *density_curve, float velscale)
487 pdr->squared_radius = pd->radius * pd->radius;
488 pdr->density = density;
489 pdr->point_data = pd->point_data;
490 pdr->falloff_type = pd->falloff_type;
493 pdr->softness = pd->falloff_softness;
494 pdr->noise_influence = pd->noise_influence;
495 pdr->point_data_used = point_data_used(pd);
496 pdr->offset = (pdr->point_data_used & POINT_DATA_VEL) ? pd->totpoints * 3 : 0;
497 pdr->density_curve = density_curve;
498 pdr->velscale = velscale;
502 static int pointdensity(PointDensity *pd,
503 const float texvec[3],
508 int retval = TEX_INT;
509 PointDensityRangeData pdr;
510 float density = 0.0f, age = 0.0f, time = 0.0f;
511 float vec[3] = {0.0f, 0.0f, 0.0f}, co[3];
512 float turb, noise_fac;
517 if ((!pd) || (!pd->point_tree))
520 init_pointdensityrangedata(pd, &pdr, &density, vec, &age,
521 (pd->flag & TEX_PD_FALLOFF_CURVE ? pd->falloff_curve : NULL),
522 pd->falloff_speed_scale * 0.001f);
523 noise_fac = pd->noise_fac * 0.5f; /* better default */
525 copy_v3_v3(co, texvec);
527 if (point_data_used(pd)) {
528 /* does a BVH lookup to find accumulated density and additional point data *
529 * stores particle velocity vector in 'vec', and particle lifetime in 'time' */
530 num = BLI_bvhtree_range_query(pd->point_tree, co, pd->radius, accum_density, &pdr);
533 mul_v3_fl(vec, 1.0f / num);
537 density = vec[0] = vec[1] = vec[2] = 0.0f;
540 if (pd->flag & TEX_PD_TURBULENCE) {
542 if (pd->noise_influence == TEX_PD_NOISE_AGE) {
543 turb = BLI_gTurbulence(pd->noise_size, texvec[0] + age, texvec[1] + age, texvec[2] + age,
544 pd->noise_depth, 0, pd->noise_basis);
546 else if (pd->noise_influence == TEX_PD_NOISE_TIME) {
547 time = R.r.cfra / (float)R.r.efra;
548 turb = BLI_gTurbulence(pd->noise_size, texvec[0] + time, texvec[1] + time, texvec[2] + time,
549 pd->noise_depth, 0, pd->noise_basis);
550 //turb = BLI_turbulence(pd->noise_size, texvec[0]+time, texvec[1]+time, texvec[2]+time, pd->noise_depth);
553 turb = BLI_gTurbulence(pd->noise_size, texvec[0] + vec[0], texvec[1] + vec[1], texvec[2] + vec[2],
554 pd->noise_depth, 0, pd->noise_basis);
557 turb -= 0.5f; /* re-center 0.0-1.0 range around 0 to prevent offsetting result */
559 /* now we have an offset coordinate to use for the density lookup */
560 co[0] = texvec[0] + noise_fac * turb;
561 co[1] = texvec[1] + noise_fac * turb;
562 co[2] = texvec[2] + noise_fac * turb;
565 /* BVH query with the potentially perturbed coordinates */
566 num = BLI_bvhtree_range_query(pd->point_tree, co, pd->radius, accum_density, &pdr);
569 mul_v3_fl(vec, 1.0f / num);
572 texres->tin = density;
577 copy_v3_v3(r_vec, vec);
583 static int pointdensity_color(PointDensity *pd, TexResult *texres, float age, const float vec[3])
590 switch (pd->color_source) {
591 case TEX_PD_COLOR_PARTAGE:
593 if (do_colorband(pd->coba, age, col)) {
594 texres->talpha = true;
595 copy_v3_v3(&texres->tr, col);
596 texres->tin *= col[3];
597 texres->ta = texres->tin;
601 case TEX_PD_COLOR_PARTSPEED:
603 float speed = len_v3(vec) * pd->speed_scale;
606 if (do_colorband(pd->coba, speed, col)) {
607 texres->talpha = true;
608 copy_v3_v3(&texres->tr, col);
609 texres->tin *= col[3];
610 texres->ta = texres->tin;
615 case TEX_PD_COLOR_PARTVEL:
616 texres->talpha = true;
617 mul_v3_v3fl(&texres->tr, vec, pd->speed_scale);
618 texres->ta = texres->tin;
620 case TEX_PD_COLOR_CONSTANT:
622 texres->tr = texres->tg = texres->tb = texres->ta = 1.0f;
629 int pointdensitytex(Tex *tex, const float texvec[3], TexResult *texres)
631 PointDensity *pd = tex->pd;
633 float vec[3] = {0.0f, 0.0f, 0.0f};
634 int retval = pointdensity(pd, texvec, texres, &age, vec);
638 if (pd->color_source == TEX_PD_COLOR_CONSTANT)
641 retval |= pointdensity_color(pd, texres, age, vec);
647 if (texres->nor!=NULL) {
648 texres->nor[0] = texres->nor[1] = texres->nor[2] = 0.0f;
653 static void sample_dummy_point_density(int resolution, float *values)
655 memset(values, 0, sizeof(float) * 4 * resolution * resolution * resolution);
658 static void particle_system_minmax(Scene *scene,
660 ParticleSystem *psys,
662 const bool use_render_params,
663 float min[3], float max[3])
665 const float size[3] = {radius, radius, radius};
666 const float cfra = BKE_scene_frame_get(scene);
667 ParticleSettings *part = psys->part;
668 ParticleSimulationData sim = {NULL};
669 ParticleData *pa = NULL;
672 float mat[4][4], imat[4][4];
674 INIT_MINMAX(min, max);
675 if (part->type == PART_HAIR) {
676 /* TOOD(sergey): Not supported currently. */
681 if (use_render_params) {
682 psys_render_set(object, psys, mat, mat, 1, 1, 0);
688 sim.psmd = psys_get_modifier(object, psys);
690 invert_m4_m4(imat, object->obmat);
691 total_particles = psys->totpart + psys->totchild;
692 psys->lattice_deform_data = psys_create_lattice_deform_data(&sim);
694 for (i = 0, pa = psys->particles; i < total_particles; i++, pa++) {
695 float co_object[3], co_min[3], co_max[3];
698 if (!psys_get_particle_state(&sim, i, &state, 0)) {
701 mul_v3_m4v3(co_object, imat, state.co);
702 sub_v3_v3v3(co_min, co_object, size);
703 add_v3_v3v3(co_max, co_object, size);
704 minmax_v3v3_v3(min, max, co_min);
705 minmax_v3v3_v3(min, max, co_max);
708 if (psys->lattice_deform_data) {
709 end_latt_deform(psys->lattice_deform_data);
710 psys->lattice_deform_data = NULL;
713 if (use_render_params) {
714 psys_render_restore(scene, object, psys);
718 void RE_cache_point_density(Scene *scene,
720 const bool use_render_params)
723 /* Same matricies/resolution as dupli_render_particle_set(). */
725 BLI_mutex_lock(&sample_mutex);
726 cache_pointdensity_ex(scene, pd, mat, mat, 1, 1, use_render_params);
727 BLI_mutex_unlock(&sample_mutex);
730 /* NOTE 1: Requires RE_cache_point_density() to be called first.
731 * NOTE 2: Frees point density structure after sampling.
733 void RE_sample_point_density(Scene *scene,
735 const int resolution,
736 const bool use_render_params,
739 const size_t resolution2 = resolution * resolution;
740 Object *object = pd->object;
742 float min[3], max[3], dim[3];
744 /* TODO(sergey): Implement some sort of assert() that point density
745 * was cached already.
748 if (object == NULL) {
749 sample_dummy_point_density(resolution, values);
753 if (pd->source == TEX_PD_PSYS) {
754 ParticleSystem *psys;
756 sample_dummy_point_density(resolution, values);
759 psys = BLI_findlink(&object->particlesystem, pd->psys - 1);
761 sample_dummy_point_density(resolution, values);
764 particle_system_minmax(scene,
772 float radius[3] = {pd->radius, pd->radius, pd->radius};
774 BKE_object_obdata_texspace_get(pd->object, NULL, &loc, &size, NULL);
775 sub_v3_v3v3(min, loc, size);
776 add_v3_v3v3(max, loc, size);
777 /* Adjust texture space to include density points on the boundaries. */
778 sub_v3_v3(min, radius);
779 add_v3_v3(max, radius);
782 sub_v3_v3v3(dim, max, min);
783 if (dim[0] <= 0.0f || dim[1] <= 0.0f || dim[2] <= 0.0f) {
784 sample_dummy_point_density(resolution, values);
788 BLI_mutex_lock(&sample_mutex);
789 for (z = 0; z < resolution; ++z) {
790 for (y = 0; y < resolution; ++y) {
791 for (x = 0; x < resolution; ++x) {
792 size_t index = z * resolution2 + y * resolution + x;
797 copy_v3_v3(texvec, min);
798 texvec[0] += dim[0] * (float)x / (float)resolution;
799 texvec[1] += dim[1] * (float)y / (float)resolution;
800 texvec[2] += dim[2] * (float)z / (float)resolution;
802 pointdensity(pd, texvec, &texres, &age, vec);
803 pointdensity_color(pd, &texres, age, vec);
805 copy_v3_v3(&values[index*4 + 0], &texres.tr);
806 values[index*4 + 3] = texres.tin;
810 free_pointdensity(pd);
811 BLI_mutex_unlock(&sample_mutex);