rigidbody: Add force field support
authorSergej Reich <sergej.reich@googlemail.com>
Wed, 23 Jan 2013 05:56:27 +0000 (05:56 +0000)
committerSergej Reich <sergej.reich@googlemail.com>
Wed, 23 Jan 2013 05:56:27 +0000 (05:56 +0000)
Force fields work with rigid bodies just like they do with other simulations.

Increase min and max strength of force fields so they can influence heavy rigid
bodies.

TODO: Adjust force field strength based on the time step taken.

Part of GSoC 2010 and 2012.
Authors: Joshua Leung (aligorith), Sergej Reich (sergof)

source/blender/blenkernel/intern/rigidbody.c
source/blender/blenloader/intern/readfile.c
source/blender/blenloader/intern/writefile.c
source/blender/makesdna/DNA_rigidbody_types.h
source/blender/makesrna/intern/rna_object_force.c
source/blender/makesrna/intern/rna_rigidbody.c

index e6f6c9a9a989cac43ae62d2fb9f0312c00cac401..90200fd6742299a120ef903bb04ad216934d7fce 100644 (file)
@@ -97,6 +97,10 @@ void BKE_rigidbody_free_world(RigidBodyWorld *rbw)
        if (rbw->objects)
                free(rbw->objects);
 
+       /* free effector weights */
+       if (rbw->effector_weights)
+               MEM_freeN(rbw->effector_weights);
+
        /* free rigidbody world itself */
        MEM_freeN(rbw);
 }
@@ -459,6 +463,8 @@ RigidBodyWorld *BKE_rigidbody_create_world(Scene *scene)
        rbw = MEM_callocN(sizeof(RigidBodyWorld), "RigidBodyWorld");
 
        /* set default settings */
+       rbw->effector_weights = BKE_add_effector_weights(NULL);
+
        rbw->ltime = PSFRA;
 
        rbw->time_scale = 1.0f;
@@ -596,6 +602,7 @@ static void rigidbody_update_sim_world(Scene *scene, RigidBodyWorld *rbw)
        /* adjust gravity to take effector weights into account */
        if (scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY) {
                copy_v3_v3(adj_gravity, scene->physics_settings.gravity);
+               mul_v3_fl(adj_gravity, rbw->effector_weights->global_gravity * rbw->effector_weights->weight[0]);
        }
        else {
                zero_v3(adj_gravity);
@@ -631,6 +638,43 @@ static void rigidbody_update_sim_ob(Scene *scene, RigidBodyWorld *rbw, Object *o
                RB_body_activate(rbo->physics_object);
                RB_body_set_loc_rot(rbo->physics_object, loc, rot);
        }
+       /* update influence of effectors - but don't do it on an effector */
+       /* only dynamic bodies need effector update */
+       else if (rbo->type == RBO_TYPE_ACTIVE && ((ob->pd == NULL) || (ob->pd->forcefield == PFIELD_NULL))) {
+               EffectorWeights *effector_weights = rbw->effector_weights;
+               EffectedPoint epoint;
+               ListBase *effectors;
+
+               /* get effectors present in the group specified by effector_weights */
+               effectors = pdInitEffectors(scene, ob, NULL, effector_weights);
+               if (effectors) {
+                       float force[3] = {0.0f, 0.0f, 0.0f};
+                       float loc[3], vel[3];
+
+                       /* create dummy 'point' which represents last known position of object as result of sim */
+                       // XXX: this can create some inaccuracies with sim position, but is probably better than using unsimulated vals?
+                       RB_body_get_position(rbo->physics_object, loc);
+                       RB_body_get_linear_velocity(rbo->physics_object, vel);
+
+                       pd_point_from_loc(scene, loc, vel, 0, &epoint);
+
+                       /* calculate net force of effectors, and apply to sim object
+                        *      - we use 'central force' since apply force requires a "relative position" which we don't have...
+                        */
+                       pdDoEffectors(effectors, NULL, effector_weights, &epoint, force, NULL);
+                       if (G.f & G_DEBUG)
+                               printf("\tapplying force (%f,%f,%f) to '%s'\n", force[0], force[1], force[2], ob->id.name + 2);
+                       /* activate object in case it is deactivated */
+                       if (!is_zero_v3(force))
+                               RB_body_activate(rbo->physics_object);
+                       RB_body_apply_central_force(rbo->physics_object, force);
+               }
+               else if (G.f & G_DEBUG)
+                       printf("\tno forces to apply to '%s'\n", ob->id.name + 2);
+
+               /* cleanup */
+               pdEndEffectors(&effectors);
+       }
        /* NOTE: passive objects don't need to be updated since they don't move */
 
        /* NOTE: no other settings need to be explicitly updated here,
index 95fa4018392ed87283e843d535de582b930d2288..b0f1d3f37eddf513e5746bc183adb9f21a1b9bd8 100644 (file)
@@ -5021,6 +5021,8 @@ static void lib_link_scene(FileData *fd, Main *main)
                                RigidBodyWorld *rbw = sce->rigidbody_world;
                                if (rbw->group)
                                        rbw->group = newlibadr(fd, sce->id.lib, rbw->group);
+                               if (rbw->effector_weights)
+                                       rbw->effector_weights->group = newlibadr(fd, sce->id.lib, rbw->effector_weights->group);
                        }
                        
                        if (sce->nodetree) {
@@ -5296,6 +5298,11 @@ static void direct_link_scene(FileData *fd, Scene *sce)
                rbw->physics_world = NULL;
                rbw->objects = NULL;
                rbw->numbodies = 0;
+
+               /* set effector weights */
+               rbw->effector_weights = newdataadr(fd, rbw->effector_weights);
+               if (!rbw->effector_weights)
+                       rbw->effector_weights = BKE_add_effector_weights(NULL);
        }
 }
 
