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.c')
-rw-r--r--source/blender/blenkernel/intern/particle.c343
1 files changed, 219 insertions, 124 deletions
diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c
index 9aacba8d02e..098700495a0 100644
--- a/source/blender/blenkernel/intern/particle.c
+++ b/source/blender/blenkernel/intern/particle.c
@@ -105,7 +105,7 @@ static void get_child_modifier_parameters(ParticleSettings *part, ParticleThread
ChildParticle *cpa, short cpa_from, int cpa_num, float *cpa_fuv, float *orco, ParticleTexture *ptex);
static void get_cpa_texture(DerivedMesh *dm, ParticleSystem *psys, ParticleSettings *part, ParticleData *par,
int child_index, int face_index, const float fw[4], float *orco, ParticleTexture *ptex, int event, float cfra);
-extern void do_child_modifiers(ParticleSimulationData *sim,
+extern void do_child_modifiers(ParticleThreadContext *ctx, ParticleSimulationData *sim,
ParticleTexture *ptex, const float par_co[3], const float par_vel[3], const float par_rot[4], const float par_orco[3],
ChildParticle *cpa, const float orco[3], float mat[4][4], ParticleKey *state, float t);
@@ -395,8 +395,10 @@ void BKE_particlesettings_free(ParticleSettings *part)
for (a = 0; a < MAX_MTEX; a++) {
mtex = part->mtex[a];
- if (mtex && mtex->tex) mtex->tex->id.us--;
- if (mtex) MEM_freeN(mtex);
+ if (mtex && mtex->tex)
+ id_us_min(&mtex->tex->id);
+ if (mtex)
+ MEM_freeN(mtex);
}
}
@@ -567,7 +569,7 @@ void psys_free(Object *ob, ParticleSystem *psys)
ob->transflag &= ~OB_DUPLIPARTS;
if (psys->part) {
- psys->part->id.us--;
+ id_us_min(&psys->part->id);
psys->part = NULL;
}
@@ -621,8 +623,8 @@ void psys_render_set(Object *ob, ParticleSystem *psys, float viewmat[4][4], floa
data->childcachebufs.last = psys->childcachebufs.last;
data->totchildcache = psys->totchildcache;
- if (psmd->dm)
- data->dm = CDDM_copy(psmd->dm);
+ if (psmd->dm_final)
+ data->dm = CDDM_copy(psmd->dm_final);
data->totdmvert = psmd->totdmvert;
data->totdmedge = psmd->totdmedge;
data->totdmface = psmd->totdmface;
@@ -663,9 +665,14 @@ void psys_render_restore(Object *ob, ParticleSystem *psys)
if (data->elems)
MEM_freeN(data->elems);
- if (psmd->dm) {
- psmd->dm->needsFree = 1;
- psmd->dm->release(psmd->dm);
+ if (psmd->dm_final) {
+ psmd->dm_final->needsFree = 1;
+ psmd->dm_final->release(psmd->dm_final);
+ }
+ if (psmd->dm_deformed) {
+ psmd->dm_deformed->needsFree = 1;
+ psmd->dm_deformed->release(psmd->dm_deformed);
+ psmd->dm_deformed = NULL;
}
psys_free_path_cache(psys, NULL);
@@ -687,14 +694,24 @@ void psys_render_restore(Object *ob, ParticleSystem *psys)
psys->childcachebufs.last = data->childcachebufs.last;
psys->totchildcache = data->totchildcache;
- psmd->dm = data->dm;
+ psmd->dm_final = data->dm;
psmd->totdmvert = data->totdmvert;
psmd->totdmedge = data->totdmedge;
psmd->totdmface = data->totdmface;
psmd->flag &= ~eParticleSystemFlag_psys_updated;
- if (psmd->dm)
- psys_calc_dmcache(ob, psmd->dm, psys);
+ if (psmd->dm_final) {
+ if (!psmd->dm_final->deformedOnly) {
+ if (ob->derivedDeform) {
+ psmd->dm_deformed = CDDM_copy(ob->derivedDeform);
+ }
+ else {
+ psmd->dm_deformed = CDDM_from_mesh((Mesh *)ob->data);
+ }
+ DM_ensure_tessface(psmd->dm_deformed);
+ }
+ psys_calc_dmcache(ob, psmd->dm_final, psmd->dm_deformed, psys);
+ }
MEM_freeN(data);
psys->renderdata = NULL;
@@ -703,13 +720,19 @@ void psys_render_restore(Object *ob, ParticleSystem *psys)
disp = psys_get_current_display_percentage(psys);
if (disp != render_disp) {
- PARTICLE_P;
+ /* Hair can and has to be recalculated if everything isn't displayed. */
+ if (psys->part->type == PART_HAIR) {
+ psys->recalc |= PSYS_RECALC_RESET;
+ }
+ else {
+ PARTICLE_P;
- LOOP_PARTICLES {
- if (psys_frand(psys, p) > disp)
- pa->flag |= PARS_NO_DISP;
- else
- pa->flag &= ~PARS_NO_DISP;
+ LOOP_PARTICLES {
+ if (psys_frand(psys, p) > disp)
+ pa->flag |= PARS_NO_DISP;
+ else
+ pa->flag &= ~PARS_NO_DISP;
+ }
}
}
}
@@ -1381,78 +1404,115 @@ static void psys_origspace_to_w(OrigSpaceFace *osface, int quad, const float w[4
}
}
-/* find the derived mesh face for a particle, set the mf passed. this is slow
- * and can be optimized but only for many lookups. returns the face index. */
-int psys_particle_dm_face_lookup(Object *ob, DerivedMesh *dm, int index, const float fw[4], struct LinkNode *node)
+/**
+ * Find the final derived mesh tessface for a particle, from its original tessface index.
+ * This is slow and can be optimized but only for many lookups.
+ *
+ * \param dm_final final DM, it may not have the same topology as original mesh.
+ * \param dm_deformed deformed-only DM, it has the exact same topology as original mesh.
+ * \param findex_orig the input tessface index.
+ * \param fw face weights (position of the particle inside the \a findex_orig tessface).
+ * \param poly_nodes may be NULL, otherwise an array of linked list, one for each final DM polygon, containing all
+ * its tessfaces indices.
+ * \return the DM tessface index.
+ */
+int psys_particle_dm_face_lookup(
+ DerivedMesh *dm_final, DerivedMesh *dm_deformed,
+ int findex_orig, const float fw[4], struct LinkNode **poly_nodes)
{
- Mesh *me = (Mesh *)ob->data;
- MPoly *mpoly;
- OrigSpaceFace *osface;
- int quad, findex, totface;
+ MFace *mtessface_final;
+ OrigSpaceFace *osface_final;
+ int pindex_orig;
float uv[2], (*faceuv)[2];
- /* double lookup */
- const int *index_mf_to_mpoly = dm->getTessFaceDataArray(dm, CD_ORIGINDEX);
- const int *index_mp_to_orig = dm->getPolyDataArray(dm, CD_ORIGINDEX);
- if (index_mf_to_mpoly == NULL) {
- index_mp_to_orig = NULL;
- }
+ const int *index_mf_to_mpoly_deformed = NULL;
+ const int *index_mf_to_mpoly = NULL;
+ const int *index_mp_to_orig = NULL;
+
+ const int totface_final = dm_final->getNumTessFaces(dm_final);
+ const int totface_deformed = dm_deformed ? dm_deformed->getNumTessFaces(dm_deformed) : totface_final;
- totface = dm->getNumTessFaces(dm);
- if (!totface) {
+ if (ELEM(0, totface_final, totface_deformed)) {
return DMCACHE_NOTFOUND;
}
- mpoly = dm->getPolyArray(dm);
- osface = dm->getTessFaceDataArray(dm, CD_ORIGSPACE);
+ index_mf_to_mpoly = dm_final->getTessFaceDataArray(dm_final, CD_ORIGINDEX);
+ index_mp_to_orig = dm_final->getPolyDataArray(dm_final, CD_ORIGINDEX);
+ BLI_assert(index_mf_to_mpoly);
+
+ if (dm_deformed) {
+ index_mf_to_mpoly_deformed = dm_deformed->getTessFaceDataArray(dm_deformed, CD_ORIGINDEX);
+ }
+ else {
+ BLI_assert(dm_final->deformedOnly);
+ index_mf_to_mpoly_deformed = index_mf_to_mpoly;
+ }
+ BLI_assert(index_mf_to_mpoly_deformed);
+
+ pindex_orig = index_mf_to_mpoly_deformed[findex_orig];
+
+ if (dm_deformed == NULL) {
+ dm_deformed = dm_final;
+ }
+
+ index_mf_to_mpoly_deformed = NULL;
- if (osface == NULL || index_mf_to_mpoly == NULL) {
- /* Assume we don't need osface data */
- if (index < totface) {
+ mtessface_final = dm_final->getTessFaceArray(dm_final);
+ osface_final = dm_final->getTessFaceDataArray(dm_final, CD_ORIGSPACE);
+
+ if (osface_final == NULL) {
+ /* Assume we don't need osface_final data, and we get a direct 1-1 mapping... */
+ if (findex_orig < totface_final) {
//printf("\tNO CD_ORIGSPACE, assuming not needed\n");
- return index;
+ return findex_orig;
}
else {
printf("\tNO CD_ORIGSPACE, error out of range\n");
return DMCACHE_NOTFOUND;
}
}
- else if (index >= me->totpoly)
+ else if (findex_orig >= dm_deformed->getNumTessFaces(dm_deformed)) {
return DMCACHE_NOTFOUND; /* index not in the original mesh */
+ }
psys_w_to_origspace(fw, uv);
- if (node) { /* we have a linked list of faces that we use, faster! */
- for (; node; node = node->next) {
- findex = GET_INT_FROM_POINTER(node->link);
- faceuv = osface[findex].uv;
- quad = (mpoly[findex].totloop == 4);
+ if (poly_nodes) {
+ /* we can have a restricted linked list of faces to check, faster! */
+ LinkNode *tessface_node = poly_nodes[pindex_orig];
+
+ for (; tessface_node; tessface_node = tessface_node->next) {
+ int findex_dst = GET_INT_FROM_POINTER(tessface_node->link);
+ faceuv = osface_final[findex_dst].uv;
/* check that this intersects - Its possible this misses :/ -
* could also check its not between */
- if (quad) {
- if (isect_point_quad_v2(uv, faceuv[0], faceuv[1], faceuv[2], faceuv[3]))
- return findex;
+ if (mtessface_final[findex_dst].v4) {
+ if (isect_point_quad_v2(uv, faceuv[0], faceuv[1], faceuv[2], faceuv[3])) {
+ return findex_dst;
+ }
+ }
+ else if (isect_point_tri_v2(uv, faceuv[0], faceuv[1], faceuv[2])) {
+ return findex_dst;
}
- else if (isect_point_tri_v2(uv, faceuv[0], faceuv[1], faceuv[2]))
- return findex;
}
}
else { /* if we have no node, try every face */
- for (findex = 0; findex < totface; findex++) {
- const int findex_orig = DM_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig, findex);
- if (findex_orig == index) {
- faceuv = osface[findex].uv;
- quad = (mpoly[findex].totloop == 4);
+ for (int findex_dst = 0; findex_dst < totface_final; findex_dst++) {
+ /* If current tessface from 'final' DM and orig tessface (given by index) map to the same orig poly... */
+ if (DM_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig, findex_dst) == pindex_orig) {
+ faceuv = osface_final[findex_dst].uv;
/* check that this intersects - Its possible this misses :/ -
* could also check its not between */
- if (quad) {
- if (isect_point_quad_v2(uv, faceuv[0], faceuv[1], faceuv[2], faceuv[3]))
- return findex;
+ if (mtessface_final[findex_dst].v4) {
+ if (isect_point_quad_v2(uv, faceuv[0], faceuv[1], faceuv[2], faceuv[3])) {
+ return findex_dst;
+ }
+ }
+ else if (isect_point_tri_v2(uv, faceuv[0], faceuv[1], faceuv[2])) {
+ return findex_dst;
}
- else if (isect_point_tri_v2(uv, faceuv[0], faceuv[1], faceuv[2]))
- return findex;
}
}
}
@@ -1521,7 +1581,7 @@ static int psys_map_index_on_dm(DerivedMesh *dm, int from, int index, int index_
}
/* interprets particle data to get a point on a mesh in object space */
-void psys_particle_on_dm(DerivedMesh *dm, int from, int index, int index_dmcache,
+void psys_particle_on_dm(DerivedMesh *dm_final, int from, int index, int index_dmcache,
const float fw[4], float foffset, float vec[3], float nor[3], float utan[3], float vtan[3],
float orco[3], float ornor[3])
{
@@ -1529,7 +1589,7 @@ void psys_particle_on_dm(DerivedMesh *dm, int from, int index, int index_dmcache
float (*orcodata)[3];
int mapindex;
- if (!psys_map_index_on_dm(dm, from, index, index_dmcache, fw, foffset, &mapindex, mapfw)) {
+ if (!psys_map_index_on_dm(dm_final, from, index, index_dmcache, fw, foffset, &mapindex, mapfw)) {
if (vec) { vec[0] = vec[1] = vec[2] = 0.0; }
if (nor) { nor[0] = nor[1] = 0.0; nor[2] = 1.0; }
if (orco) { orco[0] = orco[1] = orco[2] = 0.0; }
@@ -1540,21 +1600,27 @@ void psys_particle_on_dm(DerivedMesh *dm, int from, int index, int index_dmcache
return;
}
- orcodata = dm->getVertDataArray(dm, CD_ORCO);
+ orcodata = dm_final->getVertDataArray(dm_final, CD_ORCO);
if (from == PART_FROM_VERT) {
- dm->getVertCo(dm, mapindex, vec);
+ dm_final->getVertCo(dm_final, mapindex, vec);
if (nor) {
- dm->getVertNo(dm, mapindex, nor);
+ dm_final->getVertNo(dm_final, mapindex, nor);
normalize_v3(nor);
}
- if (orco)
- copy_v3_v3(orco, orcodata[mapindex]);
+ if (orco) {
+ if (orcodata) {
+ copy_v3_v3(orco, orcodata[mapindex]);
+ }
+ else {
+ copy_v3_v3(orco, vec);
+ }
+ }
if (ornor) {
- dm->getVertNo(dm, mapindex, ornor);
+ dm_final->getVertNo(dm_final, mapindex, ornor);
normalize_v3(ornor);
}
@@ -1568,9 +1634,9 @@ void psys_particle_on_dm(DerivedMesh *dm, int from, int index, int index_dmcache
MTFace *mtface;
MVert *mvert;
- mface = dm->getTessFaceData(dm, mapindex, CD_MFACE);
- mvert = dm->getVertDataArray(dm, CD_MVERT);
- mtface = CustomData_get_layer(&dm->faceData, CD_MTFACE);
+ mface = dm_final->getTessFaceData(dm_final, mapindex, CD_MFACE);
+ mvert = dm_final->getVertDataArray(dm_final, CD_MVERT);
+ mtface = CustomData_get_layer(&dm_final->faceData, CD_MTFACE);
if (mtface)
mtface += mapindex;
@@ -1687,7 +1753,7 @@ void psys_particle_on_emitter(ParticleSystemModifierData *psmd, int from, int in
float fuv[4], float foffset, float vec[3], float nor[3], float utan[3], float vtan[3],
float orco[3], float ornor[3])
{
- if (psmd && psmd->dm) {
+ if (psmd && psmd->dm_final) {
if (psmd->psys->part->distr == PART_DISTR_GRID && psmd->psys->part->from != PART_FROM_VERT) {
if (vec)
copy_v3_v3(vec, fuv);
@@ -1697,7 +1763,7 @@ void psys_particle_on_emitter(ParticleSystemModifierData *psmd, int from, int in
return;
}
/* we cant use the num_dmcache */
- psys_particle_on_dm(psmd->dm, from, index, index_dmcache, fuv, foffset, vec, nor, utan, vtan, orco, ornor);
+ psys_particle_on_dm(psmd->dm_final, from, index, index_dmcache, fuv, foffset, vec, nor, utan, vtan, orco, ornor);
}
else
psys_particle_on_shape(from, index, fuv, vec, nor, utan, vtan, orco, ornor);
@@ -1969,7 +2035,7 @@ void psys_find_parents(ParticleSimulationData *sim)
psys_particle_on_emitter(sim->psmd, from, cpa->num, DMCACHE_ISCHILD, cpa->fuv, cpa->foffset, co, 0, 0, 0, orco, 0);
/* Check if particle doesn't exist because of texture influence. Insert only existing particles into kdtree. */
- get_cpa_texture(sim->psmd->dm, psys, part, psys->particles + cpa->pa[0], p, cpa->num, cpa->fuv, orco, &ptex, PAMAP_DENS | PAMAP_CHILD, psys->cfra);
+ get_cpa_texture(sim->psmd->dm_final, psys, part, psys->particles + cpa->pa[0], p, cpa->num, cpa->fuv, orco, &ptex, PAMAP_DENS | PAMAP_CHILD, psys->cfra);
if (ptex.exist >= psys_frand(psys, p + 24)) {
BLI_kdtree_insert(tree, p, orco);
@@ -2052,10 +2118,20 @@ static bool psys_thread_context_init_path(ParticleThreadContext *ctx, ParticleSi
ctx->vg_effector = psys_cache_vgroup(ctx->dm, psys, PSYS_VG_EFFECTOR);
/* prepare curvemapping tables */
- if ((part->child_flag & PART_CHILD_USE_CLUMP_CURVE) && part->clumpcurve)
- curvemapping_changed_all(part->clumpcurve);
- if ((part->child_flag & PART_CHILD_USE_ROUGH_CURVE) && part->roughcurve)
- curvemapping_changed_all(part->roughcurve);
+ if ((part->child_flag & PART_CHILD_USE_CLUMP_CURVE) && part->clumpcurve) {
+ ctx->clumpcurve = curvemapping_copy(part->clumpcurve);
+ curvemapping_changed_all(ctx->clumpcurve);
+ }
+ else {
+ ctx->clumpcurve = NULL;
+ }
+ if ((part->child_flag & PART_CHILD_USE_ROUGH_CURVE) && part->roughcurve) {
+ ctx->roughcurve = curvemapping_copy(part->roughcurve);
+ curvemapping_changed_all(ctx->roughcurve);
+ }
+ else {
+ ctx->roughcurve = NULL;
+ }
return true;
}
@@ -2181,7 +2257,7 @@ static void psys_thread_create_path(ParticleTask *task, struct ChildParticle *cp
for (w = 0; w < 4; w++)
sub_v3_v3v3(off1[w], co, key[w]->co);
- psys_mat_hair_to_global(ob, ctx->sim.psmd->dm, psys->part->from, pa, hairmat);
+ psys_mat_hair_to_global(ob, ctx->sim.psmd->dm_final, psys->part->from, pa, hairmat);
}
else {
ParticleData *pa = psys->particles + cpa->parent;
@@ -2200,13 +2276,13 @@ static void psys_thread_create_path(ParticleTask *task, struct ChildParticle *cp
cpa_from = part->from;
cpa_num = pa->num;
/* XXX hack to avoid messed up particle num and subsequent crash (#40733) */
- if (cpa_num > ctx->sim.psmd->dm->getNumTessFaces(ctx->sim.psmd->dm))
+ if (cpa_num > ctx->sim.psmd->dm_final->getNumTessFaces(ctx->sim.psmd->dm_final))
cpa_num = 0;
cpa_fuv = pa->fuv;
psys_particle_on_emitter(ctx->sim.psmd, cpa_from, cpa_num, DMCACHE_ISCHILD, cpa_fuv, pa->foffset, co, ornor, 0, 0, orco, 0);
- psys_mat_hair_to_global(ob, ctx->sim.psmd->dm, psys->part->from, pa, hairmat);
+ psys_mat_hair_to_global(ob, ctx->sim.psmd->dm_final, psys->part->from, pa, hairmat);
}
child_keys->segments = ctx->segments;
@@ -2325,7 +2401,7 @@ static void psys_thread_create_path(ParticleTask *task, struct ChildParticle *cp
child_keys->segments = -1;
}
-static void exec_child_path_cache(TaskPool *UNUSED(pool), void *taskdata, int UNUSED(threadid))
+static void exec_child_path_cache(TaskPool * __restrict UNUSED(pool), void *taskdata, int UNUSED(threadid))
{
ParticleTask *task = taskdata;
ParticleThreadContext *ctx = task->ctx;
@@ -2499,15 +2575,15 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra)
if ((psys->flag & PSYS_GLOBAL_HAIR) == 0) {
if ((psys->part->flag & PART_CHILD_EFFECT) == 0)
- vg_effector = psys_cache_vgroup(psmd->dm, psys, PSYS_VG_EFFECTOR);
+ vg_effector = psys_cache_vgroup(psmd->dm_final, psys, PSYS_VG_EFFECTOR);
if (!psys->totchild)
- vg_length = psys_cache_vgroup(psmd->dm, psys, PSYS_VG_LENGTH);
+ vg_length = psys_cache_vgroup(psmd->dm_final, psys, PSYS_VG_LENGTH);
}
/* ensure we have tessfaces to be used for mapping */
if (part->from != PART_FROM_VERT) {
- DM_ensure_tessface(psmd->dm);
+ DM_ensure_tessface(psmd->dm_final);
}
/*---first main loop: create all actual particles' paths---*/
@@ -2516,7 +2592,7 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra)
psys_get_texture(sim, pa, &ptex, PAMAP_LENGTH, 0.f);
pa_length = ptex.length * (1.0f - part->randlength * psys_frand(psys, psys->seed + p));
if (vg_length)
- pa_length *= psys_particle_value_from_verts(psmd->dm, part->from, pa, vg_length);
+ pa_length *= psys_particle_value_from_verts(psmd->dm_final, part->from, pa, vg_length);
}
pind.keyed = keyed;
@@ -2533,7 +2609,7 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra)
init_particle_interpolation(sim->ob, sim->psys, pa, &pind);
/* hairmat is needed for for non-hair particle too so we get proper rotations */
- psys_mat_hair_to_global(sim->ob, psmd->dm, psys->part->from, pa, hairmat);
+ psys_mat_hair_to_global(sim->ob, psmd->dm_final, psys->part->from, pa, hairmat);
copy_v3_v3(rotmat[0], hairmat[2]);
copy_v3_v3(rotmat[1], hairmat[1]);
copy_v3_v3(rotmat[2], hairmat[0]);
@@ -2588,7 +2664,7 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra)
if ((psys->part->flag & PART_CHILD_EFFECT) == 0) {
float effector = 1.0f;
if (vg_effector)
- effector *= psys_particle_value_from_verts(psmd->dm, psys->part->from, pa, vg_effector);
+ effector *= psys_particle_value_from_verts(psmd->dm_final, psys->part->from, pa, vg_effector);
sub_v3_v3v3(vec, (cache[p] + 1)->co, cache[p]->co);
length = len_v3(vec);
@@ -2733,7 +2809,7 @@ void psys_cache_edit_paths(Scene *scene, Object *ob, PTCacheEdit *edit, float cf
init_particle_interpolation(ob, psys, pa, &pind);
if (psys) {
- psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, pa, hairmat);
+ psys_mat_hair_to_global(ob, psmd->dm_final, psys->part->from, pa, hairmat);
copy_v3_v3(rotmat[0], hairmat[2]);
copy_v3_v3(rotmat[1], hairmat[1]);
copy_v3_v3(rotmat[2], hairmat[0]);
@@ -3315,8 +3391,8 @@ void BKE_particlesettings_make_local(ParticleSettings *part)
for (psys = ob->particlesystem.first; psys; psys = psys->next) {
if (psys->part == part && ob->id.lib == 0) {
psys->part = part_new;
- part_new->id.us++;
- part->id.us--;
+ id_us_plus(&part_new->id);
+ id_us_min(&part->id);
}
}
}
@@ -3374,6 +3450,11 @@ static int get_particle_uv(DerivedMesh *dm, ParticleData *pa, int face_index, co
#define CLAMP_PARTICLE_TEXTURE_POS(type, pvalue) \
if (event & type) { \
+ CLAMP(pvalue, 0.0f, 1.0f); \
+ } (void)0
+
+#define CLAMP_WARP_PARTICLE_TEXTURE_POS(type, pvalue) \
+ if (event & type) { \
if (pvalue < 0.0f) \
pvalue = 1.0f + pvalue; \
CLAMP(pvalue, 0.0f, 1.0f); \
@@ -3431,7 +3512,7 @@ static void get_cpa_texture(DerivedMesh *dm, ParticleSystem *psys, ParticleSetti
break;
}
- externtex(mtex, texvec, &value, rgba, rgba + 1, rgba + 2, rgba + 3, 0, NULL, false);
+ externtex(mtex, texvec, &value, rgba, rgba + 1, rgba + 2, rgba + 3, 0, NULL, false, false);
if ((event & mtex->mapto) & PAMAP_ROUGH)
ptex->rough1 = ptex->rough2 = ptex->roughe = texture_value_blend(def, ptex->rough1, value, mtex->roughfac, blend);
@@ -3445,11 +3526,11 @@ static void get_cpa_texture(DerivedMesh *dm, ParticleSystem *psys, ParticleSetti
}
CLAMP_PARTICLE_TEXTURE_POS(PAMAP_LENGTH, ptex->length);
- CLAMP_PARTICLE_TEXTURE_POS(PAMAP_CLUMP, ptex->clump);
- CLAMP_PARTICLE_TEXTURE_POS(PAMAP_KINK_AMP, ptex->kink_amp);
- CLAMP_PARTICLE_TEXTURE_POS(PAMAP_KINK_FREQ, ptex->kink_freq);
- CLAMP_PARTICLE_TEXTURE_POS(PAMAP_ROUGH, ptex->rough1);
- CLAMP_PARTICLE_TEXTURE_POS(PAMAP_DENS, ptex->exist);
+ CLAMP_WARP_PARTICLE_TEXTURE_POS(PAMAP_CLUMP, ptex->clump);
+ CLAMP_WARP_PARTICLE_TEXTURE_POS(PAMAP_KINK_AMP, ptex->kink_amp);
+ CLAMP_WARP_PARTICLE_TEXTURE_POS(PAMAP_KINK_FREQ, ptex->kink_freq);
+ CLAMP_WARP_PARTICLE_TEXTURE_POS(PAMAP_ROUGH, ptex->rough1);
+ CLAMP_WARP_PARTICLE_TEXTURE_POS(PAMAP_DENS, ptex->exist);
}
void psys_get_texture(ParticleSimulationData *sim, ParticleData *pa, ParticleTexture *ptex, int event, float cfra)
{
@@ -3489,7 +3570,7 @@ void psys_get_texture(ParticleSimulationData *sim, ParticleData *pa, ParticleTex
mul_m4_v3(mtex->object->imat, texvec);
break;
case TEXCO_UV:
- if (get_particle_uv(sim->psmd->dm, pa, 0, pa->fuv, mtex->uvname, texvec))
+ if (get_particle_uv(sim->psmd->dm_final, pa, 0, pa->fuv, mtex->uvname, texvec))
break;
/* no break, failed to get uv's, so let's try orco's */
case TEXCO_ORCO:
@@ -3514,7 +3595,7 @@ void psys_get_texture(ParticleSimulationData *sim, ParticleData *pa, ParticleTex
break;
}
- externtex(mtex, texvec, &value, rgba, rgba + 1, rgba + 2, rgba + 3, 0, NULL, false);
+ externtex(mtex, texvec, &value, rgba, rgba + 1, rgba + 2, rgba + 3, 0, NULL, false, false);
if ((event & mtex->mapto) & PAMAP_TIME) {
/* the first time has to set the base value for time regardless of blend mode */
@@ -3539,14 +3620,14 @@ void psys_get_texture(ParticleSimulationData *sim, ParticleData *pa, ParticleTex
}
}
- CLAMP_PARTICLE_TEXTURE_POS(PAMAP_TIME, ptex->time);
- CLAMP_PARTICLE_TEXTURE_POS(PAMAP_LIFE, ptex->life);
- CLAMP_PARTICLE_TEXTURE_POS(PAMAP_DENS, ptex->exist);
+ CLAMP_WARP_PARTICLE_TEXTURE_POS(PAMAP_TIME, ptex->time);
+ CLAMP_WARP_PARTICLE_TEXTURE_POS(PAMAP_LIFE, ptex->life);
+ CLAMP_WARP_PARTICLE_TEXTURE_POS(PAMAP_DENS, ptex->exist);
CLAMP_PARTICLE_TEXTURE_POS(PAMAP_SIZE, ptex->size);
CLAMP_PARTICLE_TEXTURE_POSNEG(PAMAP_IVEL, ptex->ivel);
CLAMP_PARTICLE_TEXTURE_POSNEG(PAMAP_FIELD, ptex->field);
CLAMP_PARTICLE_TEXTURE_POSNEG(PAMAP_GRAVITY, ptex->gravity);
- CLAMP_PARTICLE_TEXTURE_POS(PAMAP_DAMP, ptex->damp);
+ CLAMP_WARP_PARTICLE_TEXTURE_POS(PAMAP_DAMP, ptex->damp);
CLAMP_PARTICLE_TEXTURE_POS(PAMAP_LENGTH, ptex->length);
}
/************************************************/
@@ -3689,7 +3770,7 @@ void psys_get_particle_on_path(ParticleSimulationData *sim, int p, ParticleKey *
}
else if (!keyed && !cached && !(psys->flag & PSYS_GLOBAL_HAIR)) {
if ((pa->flag & PARS_REKEY) == 0) {
- psys_mat_hair_to_global(sim->ob, sim->psmd->dm, part->from, pa, hairmat);
+ psys_mat_hair_to_global(sim->ob, sim->psmd->dm_final, part->from, pa, hairmat);
mul_m4_v3(hairmat, state->co);
mul_mat3_m4_v3(hairmat, state->vel);
@@ -3756,7 +3837,7 @@ void psys_get_particle_on_path(ParticleSimulationData *sim, int p, ParticleKey *
psys_particle_on_emitter(psmd, part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, par_co, 0, 0, 0, par_orco, 0);
if (part->type == PART_HAIR)
- psys_mat_hair_to_global(sim->ob, sim->psmd->dm, psys->part->from, pa, hairmat);
+ psys_mat_hair_to_global(sim->ob, sim->psmd->dm_final, psys->part->from, pa, hairmat);
else
unit_m4(hairmat);
@@ -3777,7 +3858,7 @@ void psys_get_particle_on_path(ParticleSimulationData *sim, int p, ParticleKey *
psys_particle_on_emitter(psmd, part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, par_co, 0, 0, 0, par_orco, 0);
if (part->type == PART_HAIR) {
psys_particle_on_emitter(psmd, cpa_from, cpa_num, DMCACHE_ISCHILD, cpa_fuv, pa->foffset, co, 0, 0, 0, orco, 0);
- psys_mat_hair_to_global(sim->ob, sim->psmd->dm, psys->part->from, pa, hairmat);
+ psys_mat_hair_to_global(sim->ob, sim->psmd->dm_final, psys->part->from, pa, hairmat);
}
else {
copy_v3_v3(orco, cpa->fuv);
@@ -3796,7 +3877,7 @@ void psys_get_particle_on_path(ParticleSimulationData *sim, int p, ParticleKey *
/* get different child parameters from textures & vgroups */
memset(&ctx, 0, sizeof(ParticleThreadContext));
ctx.sim = *sim;
- ctx.dm = psmd->dm;
+ ctx.dm = psmd->dm_final;
ctx.ma = ma;
/* TODO: assign vertex groups */
get_child_modifier_parameters(part, &ctx, cpa, cpa_from, cpa_num, cpa_fuv, orco, &ptex);
@@ -3832,23 +3913,23 @@ void psys_get_particle_on_path(ParticleSimulationData *sim, int p, ParticleKey *
copy_particle_key(&tstate, state, 1);
/* apply different deformations to the child path */
- do_child_modifiers(sim, &ptex, par->co, par->vel, par->rot, par_orco, cpa, orco, hairmat, state, t);
+ do_child_modifiers(NULL, sim, &ptex, par->co, par->vel, par->rot, par_orco, cpa, orco, hairmat, state, t);
/* try to estimate correct velocity */
if (vel) {
- ParticleKey tstate;
+ ParticleKey tstate_tmp;
float length = len_v3(state->vel);
if (t >= 0.001f) {
- tstate.time = t - 0.001f;
- psys_get_particle_on_path(sim, p, &tstate, 0);
- sub_v3_v3v3(state->vel, state->co, tstate.co);
+ tstate_tmp.time = t - 0.001f;
+ psys_get_particle_on_path(sim, p, &tstate_tmp, 0);
+ sub_v3_v3v3(state->vel, state->co, tstate_tmp.co);
normalize_v3(state->vel);
}
else {
- tstate.time = t + 0.001f;
- psys_get_particle_on_path(sim, p, &tstate, 0);
- sub_v3_v3v3(state->vel, tstate.co, state->co);
+ tstate_tmp.time = t + 0.001f;
+ psys_get_particle_on_path(sim, p, &tstate_tmp, 0);
+ sub_v3_v3v3(state->vel, tstate_tmp.co, state->co);
normalize_v3(state->vel);
}
@@ -3935,7 +4016,7 @@ int psys_get_particle_state(ParticleSimulationData *sim, int p, ParticleKey *sta
CLAMP(t, 0.0f, 1.0f);
unit_m4(mat);
- do_child_modifiers(sim, NULL, key1->co, key1->vel, key1->rot, par_orco, cpa, cpa->fuv, mat, state, t);
+ do_child_modifiers(NULL, sim, NULL, key1->co, key1->vel, key1->rot, par_orco, cpa, cpa->fuv, mat, state, t);
if (psys->lattice_deform_data)
calc_latt_deform(psys->lattice_deform_data, state->co, 1.0f);
@@ -4013,13 +4094,24 @@ void psys_get_dupli_texture(ParticleSystem *psys, ParticleSettings *part,
float loc[3];
int num;
+ /* XXX: on checking '(psmd->dm != NULL)'
+ * This is incorrect but needed for metaball evaluation.
+ * Ideally this would be calculated via the depsgraph, however with metaballs,
+ * the entire scenes dupli's are scanned, which also looks into uncalculated data.
+ *
+ * For now just include this workaround as an alternative to crashing,
+ * but longer term metaballs should behave in a more manageable way, see: T46622. */
+
uv[0] = uv[1] = 0.f;
if (cpa) {
- if (part->childtype == PART_CHILD_FACES) {
- mtface = CustomData_get_layer(&psmd->dm->faceData, CD_MTFACE);
+ if ((part->childtype == PART_CHILD_FACES) && (psmd->dm_final != NULL)) {
+ CustomData *mtf_data = psmd->dm_final->getTessFaceDataLayout(psmd->dm_final);
+ const int uv_idx = CustomData_get_render_layer(mtf_data, CD_MTFACE);
+ mtface = CustomData_get_layer_n(mtf_data, CD_MTFACE, uv_idx);
+
if (mtface) {
- mface = psmd->dm->getTessFaceData(psmd->dm, cpa->num, CD_MFACE);
+ mface = psmd->dm_final->getTessFaceData(psmd->dm_final, cpa->num, CD_MFACE);
mtface += cpa->num;
psys_interpolate_uvs(mtface, mface->v4, cpa->fuv, uv);
}
@@ -4032,21 +4124,24 @@ void psys_get_dupli_texture(ParticleSystem *psys, ParticleSettings *part,
}
}
- if (part->from == PART_FROM_FACE) {
- mtface = CustomData_get_layer(&psmd->dm->faceData, CD_MTFACE);
+ if ((part->from == PART_FROM_FACE) && (psmd->dm_final != NULL)) {
+ CustomData *mtf_data = psmd->dm_final->getTessFaceDataLayout(psmd->dm_final);
+ const int uv_idx = CustomData_get_render_layer(mtf_data, CD_MTFACE);
+ mtface = CustomData_get_layer_n(mtf_data, CD_MTFACE, uv_idx);
+
num = pa->num_dmcache;
if (num == DMCACHE_NOTFOUND)
num = pa->num;
- if (num >= psmd->dm->getNumTessFaces(psmd->dm)) {
+ if (num >= psmd->dm_final->getNumTessFaces(psmd->dm_final)) {
/* happens when simplify is enabled
* gives invalid coords but would crash otherwise */
num = DMCACHE_NOTFOUND;
}
if (mtface && !ELEM(num, DMCACHE_NOTFOUND, DMCACHE_ISCHILD)) {
- mface = psmd->dm->getTessFaceData(psmd->dm, num, CD_MFACE);
+ mface = psmd->dm_final->getTessFaceData(psmd->dm_final, num, CD_MFACE);
mtface += num;
psys_interpolate_uvs(mtface, mface->v4, pa->fuv, uv);
}
@@ -4221,7 +4316,7 @@ void psys_apply_hair_lattice(Scene *scene, Object *ob, ParticleSystem *psys)
float hairmat[4][4], imat[4][4];
for (p = 0; p < psys->totpart; p++, pa++) {
- psys_mat_hair_to_global(sim.ob, sim.psmd->dm, psys->part->from, pa, hairmat);
+ psys_mat_hair_to_global(sim.ob, sim.psmd->dm_final, psys->part->from, pa, hairmat);
invert_m4_m4(imat, hairmat);
hkey = pa->hair;