diff options
author | Lukas Tönne <lukas.toenne@gmail.com> | 2015-01-15 22:36:51 +0300 |
---|---|---|
committer | Lukas Tönne <lukas.toenne@gmail.com> | 2015-01-20 11:30:11 +0300 |
commit | 04226e324ee7d761d8a77dfdca4abc3933864f15 (patch) | |
tree | b6e8c8e027af0fbea304c2770f59a10807d75982 /source/blender/editors | |
parent | 53135f91d2ed981ad78afee544f8ea6673f0a566 (diff) |
Added space selection option to the particle system copy operator.
By default this now copies from one object's local space to another
object's local space (instead of the previous world space). This is
more useful when transferring particles between objects, because it
doesn't require moving objects on top of each other, as long as they
have similar shapes.
Diffstat (limited to 'source/blender/editors')
-rw-r--r-- | source/blender/editors/physics/particle_object.c | 109 |
1 files changed, 88 insertions, 21 deletions
diff --git a/source/blender/editors/physics/particle_object.c b/source/blender/editors/physics/particle_object.c index 8c10b672e2d..b4a7b97d87c 100644 --- a/source/blender/editors/physics/particle_object.c +++ b/source/blender/editors/physics/particle_object.c @@ -90,6 +90,8 @@ extern void update_world_cos(Object *ob, PTCacheEdit *edit); #define KEY_WCO (key->flag & PEK_USE_WCO ? key->world_co : key->co) +static float I[4][4] = {{1.0f, 0.0f, 0.0f, 0.0f}, {0.0f, 1.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 1.0f, 0.0f}, {0.0f, 0.0f, 0.0f, 1.0f}}; + /********************** particle system slot operators *********************/ static int particle_system_add_exec(bContext *C, wmOperator *UNUSED(op)) @@ -649,9 +651,12 @@ void PARTICLE_OT_disconnect_hair(wmOperatorType *ot) RNA_def_boolean(ot->srna, "all", 0, "All hair", "Disconnect all hair systems from the emitter mesh"); } -static bool remap_hair_emitter(Scene *scene, Object *UNUSED(ob), ParticleSystem *psys, +/* from/to_world_space : whether from/to particles are in world or hair space + * from/to_mat : additional transform for from/to particles (e.g. for using object space copying) + */ +static bool remap_hair_emitter(Scene *scene, Object *ob, ParticleSystem *psys, Object *target_ob, ParticleSystem *target_psys, PTCacheEdit *target_edit, - bool from_world_space, bool to_world_space) + float from_mat[4][4], float to_mat[4][4]) { ParticleSystemModifierData *target_psmd = psys_get_modifier(target_ob, target_psys); ParticleData *pa, *tpa; @@ -664,6 +669,8 @@ static bool remap_hair_emitter(Scene *scene, Object *UNUSED(ob), ParticleSystem DerivedMesh *dm, *target_dm; int numverts; int i, k; + float from_ob_imat[4][4], to_ob_imat[4][4]; + float from_imat[4][4], to_imat[4][4]; if (!target_psmd->dm) return false; @@ -674,6 +681,11 @@ static bool remap_hair_emitter(Scene *scene, Object *UNUSED(ob), ParticleSystem edit_point = target_edit ? target_edit->points : NULL; + invert_m4_m4(from_ob_imat, ob->obmat); + invert_m4_m4(to_ob_imat, target_ob->obmat); + invert_m4_m4(from_imat, from_mat); + invert_m4_m4(to_imat, to_mat); + if (target_psmd->dm->deformedOnly) { /* we don't want to mess up target_psmd->dm when converting to global coordinates below */ dm = target_psmd->dm; @@ -694,7 +706,7 @@ static bool remap_hair_emitter(Scene *scene, Object *UNUSED(ob), ParticleSystem /* convert to global coordinates */ for (i=0; i<numverts; i++) - mul_m4_v3(target_ob->obmat, mvert[i].co); + mul_m4_v3(to_mat, mvert[i].co); if (dm->getNumTessFaces(dm) != 0) { mface = dm->getTessFaceArray(dm); @@ -713,13 +725,19 @@ static bool remap_hair_emitter(Scene *scene, Object *UNUSED(ob), ParticleSystem i < target_psys->totpart; i++, tpa++, pa++) { - const float *co = from_world_space ? pa->hair[0].co : pa->hair[0].world_co; + float from_co[3]; BVHTreeNearest nearest; + if (psys->flag & PSYS_GLOBAL_HAIR) + mul_v3_m4v3(from_co, from_ob_imat, pa->hair[0].co); + else + mul_v3_m4v3(from_co, from_ob_imat, pa->hair[0].world_co); + mul_m4_v3(from_mat, from_co); + nearest.index = -1; nearest.dist_sq = FLT_MAX; - BLI_bvhtree_find_nearest(bvhtree.tree, co, &nearest, bvhtree.nearest_callback, &bvhtree); + BLI_bvhtree_find_nearest(bvhtree.tree, from_co, &nearest, bvhtree.nearest_callback, &bvhtree); if (nearest.index == -1) { if (G.debug & G_DEBUG) @@ -766,20 +784,31 @@ static bool remap_hair_emitter(Scene *scene, Object *UNUSED(ob), ParticleSystem float hairmat[4][4], imat[4][4]; float offset[3]; - /* note: using target_dm here, which is in target_ob object space and has full modifiers */ - psys_mat_hair_to_global(target_ob, target_dm, target_psys->part->from, tpa, hairmat); - invert_m4_m4(imat, hairmat); + if (target_psys->flag & PSYS_GLOBAL_HAIR) + copy_m4_m4(imat, target_ob->obmat); + else { + /* note: using target_dm here, which is in target_ob object space and has full modifiers */ + psys_mat_hair_to_object(target_ob, target_dm, target_psys->part->from, tpa, hairmat); + invert_m4_m4(imat, hairmat); + } + mul_m4_m4m4(imat, imat, to_imat); /* offset in world space */ - sub_v3_v3v3(offset, nearest.co, co); + sub_v3_v3v3(offset, nearest.co, from_co); if (edit_point) { for (k=0, key=pa->hair, tkey=tpa->hair, ekey = edit_point->keys; k<tpa->totkey; k++, key++, tkey++, ekey++) { - const float *co_orig = from_world_space ? key->co : key->world_co; + float co_orig[3]; + + if (psys->flag & PSYS_GLOBAL_HAIR) + mul_v3_m4v3(co_orig, from_ob_imat, key->co); + else + mul_v3_m4v3(co_orig, from_ob_imat, key->world_co); + mul_m4_v3(from_mat, co_orig); add_v3_v3v3(tkey->co, co_orig, offset); - if (!to_world_space) - mul_m4_v3(imat, tkey->co); + + mul_m4_v3(imat, tkey->co); ekey->flag |= PEK_USE_WCO; } @@ -788,11 +817,17 @@ static bool remap_hair_emitter(Scene *scene, Object *UNUSED(ob), ParticleSystem } else { for (k=0, key=pa->hair, tkey=tpa->hair; k<tpa->totkey; k++, key++, tkey++) { - const float *co_orig = from_world_space ? key->co : key->world_co; + float co_orig[3]; + + if (psys->flag & PSYS_GLOBAL_HAIR) + mul_v3_m4v3(co_orig, from_ob_imat, key->co); + else + mul_v3_m4v3(co_orig, from_ob_imat, key->world_co); + mul_m4_v3(from_mat, co_orig); add_v3_v3v3(tkey->co, co_orig, offset); - if (!to_world_space) - mul_m4_v3(imat, tkey->co); + + mul_m4_v3(imat, tkey->co); } } } @@ -810,14 +845,15 @@ static bool remap_hair_emitter(Scene *scene, Object *UNUSED(ob), ParticleSystem static bool connect_hair(Scene *scene, Object *ob, ParticleSystem *psys) { - const bool from_global = psys->flag & PSYS_GLOBAL_HAIR; - const bool to_global = false; + float (*from_mat)[4] = psys->flag & PSYS_GLOBAL_HAIR ? I : ob->obmat; + float (*to_mat)[4] = ob->obmat; if (!psys) return false; psys->flag &= ~PSYS_GLOBAL_HAIR; - return remap_hair_emitter(scene, ob, psys, ob, psys, psys->edit, from_global, to_global); + + return remap_hair_emitter(scene, ob, psys, ob, psys, psys->edit, from_mat, to_mat); } static int connect_hair_exec(bContext *C, wmOperator *op) @@ -869,6 +905,11 @@ void PARTICLE_OT_connect_hair(wmOperatorType *ot) /************************ particle system copy operator *********************/ +typedef enum eCopyParticlesSpace { + PAR_COPY_SPACE_OBJECT = 0, + PAR_COPY_SPACE_WORLD = 1, +} eCopyParticlesSpace; + static void copy_particle_edit(Scene *scene, Object *ob, ParticleSystem *psys, ParticleSystem *psys_from) { PTCacheEdit *edit_from = psys_from->edit, *edit; @@ -925,7 +966,7 @@ static void copy_particle_edit(Scene *scene, Object *ob, ParticleSystem *psys, P PE_undo_push(scene, "Original"); } -static bool copy_particle_systems_to_object(Scene *scene, Object *ob_from, Object *ob_to) +static bool copy_particle_systems_to_object(Scene *scene, Object *ob_from, Object *ob_to, int space) { ModifierData *md, *md_next; ParticleSystem *psys, *psys_from; @@ -997,7 +1038,24 @@ static bool copy_particle_systems_to_object(Scene *scene, Object *ob_from, Objec psys; psys = psys->next, psys_from = psys_from->next, ++i) { - remap_hair_emitter(scene, ob_from, psys_from, ob_to, psys, psys->edit, false, false); + float (*from_mat)[4], (*to_mat)[4]; + + switch (space) { + case PAR_COPY_SPACE_OBJECT: + from_mat = I; + to_mat = I; + break; + case PAR_COPY_SPACE_WORLD: + from_mat = ob_from->obmat; + to_mat = ob_to->obmat; + break; + default: + /* should not happen */ + BLI_assert(false); + break; + } + + remap_hair_emitter(scene, ob_from, psys_from, ob_to, psys, psys->edit, from_mat, to_mat); /* tag for recalc */ // psys->recalc |= PSYS_RECALC_RESET; @@ -1025,6 +1083,7 @@ static int copy_particle_systems_exec(bContext *C, wmOperator *op) { Object *ob_from = ED_object_active_context(C); Scene *scene = CTX_data_scene(C); + const int space = RNA_enum_get(op->ptr, "space"); int changed_tot = 0; int fail = 0; @@ -1032,7 +1091,7 @@ static int copy_particle_systems_exec(bContext *C, wmOperator *op) CTX_DATA_BEGIN (C, Object *, ob_to, selected_editable_objects) { if (ob_from != ob_to) { - if (copy_particle_systems_to_object(scene, ob_from, ob_to)) + if (copy_particle_systems_to_object(scene, ob_from, ob_to, space)) changed_tot++; else fail++; @@ -1051,6 +1110,12 @@ static int copy_particle_systems_exec(bContext *C, wmOperator *op) void PARTICLE_OT_copy_particle_systems(wmOperatorType *ot) { + static EnumPropertyItem space_items[] = { + {PAR_COPY_SPACE_OBJECT, "OBJECT", 0, "Object", "Copy inside each object's local space"}, + {PAR_COPY_SPACE_WORLD, "WORLD", 0, "World", "Copy in world space"}, + {0, NULL, 0, NULL, NULL} + }; + ot->name = "Copy Particle Systems"; ot->description = "Copy particle systems from the active object to selected objects"; ot->idname = "PARTICLE_OT_copy_particle_systems"; @@ -1060,4 +1125,6 @@ void PARTICLE_OT_copy_particle_systems(wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + RNA_def_enum(ot->srna, "space", space_items, PAR_COPY_SPACE_OBJECT, "Space", "Space transform for copying from one object to another"); } |