From 59a2b5017185369836678b14325666f62dba9311 Mon Sep 17 00:00:00 2001 From: Andre Susano Pinto Date: Fri, 18 Jul 2008 22:24:20 +0000 Subject: *Added "kept" mesh above surface option on shrinkwrap to nearest surface changed a few code relative to project over normal mode (to try to kept code generic and more independent of modifier itself) --- source/blender/blenkernel/BKE_shrinkwrap.h | 25 ++- source/blender/blenkernel/intern/shrinkwrap.c | 231 ++++++++++++++++++-------- source/blender/blenlib/BLI_kdopbvh.h | 5 +- source/blender/blenlib/intern/BLI_kdopbvh.c | 4 +- source/blender/makesdna/DNA_modifier_types.h | 2 + source/blender/src/buttons_editing.c | 6 + 6 files changed, 197 insertions(+), 76 deletions(-) diff --git a/source/blender/blenkernel/BKE_shrinkwrap.h b/source/blender/blenkernel/BKE_shrinkwrap.h index b0a40768e8b..a512c1d57cb 100644 --- a/source/blender/blenkernel/BKE_shrinkwrap.h +++ b/source/blender/blenkernel/BKE_shrinkwrap.h @@ -42,7 +42,27 @@ typedef char* BitSet; #define bitset_unset(set,index) ((set)[(index)>>3] &= ~(1 << ((index)&0x7))) +/* SpaceTransform stuff */ +//TODO: should move to other generic space? +struct Object; + +typedef struct SpaceTransform +{ + float local2target[4][4]; + float target2local[4][4]; + +} SpaceTransform; + +void space_transform_setup(SpaceTransform *data, struct Object *local, struct Object *target); +void space_transform_apply (SpaceTransform *data, float *co); +void space_transform_invert(SpaceTransform *data, float *co); + +void space_transform_apply_normal (SpaceTransform *data, float *co); +void space_transform_invert_normal(SpaceTransform *data, float *co); + + +/* Shrinkwrap stuff */ struct Object; struct DerivedMesh; struct ShrinkwrapModifierData; @@ -59,9 +79,7 @@ typedef struct ShrinkwrapCalcData struct DerivedMesh *target; //mesh we are shrinking to - //matrixs for local<->target space transform - float local2target[4][4]; - float target2local[4][4]; + SpaceTransform local2target; float keptDist; //Distance to kept from target (units are in local space) //float *weights; //weights of vertexs @@ -75,6 +93,7 @@ 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); + #endif diff --git a/source/blender/blenkernel/intern/shrinkwrap.c b/source/blender/blenkernel/intern/shrinkwrap.c index cb49f762cac..0aacdbc9a08 100644 --- a/source/blender/blenkernel/intern/shrinkwrap.c +++ b/source/blender/blenkernel/intern/shrinkwrap.c @@ -121,6 +121,38 @@ static float sphereray_tri_intersection(const BVHTreeRay *ray, float radius, con return FLT_MAX; } +/* Space transform */ +void space_transform_setup(SpaceTransform *data, struct Object *local, struct Object *target) +{ + Mat4Invert(target->imat, target->obmat); //Invserse might be outdated + Mat4MulSerie(data->local2target, target->imat, local->obmat, 0, 0, 0, 0, 0, 0); + Mat4Invert(data->target2local, data->local2target); +} + +void space_transform_apply(/* const */ SpaceTransform *data, float *co) +{ + VecMat4MulVecfl(co, data->local2target, co); +// Mat4Mul3Vecfl(data->local2target, co); +} + +void space_transform_invert(/* const */SpaceTransform *data, float *co) +{ + VecMat4MulVecfl(co, data->target2local, co); +// Mat4Mul3Vecfl(data->target2local, co); +} + +void space_transform_apply_normal(/* const */ SpaceTransform *data, float *no) +{ + Mat4Mul3Vecfl(data->local2target, no); + Normalize(no); // TODO: could we just determine de scale value from the matrix? +} + +void space_transform_invert_normal(/* const */ SpaceTransform *data, float *no) +{ + Mat4Mul3Vecfl(data->target2local, no); + Normalize(no); // TODO: could we just determine de scale value from the matrix? +} + /* * BVH tree from mesh vertices @@ -328,6 +360,8 @@ static float mesh_faces_spherecast(void *userdata, int index, const BVHTreeRay * hit->index = index; hit->dist = dist; VECADDFAC(hit->co, ray->origin, ray->direction, dist); + + CalcNormFloat(t0, t1, t2, hit->no); } t1 = t2; @@ -883,25 +917,24 @@ static void shrinkwrap_calc_foreach_vertex(ShrinkwrapCalcData *calc, Shrinkwrap_ { float weight = vertexgroup_get_vertex_weight(dvert, i, vgroup); - float orig[3], final[3]; //Coords relative to target + float final[3]; //Coords relative to target float normal[3]; float dist; if(weight == 0.0f) continue; //Skip vertexs where we have no influence - VecMat4MulVecfl(orig, calc->local2target, vert[i].co); - VECCOPY(final, orig); + 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); - Mat4Mul3Vecfl(calc->local2target, normal); - Normalize(normal); //Watch out for scaling (TODO: do we really needed a unit-len normal?) + space_transform_apply_normal(&calc->local2target, normal); } (callback)(calc->target, final, normal); - VecMat4MulVecfl(final, calc->target2local, final); + space_transform_invert(&calc->local2target, final); dist = VecLenf(vert[i].co, final); if(dist > 1e-5) weight *= (dist - calc->keptDist)/dist; @@ -1075,6 +1108,7 @@ static void shrinkwrap_removeUnused(ShrinkwrapCalcData *calc) calc->final = new; } + void shrinkwrap_projectToCutPlane(ShrinkwrapCalcData *calc_data) { if(calc_data->smd->cutPlane && calc_data->moved) @@ -1099,10 +1133,7 @@ void shrinkwrap_projectToCutPlane(ShrinkwrapCalcData *calc_data) return; } - Mat4Invert (calc.smd->cutPlane->imat, calc.smd->cutPlane->obmat); //inverse is outdated - Mat4MulSerie(calc.local2target, calc.smd->cutPlane->imat, calc.ob->obmat, 0, 0, 0, 0, 0, 0); - Mat4Invert(calc.target2local, calc.local2target); - + space_transform_setup(&calc.local2target, calc.ob, calc.smd->cutPlane); calc.keptDist = 0; } @@ -1172,12 +1203,10 @@ DerivedMesh *shrinkwrapModifier_do(ShrinkwrapModifierData *smd, Object *ob, Deri printf("Target derived mesh is null! :S\n"); } - //TODO should we reduce the number of matrix mults? by choosing applying matrixs to target or to derived mesh? - //Calculate matrixs for local <-> target - Mat4Invert (smd->target->imat, smd->target->obmat); //inverse is outdated - Mat4MulSerie(calc.local2target, smd->target->imat, ob->obmat, 0, 0, 0, 0, 0, 0); - Mat4Invert(calc.target2local, calc.local2target); - + //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 } @@ -1282,7 +1311,8 @@ void shrinkwrap_calc_nearest_vertex(ShrinkwrapCalcData *calc) float weight = vertexgroup_get_vertex_weight(dvert, i, vgroup); if(weight == 0.0f) continue; - VecMat4MulVecfl(tmp_co, calc->local2target, vert[i].co); + VECCOPY(tmp_co, vert[i].co); + space_transform_apply(&calc->local2target, tmp_co); if(nearest.index != -1) { @@ -1296,7 +1326,7 @@ void shrinkwrap_calc_nearest_vertex(ShrinkwrapCalcData *calc) { float dist; - VecMat4MulVecfl(tmp_co, calc->target2local, nearest.nearest); + space_transform_invert(&calc->local2target, tmp_co); dist = VecLenf(vert[i].co, tmp_co); if(dist > 1e-5) weight *= (dist - calc->keptDist)/dist; VecLerpf(vert[i].co, vert[i].co, tmp_co, weight); //linear interpolation @@ -1314,6 +1344,7 @@ void shrinkwrap_calc_nearest_vertex(ShrinkwrapCalcData *calc) * 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; @@ -1354,7 +1385,6 @@ void shrinkwrap_calc_normal_projection_raytree(ShrinkwrapCalcData *calc) 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); @@ -1404,6 +1434,61 @@ void shrinkwrap_calc_normal_projection_raytree(ShrinkwrapCalcData *calc) 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 + * Supported options are: + * 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, BVHMeshCallbackUserdata *userdata) +{ + float tmp_co[3], tmp_no[3]; + BVHTreeRayHit hit_tmp; + memcpy( &hit_tmp, hit, sizeof(hit_tmp) ); + + //Apply space transform (TODO readjust dist) + if(transf) + { + VECCOPY( tmp_co, vert ); + space_transform_apply( transf, tmp_co ); + vert = tmp_co; + + VECCOPY( tmp_no, dir ); + space_transform_apply_normal( transf, tmp_no ); + dir = tmp_no; + } + + hit_tmp.index = -1; + + BLI_bvhtree_ray_cast(tree, vert, dir, &hit_tmp, callback, userdata); + + if(hit_tmp.index != -1) + { + float dot = INPR( dir, hit_tmp.no); + + if(((options & MOD_SHRINKWRAP_CULL_TARGET_FRONTFACE) && dot < 0) + || ((options & MOD_SHRINKWRAP_CULL_TARGET_BACKFACE) && dot > 0)) + return FALSE; //Ignore hit + + + //Inverting space transform (TODO readjust dist) + if(transf) + { + space_transform_invert( transf, hit_tmp.co ); + space_transform_invert_normal( transf, hit_tmp.no ); + } + + memcpy(hit, &hit_tmp, sizeof(hit_tmp) ); + return TRUE; + } + return FALSE; +} + void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc) { @@ -1417,6 +1502,14 @@ void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc) BVHMeshCallbackUserdata userdata; BVHTree_RayCastCallback callback = NULL; + + //cutTree + BVHTree *limit_tree = NULL; + BVHMeshCallbackUserdata limit_userdata; + BVHTree_RayCastCallback limit_callback = NULL; + SpaceTransform local2cut; + + int numVerts; MVert *vert = NULL; MDeformVert *dvert = NULL; @@ -1429,6 +1522,21 @@ void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc) bvhtree_meshcallbackdata_init(&userdata, calc->target, calc->keptDist); callback = mesh_faces_spherecast; + if(calc->smd->cutPlane) + { + DerivedMesh * limit_mesh = (DerivedMesh *)calc->smd->cutPlane->derivedFinal; + if(limit_mesh) + { + BENCH(limit_tree = bvhtree_from_mesh_faces(limit_mesh, 0.0, 4, 6)); + bvhtree_meshcallbackdata_init(&limit_userdata, limit_mesh, 0.0); + limit_callback = mesh_faces_spherecast; + + space_transform_setup( &local2cut, calc->ob, calc->smd->cutPlane); + } + 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); @@ -1437,69 +1545,39 @@ void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc) for(i=0; itarget - VecMat4MulVecfl(tmp_co, calc->local2target, vert[i].co); - + VECCOPY(tmp_co, 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?) + hit.index = -1; - hit.dist = 1000; //TODO: we should use FLT_MAX here + hit.dist = lim; +/* if(limit_tree) + { + normal_projection_project_vertex(0, tmp_co, tmp_no, &local2cut, limit_tree, &hit, callback, &userdata); + } +*/ if(use_normal & MOD_SHRINKWRAP_ALLOW_DEFAULT_NORMAL) { - BLI_bvhtree_ray_cast(tree, tmp_co, tmp_no, &hit, callback, &userdata); - - if(hit.index != -1) - { - float *v0, *v1, *v2; - float facenormal[3], dot; - - bvhtree_from_mesh_get_tri(&userdata, hit.index, &v0, &v1, &v2); - CalcNormFloat(v0, v1, v2, facenormal); - dot = INPR( facenormal, tmp_no); - - if(((calc->smd->shrinkOpts & MOD_SHRINKWRAP_CULL_TARGET_FRONTFACE) && dot < 0) - || ((calc->smd->shrinkOpts & MOD_SHRINKWRAP_CULL_TARGET_BACKFACE) && dot > 0)) - { - hit.index = -1; - hit.dist = 1000; //TODO: we should use FLT_MAX here - } - } + normal_projection_project_vertex(calc->smd->shrinkOpts, tmp_co, tmp_no, &calc->local2target, tree, &hit, callback, &userdata); } + if(use_normal & MOD_SHRINKWRAP_ALLOW_INVERTED_NORMAL) { - float inv[3] = { -tmp_no[0], -tmp_no[1], -tmp_no[2] }; - BLI_bvhtree_ray_cast(tree, tmp_co, inv, &hit, callback, &userdata); - - if(hit.index != -1) - { - float *v0, *v1, *v2; - float facenormal[3], dot; - - bvhtree_from_mesh_get_tri(&userdata, hit.index, &v0, &v1, &v2); - CalcNormFloat(v0, v1, v2, facenormal); - dot = INPR( facenormal, inv); - - if(((calc->smd->shrinkOpts & MOD_SHRINKWRAP_CULL_TARGET_FRONTFACE) && dot < 0) - || ((calc->smd->shrinkOpts & MOD_SHRINKWRAP_CULL_TARGET_BACKFACE) && dot > 0)) - { - hit.index = -1; - hit.dist = 1000; //TODO: we should use FLT_MAX here - } - } + float inv_no[3] = { -tmp_no[0], -tmp_no[1], -tmp_no[2] }; + normal_projection_project_vertex(calc->smd->shrinkOpts, tmp_co, inv_no, &calc->local2target, tree, &hit, callback, &userdata); } + if(hit.index != -1) { - VecMat4MulVecfl(tmp_co, calc->target2local, hit.co); - VecLerpf(vert[i].co, vert[i].co, tmp_co, weight); //linear interpolation + VecLerpf(vert[i].co, vert[i].co, hit.co, weight); //linear interpolation if(calc->moved) bitset_set(calc->moved, i); @@ -1507,6 +1585,9 @@ void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc) } BLI_bvhtree_free(tree); + + if(limit_tree) + BLI_bvhtree_free(limit_tree); } /* @@ -1551,7 +1632,8 @@ void shrinkwrap_calc_nearest_surface_point(ShrinkwrapCalcData *calc) float weight = vertexgroup_get_vertex_weight(dvert, i, vgroup); if(weight == 0.0f) continue; - VecMat4MulVecfl(tmp_co, calc->local2target, vert[i].co); + VECCOPY(tmp_co, vert[i].co); + space_transform_apply(&calc->local2target, tmp_co); if(nearest.index != -1) { @@ -1563,11 +1645,22 @@ void shrinkwrap_calc_nearest_surface_point(ShrinkwrapCalcData *calc) if(index != -1) { - float dist; + if(calc->smd->shrinkOpts & MOD_SHRINKWRAP_KEPT_ABOVE_SURFACE) + { + float *t0, *t1, *t2; + float surface_normal[3], tmp[3]; + bvhtree_from_mesh_get_tri(&userdata, index, &t0, &t1, &t2); + CalcNormFloat(t0, t1, t2, surface_normal); + VECSUB(tmp, vert[i].co, t0 ); + VECADDFAC(tmp_co, nearest.nearest, surface_normal, calc->keptDist); - VecMat4MulVecfl(tmp_co, calc->target2local, nearest.nearest); - dist = VecLenf(vert[i].co, tmp_co); - if(dist > 1e-5) weight *= (dist - calc->keptDist)/dist; + } + else + { + float dist = VecLenf(tmp_co, nearest.nearest); + VecLerpf(tmp_co, tmp_co, nearest.nearest, (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 } } diff --git a/source/blender/blenlib/BLI_kdopbvh.h b/source/blender/blenlib/BLI_kdopbvh.h index 1e56faaff55..d090784e450 100644 --- a/source/blender/blenlib/BLI_kdopbvh.h +++ b/source/blender/blenlib/BLI_kdopbvh.h @@ -57,6 +57,7 @@ typedef struct BVHTreeRayHit { int index; /* index of the tree node (untouched if no hit is found) */ float co[3]; /* coordinates of the hit point */ + float no[3]; /* normal on hit point */ float dist; /* distance to the hit point */ } BVHTreeRayHit; @@ -84,9 +85,9 @@ BVHTreeOverlap *BLI_bvhtree_overlap(BVHTree *tree1, BVHTree *tree2, int *result) float BLI_bvhtree_getepsilon(BVHTree *tree); /* find nearest node to the given coordinates (if nearest is given it will only search nodes where square distance is smaller than nearest->dist) */ -int BLI_bvhtree_find_nearest(BVHTree *tree, float *co, BVHTreeNearest *nearest, BVHTree_NearestPointCallback callback, void *userdata); +int BLI_bvhtree_find_nearest(BVHTree *tree, const float *co, BVHTreeNearest *nearest, BVHTree_NearestPointCallback callback, void *userdata); -int BLI_bvhtree_ray_cast(BVHTree *tree, float *co, float *dir, BVHTreeRayHit *hit, BVHTree_RayCastCallback callback, void *userdata); +int BLI_bvhtree_ray_cast(BVHTree *tree, const float *co, const float *dir, BVHTreeRayHit *hit, BVHTree_RayCastCallback callback, void *userdata); #endif // BLI_KDOPBVH_H diff --git a/source/blender/blenlib/intern/BLI_kdopbvh.c b/source/blender/blenlib/intern/BLI_kdopbvh.c index 73bc3e6a9bc..58a8f9f845c 100644 --- a/source/blender/blenlib/intern/BLI_kdopbvh.c +++ b/source/blender/blenlib/intern/BLI_kdopbvh.c @@ -925,7 +925,7 @@ static void dfs_find_nearest(BVHNearestData *data, BVHNode *node) } } -int BLI_bvhtree_find_nearest(BVHTree *tree, float *co, BVHTreeNearest *nearest, BVHTree_NearestPointCallback callback, void *userdata) +int BLI_bvhtree_find_nearest(BVHTree *tree, const float *co, BVHTreeNearest *nearest, BVHTree_NearestPointCallback callback, void *userdata) { int i; @@ -1051,7 +1051,7 @@ static void dfs_raycast(BVHRayCastData *data, BVHNode *node) -int BLI_bvhtree_ray_cast(BVHTree *tree, float *co, float *dir, BVHTreeRayHit *hit, BVHTree_RayCastCallback callback, void *userdata) +int BLI_bvhtree_ray_cast(BVHTree *tree, const float *co, const float *dir, BVHTreeRayHit *hit, BVHTree_RayCastCallback callback, void *userdata) { int i; BVHRayCastData data; diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h index 9e1a6ede9f9..40c3b223e01 100644 --- a/source/blender/makesdna/DNA_modifier_types.h +++ b/source/blender/makesdna/DNA_modifier_types.h @@ -519,6 +519,8 @@ typedef struct ShrinkwrapModifierData { #define MOD_SHRINKWRAP_CULL_TARGET_FRONTFACE (1<<3) #define MOD_SHRINKWRAP_CULL_TARGET_BACKFACE (1<<4) +#define MOD_SHRINKWRAP_KEPT_ABOVE_SURFACE (1<<5) + typedef struct SimpleDeformModifierData { ModifierData modifier; diff --git a/source/blender/src/buttons_editing.c b/source/blender/src/buttons_editing.c index c30f39b5f4c..404da946a5a 100644 --- a/source/blender/src/buttons_editing.c +++ b/source/blender/src/buttons_editing.c @@ -1906,6 +1906,9 @@ static void draw_modifier(uiBlock *block, Object *ob, ModifierData *md, int *xco height = 86; if (smd->shrinkType == MOD_SHRINKWRAP_NORMAL) height += 19*5; + else if (smd->shrinkType == MOD_SHRINKWRAP_NEAREST_SURFACE) + height += 19; + } else if (md->type==eModifierType_SimpleDeform) { height += 19*5; } @@ -2547,6 +2550,9 @@ static void draw_modifier(uiBlock *block, Object *ob, ModifierData *md, int *xco 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, "Cut: ", lx, (cy-=19), buttonWidth,19, &smd->cutPlane, "Target to project points that didn't got projected over target"); } + 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/2,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); -- cgit v1.2.3