Disconnect/connect hair:

- Moves hair from face-space to global space and back.
- Allows for editing of emitter mesh after hair combing.
- Disconnect hair before doing topology changing changes in mesh edit mode, connect after changes.
- Notes:
	* The closest location on emitter surface to the hair root is used to connect the hair.
	* Emitter deflection, sticky roots and add brush don't apply for disconnect hair in particle mode.
- Todo for future:
	* Copy disconnected hair from object to another (when 2.5 has proper copy operators again).
	* Possible automatic disconnect/connect with topology changing operations in mesh edit mode.
	
Other changes/fixes:
- Proper subtypes for some particle mode notifiers.
- Particle mode selections didn't draw correctly because of using lighting for the paths.
This commit is contained in:
2009-09-05 20:12:08 +00:00
parent 05c44056dc
commit 08b8fc34cf
13 changed files with 294 additions and 43 deletions

View File

@@ -85,6 +85,8 @@ void PARTICLE_OT_new_target(struct wmOperatorType *ot);
void PARTICLE_OT_remove_target(struct wmOperatorType *ot);
void PARTICLE_OT_target_move_up(struct wmOperatorType *ot);
void PARTICLE_OT_target_move_down(struct wmOperatorType *ot);
void PARTICLE_OT_connect_hair(struct wmOperatorType *ot);
void PARTICLE_OT_disconnect_hair(struct wmOperatorType *ot);
void SCENE_OT_render_layer_add(struct wmOperatorType *ot);
void SCENE_OT_render_layer_remove(struct wmOperatorType *ot);

View File

