diff options
author | Andre Susano Pinto <andresusanopinto@gmail.com> | 2008-07-25 22:48:24 +0400 |
---|---|---|
committer | Andre Susano Pinto <andresusanopinto@gmail.com> | 2008-07-25 22:48:24 +0400 |
commit | 1537e75cba4df5604b695be54bbae724df5d4095 (patch) | |
tree | ae4dfe556f4d0a952a03dd453a8d66debb83aed6 /source/blender | |
parent | aec6b78deda32d7aa1631ec76efda5bcea83a8c9 (diff) |
Converted shrinkwrap to a DeformOnly modifier
*the options "remove faces", "merge" points were removed
*made shrinkwrap work with CVs (curves and nurbs surfaces)
*cleanup shrinkwrap code.. (removed bruteforces and raytree methods)
Diffstat (limited to 'source/blender')
-rw-r--r-- | source/blender/blenkernel/BKE_shrinkwrap.h | 20 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/modifier.c | 31 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/shrinkwrap.c | 581 | ||||
-rw-r--r-- | source/blender/makesdna/DNA_modifier_types.h | 4 | ||||
-rw-r--r-- | source/blender/src/buttons_editing.c | 26 |
5 files changed, 169 insertions, 493 deletions
diff --git a/source/blender/blenkernel/BKE_shrinkwrap.h b/source/blender/blenkernel/BKE_shrinkwrap.h index f84b8fb6ec4..739027fc95f 100644 --- a/source/blender/blenkernel/BKE_shrinkwrap.h +++ b/source/blender/blenkernel/BKE_shrinkwrap.h @@ -53,7 +53,8 @@ typedef struct SpaceTransform } SpaceTransform; -void space_transform_setup(SpaceTransform *data, struct Object *local, struct Object *target); +void space_transform_from_matrixs(SpaceTransform *data, float local[][4], float target[][4]); +#define space_transform_setup(data, local, target) space_transform_from_matrixs(data, (local)->obmat, (target)->obmat) void space_transform_apply (const SpaceTransform *data, float *co); void space_transform_invert(const SpaceTransform *data, float *co); @@ -93,8 +94,7 @@ struct BVHTree* bvhtree_from_mesh_verts(struct BVHTreeFromMesh *data, struct Der // Builds a bvh tree where nodes are the faces of the given mesh. And configures BVHMesh if one is given. struct BVHTree* bvhtree_from_mesh_faces(struct BVHTreeFromMesh *data, struct DerivedMesh *mesh, float epsilon, int tree_type, int axis); - - +int normal_projection_project_vertex(char options, const float *vert, const float *dir, const SpaceTransform *transf, BVHTree *tree, BVHTreeRayHit *hit, BVHTree_RayCastCallback callback, void *userdata); /* Shrinkwrap stuff */ struct Object; @@ -109,18 +109,15 @@ typedef struct ShrinkwrapCalcData ShrinkwrapModifierData *smd; //shrinkwrap modifier data struct Object *ob; //object we are applying shrinkwrap to - struct DerivedMesh *original; //mesh before shrinkwrap (TODO clean this variable.. we don't really need it) - struct BVHTree *original_tree; //BVHTree build with the original mesh (to be used on kept volume) - struct BVHMeshCallbackUserdata *callback; + struct DerivedMesh *original; //mesh before shrinkwrap - struct DerivedMesh *final; //initially a copy of original mesh.. mesh thats going to be shrinkwrapped + float (*vertexCos)[3]; //vertexs being shrinkwraped + int numVerts; - struct DerivedMesh *target; //mesh we are shrinking to - - SpaceTransform local2target; + struct DerivedMesh *target; //mesh we are shrinking to + SpaceTransform local2target; //transform to move bettwem local and target space float keptDist; //Distance to kept from target (units are in local space) - //float *weights; //weights of vertexs BitSet moved; //BitSet indicating if vertex has moved } ShrinkwrapCalcData; @@ -130,6 +127,7 @@ void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *data); void shrinkwrap_calc_nearest_surface_point(ShrinkwrapCalcData *data); struct DerivedMesh *shrinkwrapModifier_do(struct ShrinkwrapModifierData *smd, struct Object *ob, struct DerivedMesh *dm, int useRenderParams, int isFinalCalc); +void shrinkwrapModifier_deform(struct ShrinkwrapModifierData *smd, struct Object *ob, struct DerivedMesh *dm, float (*vertexCos)[3], int numVerts); #endif diff --git a/source/blender/blenkernel/intern/modifier.c b/source/blender/blenkernel/intern/modifier.c index 124474ca09c..502be6b3af3 100644 --- a/source/blender/blenkernel/intern/modifier.c +++ b/source/blender/blenkernel/intern/modifier.c @@ -7198,7 +7198,6 @@ static void shrinkwrapModifier_initData(ModifierData *md) smd->shrinkType = MOD_SHRINKWRAP_NEAREST_SURFACE; smd->shrinkOpts = MOD_SHRINKWRAP_ALLOW_DEFAULT_NORMAL; smd->keptDist = 0.0f; - smd->mergeDist = 0.0f; smd->target = 0; smd->cutPlane = 0; @@ -7213,7 +7212,6 @@ static void shrinkwrapModifier_copyData(ModifierData *md, ModifierData *target) tsmd->cutPlane = smd->cutPlane; strcpy(tsmd->vgroup_name, smd->vgroup_name); tsmd->keptDist = smd->keptDist; - tsmd->mergeDist = smd->mergeDist; tsmd->shrinkType = smd->shrinkType; tsmd->shrinkOpts = smd->shrinkOpts; } @@ -7243,7 +7241,7 @@ static void shrinkwrapModifier_foreachObjectLink(ModifierData *md, Object *ob, O walk(userData, ob, &smd->target); walk(userData, ob, &smd->cutPlane); } - +/* static DerivedMesh *shrinkwrapModifier_applyModifier(ModifierData *md, Object *ob, DerivedMesh *derivedData, int useRenderParams, int isFinalCalc) { return shrinkwrapModifier_do((ShrinkwrapModifierData*)md,ob,derivedData,useRenderParams,isFinalCalc); @@ -7253,6 +7251,26 @@ static DerivedMesh *shrinkwrapModifier_applyModifierEM(ModifierData *md, Object { return shrinkwrapModifier_do((ShrinkwrapModifierData*)md,ob,derivedData,0,0); } +*/ +static void shrinkwrapModifier_deformVerts(ModifierData *md, Object *ob, DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts) +{ + shrinkwrapModifier_deform((ShrinkwrapModifierData*)md, ob, derivedData, vertexCos, numVerts); +} + +static void shrinkwrapModifier_deformVertsEM(ModifierData *md, Object *ob, EditMesh *editData, DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts) +{ + DerivedMesh *dm; + + if(!derivedData && ob->type == OB_MESH) + dm = CDDM_from_editmesh(editData, ob->data); + else + dm = CDDM_copy(derivedData); //TODO: this is only needed if derevedData doenst supports getVertexArray + + shrinkwrapModifier_deform((ShrinkwrapModifierData*)md, ob, dm, vertexCos, numVerts); + + if(dm != derivedData) + dm->release(dm); +} static void shrinkwrapModifier_updateDepgraph(ModifierData *md, DagForest *forest, Object *ob, DagNode *obNode) { @@ -7645,8 +7663,9 @@ ModifierTypeInfo *modifierType_getInfo(ModifierType type) mti->applyModifier = explodeModifier_applyModifier; mti = INIT_TYPE(Shrinkwrap); - mti->type = eModifierTypeType_Nonconstructive; + mti->type = eModifierTypeType_OnlyDeform; mti->flags = eModifierTypeFlag_AcceptsMesh + | eModifierTypeFlag_AcceptsCVs | eModifierTypeFlag_SupportsEditmode | eModifierTypeFlag_EnableInEditmode; @@ -7655,8 +7674,8 @@ ModifierTypeInfo *modifierType_getInfo(ModifierType type) mti->requiredDataMask = shrinkwrapModifier_requiredDataMask; mti->isDisabled = shrinkwrapModifier_isDisabled; mti->foreachObjectLink = shrinkwrapModifier_foreachObjectLink; - mti->applyModifier = shrinkwrapModifier_applyModifier; - mti->applyModifierEM = shrinkwrapModifier_applyModifierEM; + mti->deformVerts = shrinkwrapModifier_deformVerts; + mti->deformVertsEM = shrinkwrapModifier_deformVertsEM; mti->updateDepgraph = shrinkwrapModifier_updateDepgraph; mti = INIT_TYPE(SimpleDeform); diff --git a/source/blender/blenkernel/intern/shrinkwrap.c b/source/blender/blenkernel/intern/shrinkwrap.c index 648071b2c9f..53051b3cfd7 100644 --- a/source/blender/blenkernel/intern/shrinkwrap.c +++ b/source/blender/blenkernel/intern/shrinkwrap.c @@ -136,10 +136,11 @@ static float sphereray_tri_intersection(const BVHTreeRay *ray, float radius, con } /* Space transform */ -void space_transform_setup(SpaceTransform *data, struct Object *local, struct Object *target) +void space_transform_from_matrixs(SpaceTransform *data, float local[4][4], float target[4][4]) { - Mat4Invert(target->imat, target->obmat); //Invserse might be outdated - Mat4MulSerie(data->local2target, target->imat, local->obmat, 0, 0, 0, 0, 0, 0); + float itarget[4][4]; + Mat4Invert(itarget, target); //Invserse might be outdated + Mat4MulSerie(data->local2target, itarget, local, 0, 0, 0, 0, 0, 0); Mat4Invert(data->target2local, data->local2target); } @@ -348,142 +349,9 @@ static void mesh_faces_spherecast(void *userdata, int index, const BVHTreeRay *r t3 = NULL; } while(t2); - - //return hit->dist; } -/* - * Raytree from mesh - */ -static MVert *raytree_from_mesh_verts = NULL; -static MFace *raytree_from_mesh_faces = NULL; - -static int raytree_check_always(Isect *is, int ob, RayFace *face) -{ - return TRUE; -} -static void raytree_from_mesh_get_coords(RayFace *face, float **v1, float **v2, float **v3, float **v4) -{ - MFace *mface= raytree_from_mesh_faces + (int)face/2 - 1 ; - - if(face == (RayFace*)(-1)) - { - *v1 = NULL; - *v2 = NULL; - *v3 = NULL; - *v4 = NULL; - return; - } - - //Nasty quad splitting - if(((int)face) & 1) // we want the 2 triangle of the quad - { - *v1= raytree_from_mesh_verts[mface->v1].co; - *v2= raytree_from_mesh_verts[mface->v3].co; - *v3= raytree_from_mesh_verts[mface->v4].co; - *v4= NULL; - } - else - { - *v1= raytree_from_mesh_verts[mface->v1].co; - *v2= raytree_from_mesh_verts[mface->v2].co; - *v3= raytree_from_mesh_verts[mface->v3].co; - *v4= NULL; - } -} - -/* - * Creates a raytree from the given mesh - * No copy of the mesh is done, so it must exist and remain - * imutable as long the tree is intended to be used - * - * No more than 1 raytree can exist.. since this code uses a static variable - * to pass data to raytree_from_mesh_get_coords - */ -static RayTree* raytree_create_from_mesh(DerivedMesh *mesh) -{ - int i; - float min[3], max[3]; - - RayTree*tree= NULL; - - int numFaces= mesh->getNumFaces(mesh); - MFace *face = mesh->getFaceDataArray(mesh, CD_MFACE); - int numVerts= mesh->getNumVerts(mesh); - - //Initialize static vars - raytree_from_mesh_verts = mesh->getVertDataArray(mesh, CD_MVERT); - raytree_from_mesh_faces = face; - - - //calculate bounding box - INIT_MINMAX(min, max); - - for(i=0; i<numVerts; i++) - DO_MINMAX(raytree_from_mesh_verts[i].co, min, max); - - tree = RE_ray_tree_create(64, numFaces, min, max, raytree_from_mesh_get_coords, raytree_check_always, NULL, NULL); - if(tree == NULL) - return NULL; - - //Add faces to the RayTree (RayTree uses face=0, with some special value to setup things) - for(i=1; i<=numFaces; i++) - { - RE_ray_tree_add_face(tree, 0, (RayFace*)(i*2) ); - - //Theres some nasty thing with non-coplanar quads (that I can't find the issue) - //so we split quads (an odd numbered face represents the second triangle of the quad) - if(face[i-1].v4) - RE_ray_tree_add_face(tree, 0, (RayFace*)(i*2+1)); - } - - RE_ray_tree_done(tree); - - return tree; -} - -static void free_raytree_from_mesh(RayTree *tree) -{ - raytree_from_mesh_verts = NULL; - RE_ray_tree_free(tree); -} - -/* - * Cast a ray on the specified direction - * Returns the distance the ray must travel until intersect something - * Returns FLT_MAX in case of nothing intersection - * if facenormal is given, it will be overwritted with the normal of the face the ray collided with - */ -static float raytree_cast_ray(RayTree *tree, const float *coord, const float *direction, float *facenormal) -{ - Isect isec; - float *v1, *v2, *v3, *v4; - - /* Setup intersection */ - isec.mode = RE_RAY_MIRROR; /* We want closest intersection */ - isec.lay = -1; - isec.face_last = NULL; - isec.faceorig = (RayFace*)(-1); - isec.labda = 1e10f; - - VECCOPY(isec.start, coord); - VECCOPY(isec.vec, direction); - VECADDFAC(isec.end, isec.start, isec.vec, isec.labda); - - if(!RE_ray_tree_intersect(tree, &isec)) - return FLT_MAX; - - if(facenormal) - { - raytree_from_mesh_get_coords( isec.face, &v1, &v2, &v3, &v4); - CalcNormFloat(v1, v2, v3, facenormal); - } - - isec.labda = ABS(isec.labda); - VECADDFAC(isec.end, isec.start, isec.vec, isec.labda); - return VecLenf((float*)coord, (float*)isec.end); -} /* * Returns the squared distance between two given points @@ -760,174 +628,6 @@ static float nearest_point_in_tri_surface(const float *point, const float *v0, c return plane_sdist + normal_dist*normal_dist; } - - -/* - * Shrink to nearest surface point on target mesh - */ -static void bruteforce_shrinkwrap_calc_nearest_surface_point(DerivedMesh *target, float *co, float *unused) -{ - float minDist = FLT_MAX; - float orig_co[3]; - - int i; - int numFaces = target->getNumFaces(target); - MVert *vert = target->getVertDataArray(target, CD_MVERT); - MFace *face = target->getFaceDataArray(target, CD_MFACE); - - VECCOPY(orig_co, co); - - for (i = 0; i < numFaces; i++) - { - float *v0, *v1, *v2, *v3; - - v0 = vert[ face[i].v1 ].co; - v1 = vert[ face[i].v2 ].co; - v2 = vert[ face[i].v3 ].co; - v3 = face[i].v4 ? vert[ face[i].v4 ].co : 0; - - while(v2) - { - float dist; - float tmp[3]; - - dist = nearest_point_in_tri_surface(orig_co, v0, v1, v2, tmp); - - if(dist < minDist) - { - minDist = dist; - VECCOPY(co, tmp); - } - - v1 = v2; - v2 = v3; - v3 = 0; - } - } -} - -/* - * Projects the vertex on the normal direction over the target mesh - */ -static void bruteforce_shrinkwrap_calc_normal_projection(DerivedMesh *target, float *co, float *vnormal) -{ - //TODO: this should use raycast code probably existent in blender - float minDist = FLT_MAX; - float orig_co[3]; - - int i; - int numFaces = target->getNumFaces(target); - MVert *vert = target->getVertDataArray(target, CD_MVERT); - MFace *face = target->getFaceDataArray(target, CD_MFACE); - - VECCOPY(orig_co, co); - - for (i = 0; i < numFaces; i++) - { - float *v0, *v1, *v2, *v3; - - v0 = vert[ face[i].v1 ].co; - v1 = vert[ face[i].v2 ].co; - v2 = vert[ face[i].v3 ].co; - v3 = face[i].v4 ? vert[ face[i].v4 ].co : 0; - - while(v2) - { - float dist; - float pnormal[3]; - - CalcNormFloat(v0, v1, v2, pnormal); - dist = ray_intersect_plane(orig_co, vnormal, v0, pnormal); - - if(fabs(dist) < minDist) - { - float tmp[3], nearest[3]; - VECADDFAC(tmp, orig_co, vnormal, dist); - - if( fabs(nearest_point_in_tri_surface(tmp, v0, v1, v2, nearest)) < 0.0001) - { - minDist = fabs(dist); - VECCOPY(co, nearest); - } - } - v1 = v2; - v2 = v3; - v3 = 0; - } - } -} - -/* - * Shrink to nearest vertex on target mesh - */ -static void bruteforce_shrinkwrap_calc_nearest_vertex(DerivedMesh *target, float *co, float *unused) -{ - float minDist = FLT_MAX; - float orig_co[3]; - - int i; - int numVerts = target->getNumVerts(target); - MVert *vert = target->getVertDataArray(target, CD_MVERT); - - VECCOPY(orig_co, co); - - for (i = 0; i < numVerts; i++) - { - float sdist = squared_dist( orig_co, vert[i].co); - - if(sdist < minDist) - { - minDist = sdist; - VECCOPY(co, vert[i].co); - } - } -} - - -static void shrinkwrap_calc_foreach_vertex(ShrinkwrapCalcData *calc, Shrinkwrap_ForeachVertexCallback callback) -{ - int i; - int vgroup = get_named_vertexgroup_num(calc->ob, calc->smd->vgroup_name); - int numVerts = 0; - - MDeformVert *dvert = NULL; - MVert *vert = NULL; - - numVerts = calc->final->getNumVerts(calc->final); - dvert = calc->final->getVertDataArray(calc->final, CD_MDEFORMVERT); - vert = calc->final->getVertDataArray(calc->final, CD_MVERT); - - //Shrink (calculate each vertex final position) - for(i = 0; i<numVerts; i++) - { - float weight = vertexgroup_get_vertex_weight(dvert, i, vgroup); - - float final[3]; //Coords relative to target - float normal[3]; - float dist; - - if(weight == 0.0f) continue; //Skip vertexs where we have no influence - - VECCOPY(final, vert[i].co); - space_transform_apply(&calc->local2target, final); - - //We also need to apply the rotation to normal - if(calc->smd->shrinkType == MOD_SHRINKWRAP_NORMAL) - { - NormalShortToFloat(normal, vert[i].no); - space_transform_apply_normal(&calc->local2target, normal); - } - (callback)(calc->target, final, normal); - - space_transform_invert(&calc->local2target, final); - - dist = VecLenf(vert[i].co, final); - if(dist > 1e-5) weight *= (dist - calc->keptDist)/dist; - VecLerpf(vert[i].co, vert[i].co, final, weight); //linear interpolation - } -} - - /* * This function removes Unused faces, vertexs and edges from calc->target * @@ -936,6 +636,7 @@ static void shrinkwrap_calc_foreach_vertex(ShrinkwrapCalcData *calc, Shrinkwrap_ * In case it creates a new DerivedMesh, the old calc->final is freed */ //TODO memory checks on allocs +/* static void shrinkwrap_removeUnused(ShrinkwrapCalcData *calc) { int i, t; @@ -1001,7 +702,7 @@ static void shrinkwrap_removeUnused(ShrinkwrapCalcData *calc) face[i].v4 = 0; //this quad turned on a tri } -/* +#if 0 if(face[i].v4 && res == 3) { if(!bitset_get(moved_verts, face[i].v1)) @@ -1020,7 +721,7 @@ static void shrinkwrap_removeUnused(ShrinkwrapCalcData *calc) face[i].v4 = 0; //this quad turned on a tri } -*/ +#endif bitset_set(used_faces, i); //Mark face to maintain numUsedFaces++; @@ -1159,9 +860,10 @@ void shrinkwrap_projectToCutPlane(ShrinkwrapCalcData *calc_data) } } - +*/ /* Main shrinkwrap function */ +/* DerivedMesh *shrinkwrapModifier_do(ShrinkwrapModifierData *smd, Object *ob, DerivedMesh *dm, int useRenderParams, int isFinalCalc) { @@ -1265,8 +967,77 @@ DerivedMesh *shrinkwrapModifier_do(ShrinkwrapModifierData *smd, Object *ob, Deri return calc.final; } +*/ + +/* Main shrinkwrap function */ +void shrinkwrapModifier_deform(ShrinkwrapModifierData *smd, Object *ob, DerivedMesh *dm, float (*vertexCos)[3], int numVerts) +{ + + ShrinkwrapCalcData calc; + memset(&calc, 0, sizeof(calc)); + + //Init Shrinkwrap calc data + calc.smd = smd; + + calc.ob = ob; + calc.original = dm; + + calc.numVerts = numVerts; + calc.vertexCos = vertexCos; + + //remove loop dependencies on derived meshs (TODO should this be done elsewhere?) + if(smd->target == ob) smd->target = NULL; + if(smd->cutPlane == ob) smd->cutPlane = NULL; + if(smd->target) + { + //TODO currently we need a copy in case object_get_derived_final returns an emDM that does not defines getVertArray or getFace array + calc.target = CDDM_copy( object_get_derived_final(smd->target, CD_MASK_BAREMESH) ); + + if(!calc.target) + { + printf("Target derived mesh is null! :S\n"); + } + + //TODO there might be several "bugs" on non-uniform scales matrixs.. because it will no longer be nearest surface, not sphere projection + //because space has been deformed + space_transform_setup(&calc.local2target, ob, smd->target); + + calc.keptDist = smd->keptDist; //TODO: smd->keptDist is in global units.. must change to local + } + + //Projecting target defined - lets work! + if(calc.target) + { + + printf("Shrinkwrap (%s)%d over (%s)%d\n", + calc.ob->id.name, calc.numVerts, + calc.smd->target->id.name, calc.target->getNumVerts(calc.target) + ); + + + switch(smd->shrinkType) + { + case MOD_SHRINKWRAP_NEAREST_SURFACE: + shrinkwrap_calc_nearest_surface_point(&calc); + break; + + case MOD_SHRINKWRAP_NORMAL: + shrinkwrap_calc_normal_projection(&calc); + break; + + case MOD_SHRINKWRAP_NEAREST_VERTEX: + shrinkwrap_calc_nearest_vertex(&calc); + break; + } + + //free derived mesh + calc.target->release( calc.target ); + calc.target = NULL; + } +} + /* * Shrinkwrap to the nearest vertex * @@ -1277,15 +1048,12 @@ void shrinkwrap_calc_nearest_vertex(ShrinkwrapCalcData *calc) { int i; int vgroup = get_named_vertexgroup_num(calc->ob, calc->smd->vgroup_name); - float tmp_co[3]; + float *co; BVHTreeFromMesh treeData; BVHTreeNearest nearest; - int numVerts; - MVert *vert = NULL; - MDeformVert *dvert = NULL; - + MDeformVert *dvert = calc->original ? calc->original->getVertDataArray(calc->original, CD_MDEFORMVERT) : NULL; bvhtree_from_mesh_verts(&treeData, calc->target, 0.0, 2, 6); @@ -1295,26 +1063,21 @@ void shrinkwrap_calc_nearest_vertex(ShrinkwrapCalcData *calc) nearest.index = -1; nearest.dist = FLT_MAX; - - //Find the nearest vertex - numVerts= calc->final->getNumVerts(calc->final); - vert = calc->final->getVertDataArray(calc->final, CD_MVERT); - dvert = calc->final->getVertDataArray(calc->final, CD_MDEFORMVERT); - - for(i=0; i<numVerts; i++) + for(co = calc->vertexCos[i=0]; i<calc->numVerts; co = calc->vertexCos[++i]) { int index; + float tmp_co[3]; float weight = vertexgroup_get_vertex_weight(dvert, i, vgroup); if(weight == 0.0f) continue; - VECCOPY(tmp_co, vert[i].co); + VECCOPY(tmp_co, co); space_transform_apply(&calc->local2target, tmp_co); + //Use local proximity heuristics (to reduce the nearest search) if(nearest.index != -1) - { nearest.dist = squared_dist(tmp_co, nearest.co); - } - else nearest.dist = FLT_MAX; + else + nearest.dist = FLT_MAX; index = BLI_bvhtree_find_nearest(treeData.tree, tmp_co, &nearest, treeData.nearest_callback, &treeData); @@ -1323,9 +1086,10 @@ void shrinkwrap_calc_nearest_vertex(ShrinkwrapCalcData *calc) float dist; VECCOPY(tmp_co, nearest.co); space_transform_invert(&calc->local2target, tmp_co); - dist = VecLenf(vert[i].co, tmp_co); + + dist = VecLenf(co, tmp_co); if(dist > 1e-5) weight *= (dist - calc->keptDist)/dist; - VecLerpf(vert[i].co, vert[i].co, tmp_co, weight); //linear interpolation + VecLerpf(co, co, tmp_co, weight); //linear interpolation } } @@ -1333,104 +1097,6 @@ void shrinkwrap_calc_nearest_vertex(ShrinkwrapCalcData *calc) } /* - * Shrinkwrap projecting vertexs allong their normals over the target - * - * it builds a RayTree from the target mesh and then performs a - * raycast for each vertex (ray direction = normal) - */ -/* -void shrinkwrap_calc_normal_projection_raytree(ShrinkwrapCalcData *calc) -{ - int i; - int vgroup = get_named_vertexgroup_num(calc->ob, calc->smd->vgroup_name); - char use_normal = calc->smd->shrinkOpts; - RayTree *target = NULL; - - int numVerts; - MVert *vert = NULL; - MDeformVert *dvert = NULL; - float tmp_co[3], tmp_no[3]; - - if( (use_normal & (MOD_SHRINKWRAP_ALLOW_INVERTED_NORMAL | MOD_SHRINKWRAP_ALLOW_DEFAULT_NORMAL)) == 0) - return; //Nothing todo - - //setup raytracing - BENCH(target = raytree_create_from_mesh(calc->target)); - if(target == NULL) return OUT_OF_MEMORY(); - - - - //Project each vertex along normal - numVerts= calc->final->getNumVerts(calc->final); - vert = calc->final->getVertDataArray(calc->final, CD_MVERT); - dvert = calc->final->getVertDataArray(calc->final, CD_MDEFORMVERT); - - for(i=0; i<numVerts; i++) - { - float dist = FLT_MAX; - float weight = vertexgroup_get_vertex_weight(dvert, i, vgroup); - float face_normal[3]; - if(weight == 0.0f) continue; - - //Transform coordinates local->target - VecMat4MulVecfl(tmp_co, calc->local2target, vert[i].co); - - NormalShortToFloat(tmp_no, vert[i].no); - Mat4Mul3Vecfl(calc->local2target, tmp_no); //Watch out for scaling on normal - Normalize(tmp_no); //(TODO: do we really needed a unit-len normal? and we could know the scale factor before hand?) - - if(use_normal & MOD_SHRINKWRAP_ALLOW_DEFAULT_NORMAL) - { - dist = raytree_cast_ray(target, tmp_co, tmp_no, face_normal); - - if((calc->smd->shrinkOpts & MOD_SHRINKWRAP_CULL_TARGET_FRONTFACE) && INPR(tmp_no, face_normal) < 0) - dist = FLT_MAX; - if((calc->smd->shrinkOpts & MOD_SHRINKWRAP_CULL_TARGET_BACKFACE) && INPR(tmp_no, face_normal) > 0) - dist = FLT_MAX; - } - - if(use_normal & MOD_SHRINKWRAP_ALLOW_INVERTED_NORMAL) - { - float inv[3]; // = {-tmp_no[0], -tmp_no[1], -tmp_no[2]}; - float tdist; - - inv[0] = -tmp_no[0]; - inv[1] = -tmp_no[1]; - inv[2] = -tmp_no[2]; - - tdist = raytree_cast_ray(target, tmp_co, inv, 0); - - if((calc->smd->shrinkOpts & MOD_SHRINKWRAP_CULL_TARGET_FRONTFACE) && INPR(tmp_no, face_normal) < 0) - tdist = FLT_MAX; - if((calc->smd->shrinkOpts & MOD_SHRINKWRAP_CULL_TARGET_BACKFACE) && INPR(tmp_no, face_normal) > 0) - tdist = FLT_MAX; - - if(ABS(tdist) < ABS(dist)) - dist = -tdist; - } - - if(ABS(dist) != FLT_MAX) - { - float dist_t; - - VECADDFAC(tmp_co, tmp_co, tmp_no, dist); - VecMat4MulVecfl(tmp_co, calc->target2local, tmp_co); - - dist_t = VecLenf(vert[i].co, tmp_co); - if(dist_t > 1e-5) weight *= (dist_t - calc->keptDist)/dist_t; - VecLerpf(vert[i].co, vert[i].co, tmp_co, weight); //linear interpolation - - if(calc->moved) - bitset_set(calc->moved, i); - } - - } - - free_raytree_from_mesh(target); -} -*/ - -/* * This function raycast a single vertex and updates the hit if the "hit" is considered valid. * Returns TRUE if "hit" was updated. * Opts control whether an hit is valid or not @@ -1438,7 +1104,7 @@ void shrinkwrap_calc_normal_projection_raytree(ShrinkwrapCalcData *calc) * MOD_SHRINKWRAP_CULL_TARGET_FRONTFACE (front faces hits are ignored) * MOD_SHRINKWRAP_CULL_TARGET_BACKFACE (back faces hits are ignored) */ -static int normal_projection_project_vertex(char options, const float *vert, const float *dir, const SpaceTransform *transf, BVHTree *tree, BVHTreeRayHit *hit, BVHTree_RayCastCallback callback, void *userdata) +int normal_projection_project_vertex(char options, const float *vert, const float *dir, const SpaceTransform *transf, BVHTree *tree, BVHTreeRayHit *hit, BVHTree_RayCastCallback callback, void *userdata) { float tmp_co[3], tmp_no[3]; const float *co, *no; @@ -1498,30 +1164,34 @@ void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc) int i; int vgroup = get_named_vertexgroup_num(calc->ob, calc->smd->vgroup_name); char use_normal = calc->smd->shrinkOpts; + float *co; //setup raytracing BVHTreeFromMesh treeData; BVHTreeRayHit hit; - -/* //cutTree DerivedMesh * limit_mesh = NULL; BVHTreeFromMesh limitData; SpaceTransform local2cut; -*/ - int numVerts; - MVert *vert = NULL; - MDeformVert *dvert = NULL; + MVert *vert = calc->original ? calc->original->getVertDataArray(calc->original, CD_MVERT) : NULL; //Needed because of vertex normal + MDeformVert *dvert = calc->original ? calc->original->getVertDataArray(calc->original, CD_MDEFORMVERT) : NULL; - if( (use_normal & (MOD_SHRINKWRAP_ALLOW_INVERTED_NORMAL | MOD_SHRINKWRAP_ALLOW_DEFAULT_NORMAL)) == 0) + if(vert == NULL) + { + printf("Shrinkwrap cant normal project witouth normal information"); + return; + } + if((use_normal & (MOD_SHRINKWRAP_ALLOW_INVERTED_NORMAL | MOD_SHRINKWRAP_ALLOW_DEFAULT_NORMAL)) == 0) return; //Nothing todo + CDDM_calc_normals(calc->original); //Normals maybe arent yet calculated + bvhtree_from_mesh_faces(&treeData, calc->target, calc->keptDist, 4, 6); if(treeData.tree == NULL) return OUT_OF_MEMORY(); -/* + if(calc->smd->cutPlane) { space_transform_setup( &local2cut, calc->ob, calc->smd->cutPlane); @@ -1533,14 +1203,8 @@ void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc) else printf("CutPlane finalDerived mesh is null\n"); } -*/ - - //Project each vertex along normal - numVerts= calc->final->getNumVerts(calc->final); - vert = calc->final->getVertDataArray(calc->final, CD_MVERT); - dvert = calc->final->getVertDataArray(calc->final, CD_MDEFORMVERT); - for(i=0; i<numVerts; i++) + for(co = calc->vertexCos[i=0]; i<calc->numVerts; co = calc->vertexCos[++i]) { float tmp_co[3], tmp_no[3]; float lim = 1000; //TODO: we should use FLT_MAX here, but sweepsphere code isnt prepared for that @@ -1549,7 +1213,7 @@ void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc) if(weight == 0.0f) continue; - VECCOPY(tmp_co, vert[i].co); + VECCOPY(tmp_co, co); NormalShortToFloat(tmp_no, vert[i].no); @@ -1559,10 +1223,9 @@ void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc) if(use_normal & MOD_SHRINKWRAP_ALLOW_DEFAULT_NORMAL) { -/* - if(limit_tree) - normal_projection_project_vertex(0, tmp_co, tmp_no, &local2cut, limit_tree, &hit, limit_callback, &limit_userdata); -*/ + + if(limitData.tree) + normal_projection_project_vertex(0, tmp_co, tmp_no, &local2cut, limitData.tree, &hit, limitData.raycast_callback, &limitData); if(normal_projection_project_vertex(calc->smd->shrinkOpts, tmp_co, tmp_no, &calc->local2target, treeData.tree, &hit, treeData.raycast_callback, &treeData)) moved = TRUE; @@ -1573,10 +1236,10 @@ void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc) { float inv_no[3] = { -tmp_no[0], -tmp_no[1], -tmp_no[2] }; -/* - if(limit_tree) - normal_projection_project_vertex(0, tmp_co, inv_no, &local2cut, limit_tree, &hit, limit_callback, &limit_userdata); -*/ + + if(limitData.tree) + normal_projection_project_vertex(0, tmp_co, inv_no, &local2cut, limitData.tree, &hit, limitData.raycast_callback, &limitData); + if(normal_projection_project_vertex(calc->smd->shrinkOpts, tmp_co, inv_no, &calc->local2target, treeData.tree, &hit, treeData.raycast_callback, &treeData)) moved = TRUE; } @@ -1584,7 +1247,7 @@ void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc) if(hit.index != -1) { - VecLerpf(vert[i].co, vert[i].co, hit.co, weight); + VecLerpf(co, co, hit.co, weight); if(moved && calc->moved) bitset_set(calc->moved, i); @@ -1593,13 +1256,12 @@ void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc) BLI_bvhtree_free(treeData.tree); -/* + if(limitData.tree) BLI_bvhtree_free(limitData.tree); if(limit_mesh) limit_mesh->release(limit_mesh); -*/ } /* @@ -1612,14 +1274,12 @@ void shrinkwrap_calc_nearest_surface_point(ShrinkwrapCalcData *calc) { int i; int vgroup = get_named_vertexgroup_num(calc->ob, calc->smd->vgroup_name); - float tmp_co[3]; + float *co; BVHTreeFromMesh treeData; BVHTreeNearest nearest; - int numVerts; - MVert *vert = NULL; - MDeformVert *dvert = NULL; + MDeformVert *dvert = calc->original ? calc->original->getVertDataArray(calc->original, CD_MDEFORMVERT) : NULL; //Create a bvh-tree of the given target @@ -1632,17 +1292,14 @@ void shrinkwrap_calc_nearest_surface_point(ShrinkwrapCalcData *calc) //Find the nearest vertex - numVerts= calc->final->getNumVerts(calc->final); - vert = calc->final->getVertDataArray(calc->final, CD_MVERT); - dvert = calc->final->getVertDataArray(calc->final, CD_MDEFORMVERT); - - for(i=0; i<numVerts; i++) + for(co = calc->vertexCos[i=0]; i<calc->numVerts; co = calc->vertexCos[++i]) { int index; + float tmp_co[3]; float weight = vertexgroup_get_vertex_weight(dvert, i, vgroup); if(weight == 0.0f) continue; - VECCOPY(tmp_co, vert[i].co); + VECCOPY(tmp_co, co); space_transform_apply(&calc->local2target, tmp_co); if(nearest.index != -1) @@ -1665,7 +1322,7 @@ void shrinkwrap_calc_nearest_surface_point(ShrinkwrapCalcData *calc) VecLerpf(tmp_co, tmp_co, nearest.co, (dist - calc->keptDist)/dist); //linear interpolation } space_transform_invert(&calc->local2target, tmp_co); - VecLerpf(vert[i].co, vert[i].co, tmp_co, weight); //linear interpolation + VecLerpf(co, co, tmp_co, weight); //linear interpolation } } diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h index 40c3b223e01..44a7017158b 100644 --- a/source/blender/makesdna/DNA_modifier_types.h +++ b/source/blender/makesdna/DNA_modifier_types.h @@ -499,11 +499,9 @@ typedef struct ShrinkwrapModifierData { struct Object *cutPlane;/* shrink target */ char vgroup_name[32]; /* optional vertexgroup name */ float keptDist; /* distance offset from mesh/projection point */ - float mergeDist; /* distance to merge vertexs */ short shrinkType; /* shrink type projection */ short shrinkOpts; /* shrink options */ - int pad; } ShrinkwrapModifierData; /* Shrinkwrap->shrinkType */ @@ -514,7 +512,7 @@ typedef struct ShrinkwrapModifierData { /* Shrinkwrap->shrinkOpts */ #define MOD_SHRINKWRAP_ALLOW_DEFAULT_NORMAL (1<<0) #define MOD_SHRINKWRAP_ALLOW_INVERTED_NORMAL (1<<1) -#define MOD_SHRINKWRAP_REMOVE_UNPROJECTED_FACES (1<<2) +/* #define MOD_SHRINKWRAP_REMOVE_UNPROJECTED_FACES (1<<2) / * Currently dropped to make shrinkwrap a deform only modifier */ #define MOD_SHRINKWRAP_CULL_TARGET_FRONTFACE (1<<3) #define MOD_SHRINKWRAP_CULL_TARGET_BACKFACE (1<<4) diff --git a/source/blender/src/buttons_editing.c b/source/blender/src/buttons_editing.c index 235463d5a75..d0b970bf5c6 100644 --- a/source/blender/src/buttons_editing.c +++ b/source/blender/src/buttons_editing.c @@ -1903,9 +1903,9 @@ static void draw_modifier(uiBlock *block, Object *ob, ModifierData *md, int *xco height = 94; } else if (md->type==eModifierType_Shrinkwrap) { ShrinkwrapModifierData *smd = (ShrinkwrapModifierData*) md; - height = 86; + height = 86 + 3; if (smd->shrinkType == MOD_SHRINKWRAP_NORMAL) - height += 19*5; + height += 19*3; else if (smd->shrinkType == MOD_SHRINKWRAP_NEAREST_SURFACE) height += 19; @@ -2535,31 +2535,35 @@ static void draw_modifier(uiBlock *block, Object *ob, ModifierData *md, int *xco ShrinkwrapModifierData *smd = (ShrinkwrapModifierData*) md; char shrinktypemenu[]="Shrinkwrap type%t|nearest surface point %x0|normal projection %x1|nearest vertex %x2"; - uiDefButS(block, MENU, B_MODIFIER_RECALC, shrinktypemenu, lx,(cy-=19),buttonWidth,19, &smd->shrinkType, 0, 0, 0, 0, "Selects type of shrinkwrap algorithm for target position."); + uiDefIDPoinBut(block, modifier_testMeshObj, ID_OB, B_CHANGEDEP, "Ob: ", lx, (cy-=19), buttonWidth,19, &smd->target, "Target to shrink to"); + + but=uiDefBut(block, TEX, B_MODIFIER_RECALC, "VGroup: ", lx, (cy-=19), buttonWidth,19, &smd->vgroup_name, 0, 31, 0, 0, "Vertex Group name"); + uiButSetCompleteFunc(but, autocomplete_vgroup, (void *)ob); + + uiDefButF(block, NUM, B_MODIFIER_RECALC, "Offset:", lx,(cy-=19),buttonWidth,19, &smd->keptDist, 0.0f, 100.0f, 1.0f, 0, "Specify distance to kept from the target"); + + cy -= 3; + uiDefButS(block, MENU, B_MODIFIER_RECALC, shrinktypemenu, lx,(cy-=19),buttonWidth,19, &smd->shrinkType, 0, 0, 0, 0, "Selects type of shrinkwrap algorithm for target position."); if (smd->shrinkType == MOD_SHRINKWRAP_NORMAL){ uiDefButBitS(block, TOG, MOD_SHRINKWRAP_ALLOW_DEFAULT_NORMAL, B_MODIFIER_RECALC, "Default normal", lx,(cy-=19),buttonWidth/2,19, &smd->shrinkOpts, 0, 0, 0, 0, "Allows vertices to move in the normal direction"); uiDefButBitS(block, TOG, MOD_SHRINKWRAP_ALLOW_INVERTED_NORMAL, B_MODIFIER_RECALC, "Invert normal", lx + buttonWidth/2,cy,buttonWidth/2,19, &smd->shrinkOpts, 0, 0, 0, 0, "Allows vertices to move in the inverse direction of their normal"); - uiDefButBitS(block, TOG, MOD_SHRINKWRAP_REMOVE_UNPROJECTED_FACES, B_MODIFIER_RECALC, "Remove faces", lx,(cy-=19),buttonWidth,19, &smd->shrinkOpts, 0, 0, 0, 0, "Remove faces where all vertices haven't been projected"); +/* uiDefButBitS(block, TOG, MOD_SHRINKWRAP_REMOVE_UNPROJECTED_FACES, B_MODIFIER_RECALC, "Remove faces", lx,(cy-=19),buttonWidth,19, &smd->shrinkOpts, 0, 0, 0, 0, "Remove faces where all vertices haven't been projected"); */ uiDefButBitS(block, TOG, MOD_SHRINKWRAP_CULL_TARGET_FRONTFACE, B_MODIFIER_RECALC, "Cull frontfaces",lx,(cy-=19),buttonWidth/2,19, &smd->shrinkOpts, 0, 0, 0, 0, "Controls whether a vertex can be projected to a front face on target"); uiDefButBitS(block, TOG, MOD_SHRINKWRAP_CULL_TARGET_BACKFACE, B_MODIFIER_RECALC, "Cull backfaces", lx+buttonWidth/2,cy,buttonWidth/2,19, &smd->shrinkOpts, 0, 0, 0, 0, "Controls whether a vertex can be projected to a back face on target"); - uiDefButF(block, NUM, B_MODIFIER_RECALC, "Merge Dist:", lx,(cy-=19),buttonWidth,19, &smd->mergeDist, 0.0f, 0.01f, 0.01f, 0.01f, "Specify merge distance"); - uiDefIDPoinBut(block, modifier_testMeshObj, ID_OB, B_CHANGEDEP, "Ob2: ", lx, (cy-=19), buttonWidth,19, &smd->cutPlane, "Target to project points that didn't got projected over target"); +/* uiDefButF(block, NUM, B_MODIFIER_RECALC, "Merge Dist:", lx,(cy-=19),buttonWidth,19, &smd->mergeDist, 0.0f, 0.01f, 0.01f, 0.01f, "Specify merge distance"); */ + uiDefIDPoinBut(block, modifier_testMeshObj, ID_OB, B_CHANGEDEP, "Ob2: ", lx, (cy-=19), buttonWidth,19, &smd->cutPlane, "Aditional mesh to project over"); } else if (smd->shrinkType == MOD_SHRINKWRAP_NEAREST_SURFACE){ uiDefButBitS(block, TOG, MOD_SHRINKWRAP_KEPT_ABOVE_SURFACE, B_MODIFIER_RECALC, "Above surface", lx,(cy-=19),buttonWidth,19, &smd->shrinkOpts, 0, 0, 0, 0, "Vertices are kept on the front side of faces"); } - but=uiDefBut(block, TEX, B_MODIFIER_RECALC, "VGroup: ", lx, (cy-=19), buttonWidth,19, &smd->vgroup_name, 0, 31, 0, 0, "Vertex Group name"); - uiButSetCompleteFunc(but, autocomplete_vgroup, (void *)ob); - - uiDefIDPoinBut(block, modifier_testMeshObj, ID_OB, B_CHANGEDEP, "Ob: ", lx, (cy-=19), buttonWidth,19, &smd->target, "Target to shrink to"); - uiDefButF(block, NUM, B_MODIFIER_RECALC, "Offset:", lx,(cy-=19),buttonWidth,19, &smd->keptDist, 0.0f, 100.0f, 1.0f, 0, "Specify distance to kept from the target"); uiBlockEndAlign(block); + } else if (md->type==eModifierType_SimpleDeform) { SimpleDeformModifierData *smd = (SimpleDeformModifierData*) md; |