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); }
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; }
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; }