@@ -35,6 +35,8 @@
#include "DNA_group_types.h"
#include "DNA_object_types.h"
#include "DNA_material_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_modifier_types.h"
#include "DNA_node_types.h"
#include "DNA_texture_types.h"
#include "DNA_scene_types.h"
@@ -42,8 +44,11 @@
#include "DNA_space_types.h"
#include "DNA_world_types.h"
#include "BKE_bvhutils.h"
#include "BKE_cdderivedmesh.h"
#include "BKE_context.h"
#include "BKE_depsgraph.h"
#include "BKE_DerivedMesh.h"
#include "BKE_group.h"
#include "BKE_font.h"
#include "BKE_library.h"
@@ -51,11 +56,13 @@
#include "BKE_material.h"
#include "BKE_node.h"
#include "BKE_particle.h"
#include "BKE_pointcache.h"
#include "BKE_scene.h"
#include "BKE_texture.h"
#include "BKE_utildefines.h"
#include "BKE_world.h"
#include "BLI_arithb.h"
#include "BLI_editVert.h"
#include "BLI_listbase.h"
@@ -838,6 +845,217 @@ void PARTICLE_OT_target_move_down(wmOperatorType *ot)
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
}
/************************ connect/disconnect hair operators *********************/
static void disconnect_hair(Scene *scene, Object *ob, ParticleSystem *psys)
{
ParticleSystemModifierData *psmd = psys_get_modifier(ob,psys);
ParticleData *pa = psys->particles;
PTCacheEdit *edit = psys->edit;
PTCacheEditPoint *point = edit ? edit->points : NULL;
PTCacheEditKey *ekey = NULL;
HairKey *key;
int i, k;
float hairmat[4][4];
if(!ob || !psys || psys->flag & PSYS_GLOBAL_HAIR)
return;
if(!psys->part || psys->part->type != PART_HAIR)
return;
for(i=0; i<psys->totpart; i++,pa++) {
if(point) {
ekey = point->keys;
point++;
}
psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, pa, hairmat);
for(k=0,key=pa->hair; k<pa->totkey; k++,key++) {
Mat4MulVecfl(hairmat,key->co);
if(ekey) {
ekey->flag &= ~PEK_USE_WCO;
ekey++;
}
}
}
psys_free_path_cache(psys, psys->edit);
psys->flag |= PSYS_GLOBAL_HAIR;
PE_update_object(scene, ob, 0);
}
static int disconnect_hair_exec(bContext *C, wmOperator *op)
{
Scene *scene= CTX_data_scene(C);
Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
ParticleSystem *psys= NULL;
int all = RNA_boolean_get(op->ptr, "all");
if(!ob)
return OPERATOR_CANCELLED;
if(all) {
for(psys=ob->particlesystem.first; psys; psys=psys->next) {
disconnect_hair(scene, ob, psys);
}
}
else {
psys = ptr.data;
disconnect_hair(scene, ob, psys);
}
WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
return OPERATOR_FINISHED;
}
void PARTICLE_OT_disconnect_hair(wmOperatorType *ot)
{
ot->name= "Disconnect Hair";
ot->description= "Disconnect hair from the emitter mesh.";
ot->idname= "PARTICLE_OT_disconnect_hair";
ot->exec= disconnect_hair_exec;
/* flags */
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
RNA_def_boolean(ot->srna, "all", 0, "All hair", "Disconnect all hair systems from the emitter mesh");
}
static void connect_hair(Scene *scene, Object *ob, ParticleSystem *psys)
{
ParticleSystemModifierData *psmd = psys_get_modifier(ob,psys);
ParticleData *pa = psys->particles;
PTCacheEdit *edit = psys->edit;
PTCacheEditPoint *point = edit ? edit->points : NULL;
PTCacheEditKey *ekey;
HairKey *key;
BVHTreeFromMesh bvhtree;
BVHTreeNearest nearest;
MFace *mface;
DerivedMesh *dm = CDDM_copy(psmd->dm);
int numverts = dm->getNumVerts (dm);
int i, k;
float hairmat[4][4], imat[4][4];
float v[4][3], vec[3];
if(!psys || !psys->part || psys->part->type != PART_HAIR)
return;
memset( &bvhtree, 0, sizeof(bvhtree) );
/* convert to global coordinates */
for (i=0; i<numverts; i++)
Mat4MulVecfl (ob->obmat, CDDM_get_vert(dm, i)->co);
bvhtree_from_mesh_faces(&bvhtree, dm, 0.0, 2, 6);
for(i=0; i<psys->totpart; i++,pa++) {
key = pa->hair;
nearest.index = -1;
nearest.dist = FLT_MAX;
BLI_bvhtree_find_nearest(bvhtree.tree, key->co, &nearest, bvhtree.nearest_callback, &bvhtree);
if(nearest.index == -1) {
printf("No nearest point found for hair root!");
continue;
}
mface = CDDM_get_face(dm,nearest.index);
VecCopyf(v[0], CDDM_get_vert(dm,mface->v1)->co);
VecCopyf(v[1], CDDM_get_vert(dm,mface->v2)->co);
VecCopyf(v[2], CDDM_get_vert(dm,mface->v3)->co);
if(mface->v4) {
VecCopyf(v[3], CDDM_get_vert(dm,mface->v4)->co);
MeanValueWeights(v, 4, nearest.co, pa->fuv);
}
else
MeanValueWeights(v, 3, nearest.co, pa->fuv);
pa->num = nearest.index;
pa->num_dmcache = psys_particle_dm_face_lookup(ob,psmd->dm,pa->num,pa->fuv,NULL);
psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, pa, hairmat);
Mat4Invert(imat,hairmat);
VECSUB(vec, nearest.co, key->co);
if(point) {
ekey = point->keys;
point++;
}
for(k=0,key=pa->hair; k<pa->totkey; k++,key++) {
VECADD(key->co, key->co, vec);
Mat4MulVecfl(imat,key->co);
if(ekey) {
ekey->flag |= PEK_USE_WCO;
ekey++;
}
}
}
free_bvhtree_from_mesh(&bvhtree);
dm->release(dm);
psys_free_path_cache(psys, psys->edit);
psys->flag &= ~PSYS_GLOBAL_HAIR;
PE_update_object(scene, ob, 0);
}
static int connect_hair_exec(bContext *C, wmOperator *op)
{
Scene *scene= CTX_data_scene(C);
Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
ParticleSystem *psys= NULL;
int all = RNA_boolean_get(op->ptr, "all");
if(!ob)
return OPERATOR_CANCELLED;
if(all) {
for(psys=ob->particlesystem.first; psys; psys=psys->next) {
connect_hair(scene, ob, psys);
}
}
else {
psys = ptr.data;
connect_hair(scene, ob, psys);
}
WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
return OPERATOR_FINISHED;
}
void PARTICLE_OT_connect_hair(wmOperatorType *ot)
{
ot->name= "Connect Hair";
ot->description= "Connect hair to the emitter mesh.";
ot->idname= "PARTICLE_OT_connect_hair";
ot->exec= connect_hair_exec;
/* flags */
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
RNA_def_boolean(ot->srna, "all", 0, "All hair", "Connect all hair systems to the emitter mesh");
}
/********************** render layer operators *********************/
static int render_layer_add_exec(bContext *C, wmOperator *op)

View File

@@ -204,6 +204,8 @@ void buttons_operatortypes(void)
WM_operatortype_append(PARTICLE_OT_remove_target);
WM_operatortype_append(PARTICLE_OT_target_move_up);
WM_operatortype_append(PARTICLE_OT_target_move_down);
WM_operatortype_append(PARTICLE_OT_connect_hair);
WM_operatortype_append(PARTICLE_OT_disconnect_hair);
WM_operatortype_append(SCENE_OT_render_layer_add);
WM_operatortype_append(SCENE_OT_render_layer_remove);