Mesh effector surface option:
authorJanne Karhu <jhkarh@gmail.com>
Fri, 10 Apr 2009 19:40:21 +0000 (19:40 +0000)
committerJanne Karhu <jhkarh@gmail.com>
Fri, 10 Apr 2009 19:40:21 +0000 (19:40 +0000)
- Most mesh particle effectors can now have their effection point taken per particle as the nearest point on the mesh surface.
- This is activated with the "surface" button in the effector field panel.
- Activating the option adds a "surface" entry to the modifier stack where the state of the mesh is read from.

For an example of usage see http://www.youtube.com/watch?v=3XkO1EAmJks.

source/blender/blenkernel/intern/modifier.c
source/blender/blenkernel/intern/particle_system.c
source/blender/blenloader/intern/readfile.c
source/blender/makesdna/DNA_modifier_types.h
source/blender/makesdna/DNA_object_force.h
source/blender/src/buttons_editing.c
source/blender/src/buttons_object.c

index d182e3124fc5b2a9790b84a00d0ba0e555210706..1068950d0d6165832332ed21d5289692a7fd1afc 100644 (file)
@@ -6016,6 +6016,82 @@ static void collisionModifier_deformVerts(
 }
 
 
+
+/* Surface */
+
+static void surfaceModifier_initData(ModifierData *md) 
+{
+       SurfaceModifierData *surmd = (SurfaceModifierData*) md;
+       
+       surmd->bvhtree = NULL;
+}
+
+static void surfaceModifier_freeData(ModifierData *md)
+{
+       SurfaceModifierData *surmd = (SurfaceModifierData*) md;
+       
+       if (surmd)
+       {
+               if(surmd->bvhtree) {
+                       free_bvhtree_from_mesh(surmd->bvhtree);
+                       MEM_freeN(surmd->bvhtree);
+               }
+
+               surmd->dm->release(surmd->dm);
+               
+               surmd->bvhtree = NULL;
+               surmd->dm = NULL;
+       }
+}
+
+static int surfaceModifier_dependsOnTime(ModifierData *md)
+{
+       return 1;
+}
+
+static void surfaceModifier_deformVerts(
+                                         ModifierData *md, Object *ob, DerivedMesh *derivedData,
+       float (*vertexCos)[3], int numVerts)
+{
+       SurfaceModifierData *surmd = (SurfaceModifierData*) md;
+       DerivedMesh *dm = NULL;
+       float current_time = 0;
+       unsigned int numverts = 0, i = 0;
+       
+       if(surmd->dm)
+               surmd->dm->release(surmd->dm);
+
+       /* if possible use/create DerivedMesh */
+       if(derivedData) surmd->dm = CDDM_copy(derivedData);
+       else if(ob->type==OB_MESH) surmd->dm = CDDM_from_mesh(ob->data, ob);
+       
+       if(!ob->pd)
+       {
+               printf("surfaceModifier_deformVerts: Should not happen!\n");
+               return;
+       }
+       
+       if(surmd->dm)
+       {
+               CDDM_apply_vert_coords(surmd->dm, vertexCos);
+               CDDM_calc_normals(surmd->dm);
+               
+               numverts = surmd->dm->getNumVerts ( surmd->dm );
+
+               /* convert to global coordinates */
+               for(i = 0; i<numverts; i++)
+                       Mat4MulVecfl(ob->obmat, CDDM_get_vert(surmd->dm, i)->co);
+
+               if(surmd->bvhtree)
+                       free_bvhtree_from_mesh(surmd->bvhtree);
+               else
+                       surmd->bvhtree = MEM_callocN(sizeof(BVHTreeFromMesh), "BVHTreeFromMesh");
+
+               bvhtree_from_mesh_faces(surmd->bvhtree, surmd->dm, 0.0, 2, 6);
+       }
+}
+
+
 /* Boolean */
 
 static void booleanModifier_copyData(ModifierData *md, ModifierData *target)
