Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/blenkernel/intern/particle_system.c')
-rw-r--r--source/blender/blenkernel/intern/particle_system.c391
1 files changed, 344 insertions, 47 deletions
diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c
index 89db2dd45a9..cf4bf32fd77 100644
--- a/source/blender/blenkernel/intern/particle_system.c
+++ b/source/blender/blenkernel/intern/particle_system.c
@@ -84,6 +84,7 @@
#include "BKE_object.h"
#include "BKE_material.h"
#include "BKE_cloth.h"
+#include "BKE_key.h"
#include "BKE_lattice.h"
#include "BKE_pointcache.h"
#include "BKE_mesh.h"
@@ -1201,7 +1202,7 @@ void psys_make_temp_pointcache(Object *ob, ParticleSystem *psys)
PTCacheID pid;
BKE_ptcache_id_from_particles(&pid, ob, psys);
cache->flag &= ~PTCACHE_DISK_CACHE;
- BKE_ptcache_disk_to_mem(&pid);
+ BKE_ptcache_disk_to_mem(&pid, false);
cache->flag |= PTCACHE_DISK_CACHE;
}
}
@@ -1291,7 +1292,7 @@ static void psys_update_effectors(ParticleSimulationData *sim)
{
pdEndEffectors(&sim->psys->effectors);
sim->psys->effectors = pdInitEffectors(sim->scene, sim->ob, sim->psys,
- sim->psys->part->effector_weights, true);
+ sim->psys->part->effector_weights);
precalc_guides(sim, sim->psys->effectors);
}
@@ -2896,79 +2897,93 @@ static void collision_check(ParticleSimulationData *sim, int p, float dfra, floa
/************************************************/
/* Hair */
/************************************************/
-/* check if path cache or children need updating and do it if needed */
-static void psys_update_path_cache(ParticleSimulationData *sim, float cfra)
+
+static bool psys_needs_path_cache(ParticleSimulationData *sim)
{
ParticleSystem *psys = sim->psys;
ParticleSettings *part = psys->part;
ParticleEditSettings *pset = &sim->scene->toolsettings->particle;
Base *base;
- int distr=0, alloc=0, skip=0;
-
- if ((psys->part->childtype && psys->totchild != psys_get_tot_child(sim->scene, psys)) || psys->recalc&PSYS_RECALC_RESET)
- alloc=1;
-
- if (alloc || psys->recalc&PSYS_RECALC_CHILD || (psys->vgroup[PSYS_VG_DENSITY] && (sim->ob && sim->ob->mode & OB_MODE_WEIGHT_PAINT)))
- distr=1;
-
- if (distr) {
- if (alloc)
- realloc_particles(sim, sim->psys->totpart);
-
- if (psys_get_tot_child(sim->scene, psys)) {
- /* don't generate children while computing the hair keys */
- if (!(psys->part->type == PART_HAIR) || (psys->flag & PSYS_HAIR_DONE)) {
- distribute_particles(sim, PART_FROM_CHILD);
-
- if (part->childtype==PART_CHILD_FACES && part->parents != 0.0f)
- psys_find_parents(sim);
+
+ /* particle instance modifier with "path" option need cached paths even if particle system doesn't */
+ for (base = sim->scene->base.first; base; base= base->next) {
+ ModifierData *md = modifiers_findByType(base->object, eModifierType_ParticleInstance);
+ if (md) {
+ ParticleInstanceModifierData *pimd = (ParticleInstanceModifierData *)md;
+ if (pimd->flag & eParticleInstanceFlag_Path && pimd->ob == sim->ob && pimd->psys == (psys - (ParticleSystem*)sim->ob->particlesystem.first)) {
+ return true;
}
}
- else
- psys_free_children(psys);
}
-
+
if ((part->type==PART_HAIR || psys->flag&PSYS_KEYED || psys->pointcache->flag & PTCACHE_BAKED)==0)
- skip = 1; /* only hair, keyed and baked stuff can have paths */
+ return false; /* only hair, keyed and baked stuff can have paths */
else if (part->ren_as != PART_DRAW_PATH && !(part->type==PART_HAIR && ELEM(part->ren_as, PART_DRAW_OB, PART_DRAW_GR)))
- skip = 1; /* particle visualization must be set as path */
+ return false; /* particle visualization must be set as path */
else if (!psys->renderdata) {
- if (part->draw_as != PART_DRAW_REND)
- skip = 1; /* draw visualization */
+ if (!ELEM(part->draw_as, PART_DRAW_REND, PART_DRAW_HULL))
+ return false; /* not a mode that requires paths */
else if (psys->pointcache->flag & PTCACHE_BAKING)
- skip = 1; /* no need to cache paths while baking dynamics */
+ return false; /* no need to cache paths while baking dynamics */
else if (psys_in_edit_mode(sim->scene, psys)) {
if ((pset->flag & PE_DRAW_PART)==0)
- skip = 1;
+ return false;
else if (part->childtype==0 && (psys->flag & PSYS_HAIR_DYNAMICS && psys->pointcache->flag & PTCACHE_BAKED)==0)
- skip = 1; /* in edit mode paths are needed for child particles and dynamic hair */
+ return false; /* in edit mode paths are needed for child particles and dynamic hair */
}
}
+
+ return true;
+}
+/* check if path cache or children need updating and do it if needed */
+static void psys_update_path_cache(ParticleSimulationData *sim, float cfra)
+{
+ ParticleSystem *psys = sim->psys;
+ ParticleSettings *part = psys->part;
- /* particle instance modifier with "path" option need cached paths even if particle system doesn't */
- for (base = sim->scene->base.first; base; base= base->next) {
- ModifierData *md = modifiers_findByType(base->object, eModifierType_ParticleInstance);
- if (md) {
- ParticleInstanceModifierData *pimd = (ParticleInstanceModifierData *)md;
- if (pimd->flag & eParticleInstanceFlag_Path && pimd->ob == sim->ob && pimd->psys == (psys - (ParticleSystem*)sim->ob->particlesystem.first)) {
- skip = 0;
- break;
+ /* check if particles need to be reallocated or redistributed */
+ {
+ bool alloc = false, distr = false;
+
+ if ((psys->part->childtype && psys->totchild != psys_get_tot_child(sim->scene, psys)) || psys->recalc&PSYS_RECALC_RESET)
+ alloc = true;
+
+ if (alloc || psys->recalc&PSYS_RECALC_CHILD || (psys->vgroup[PSYS_VG_DENSITY] && (sim->ob && sim->ob->mode & OB_MODE_WEIGHT_PAINT)))
+ distr = true;
+
+ if (distr) {
+ if (alloc)
+ realloc_particles(sim, sim->psys->totpart);
+
+ if (psys_get_tot_child(sim->scene, psys)) {
+ /* don't generate children while computing the hair keys */
+ if (!(psys->part->type == PART_HAIR) || (psys->flag & PSYS_HAIR_DONE)) {
+ distribute_particles(sim, PART_FROM_CHILD);
+
+ if (part->childtype==PART_CHILD_FACES && part->parents != 0.0f)
+ psys_find_parents(sim);
+ }
}
+ else
+ psys_free_children(psys);
}
}
- if (!skip) {
+ if (psys_needs_path_cache(sim)) {
+
psys_cache_paths(sim, cfra);
/* for render, child particle paths are computed on the fly */
if (part->childtype) {
+ bool do_child_paths = true;
+
if (!psys->totchild)
- skip = 1;
+ do_child_paths = false;
else if (psys->part->type == PART_HAIR && (psys->flag & PSYS_HAIR_DONE)==0)
- skip = 1;
+ do_child_paths = false;
- if (!skip)
+ if (do_child_paths)
psys_cache_child_paths(sim, cfra, 0);
}
}
@@ -3015,6 +3030,120 @@ static MDeformVert *hair_set_pinning(MDeformVert *dvert, float weight)
return dvert;
}
+bool psys_hair_update_preview(ParticleSimulationData *sim)
+{
+#ifdef USE_PARTICLE_PREVIEW
+ ParticleSystem *psys = sim->psys;
+ ParticleSettings *part = psys->part;
+ DerivedMesh *dm = sim->psmd->dm;
+ const float ratio = psys->hair_preview_factor * 0.01f;
+ /* target number of simulated hairs
+ * NOTE: this has to be reached exactly, in order to allow
+ * comparison with the psys->hair_num_simulated value!
+ */
+ const int num_simulated = psys->totpart * ratio;
+
+ if (!(part->type == PART_HAIR))
+ return false;
+ if (num_simulated == psys->hair_num_simulated)
+ return false;
+
+ { /* Random hair selection method */
+ KDTree *tree = BLI_kdtree_new(num_simulated); /* kdtree for finding nearest simulated hairs for blending */
+ RNG *rng = BLI_rng_new(98250 + psys->seed);
+ ParticleData *pa;
+ int cur_simulated = 0;
+ int i;
+
+ /* construct a kd-tree of all simulated hairs */
+ pa = psys->particles;
+ for (i = 0; i < psys->totpart; ++i, ++pa) {
+ bool simulate = true;
+ if (cur_simulated == num_simulated) {
+ /* don't simulate more than the total number */
+ simulate = false;
+ }
+ else if (num_simulated - cur_simulated <= psys->totpart - i) {
+ /* only allow disabling if the target sim number
+ * can be reached with the remaining hairs
+ */
+ simulate = BLI_rng_get_float(rng) < ratio;
+ }
+
+ if (simulate) {
+ float co[3];
+
+ pa->flag &= ~PARS_HAIR_BLEND;
+
+ if (pa->totkey >= 2) {
+ psys_particle_on_dm(dm, part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, co, 0, 0, 0, 0, 0);
+ BLI_kdtree_insert(tree, i, co);
+ }
+
+ ++cur_simulated;
+ }
+ else {
+ pa->flag |= PARS_HAIR_BLEND;
+ }
+ }
+
+ BLI_kdtree_balance(tree);
+
+ /* look up nearest simulated hairs for preview hairs and calculate blending weights */
+ pa = psys->particles;
+ for (i = 0; i < psys->totpart; ++i, ++pa) {
+ if (pa->flag & PARS_HAIR_BLEND) {
+ float co[3];
+ int maxw, w;
+ KDTreeNearest nearest[4];
+
+ psys_particle_on_dm(dm, part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, co, 0, 0, 0, 0, 0);
+ maxw = BLI_kdtree_find_nearest_n(tree, co, nearest, 4);
+ if (maxw == 1) {
+ pa->blend_index[0] = nearest[0].index;
+ pa->blend_weight[0] = 1.0f;
+ }
+ else if (maxw > 1) {
+ float norm, totdist = 0.0f;
+ for (w = 0; w < maxw; ++w)
+ totdist += nearest[w].dist;
+ norm = totdist > 0.0f ? 1.0f / (totdist * (float)(maxw - 1)) : 0.0f;
+
+ for (w = 0; w < maxw; ++w) {
+ pa->blend_index[w] = nearest[w].index;
+ pa->blend_weight[w] = (totdist - nearest[w].dist) * norm;
+ }
+ }
+ /* clear unused weights */
+ for (w = maxw; w < 4; ++w) {
+ pa->blend_index[w] = -1;
+ pa->blend_weight[w] = 0.0f;
+ }
+ }
+ else {
+ pa->blend_index[0] = -1;
+ pa->blend_index[1] = -1;
+ pa->blend_index[2] = -1;
+ pa->blend_index[3] = -1;
+ pa->blend_weight[0] = 0.0f;
+ pa->blend_weight[1] = 0.0f;
+ pa->blend_weight[2] = 0.0f;
+ pa->blend_weight[3] = 0.0f;
+ }
+ }
+
+ BLI_kdtree_free(tree);
+ BLI_rng_free(rng);
+ }
+
+ psys->hair_num_simulated = num_simulated;
+ return true;
+#else
+ (void)sim;
+ return false;
+#endif
+}
+
static void hair_create_input_dm(ParticleSimulationData *sim, int totpoint, int totedge, DerivedMesh **r_dm, ClothHairData **r_hairdata)
{
ParticleSystem *psys = sim->psys;
@@ -3030,6 +3159,8 @@ static void hair_create_input_dm(ParticleSimulationData *sim, int totpoint, int
float hairmat[4][4];
float max_length;
float hair_radius;
+ float *shapekey_data, *shapekey;
+ int totshapekey;
dm = *r_dm;
if (!dm) {
@@ -3060,6 +3191,8 @@ static void hair_create_input_dm(ParticleSimulationData *sim, int totpoint, int
/* XXX placeholder for more flexible future hair settings */
hair_radius = part->size;
+ shapekey = shapekey_data = BKE_key_evaluate_particles(sim->ob, psys, sim->scene ? sim->scene->r.cfra : 0.0f, &totshapekey);
+
/* make vgroup for pin roots etc.. */
hair_index = 1;
LOOP_PARTICLES {
@@ -3080,8 +3213,15 @@ static void hair_create_input_dm(ParticleSimulationData *sim, int totpoint, int
ClothHairData *hair;
float *co, *co_next;
- co = key->co;
- co_next = (key+1)->co;
+ if (shapekey) {
+ co = shapekey;
+ co_next = shapekey + 3;
+ shapekey += 3;
+ }
+ else {
+ co = key->co;
+ co_next = (key+1)->co;
+ }
/* create fake root before actual root to resist bending */
if (k==0) {
@@ -3101,6 +3241,14 @@ static void hair_create_input_dm(ParticleSimulationData *sim, int totpoint, int
dvert = hair_set_pinning(dvert, 1.0f);
+#ifdef USE_PARTICLE_PREVIEW
+ /* tag vert if hair is not simulated */
+ if (pa->flag & PARS_HAIR_BLEND)
+ mvert->flag |= ME_VERT_TMP_TAG;
+ else
+ mvert->flag &= ~ME_VERT_TMP_TAG;
+#endif
+
mvert++;
medge++;
}
@@ -3127,6 +3275,14 @@ static void hair_create_input_dm(ParticleSimulationData *sim, int totpoint, int
else
dvert = hair_set_pinning(dvert, 1.0f);
+#ifdef USE_PARTICLE_PREVIEW
+ /* tag vert if hair is not simulated */
+ if (pa->flag & PARS_HAIR_BLEND)
+ mvert->flag |= ME_VERT_TMP_TAG;
+ else
+ mvert->flag &= ~ME_VERT_TMP_TAG;
+#endif
+
mvert++;
if (k)
medge++;
@@ -3136,6 +3292,105 @@ static void hair_create_input_dm(ParticleSimulationData *sim, int totpoint, int
}
}
+#ifdef USE_PARTICLE_PREVIEW
+static void hair_deform_preview_curve(ParticleSystem *psys, ParticleData *pa, float (*deformedVerts)[3], ClothHairData *hairdata)
+{
+ ParticleData *particles = psys->particles;
+ HairKey *hkey;
+ float (*vert)[3];
+ ClothHairData *root;
+ int k;
+ float totlen, norm;
+
+ /* first key is root, no blending for them */
+ if (pa->totkey < 2)
+ return;
+
+ /* calculate normalization factor to equally parameterize hairs */
+ totlen = 0.0f;
+ hkey = pa->hair;
+ for (k = 0; k < pa->totkey - 1; ++k, ++hkey)
+ totlen += len_v3v3((hkey+1)->co, hkey->co);
+ norm = totlen > 0.0f ? 1.0f / totlen : 0.0f;
+
+ totlen = 0.0f;
+ hkey = pa->hair;
+ vert = deformedVerts + pa->hair_index;
+ root = hairdata + pa->hair_index;
+ for (k = 0; k < pa->totkey; ++k, ++hkey, ++vert, ++root) {
+ float param;
+ int w;
+
+ if (k == 0) /* skip root vertex */
+ continue;
+ param = totlen * norm;
+ totlen += len_v3v3(hkey->co, (hkey-1)->co);
+
+ zero_v3(vert[0]);
+ for (w = 0; w < 4; ++w) {
+ ParticleData *blend_pa;
+ float (*blend_vert)[3];
+ ClothHairData *blend_hair;
+ float blend_key, blend_factor;
+ int blend_totkey, blend_index;
+ float co[3];
+
+ if (pa->blend_index[w] < 0)
+ continue;
+
+ blend_pa = particles + pa->blend_index[w];
+ blend_totkey = blend_pa->totkey;
+
+ blend_key = param * (float)blend_totkey;
+ blend_index = (int)blend_key;
+ if (blend_index >= blend_totkey - 1) {
+ blend_index = blend_totkey - 2;
+ blend_factor = 1.0f;
+ }
+ else {
+ blend_factor = blend_key - floorf(blend_key);
+ }
+
+ /* pa->hair_index is set when creating input_dm,
+ * use it here to map to output mvert index
+ */
+ blend_vert = deformedVerts + blend_pa->hair_index + blend_index;
+ blend_hair = hairdata + blend_pa->hair_index + blend_index;
+
+ interp_v3_v3v3(co, blend_vert[0], blend_vert[1], blend_factor);
+
+ /* transform parent vector from world to root space, then back into root space of the blended hair */
+ sub_v3_v3(co, blend_hair->loc);
+ /* note: rotation transform disabled, this does not work nicely with global force directions (gravity, wind etc.)
+ * these forces would also get rotated, giving movement in a different direction than the force would actually incur.
+ * would have to split internal (stretch, bend) and external forces somehow to make this plausible
+ */
+#if 0
+ mul_transposed_m3_v3(blend_hair->rot, co);
+ mul_m3_v3(root->rot, co);
+#endif
+ add_v3_v3(co, root->loc);
+
+ madd_v3_v3fl(vert[0], co, pa->blend_weight[w]);
+ }
+ }
+}
+
+static void hair_deform_preview_hairs(ParticleSimulationData *sim, float (*deformedVerts)[3], ClothHairData *roots)
+{
+ ParticleSystem *psys = sim->psys;
+ ParticleData *pa;
+ int p;
+
+ pa = psys->particles;
+ for (p = 0; p < psys->totpart; ++p, ++pa) {
+ if (pa->flag & PARS_HAIR_BLEND) {
+ hair_deform_preview_curve(psys, pa, deformedVerts, roots);
+ }
+ }
+}
+#endif
+
static void do_hair_dynamics(ParticleSimulationData *sim)
{
ParticleSystem *psys = sim->psys;
@@ -3146,6 +3401,11 @@ static void do_hair_dynamics(ParticleSimulationData *sim)
float (*deformedVerts)[3];
bool realloc_roots;
+ if (psys_hair_update_preview(sim)) {
+ if (psys->clmd)
+ cloth_free_modifier(psys->clmd);
+ }
+
if (!psys->clmd) {
psys->clmd = (ClothModifierData*)modifier_new(eModifierType_Cloth);
psys->clmd->sim_parms->goalspring = 0.0f;
@@ -3197,6 +3457,9 @@ static void do_hair_dynamics(ParticleSimulationData *sim)
psys->hair_out_dm->getVertCos(psys->hair_out_dm, deformedVerts);
clothModifier_do(psys->clmd, sim->scene, sim->ob, psys->hair_in_dm, deformedVerts);
+#ifdef USE_PARTICLE_PREVIEW
+ hair_deform_preview_hairs(sim, deformedVerts, psys->clmd->roots);
+#endif
CDDM_apply_vert_coords(psys->hair_out_dm, deformedVerts);
@@ -3210,7 +3473,14 @@ static void hair_step(ParticleSimulationData *sim, float cfra)
ParticleSystem *psys = sim->psys;
ParticleSettings *part = psys->part;
PARTICLE_P;
+ PARTICLE_PSMD;
float disp = psys_get_current_display_percentage(psys);
+ float *shapekey_data = NULL, *shapekey;
+ int totshapekey;
+
+ if (part->type == PART_HAIR) {
+ shapekey = shapekey_data = BKE_key_evaluate_particles(sim->ob, sim->psys, sim->scene ? sim->scene->r.cfra : 0.0f, &totshapekey);
+ }
LOOP_PARTICLES {
pa->size = part->size;
@@ -3221,8 +3491,35 @@ static void hair_step(ParticleSimulationData *sim, float cfra)
pa->flag |= PARS_NO_DISP;
else
pa->flag &= ~PARS_NO_DISP;
+
+ if (part->type == PART_HAIR) {
+ float hairmat[4][4];
+ HairKey *hkey;
+ int k;
+
+ psys_mat_hair_to_global(sim->ob, psmd->dm, psys->part->from, pa, hairmat);
+
+ /* update world coordinates and calculate shapekey result if needed */
+ for (k = 0, hkey = pa->hair; k < pa->totkey; ++k, ++hkey) {
+ const float *co;
+ if (shapekey) {
+ co = shapekey;
+ shapekey += 3;
+
+ copy_v3_v3(hkey->co, co);
+ }
+ else {
+ co = hkey->co;
+ }
+
+ mul_v3_m4v3(hkey->world_co, hairmat, co);
+ }
+ }
}
+ if (shapekey_data)
+ MEM_freeN(shapekey_data);
+
if (psys->recalc & PSYS_RECALC_RESET) {
/* need this for changing subsurf levels */
psys_calc_dmcache(sim->ob, sim->psmd->dm, psys);