index a52e4e28981d16769b2d44740cca5acb1122d0a8..da50a05a3d99a6a2a1be2a14ac6323b4a1969700 100644 (file)
@@ -2306,6 +2306,7 @@ static void write_scenes(WriteData *wd, ListBase *scebase)
                /* writing RigidBodyWorld data to the blend file */
                if (sce->rigidbody_world) {
                        writestruct(wd, DATA, "RigidBodyWorld", 1, sce->rigidbody_world);
+                       writestruct(wd, DATA, "EffectorWeights", 1, sce->rigidbody_world->effector_weights);
                }
                
                sce= sce->id.next;
index 8c66a5b23335f76d5f7eabe03527b40aa78d7656..43c2cdb227a958b0318d5277750ff35d8f02a80c 100644 (file)
@@ -37,6 +37,8 @@
 
 struct Group;
 
+struct EffectorWeights;
+
 /* ******************************** */
 /* RigidBody World */
 
@@ -46,6 +48,8 @@ struct Group;
  */
 typedef struct RigidBodyWorld {
        /* Sim World Settings ------------------------------------------------------------- */
+       struct EffectorWeights *effector_weights; /* effectors info */
+
        struct Group *group;            /* Group containing objects to use for Rigid Bodies */
        struct Object **objects;        /* Array to access group objects by index, only used at runtime */
        
index 0c2944b39667f79a8950053d0243c5225e55bc16..873ea49824c6382a90aff4a8540f4da2c73a9f58 100644 (file)
@@ -1182,7 +1182,7 @@ static void rna_def_field(BlenderRNA *brna)
        
        prop = RNA_def_property(srna, "strength", PROP_FLOAT, PROP_NONE);
        RNA_def_property_float_sdna(prop, NULL, "f_strength");
-       RNA_def_property_range(prop, -1000.0f, 1000.0f);
+       RNA_def_property_range(prop, -FLT_MAX, FLT_MAX);
        RNA_def_property_ui_text(prop, "Strength", "Strength of force field");
        RNA_def_property_update(prop, 0, "rna_FieldSettings_update");
 
index c7d6324b8815d011525f3ed0e401a24dd3baf1ff..cd8b63cd0deb3ea772ec63ae92e0462f346e0171 100644 (file)
@@ -345,6 +345,12 @@ static void rna_def_rigidbody_world(BlenderRNA *brna)
        RNA_def_property_boolean_funcs(prop, NULL, "rna_RigidBodyWorld_split_impulse_set");
        RNA_def_property_ui_text(prop, "Split Impulse", "Reduces extra velocity that can build up when objects collide (lowers simulation stabilty a litte so use only when necessary)");
        RNA_def_property_update(prop, NC_SCENE, "rna_RigidBodyWorld_reset");
+
+       /* effector weights */
+       prop = RNA_def_property(srna, "effector_weights", PROP_POINTER, PROP_NONE);
+       RNA_def_property_struct_type(prop, "EffectorWeights");
+       RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+       RNA_def_property_ui_text(prop, "Effector Weights", "");
 }
 
 static void rna_def_rigidbody_object(BlenderRNA *brna)