@@ -8217,6 +8293,14 @@ ModifierTypeInfo *modifierType_getInfo(ModifierType type)
                mti->deformVerts = collisionModifier_deformVerts;
                // mti->copyData = collisionModifier_copyData;
 
+               mti = INIT_TYPE(Surface);
+               mti->type = eModifierTypeType_OnlyDeform;
+               mti->initData = surfaceModifier_initData;
+               mti->flags = eModifierTypeFlag_AcceptsMesh;
+               mti->dependsOnTime = surfaceModifier_dependsOnTime;
+               mti->freeData = surfaceModifier_freeData; 
+               mti->deformVerts = surfaceModifier_deformVerts;
+
                mti = INIT_TYPE(Boolean);
                mti->type = eModifierTypeType_Nonconstructive;
                mti->flags = eModifierTypeFlag_AcceptsMesh
index 0ffdd11c37ac5391643e6232e77497967c1f3ed3..bbf62d033bf6a1b74938c1bb94b09a312d17409a 100644 (file)
@@ -77,6 +77,7 @@
 #include "BKE_mesh.h"
 #include "BKE_modifier.h"
 #include "BKE_scene.h"
+#include "BKE_bvhutils.h"
 
 #include "PIL_time.h"
 
@@ -2447,7 +2448,6 @@ void psys_end_effectors(ParticleSystem *psys)
                        
                        if(ec->rng)
                                rng_free(ec->rng);
-                       
                }
 
                BLI_freelistN(lb);
