static void psys_uv_to_w(float u, float v, int quad, float *w)
{
	float vert[4][3], co[3];

	if (!quad) {
		if (u+v > 1.0f)
			v= 1.0f-v;
		else
			u= 1.0f-u;
	}

	vert[0][0] = 0.0f; vert[0][1] = 0.0f; vert[0][2] = 0.0f;
	vert[1][0] = 1.0f; vert[1][1] = 0.0f; vert[1][2] = 0.0f;
	vert[2][0] = 1.0f; vert[2][1] = 1.0f; vert[2][2] = 0.0f;

	co[0] = u;
	co[1] = v;
	co[2] = 0.0f;

	if (quad) {
		vert[3][0] = 0.0f; vert[3][1] = 1.0f; vert[3][2] = 0.0f;
		interp_weights_poly_v3( w,vert, 4, co);
	}
	else {
		interp_weights_poly_v3( w,vert, 3, co);
		w[3] = 0.0f;
	}
}
/* Adopted from BM_loop_interp_from_face(),
 *
 * Transform matrix is used in cases when target coordinate needs
 * to be converted to source space (namely when interpolating
 * boolean result loops from second operand).
 *
 * TODO(sergey): Consider making it a generic function in DerivedMesh.c.
 */
static void DM_loop_interp_from_poly(DerivedMesh *source_dm,
                                     MVert *source_mverts,
                                     MLoop *source_mloops,
                                     MPoly *source_poly,
                                     DerivedMesh *target_dm,
                                     MVert *target_mverts,
                                     MLoop *target_mloop,
                                     float transform[4][4],
                                     int target_loop_index)
{
	float (*cos_3d)[3] = BLI_array_alloca(cos_3d, source_poly->totloop);
	int *source_indices = BLI_array_alloca(source_indices, source_poly->totloop);
	float *weights = BLI_array_alloca(weights, source_poly->totloop);
	int i;
	int target_vert_index = target_mloop[target_loop_index].v;
	float coord[3];

	for (i = 0; i < source_poly->totloop; ++i) {
		MLoop *mloop = &source_mloops[source_poly->loopstart + i];
		source_indices[i] = source_poly->loopstart + i;
		copy_v3_v3(cos_3d[i], source_mverts[mloop->v].co);
	}

	if (transform) {
		mul_v3_m4v3(coord, transform, target_mverts[target_vert_index].co);
	}
	else {
		copy_v3_v3(coord, target_mverts[target_vert_index].co);
	}

	interp_weights_poly_v3(weights, cos_3d, source_poly->totloop, coord);

	DM_interp_loop_data(source_dm, target_dm, source_indices, weights,
	                    source_poly->totloop, target_loop_index);
}
Exemple #3
0
static MDefBoundIsect *meshdeform_ray_tree_intersect(MeshDeformBind *mdb, float *co1, float *co2)
{
	MDefBoundIsect *isect;
	MeshDeformIsect isec;
	float (*cagecos)[3];
	MFace *mface;
	float vert[4][3], len, end[3];
	static float epsilon[3]= {0, 0, 0}; //1e-4, 1e-4, 1e-4};

	/* setup isec */
	memset(&isec, 0, sizeof(isec));
	isec.labda= 1e10f;

	VECADD(isec.start, co1, epsilon);
	VECADD(end, co2, epsilon);
	sub_v3_v3v3(isec.vec, end, isec.start);

	if(meshdeform_intersect(mdb, &isec)) {
		len= isec.labda;
		mface=(MFace*)isec.face;

		/* create MDefBoundIsect */
		isect= BLI_memarena_alloc(mdb->memarena, sizeof(*isect));

		/* compute intersection coordinate */
		isect->co[0]= co1[0] + isec.vec[0]*len;
		isect->co[1]= co1[1] + isec.vec[1]*len;
		isect->co[2]= co1[2] + isec.vec[2]*len;

		isect->len= len_v3v3(co1, isect->co);
		if(isect->len < MESHDEFORM_LEN_THRESHOLD)
			isect->len= MESHDEFORM_LEN_THRESHOLD;

		isect->v[0]= mface->v1;
		isect->v[1]= mface->v2;
		isect->v[2]= mface->v3;
		isect->v[3]= mface->v4;
		isect->nvert= (mface->v4)? 4: 3;

		isect->facing= isec.isect;

		/* compute mean value coordinates for interpolation */
		cagecos= mdb->cagecos;
		copy_v3_v3(vert[0], cagecos[mface->v1]);
		copy_v3_v3(vert[1], cagecos[mface->v2]);
		copy_v3_v3(vert[2], cagecos[mface->v3]);
		if(mface->v4) copy_v3_v3(vert[3], cagecos[mface->v4]);
		interp_weights_poly_v3( isect->uvw,vert, isect->nvert, isect->co);

		return isect;
	}

	return NULL;
}
static MDefBoundIsect *meshdeform_ray_tree_intersect(MeshDeformBind *mdb, const float co1[3], const float co2[3])
{
	BVHTreeRayHit hit;
	MeshDeformIsect isect_mdef;
	struct MeshRayCallbackData data = {
		mdb,
		&isect_mdef,
	};
	float end[3], vec_normal[3];

	/* happens binding when a cage has no faces */
	if (UNLIKELY(mdb->bvhtree == NULL))
		return NULL;

	/* setup isec */
	memset(&isect_mdef, 0, sizeof(isect_mdef));
	isect_mdef.lambda = 1e10f;

	copy_v3_v3(isect_mdef.start, co1);
	copy_v3_v3(end, co2);
	sub_v3_v3v3(isect_mdef.vec, end, isect_mdef.start);
	isect_mdef.vec_length = normalize_v3_v3(vec_normal, isect_mdef.vec);

	hit.index = -1;
	hit.dist = BVH_RAYCAST_DIST_MAX;
	if (BLI_bvhtree_ray_cast(mdb->bvhtree, isect_mdef.start, vec_normal,
	                         0.0, &hit, harmonic_ray_callback, &data) != -1)
	{
		const MLoop *mloop = mdb->cagedm_cache.mloop;
		const MLoopTri *lt = &mdb->cagedm_cache.looptri[hit.index];
		const MPoly *mp = &mdb->cagedm_cache.mpoly[lt->poly];
		const float (*cagecos)[3] = mdb->cagecos;
		const float len = isect_mdef.lambda;
		MDefBoundIsect *isect;

		float (*mp_cagecos)[3] = BLI_array_alloca(mp_cagecos, mp->totloop);
		int i;

		/* create MDefBoundIsect, and extra for 'poly_weights[]' */
		isect = BLI_memarena_alloc(mdb->memarena, sizeof(*isect) + (sizeof(float) * mp->totloop));

		/* compute intersection coordinate */
		madd_v3_v3v3fl(isect->co, co1, isect_mdef.vec, len);

		isect->facing = isect_mdef.isect;

		isect->poly_index = lt->poly;

		isect->len = max_ff(len_v3v3(co1, isect->co), MESHDEFORM_LEN_THRESHOLD);

		/* compute mean value coordinates for interpolation */
		for (i = 0; i < mp->totloop; i++) {
			copy_v3_v3(mp_cagecos[i], cagecos[mloop[mp->loopstart + i].v]);
		}

		interp_weights_poly_v3(isect->poly_weights, mp_cagecos, mp->totloop, isect->co);

		return isect;
	}

	return NULL;
}
/* 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;
}
Exemple #6
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;
}