/* 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,
                               float from_mat[4][4], float to_mat[4][4], bool from_global, bool to_global)
{
	ParticleSystemModifierData *target_psmd = psys_get_modifier(target_ob, target_psys);
	ParticleData *pa, *tpa;
	PTCacheEditPoint *edit_point;
	PTCacheEditKey *ekey;
	BVHTreeFromMesh bvhtree= {NULL};
	MFace *mface = NULL, *mf;
	MEdge *medge = NULL, *me;
	MVert *mvert;
	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;
	if (!psys->part || psys->part->type != PART_HAIR)
		return false;
	if (!target_psys->part || target_psys->part->type != PART_HAIR)
		return false;
	
	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;
	}
	else {
		/* warning: this rebuilds target_psmd->dm! */
		dm = mesh_get_derived_deform(scene, target_ob, CD_MASK_BAREMESH | CD_MASK_MFACE);
	}
	target_dm = target_psmd->dm;
	/* don't modify the original vertices */
	dm = CDDM_copy(dm);

	/* BMESH_ONLY, deform dm may not have tessface */
	DM_ensure_tessface(dm);

	numverts = dm->getNumVerts(dm);
	mvert = dm->getVertArray(dm);

	/* convert to global coordinates */
	for (i=0; i<numverts; i++)
		mul_m4_v3(to_mat, mvert[i].co);

	if (dm->getNumTessFaces(dm) != 0) {
		mface = dm->getTessFaceArray(dm);
		bvhtree_from_mesh_faces(&bvhtree, dm, 0.0, 2, 6);
	}
	else if (dm->getNumEdges(dm) != 0) {
		medge = dm->getEdgeArray(dm);
		bvhtree_from_mesh_edges(&bvhtree, dm, 0.0, 2, 6);
	}
	else {
		dm->release(dm);
		return false;
	}

	for (i = 0, tpa = target_psys->particles, pa = psys->particles;
	     i < target_psys->totpart;
	     i++, tpa++, pa++) {

		float from_co[3];
		BVHTreeNearest nearest;

		if (from_global)
			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, from_co, &nearest, bvhtree.nearest_callback, &bvhtree);

		if (nearest.index == -1) {
			if (G.debug & G_DEBUG)
				printf("No nearest point found for hair root!");
			continue;
		}

		if (mface) {
			float v[4][3];
			
			mf = &mface[nearest.index];

			copy_v3_v3(v[0], mvert[mf->v1].co);
			copy_v3_v3(v[1], mvert[mf->v2].co);
			copy_v3_v3(v[2], mvert[mf->v3].co);
			if (mf->v4) {
				copy_v3_v3(v[3], mvert[mf->v4].co);
				interp_weights_poly_v3(tpa->fuv, v, 4, nearest.co);
			}
			else
				interp_weights_poly_v3(tpa->fuv, v, 3, nearest.co);
			tpa->foffset = 0.0f;

			tpa->num = nearest.index;
			tpa->num_dmcache = psys_particle_dm_face_lookup(target_ob, target_dm, tpa->num, tpa->fuv, NULL);
		}
		else {
			me = &medge[nearest.index];

			tpa->fuv[1] = line_point_factor_v3(nearest.co,
			                                   mvert[me->v1].co,
			                                   mvert[me->v2].co);
			tpa->fuv[0] = 1.0f - tpa->fuv[1];
			tpa->fuv[2] = tpa->fuv[3] = 0.0f;
			tpa->foffset = 0.0f;

			tpa->num = nearest.index;
			tpa->num_dmcache = -1;
		}

		/* translate hair keys */
		{
			HairKey *key, *tkey;
			float hairmat[4][4], imat[4][4];
			float offset[3];
			
			if (to_global)
				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, 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++) {
					float co_orig[3];
					
					if (from_global)
						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);
					
					mul_m4_v3(imat, tkey->co);
					
					ekey->flag |= PEK_USE_WCO;
				}
				
				edit_point++;
			}
			else {
				for (k=0, key=pa->hair, tkey=tpa->hair; k<tpa->totkey; k++, key++, tkey++) {
					float co_orig[3];
					
					if (from_global)
						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);
					
					mul_m4_v3(imat, tkey->co);
				}
			}
		}
	}

	free_bvhtree_from_mesh(&bvhtree);
	dm->release(dm);

	psys_free_path_cache(target_psys, target_edit);

	PE_update_object(scene, target_ob, 0);

	return true;
}
Esempio n. 2
0
static int connect_hair(Scene *scene, Object *ob, ParticleSystem *psys)
{
	ParticleSystemModifierData *psmd = psys_get_modifier(ob, psys);
	ParticleData *pa;
	PTCacheEdit *edit;
	PTCacheEditPoint *point;
	PTCacheEditKey *ekey = NULL;
	HairKey *key;
	BVHTreeFromMesh bvhtree= {NULL};
	BVHTreeNearest nearest;
	MFace *mface, *mf;
	MVert *mvert;
	DerivedMesh *dm = NULL;
	int numverts;
	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 || !psmd->dm)
		return FALSE;
	
	edit= psys->edit;
	point=  edit ? edit->points : NULL;
	
	if (psmd->dm->deformedOnly) {
		/* we don't want to mess up psmd->dm when converting to global coordinates below */
		dm = psmd->dm;
	}
	else {
		dm = mesh_get_derived_deform(scene, ob, CD_MASK_BAREMESH);
	}
	/* don't modify the original vertices */
	dm = CDDM_copy(dm);

	/* BMESH_ONLY, deform dm may not have tessface */
	DM_ensure_tessface(dm);

	numverts = dm->getNumVerts(dm);

	mvert = dm->getVertArray(dm);
	mface = dm->getTessFaceArray(dm);

	/* convert to global coordinates */
	for (i=0; i<numverts; i++)
		mul_m4_v3(ob->obmat, mvert[i].co);

	bvhtree_from_mesh_faces(&bvhtree, dm, 0.0, 2, 6);

	for (i=0, pa= psys->particles; 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) {
			if (G.debug & G_DEBUG)
				printf("No nearest point found for hair root!");
			continue;
		}

		mf = &mface[nearest.index];

		copy_v3_v3(v[0], mvert[mf->v1].co);
		copy_v3_v3(v[1], mvert[mf->v2].co);
		copy_v3_v3(v[2], mvert[mf->v3].co);
		if (mf->v4) {
			copy_v3_v3(v[3], mvert[mf->v4].co);
			interp_weights_poly_v3(pa->fuv, v, 4, nearest.co);
		}
		else
			interp_weights_poly_v3(pa->fuv, v, 3, nearest.co);

		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);
		invert_m4_m4(imat, hairmat);

		sub_v3_v3v3(vec, nearest.co, key->co);

		if (point) {
			ekey = point->keys;
			point++;
		}

		for (k=0, key=pa->hair; k<pa->totkey; k++, key++) {
			add_v3_v3(key->co, vec);
			mul_m4_v3(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);

	return TRUE;
}