@@ -2544,6 +2544,7 @@ void do_effectors(int pa_no, ParticleData *pa, ParticleKey *state, Object *ob, P
        ParticleData *epa;
        ParticleKey estate;
        PartDeflect *pd;
+       SurfaceModifierData *surmd = NULL;
        ListBase *lb=&psys->effectors;
        ParticleEffectorCache *ec;
        float distance, vec_to_part[3];
@@ -2571,8 +2572,34 @@ void do_effectors(int pa_no, ParticleData *pa, ParticleKey *state, Object *ob, P
                                if(psys->part->type!=PART_HAIR && psys->part->integrator)
                                        where_is_object_time(eob,cfra);
 
-                               /* use center of object for distance calculus */
-                               VecSubf(vec_to_part, state->co, eob->obmat[3]);
+                               if(pd && pd->flag&PFIELD_SURFACE) {
+                                       surmd = (SurfaceModifierData *)modifiers_findByType ( eob, eModifierType_Surface );
+                               }
+                               if(surmd) {
+                                       /* closest point in the object surface is an effector */
+                                       BVHTreeNearest nearest;
+                                       float velocity[3];
+
+                                       nearest.index = -1;
+                                       nearest.dist = FLT_MAX;
+
+                                       /* using velocity corrected location allows for easier sliding over effector surface */
+                                       VecCopyf(velocity, state->vel);
+                                       VecMulf(velocity, psys_get_timestep(psys->part));
+                                       VecAddf(vec_to_part, state->co, velocity);
+
+                                       BLI_bvhtree_find_nearest(surmd->bvhtree->tree, vec_to_part, &nearest, surmd->bvhtree->nearest_callback, surmd->bvhtree);
+
+                                       if(nearest.index != -1) {
+                                               VecSubf(vec_to_part, state->co, nearest.co);
+                                       }
+                                       else
+                                               vec_to_part[0] = vec_to_part[1] = vec_to_part[2] = 0.0f;
+                               }
+                               else 
+                                       /* use center of object for distance calculus */
+                                       VecSubf(vec_to_part, state->co, eob->obmat[3]);
+
                                distance = VecLength(vec_to_part);
 
                                falloff=effector_falloff(pd,eob->obmat[2],vec_to_part);
index 06c8370bde2d48b7d968d150d07c0409fdd8a3ab..63dd1e8e6cb93a188778ead38bf9c24fac84c8b1 100644 (file)
@@ -3207,6 +3207,12 @@ static void direct_link_modifiers(FileData *fd, ListBase *lb)
                        collmd->mfaces = NULL;
                        
                }
+               else if (md->type==eModifierType_Surface) {
+                       SurfaceModifierData *surmd = (SurfaceModifierData*) md;
+
+                       surmd->dm = NULL;
+                       surmd->bvhtree = NULL;
+               }
                else if (md->type==eModifierType_Hook) {
                        HookModifierData *hmd = (HookModifierData*) md;
 
index ae07434a37ffe1a36c181a9fc0bbd1a3dc514b46..077481dfa6ede0f5467b52b6eb71e28ee5e6b53f 100644 (file)
@@ -39,6 +39,7 @@ typedef enum ModifierType {
        eModifierType_Fluidsim,
        eModifierType_Mask,
        eModifierType_SimpleDeform,
+       eModifierType_Surface,
        NUM_MODIFIER_TYPES
 } ModifierType;
 
@@ -418,6 +419,14 @@ typedef struct CollisionModifierData {
        struct BVHTree *bvhtree; /* bounding volume hierarchy for this cloth object */
 } CollisionModifierData;
 
+typedef struct SurfaceModifierData {
+       ModifierData    modifier;
+
+       struct DerivedMesh *dm;
+
+       struct BVHTreeFromMesh *bvhtree; /* bounding volume hierarchy of the mesh faces */
+} SurfaceModifierData;
+
 typedef enum {
        eBooleanModifierOp_Intersect,
        eBooleanModifierOp_Union,
index 21c5242a703cafb9526aaafa2e80ca4df45fc468..49435000820d81f4ca96779897a27e91ea7ddfcd 100644 (file)
@@ -225,6 +225,7 @@ typedef struct SoftBody {
 #define PFIELD_USEMAXR                 512
 #define PFIELD_USEMINR                 1024
 #define PFIELD_TEX_ROOTCO              2048
+#define PFIELD_SURFACE                 4096
 
 /* pd->falloff */
 #define PFIELD_FALL_SPHERE             0
index 8b249815b6fb188ce52592b1fb349510e38c6556..2ec30bfa864e93418bba85d358916ff694747765 100644 (file)
@@ -1031,7 +1031,7 @@ static uiBlock *modifiers_add_menu(void *ob_v)
                /* Only allow adding through appropriate other interfaces */
                if(ELEM3(i, eModifierType_Softbody, eModifierType_Hook, eModifierType_ParticleSystem)) continue;
                
-               if(ELEM3(i, eModifierType_Cloth, eModifierType_Collision, eModifierType_Fluidsim)) continue;
+               if(ELEM4(i, eModifierType_Cloth, eModifierType_Collision, eModifierType_Surface, eModifierType_Fluidsim)) continue;
 
                if((mti->flags&eModifierTypeFlag_AcceptsCVs) ||
                   (ob->type==OB_MESH && (mti->flags&eModifierTypeFlag_AcceptsMesh))) {
@@ -1771,7 +1771,7 @@ static void draw_modifier(uiBlock *block, Object *ob, ModifierData *md, int *xco
                uiDefBut(block, TEX, B_MODIFIER_REDRAW, "", x+10, y-1, buttonWidth-60, 19, md->name, 0.0, sizeof(md->name)-1, 0.0, 0.0, "Modifier name"); 
 
                /* Softbody not allowed in this situation, enforce! */
-               if ((md->type!=eModifierType_Softbody && md->type!=eModifierType_Collision) || !(ob->pd && ob->pd->deflect)) {
+               if (((md->type!=eModifierType_Softbody && md->type!=eModifierType_Collision) || !(ob->pd && ob->pd->deflect)) && (md->type!=eModifierType_Surface)) {
                        uiDefIconButBitI(block, TOG, eModifierMode_Render, B_MODIFIER_RECALC, ICON_SCENE, x+10+buttonWidth-60, y-1, 19, 19,&md->mode, 0, 0, 1, 0, "Enable modifier during rendering");
                        but= uiDefIconButBitI(block, TOG, eModifierMode_Realtime, B_MODIFIER_RECALC, VICON_VIEW3D, x+10+buttonWidth-40, y-1, 19, 19,&md->mode, 0, 0, 1, 0, "Enable modifier during interactive display");
                        if (mti->flags&eModifierTypeFlag_SupportsEditmode) {
@@ -1813,7 +1813,7 @@ static void draw_modifier(uiBlock *block, Object *ob, ModifierData *md, int *xco
                
                // deletion over the deflection panel
                // fluid particle modifier can't be deleted here
-               if(md->type!=eModifierType_Fluidsim && md->type!=eModifierType_Collision && !modifier_is_fluid_particles(md))
+               if(md->type!=eModifierType_Fluidsim && md->type!=eModifierType_Collision && md->type!=eModifierType_Surface && !modifier_is_fluid_particles(md))
                {
                        but = uiDefIconBut(block, BUT, B_MODIFIER_RECALC, VICON_X, x+width-70+40, y, 16, 16, NULL, 0.0, 0.0, 0.0, 0.0, "Delete modifier");
                        uiButSetFunc(but, modifiers_del, ob, md);
@@ -1884,6 +1884,8 @@ static void draw_modifier(uiBlock *block, Object *ob, ModifierData *md, int *xco
                        height = 31;
                } else if (md->type==eModifierType_Collision) {
                        height = 31;
+               } else if (md->type==eModifierType_Surface) {
+                       height = 31;
                } else if (md->type==eModifierType_Fluidsim) {
                        height = 31;
                } else if (md->type==eModifierType_Boolean) {
@@ -1924,7 +1926,7 @@ static void draw_modifier(uiBlock *block, Object *ob, ModifierData *md, int *xco
 
                y -= 18;
 
-               if (!isVirtual && (md->type!=eModifierType_Collision)) {
+               if (!isVirtual && (md->type!=eModifierType_Collision) && (md->type!=eModifierType_Surface)) {
                        uiSetButLock(object_data_is_libdata(ob), ERROR_LIBDATA_MESSAGE); /* only here obdata, the rest of modifiers is ob level */
 
                        uiBlockBeginAlign(block);
@@ -2369,6 +2371,8 @@ static void draw_modifier(uiBlock *block, Object *ob, ModifierData *md, int *xco
 
                } else if (md->type==eModifierType_Collision) {
                        uiDefBut(block, LABEL, 1, "See Collision panel.",       lx, (cy-=19), buttonWidth,19, NULL, 0.0, 0.0, 0, 0, "");
+               } else if (md->type==eModifierType_Surface) {
+                       uiDefBut(block, LABEL, 1, "See Fields panel.",  lx, (cy-=19), buttonWidth,19, NULL, 0.0, 0.0, 0, 0, "");
                } else if (md->type==eModifierType_Fluidsim) {
                        uiDefBut(block, LABEL, 1, "See Fluidsim panel.",        lx, (cy-=19), buttonWidth,19, NULL, 0.0, 0.0, 0, 0, "");
                } else if (md->type==eModifierType_Boolean) {
index 5c41390b150fb5d0f175c8a5167ffbb0ec77670c..7fc504ba8d3fefccb2e258ee9059daab01434002 100644 (file)
@@ -3340,6 +3340,35 @@ static void object_panel_collision(Object *ob)
                }
        }
 }
+static void object_surface__enabletoggle ( void *ob_v, void *arg2 )
+{
+       Object *ob = ob_v;
+       PartDeflect *pd= ob->pd;
+       ModifierData *md = modifiers_findByType ( ob, eModifierType_Surface );
+       
+       if(!md)
+       {
+               if(pd && (pd->flag & PFIELD_SURFACE)
+                       && ELEM5(pd->forcefield,PFIELD_HARMONIC,PFIELD_FORCE,PFIELD_HARMONIC,PFIELD_CHARGE,PFIELD_LENNARDJ))
+               {
+                       md = modifier_new ( eModifierType_Surface );
+                       BLI_addtail ( &ob->modifiers, md );
+                       DAG_scene_sort(G.scene);
+                       DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
+                       allqueue(REDRAWBUTSEDIT, 0);
+                       allqueue(REDRAWVIEW3D, 0);
+               }
+       }
+       else if(!pd || !(pd->flag & PFIELD_SURFACE)
+               || ELEM5(pd->forcefield,PFIELD_HARMONIC,PFIELD_FORCE,PFIELD_HARMONIC,PFIELD_CHARGE,PFIELD_LENNARDJ))
+       {
+               DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
+               BLI_remlink ( &ob->modifiers, md );
+               modifier_free ( md );
+               DAG_scene_sort(G.scene);
+               allqueue(REDRAWBUTSEDIT, 0);
+       }
+}
 static void object_panel_fields(Object *ob)
 {
        uiBlock *block;
@@ -3425,9 +3454,12 @@ static void object_panel_fields(Object *ob)
                }
                
                if(ob->particlesystem.first)
-                       uiDefButS(block, MENU, B_FIELD_DEP, menustr,                    80,180,70,20, &pd->forcefield, 0.0, 0.0, 0, 0, tipstr);
+                       but = uiDefButS(block, MENU, B_FIELD_DEP, menustr,                      80,180,70,20, &pd->forcefield, 0.0, 0.0, 0, 0, tipstr);
                else
-                       uiDefButS(block, MENU, B_FIELD_DEP, menustr,                    10,180,140,20, &pd->forcefield, 0.0, 0.0, 0, 0, tipstr);
+                       but = uiDefButS(block, MENU, B_FIELD_DEP, menustr,                      10,180,140,20, &pd->forcefield, 0.0, 0.0, 0, 0, tipstr);
+
+               if(!particles)
+                       uiButSetFunc(but, object_surface__enabletoggle, ob, NULL);
 
                uiBlockEndAlign(block);
                uiDefBut(block, LABEL, 0, "",160,180,150,2, NULL, 0.0, 0, 0, 0, "");
@@ -3472,7 +3504,12 @@ static void object_panel_fields(Object *ob)
                        }
                        else if(particles==0 && ELEM(pd->forcefield,PFIELD_VORTEX,PFIELD_WIND)==0){
                                //uiDefButF(block, NUM, B_FIELD_CHANGE, "Distance: ",   10,20,140,20, &pd->f_dist, 0, 1000.0, 10, 0, "Falloff power (real gravitational fallof = 2)");
-                               uiDefButBitS(block, TOG, PFIELD_PLANAR, B_FIELD_CHANGE, "Planar",       10,15,140,20, &pd->flag, 0.0, 0, 0, 0, "Create planar field");
+                               uiDefButBitS(block, TOG, PFIELD_PLANAR, B_FIELD_CHANGE, "Planar",       10,35,140,20, &pd->flag, 0.0, 0, 0, 0, "Create planar field");
+                       }
+                       
+                       if(particles==0 && ELEM5(pd->forcefield,PFIELD_HARMONIC,PFIELD_FORCE,PFIELD_HARMONIC,PFIELD_CHARGE,PFIELD_LENNARDJ)) {
+                               but = uiDefButBitS(block, TOG, PFIELD_SURFACE, B_FIELD_CHANGE, "Surface",       10,15,140,20, &pd->flag, 0.0, 0, 0, 0, "Use closest point on surface");
+                               uiButSetFunc(but, object_surface__enabletoggle, ob, NULL);
                        }
                        uiBlockEndAlign(block);