Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJanne Karhu <jhkarh@gmail.com>2009-10-01 02:10:14 +0400
committerJanne Karhu <jhkarh@gmail.com>2009-10-01 02:10:14 +0400
commitbff893a42047cfc92671f878109c1ff17ce5f8a2 (patch)
treef18bfc386773e1878fc4805a57618af481bc876e /source/blender/blenkernel
parent7d9bfdc31ab179b4dd4a626bc8f9a873c59402b4 (diff)
Unified effector functionality for particles, cloth and softbody
* Unified scene wide gravity (currently in scene buttons) instead of each simulation having it's own gravity. * Weight parameters for all effectors and an effector group setting. * Every effector can use noise. * Most effectors have "shapes" point, plane, surface, every point. - "Point" is most like the old effectors and uses the effector location as the effector point. - "Plane" uses the closest point on effectors local xy-plane as the effector point. - "Surface" uses the closest point on an effector object's surface as the effector point. - "Every Point" uses every point in a mesh effector object as an effector point. - The falloff is calculated from this point, so for example with "surface" shape and "use only negative z axis" it's possible to apply force only "inside" the effector object. * Spherical effector is now renamed as "force" as it's no longer just spherical. * New effector parameter "flow", which makes the effector act as surrounding air velocity, so the resulting force is proportional to the velocity difference of the point and "air velocity". For example a wind field with flow=1.0 results in proper non-accelerating wind. * New effector fields "turbulence", which creates nice random flow paths, and "drag", which slows the points down. * Much improved vortex field. * Effectors can now effect particle rotation as well as location. * Use full, or only positive/negative z-axis to apply force (note. the z-axis is the surface normal in the case of effector shape "surface") * New "force field" submenu in add menu, which adds an empty with the chosen effector (curve object for corve guides). * Other dynamics should be quite easy to add to the effector system too if wanted. * "Unified" doesn't mean that force fields give the exact same results for particles, softbody & cloth, since their final effect depends on many external factors, like for example the surface area of the effected faces. Code changes * Subversion bump for correct handling of global gravity. * Separate ui py file for common dynamics stuff. * Particle settings updating is flushed with it's id through DAG_id_flush_update(..). Known issues * Curve guides don't yet have all ui buttons in place, but they should work none the less. * Hair dynamics don't yet respect force fields. Other changes * Particle emission defaults now to frames 1-200 with life of 50 frames to fill the whole default timeline. * Many particles drawing related crashes fixed. * Sometimes particles didn't update on first frame properly. * Hair with object/group visualization didn't work properly. * Memory leaks with PointCacheID lists (Genscher, remember to free pidlists after use :).
Diffstat (limited to 'source/blender/blenkernel')
-rw-r--r--source/blender/blenkernel/BKE_collision.h9
-rw-r--r--source/blender/blenkernel/BKE_effect.h109
-rw-r--r--source/blender/blenkernel/BKE_particle.h65
-rw-r--r--source/blender/blenkernel/intern/boids.c187
-rw-r--r--source/blender/blenkernel/intern/cloth.c7
-rw-r--r--source/blender/blenkernel/intern/collision.c91
-rw-r--r--source/blender/blenkernel/intern/depsgraph.c54
-rw-r--r--source/blender/blenkernel/intern/effect.c855
-rw-r--r--source/blender/blenkernel/intern/implicit.c22
-rw-r--r--source/blender/blenkernel/intern/modifier.c7
-rw-r--r--source/blender/blenkernel/intern/object.c15
-rw-r--r--source/blender/blenkernel/intern/particle.c307
-rw-r--r--source/blender/blenkernel/intern/particle_system.c686
-rw-r--r--source/blender/blenkernel/intern/pointcache.c4
-rw-r--r--source/blender/blenkernel/intern/scene.c4
-rw-r--r--source/blender/blenkernel/intern/smoke.c3
-rw-r--r--source/blender/blenkernel/intern/softbody.c67
17 files changed, 1267 insertions, 1225 deletions
diff --git a/source/blender/blenkernel/BKE_collision.h b/source/blender/blenkernel/BKE_collision.h
index e0df75f41b9..5ca8ad892ac 100644
--- a/source/blender/blenkernel/BKE_collision.h
+++ b/source/blender/blenkernel/BKE_collision.h
@@ -141,6 +141,15 @@ void interpolateOnTriangle ( float to[3], float v1[3], float v2[3], float v3[3],
/////////////////////////////////////////////////
Object **get_collisionobjects(struct Scene *scene, Object *self, int *numcollobj);
+typedef struct ColliderCache {
+ struct ColliderCache *next, *prev;
+ struct Object *ob;
+ struct CollisionModifierData *collmd;
+} ColliderCache;
+
+struct ListBase *get_collider_cache(struct Scene *scene, Object *self);
+void free_collider_cache(struct ListBase **colliders);
+
/////////////////////////////////////////////////
diff --git a/source/blender/blenkernel/BKE_effect.h b/source/blender/blenkernel/BKE_effect.h
index e21e83bf5cf..83ec7c13946 100644
--- a/source/blender/blenkernel/BKE_effect.h
+++ b/source/blender/blenkernel/BKE_effect.h
@@ -32,6 +32,7 @@
#define BKE_EFFECT_H
#include "DNA_object_types.h"
+#include "DNA_modifier_types.h"
struct Object;
struct Scene;
@@ -40,20 +41,72 @@ struct ListBase;
struct Particle;
struct Group;
struct RNG;
+struct ParticleSimulationData;
+struct ParticleData;
+struct ParticleKey;
-struct PartDeflect *object_add_collision_fields(void);
+struct EffectorWeights *BKE_add_effector_weights(struct Group *group);
+struct PartDeflect *object_add_collision_fields(int type);
-typedef struct pEffectorCache {
- struct pEffectorCache *next, *prev;
- Object *ob;
-
- /* precalculated variables */
- float oldloc[3], oldspeed[3];
- float scale, time_scale;
- float guide_dist;
+/* Input to effector code */
+typedef struct EffectedPoint {
+ float *loc;
+ float *vel;
+ float *ave; /* angular velocity for particles with dynamic rotation */
+ float *rot; /* rotation quaternion for particles with dynamic rotation */
+ float vel_to_frame;
+ float vel_to_sec;
+
+ /* only for particles */
+ float size, charge;
+
+ unsigned int flag;
+ int index;
+
+ struct ParticleSystem *psys; /* particle system the point belongs to */
+} EffectedPoint;
+
+typedef struct GuideEffectorData {
+ float vec_to_point[3];
+ float strength;
+} GuideEffectorData;
+
+typedef struct EffectorData {
+ /* Effector point */
+ float loc[3];
+ float nor[3];
+ float vel[3];
+
+ float vec_to_point[3];
+ float distance, falloff;
+
+ /* only for effector particles */
+ float size, charge;
+
+ /* only for vortex effector with surface falloff */
+ float nor2[3], vec_to_point2[3];
+
+ int *index; /* point index */
+} EffectorData;
+
+/* used for calculating the effector force */
+typedef struct EffectorCache {
+ struct EffectorCache *next, *prev;
+
+ struct Scene *scene;
+ struct Object *ob;
+ struct ParticleSystem *psys;
+ struct SurfaceModifierData *surmd;
- Object obcopy; /* for restoring transformation data */
-} pEffectorCache;
+ struct PartDeflect *pd;
+
+ /* precalculated for guides */
+ struct GuideEffectorData *guide_data;
+ float guide_loc[4], guide_dir[3], guide_radius;
+
+ float frame;
+ int flag;
+} EffectorCache;
void free_effect(struct Effect *eff);
void free_effects(struct ListBase *lb);
@@ -61,23 +114,33 @@ struct Effect *copy_effect(struct Effect *eff);
void copy_effects(struct ListBase *lbn, struct ListBase *lb);
void deselectall_eff(struct Object *ob);
-/* particle deflector */
-#define PE_WIND_AS_SPEED 0x00000001
-
struct PartEff *give_parteff(struct Object *ob);
-struct ListBase *pdInitEffectors(struct Scene *scene, struct Object *obsrc, struct Group *group);
-void pdEndEffectors(struct ListBase *lb);
-void pdDoEffectors(struct Scene *scene, struct ListBase *lb, float *opco, float *force,
- float *speed, float cur_time, float loc_time, unsigned int flags);
+
+
+void free_partdeflect(struct PartDeflect *pd);
+struct ListBase *pdInitEffectors(struct Scene *scene, struct Object *ob_src, struct ParticleSystem *psys_src, struct EffectorWeights *weights);
+void pdEndEffectors(struct ListBase **effectors);
+void pdDoEffectors(struct ListBase *effectors, struct ListBase *colliders, struct EffectorWeights *weights, struct EffectedPoint *point, float *force, float *impulse);
+
+void pd_point_from_particle(struct ParticleSimulationData *sim, struct ParticleData *pa, struct ParticleKey *state, struct EffectedPoint *point);
+void pd_point_from_loc(struct Scene *scene, float *loc, float *vel, int index, struct EffectedPoint *point);
+void pd_point_from_soft(struct Scene *scene, float *loc, float *vel, int index, struct EffectedPoint *point);
+
+/* needed for boids */
+float effector_falloff(struct EffectorCache *eff, struct EffectorData *efd, struct EffectedPoint *point, struct EffectorWeights *weights);
+int closest_point_on_surface(struct SurfaceModifierData *surmd, float *co, float *surface_co, float *surface_nor, float *surface_vel);
+int get_effector_data(struct EffectorCache *eff, struct EffectorData *efd, struct EffectedPoint *point, int real_velocity);
/* required for particle_system.c */
-void do_physical_effector(struct Scene *scene, struct Object *ob, float *opco, short type, float force_val, float distance,
- float falloff, float size, float damp, float *eff_velocity, float *vec_to_part,
- float *velocity, float *field, int planar, struct RNG *rng, float noise_factor,
- float charge, float pa_size);
-float effector_falloff(struct PartDeflect *pd, float *eff_velocity, float *vec_to_part);
+//void do_physical_effector(struct EffectorData *eff, struct EffectorPoint *point, float *total_force);
+//float effector_falloff(struct EffectorData *eff, struct EffectorPoint *point, struct EffectorWeights *weights);
+/* EffectedPoint->flag */
+#define PE_WIND_AS_SPEED 1
+#define PE_DYNAMIC_ROTATION 2
+/* EffectorData->flag */
+#define PE_VELOCITY_TO_IMPULSE 1
#endif
diff --git a/source/blender/blenkernel/BKE_particle.h b/source/blender/blenkernel/BKE_particle.h
index 5850ddaca08..e0259ff10dd 100644
--- a/source/blender/blenkernel/BKE_particle.h
+++ b/source/blender/blenkernel/BKE_particle.h
@@ -76,39 +76,18 @@ typedef struct ParticleSimulationData {
struct Object *ob;
struct ParticleSystem *psys;
struct ParticleSystemModifierData *psmd;
- float timestep;
+ struct ListBase *colliders;
} ParticleSimulationData;
-typedef struct ParticleEffectorCache {
- struct ParticleEffectorCache *next, *prev;
- struct Object *ob;
-
- /* precalculated variables for guides */
- float firstloc[4], firstdir[3];
- float *distances;
- float *locations;
- /* precalculated variables for deflection */
- float ob_minmax[6];
- float *face_minmax;
- float *vert_cos;
- /* precalculated variables for boids */
- struct KDTree *tree;
-
- short type, psys_nbr;
-
- struct Object obcopy; /* for restoring transformation data */
- struct RNG *rng; /* random noise generator for e.g. wind */
-} ParticleEffectorCache;
-
-typedef struct ParticleReactEvent {
- struct ParticleReactEvent *next, *prev;
- int event, pa_num;
- Object *ob;
- struct ParticleSystem *psys;
- struct ParticleKey state;
-
- float time, size;
-}ParticleReactEvent;
+//typedef struct ParticleReactEvent {
+// struct ParticleReactEvent *next, *prev;
+// int event, pa_num;
+// Object *ob;
+// struct ParticleSystem *psys;
+// struct ParticleKey state;
+//
+// float time, size;
+//}ParticleReactEvent;
typedef struct ParticleTexture{
float ivel; /* used in reset */
@@ -185,8 +164,8 @@ typedef struct ParticleBillboardData
/* container for moving data between deflet_particle and particle_intersect_face */
typedef struct ParticleCollision
{
- struct Object *ob, *ob_t; // collided and current objects
- struct CollisionModifierData *md; // collision modifier for ob_t;
+ struct Object *ob, *hit_ob; // collided and current objects
+ struct CollisionModifierData *md, *hit_md; // collision modifiers for current and hit object;
float nor[3]; // normal at collision point
float vel[3]; // velocity of collision point
float co1[3], co2[3]; // ray start and end points
@@ -244,7 +223,6 @@ void object_add_particle_system(struct Scene *scene, struct Object *ob);
void object_remove_particle_system(struct Scene *scene, struct Object *ob);
struct ParticleSettings *psys_new_settings(char *name, struct Main *main);
struct ParticleSettings *psys_copy_settings(struct ParticleSettings *part);
-void psys_flush_particle_settings(struct Scene *scene, struct ParticleSettings *part, int recalc);
void make_local_particlesettings(struct ParticleSettings *part);
void psys_reset(struct ParticleSystem *psys, int mode);
@@ -254,7 +232,8 @@ void psys_find_parents(struct ParticleSimulationData *sim);
void psys_cache_paths(struct ParticleSimulationData *sim, float cfra);
void psys_cache_edit_paths(struct Scene *scene, struct Object *ob, struct PTCacheEdit *edit, float cfra);
void psys_cache_child_paths(struct ParticleSimulationData *sim, float cfra, int editupdate);
-int do_guide(struct Scene *scene, struct ParticleKey *state, int pa_num, float time, struct ListBase *lb);
+int do_guides(struct ListBase *effectors, ParticleKey *state, int pa_num, float time);
+void precalc_guides(struct ParticleSimulationData *sim, struct ListBase *effectors);
float psys_get_timestep(struct ParticleSimulationData *sim);
float psys_get_child_time(struct ParticleSystem *psys, struct ChildParticle *cpa, float cfra, float *birthtime, float *dietime);
float psys_get_child_size(struct ParticleSystem *psys, struct ChildParticle *cpa, float cfra, float *pa_time);
@@ -273,9 +252,7 @@ void psys_make_billboard(ParticleBillboardData *bb, float xvec[3], float yvec[3]
/* particle_system.c */
struct ParticleSystem *psys_get_target_system(struct Object *ob, struct ParticleTarget *pt);
void psys_count_keyed_targets(struct ParticleSimulationData *sim);
-//void psys_get_reactor_target(struct ParticleSimulationData *sim, struct Object **target_ob, struct ParticleSystem **target_psys);
-
-int psys_update_effectors(ParticleSimulationData *sim, float cfra, int precalc);
+void psys_update_particle_tree(struct ParticleSystem *psys, float cfra);
void psys_make_temp_pointcache(struct Object *ob, struct ParticleSystem *psys);
void psys_get_pointcache_start_end(struct Scene *scene, ParticleSystem *psys, int *sfra, int *efra);
@@ -316,29 +293,17 @@ void psys_particle_on_dm(struct DerivedMesh *dm, int from, int index, int index_
/* particle_system.c */
void initialize_particle(struct ParticleSimulationData *sim, struct ParticleData *pa, int p);
-
-int effector_find_co(struct Scene *scene, float *pco, struct SurfaceModifierData *sur, struct Object *ob, struct PartDeflect *pd, float *co, float *nor, float *vel, int *index);
-void do_effectors(struct ParticleSimulationData *sim, int pa_no, struct ParticleData *pa, struct ParticleKey *state, float *texco, float *force_field, float *vel,float framestep, float cfra);
-void psys_end_effectors(struct ParticleSystem *psys);
-
void psys_calc_dmcache(struct Object *ob, struct DerivedMesh *dm, struct ParticleSystem *psys);
int psys_particle_dm_face_lookup(struct Object *ob, struct DerivedMesh *dm, int index, float *fw, struct LinkNode *node);
void reset_particle(struct ParticleSimulationData *sim, struct ParticleData *pa, float dtime, float cfra);
-
/* psys_reset */
#define PSYS_RESET_ALL 1
#define PSYS_RESET_DEPSGRAPH 2
#define PSYS_RESET_CHILDREN 3
#define PSYS_RESET_CACHE_MISS 4
-/* ParticleEffectorCache->type */
-#define PSYS_EC_EFFECTOR 1
-#define PSYS_EC_DEFLECT 2
-#define PSYS_EC_PARTICLE 4
-#define PSYS_EC_REACTOR 8
-
/* index_dmcache */
#define DMCACHE_NOTFOUND -1
#define DMCACHE_ISCHILD -2
diff --git a/source/blender/blenkernel/intern/boids.c b/source/blender/blenkernel/intern/boids.c
index 7c3f3a7876f..76824d3a34a 100644
--- a/source/blender/blenkernel/intern/boids.c
+++ b/source/blender/blenkernel/intern/boids.c
@@ -47,6 +47,7 @@
#include "BLI_blenlib.h"
#include "BLI_kdtree.h"
#include "BLI_kdopbvh.h"
+#include "BKE_collision.h"
#include "BKE_effect.h"
#include "BKE_boids.h"
#include "BKE_particle.h"
@@ -72,112 +73,91 @@ static int rule_goal_avoid(BoidRule *rule, BoidBrainData *bbd, BoidValues *val,
{
BoidRuleGoalAvoid *gabr = (BoidRuleGoalAvoid*) rule;
BoidSettings *boids = bbd->part->boids;
- ParticleEffectorCache *ec;
Object *priority_ob = NULL;
BoidParticle *bpa = pa->boid;
+ EffectedPoint epoint;
+ ListBase *effectors = bbd->sim->psys->effectors;
+ EffectorCache *cur, *eff = NULL;
+ EffectorData efd, cur_efd;
float vec[3] = {0.0f, 0.0f, 0.0f}, loc[3] = {0.0f, 0.0f, 0.0f};
float mul = (rule->type == eBoidRuleType_Avoid ? 1.0 : -1.0);
float priority = 0.0f, len = 0.0f;
int ret = 0;
- /* first find out goal/predator with highest priority */
- /* if rule->ob specified use it */
- if(gabr->ob && (rule->type != eBoidRuleType_Goal || gabr->ob != bpa->ground)) {
- PartDeflect *pd = gabr->ob->pd;
- float vec_to_part[3];
-
- if(pd && pd->forcefield == PFIELD_BOID) {
- effector_find_co(bbd->sim->scene, pa->prev_state.co, NULL, gabr->ob, pd, loc, vec, NULL, NULL);
-
- VecSubf(vec_to_part, pa->prev_state.co, loc);
+ pd_point_from_particle(bbd->sim, pa, &pa->state, &epoint);
- priority = mul * pd->f_strength * effector_falloff(pd, vec, vec_to_part);
- }
- else
- priority = 1.0;
-
- priority = 1.0;
- priority_ob = gabr->ob;
- }
- else for(ec=bbd->sim->psys->effectors.first; ec; ec=ec->next) {
- if(ec->type & PSYS_EC_EFFECTOR) {
- Object *eob = ec->ob;
- PartDeflect *pd = eob->pd;
-
- /* skip current object */
- if(rule->type == eBoidRuleType_Goal && eob == bpa->ground)
- continue;
-
- if(pd->forcefield == PFIELD_BOID && mul * pd->f_strength > 0.0f) {
- float vec_to_part[3], temp;
-
- effector_find_co(bbd->sim->scene, pa->prev_state.co, NULL, eob, pd, loc, vec, NULL, NULL);
-
- VecSubf(vec_to_part, pa->prev_state.co, loc);
-
- temp = mul * pd->f_strength * effector_falloff(pd, vec, vec_to_part);
-
- if(temp == 0.0f)
- ; /* do nothing */
- else if(temp > priority) {
- priority = temp;
- priority_ob = eob;
- len = VecLength(vec_to_part);
- }
- /* choose closest object with same priority */
- else if(temp == priority) {
- float len2 = VecLength(vec_to_part);
-
- if(len2 < len) {
- priority_ob = eob;
- len = len2;
- }
+ /* first find out goal/predator with highest priority */
+ if(effectors) for(cur = effectors->first; cur; cur=cur->next) {
+ Object *eob = cur->ob;
+ PartDeflect *pd = cur->pd;
+
+ if(gabr->ob && (rule->type != eBoidRuleType_Goal || gabr->ob != bpa->ground)) {
+ if(gabr->ob == eob) {
+ /* TODO: objects without any effector and effectors with multiple points */
+ if(get_effector_data(cur, &efd, &epoint, 0)) {
+ if(cur->pd && cur->pd->forcefield == PFIELD_BOID)
+ priority = mul * pd->f_strength * effector_falloff(cur, &efd, &epoint, bbd->part->effector_weights);
+ else
+ priority = 1.0;
+
+ eff = cur;
}
+ break;
+ }
+ }
+ else if(rule->type == eBoidRuleType_Goal && eob == bpa->ground)
+ ; /* skip current object */
+ else if(pd->forcefield == PFIELD_BOID && mul * pd->f_strength > 0.0f && get_effector_data(eff, &efd, &epoint, 0)) {
+ float temp = mul * pd->f_strength * effector_falloff(cur, &cur_efd, &epoint, bbd->part->effector_weights);
+
+ if(temp == 0.0f)
+ ; /* do nothing */
+ else if(temp > priority) {
+ priority = temp;
+ eff = cur;
+ efd = cur_efd;
+ len = efd.distance;
+ }
+ /* choose closest object with same priority */
+ else if(temp == priority && efd.distance < len) {
+ eff = cur;
+ efd = cur_efd;
+ len = efd.distance;
}
}
}
/* then use that effector */
if(priority > (rule->type==eBoidRuleType_Avoid ? gabr->fear_factor : 0.0f)) { /* with avoid, factor is "fear factor" */
- Object *eob = priority_ob;
+ Object *eob = eff->ob;
PartDeflect *pd = eob->pd;
- float vec_to_part[3];
- float surface = 0.0f;
- float nor[3];
+ float surface = pd->shape == PFIELD_SHAPE_SURFACE ? 1.0f : 0.0f;
if(gabr->options & BRULE_GOAL_AVOID_PREDICT) {
/* estimate future location of target */
- surface = (float)effector_find_co(bbd->sim->scene, pa->prev_state.co, NULL, eob, pd, loc, nor, vec, NULL);
-
- VecSubf(vec_to_part, pa->prev_state.co, loc);
- len = Normalize(vec_to_part);
+ get_effector_data(eff, &efd, &epoint, 1);
- VecMulf(vec, len / (val->max_speed * bbd->timestep));
- VecAddf(loc, loc, vec);
- VecSubf(vec_to_part, pa->prev_state.co, loc);
- }
- else {
- surface = (float)effector_find_co(bbd->sim->scene, pa->prev_state.co, NULL, eob, pd, loc, nor, NULL, NULL);
-
- VecSubf(vec_to_part, pa->prev_state.co, loc);
- len = VecLength(vec_to_part);
+ VecMulf(efd.vel, efd.distance / (val->max_speed * bbd->timestep));
+ VecAddf(efd.loc, efd.loc, efd.vel);
+ VecSubf(efd.vec_to_point, pa->prev_state.co, efd.loc);
+ efd.distance = VecLength(efd.vec_to_point);
}
if(rule->type == eBoidRuleType_Goal && boids->options & BOID_ALLOW_CLIMB && surface!=0.0f) {
if(!bbd->goal_ob || bbd->goal_priority < priority) {
bbd->goal_ob = eob;
- VECCOPY(bbd->goal_co, loc);
- VECCOPY(bbd->goal_nor, nor);
+ VECCOPY(bbd->goal_co, efd.loc);
+ VECCOPY(bbd->goal_nor, efd.nor);
}
}
else if(rule->type == eBoidRuleType_Avoid && bpa->data.mode == eBoidMode_Climbing &&
priority > 2.0f * gabr->fear_factor) {
/* detach from surface and try to fly away from danger */
- VECCOPY(vec_to_part, bpa->gravity);
- VecMulf(vec_to_part, -1.0f);
+ VECCOPY(efd.vec_to_point, bpa->gravity);
+ VecMulf(efd.vec_to_point, -1.0f);
}
- VECCOPY(bbd->wanted_co, vec_to_part);
+ VECCOPY(bbd->wanted_co, efd.vec_to_point);
VecMulf(bbd->wanted_co, mul);
bbd->wanted_speed = val->max_speed * priority;
@@ -188,8 +168,8 @@ static int rule_goal_avoid(BoidRule *rule, BoidBrainData *bbd, BoidValues *val,
surface *= pa->size * boids->height;
- if(len2 > 0.0f && len - surface < len2) {
- len2 = (len - surface)/len2;
+ if(len2 > 0.0f && efd.distance - surface < len2) {
+ len2 = (efd.distance - surface)/len2;
bbd->wanted_speed *= pow(len2, boids->landing_smoothness);
}
}
@@ -204,9 +184,9 @@ static int rule_avoid_collision(BoidRule *rule, BoidBrainData *bbd, BoidValues *
{
BoidRuleAvoidCollision *acbr = (BoidRuleAvoidCollision*) rule;
KDTreeNearest *ptn = NULL;
- ParticleEffectorCache *ec;
ParticleTarget *pt;
BoidParticle *bpa = pa->boid;
+ ColliderCache *coll;
float vec[3] = {0.0f, 0.0f, 0.0f}, loc[3] = {0.0f, 0.0f, 0.0f};
float co1[3], vel1[3], co2[3], vel2[3];
float len, t, inp, t_min = 2.0f;
@@ -214,7 +194,7 @@ static int rule_avoid_collision(BoidRule *rule, BoidBrainData *bbd, BoidValues *
int ret = 0;
//check deflector objects first
- if(acbr->options & BRULE_ACOLL_WITH_DEFLECTORS) {
+ if(acbr->options & BRULE_ACOLL_WITH_DEFLECTORS && bbd->sim->colliders) {
ParticleCollision col;
BVHTreeRayHit hit;
float radius = val->personal_space * pa->size, ray_dir[3];
@@ -228,20 +208,16 @@ static int rule_avoid_collision(BoidRule *rule, BoidBrainData *bbd, BoidValues *
hit.dist = col.ray_len = VecLength(ray_dir);
/* find out closest deflector object */
- for(ec=bbd->sim->psys->effectors.first; ec; ec=ec->next) {
- if(ec->type & PSYS_EC_DEFLECT) {
- Object *eob = ec->ob;
-
- /* don't check with current ground object */
- if(eob == bpa->ground)
- continue;
+ for(coll = bbd->sim->colliders->first; coll; coll=coll->next) {
+ /* don't check with current ground object */
+ if(coll->ob == bpa->ground)
+ continue;
- col.md = ( CollisionModifierData * ) ( modifiers_findByType ( eob, eModifierType_Collision ) );
- col.ob_t = eob;
+ col.ob = coll->ob;
+ col.md = coll->collmd;
- if(col.md && col.md->bvhtree)
- BLI_bvhtree_ray_cast(col.md->bvhtree, col.co1, ray_dir, radius, &hit, particle_intersect_face, &col);
- }
+ if(col.md && col.md->bvhtree)
+ BLI_bvhtree_ray_cast(col.md->bvhtree, col.co1, ray_dir, radius, &hit, particle_intersect_face, &col);
}
/* then avoid that object */
if(hit.index>=0) {
@@ -756,25 +732,28 @@ static Object *boid_find_ground(BoidBrainData *bbd, ParticleData *pa, float *gro
if(bpa->data.mode == eBoidMode_Climbing) {
SurfaceModifierData *surmd = NULL;
float x[3], v[3];
-
+
surmd = (SurfaceModifierData *)modifiers_findByType ( bpa->ground, eModifierType_Surface );
/* take surface velocity into account */
- effector_find_co(bbd->sim->scene, pa->state.co, surmd, NULL, NULL, x, NULL, v, NULL);
+ closest_point_on_surface(surmd, pa->state.co, x, NULL, v);
VecAddf(x, x, v);
/* get actual position on surface */
- effector_find_co(bbd->sim->scene, x, surmd, NULL, NULL, ground_co, ground_nor, NULL, NULL);
+ closest_point_on_surface(surmd, x, ground_co, ground_nor, NULL);
return bpa->ground;
}
else {
float zvec[3] = {0.0f, 0.0f, 2000.0f};
ParticleCollision col;
+ ColliderCache *coll;
BVHTreeRayHit hit;
- ParticleEffectorCache *ec;
float radius = 0.0f, t, ray_dir[3];
+ if(!bbd->sim->colliders)
+ return NULL;
+
VECCOPY(col.co1, pa->state.co);
VECCOPY(col.co2, pa->state.co);
VecAddf(col.co1, col.co1, zvec);
@@ -785,16 +764,12 @@ static Object *boid_find_ground(BoidBrainData *bbd, ParticleData *pa, float *gro
hit.dist = col.ray_len = VecLength(ray_dir);
/* find out upmost deflector object */
- for(ec=bbd->sim->psys->effectors.first; ec; ec=ec->next) {
- if(ec->type & PSYS_EC_DEFLECT) {
- Object *eob = ec->ob;
+ for(coll = bbd->sim->colliders->first; coll; coll = coll->next){
+ col.ob = coll->ob;
+ col.md = coll->collmd;
- col.md = ( CollisionModifierData * ) ( modifiers_findByType ( eob, eModifierType_Collision ) );
- col.ob_t = eob;
-
- if(col.md && col.md->bvhtree)
- BLI_bvhtree_ray_cast(col.md->bvhtree, col.co1, ray_dir, radius, &hit, particle_intersect_face, &col);
- }
+ if(col.md && col.md->bvhtree)
+ BLI_bvhtree_ray_cast(col.md->bvhtree, col.co1, ray_dir, radius, &hit, particle_intersect_face, &col);
}
/* then use that object */
if(hit.index>=0) {
@@ -802,7 +777,7 @@ static Object *boid_find_ground(BoidBrainData *bbd, ParticleData *pa, float *gro
VecLerpf(ground_co, col.co1, col.co2, t);
VECCOPY(ground_nor, col.nor);
Normalize(ground_nor);
- return col.ob;
+ return col.hit_ob;
}
else {
/* default to z=0 */
@@ -1068,6 +1043,7 @@ void boid_body(BoidBrainData *bbd, ParticleData *pa)
BoidSettings *boids = bbd->part->boids;
BoidParticle *bpa = pa->boid;
BoidValues val;
+ EffectedPoint epoint;
float acc[3] = {0.0f, 0.0f, 0.0f}, tan_acc[3], nor_acc[3];
float dvec[3], bvec[3];
float new_dir[3], new_speed;
@@ -1208,7 +1184,8 @@ void boid_body(BoidBrainData *bbd, ParticleData *pa)
}
/* account for effectors */
- do_effectors(bbd->sim, p, pa, &pa->state, pa->state.co, force, tvel, bbd->dfra, bbd->cfra);
+ pd_point_from_particle(bbd->sim, pa, &pa->state, &epoint);
+ pdDoEffectors(bbd->sim->psys->effectors, bbd->sim->colliders, bbd->part->effector_weights, &epoint, force, NULL);
if(ELEM(bpa->data.mode, eBoidMode_OnLand, eBoidMode_Climbing)) {
float length = Normalize(force);
diff --git a/source/blender/blenkernel/intern/cloth.c b/source/blender/blenkernel/intern/cloth.c
index 5cfbd5c18dc..74f88a77e63 100644
--- a/source/blender/blenkernel/intern/cloth.c
+++ b/source/blender/blenkernel/intern/cloth.c
@@ -153,6 +153,9 @@ void cloth_init ( ClothModifierData *clmd )
clmd->sim_parms->defgoal = 0.0f;
clmd->sim_parms->goalspring = 1.0f;
clmd->sim_parms->goalfrict = 0.0f;
+
+ if(!clmd->sim_parms->effector_weights)
+ clmd->sim_parms->effector_weights = BKE_add_effector_weights(NULL);
}
static BVHTree *bvhselftree_build_from_cloth (ClothModifierData *clmd, float epsilon)
@@ -402,6 +405,8 @@ static int do_step_cloth(Object *ob, ClothModifierData *clmd, DerivedMesh *resul
VECCOPY(verts->xconst, mvert[i].co);
Mat4MulVecfl(ob->obmat, verts->xconst);
}
+
+ effectors = pdInitEffectors(clmd->scene, ob, NULL, clmd->sim_parms->effector_weights);
tstart();
@@ -411,6 +416,8 @@ static int do_step_cloth(Object *ob, ClothModifierData *clmd, DerivedMesh *resul
tend();
+ pdEndEffectors(&effectors);
+
// printf ( "%f\n", ( float ) tval() );
return ret;
diff --git a/source/blender/blenkernel/intern/collision.c b/source/blender/blenkernel/intern/collision.c
index 20fc1708454..8c664bc1a57 100644
--- a/source/blender/blenkernel/intern/collision.c
+++ b/source/blender/blenkernel/intern/collision.c
@@ -1392,6 +1392,97 @@ Object **get_collisionobjects(Scene *scene, Object *self, int *numcollobj)
return objs;
}
+ListBase *get_collider_cache(Scene *scene, Object *self)
+{
+ Base *base=NULL;
+ ListBase *objs = NULL;
+ Object *coll_ob = NULL;
+ CollisionModifierData *collmd = NULL;
+ ColliderCache *col;
+
+ // check all collision objects
+ for ( base = scene->base.first; base; base = base->next )
+ {
+ /*Only proceed for mesh object in same layer */
+ if(base->object->type!=OB_MESH)
+ continue;
+
+ if(self && (base->lay & self->lay)==0)
+ continue;
+
+
+ coll_ob = base->object;
+
+ if(coll_ob == self)
+ continue;
+
+ if(coll_ob->pd && coll_ob->pd->deflect)
+ {
+ collmd = ( CollisionModifierData * ) modifiers_findByType ( coll_ob, eModifierType_Collision );
+ }
+ else
+ collmd = NULL;
+
+ if ( collmd )
+ {
+ if(objs == NULL)
+ objs = MEM_callocN(sizeof(ListBase), "ColliderCache array");
+
+ col = MEM_callocN(sizeof(ColliderCache), "ColliderCache");
+ col->ob = coll_ob;
+ col->collmd = collmd;
+ /* make sure collider is properly set up */
+ collision_move_object(collmd, 1.0, 0.0);
+ BLI_addtail(objs, col);
+ }
+ else if ( coll_ob->dup_group )
+ {
+ GroupObject *go;
+ Group *group = coll_ob->dup_group;
+
+ for ( go= group->gobject.first; go; go= go->next )
+ {
+ coll_ob = go->ob;
+ collmd = NULL;
+
+ if(coll_ob == self)
+ continue;
+
+ if(coll_ob->pd && coll_ob->pd->deflect)
+ {
+ collmd = ( CollisionModifierData * ) modifiers_findByType ( coll_ob, eModifierType_Collision );
+ }
+ else
+ collmd = NULL;
+
+ if ( !collmd )
+ continue;
+
+ if( !collmd->bvhtree)
+ continue;
+
+ if(objs == NULL)
+ objs = MEM_callocN(sizeof(ListBase), "ColliderCache array");
+
+ col = MEM_callocN(sizeof(ColliderCache), "ColliderCache");
+ col->ob = coll_ob;
+ col->collmd = collmd;
+ /* make sure collider is properly set up */
+ collision_move_object(collmd, 1.0, 0.0);
+ BLI_addtail(objs, col);
+ }
+ }
+ }
+ return objs;
+}
+void free_collider_cache(ListBase **colliders)
+{
+ if(*colliders) {
+ BLI_freelistN(*colliders);
+ MEM_freeN(*colliders);
+ *colliders = NULL;
+ }
+}
static void cloth_bvh_objcollisions_nearcheck ( ClothModifierData * clmd, CollisionModifierData *collmd, CollPair **collisions, CollPair **collisions_index, int numresult, BVHTreeOverlap *overlap)
{
int i;
diff --git a/source/blender/blenkernel/intern/depsgraph.c b/source/blender/blenkernel/intern/depsgraph.c
index 608cfe03b72..a8cec6070a0 100644
--- a/source/blender/blenkernel/intern/depsgraph.c
+++ b/source/blender/blenkernel/intern/depsgraph.c
@@ -521,8 +521,8 @@ static void build_dag_object(DagForest *dag, DagNode *scenenode, Scene *scene, O
/* softbody collision */
if((ob->type==OB_MESH) || (ob->type==OB_CURVE) || (ob->type==OB_LATTICE))
- if(modifiers_isSoftbodyEnabled(ob) || modifiers_isClothEnabled(ob))
- dag_add_collision_field_relation(dag, scene, ob, node);
+ if(modifiers_isSoftbodyEnabled(ob) || modifiers_isClothEnabled(ob) || ob->particlesystem.first)
+ dag_add_collision_field_relation(dag, scene, ob, node); /* TODO: use effectorweight->group */
if (ob->type==OB_MBALL) {
Object *mom= find_basis_mball(scene, ob);
@@ -554,14 +554,14 @@ static void build_dag_object(DagForest *dag, DagNode *scenenode, Scene *scene, O
psys= ob->particlesystem.first;
if(psys) {
- ParticleEffectorCache *nec;
GroupObject *go;
for(; psys; psys=psys->next) {
BoidRule *rule = NULL;
BoidState *state = NULL;
- ParticleSimulationData sim = {scene, ob, psys, NULL};
ParticleSettings *part= psys->part;
+ ListBase *effectors = NULL;
+ EffectorCache *eff;
dag_add_relation(dag, node, node, DAG_RL_OB_DATA, "Particle-Object Relation");
@@ -593,33 +593,17 @@ static void build_dag_object(DagForest *dag, DagNode *scenenode, Scene *scene, O
}
}
- psys_update_effectors(&sim, 0.0, 0);
+ effectors = pdInitEffectors(scene, ob, psys, part->effector_weights);
- for(nec= psys->effectors.first; nec; nec= nec->next) {
- Object *ob1= nec->ob;
-
- if(nec->type & PSYS_EC_EFFECTOR) {
- node2 = dag_get_node(dag, ob1);
- if(ob1->pd->forcefield==PFIELD_GUIDE)
- dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA|DAG_RL_OB_DATA, "Particle Field");
- else
- dag_add_relation(dag, node2, node, DAG_RL_OB_DATA, "Particle Field");
- }
- else if(nec->type & PSYS_EC_DEFLECT) {
- node2 = dag_get_node(dag, ob1);
- dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA|DAG_RL_OB_DATA, "Particle Collision");
- }
- else if(nec->type & PSYS_EC_PARTICLE) {
- node2 = dag_get_node(dag, ob1);
- dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA, "Particle Field");
- }
-
- if(nec->type & PSYS_EC_REACTOR) {
- node2 = dag_get_node(dag, ob1);
- dag_add_relation(dag, node, node2, DAG_RL_DATA_DATA, "Particle Reactor");
+ if(effectors) for(eff = effectors->first; eff; eff=eff->next) {
+ if(eff->psys) {
+ node2 = dag_get_node(dag, eff->ob);
+ dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA|DAG_RL_OB_DATA, "Particle Field");
}
}
+ pdEndEffectors(&effectors);
+
if(part->boids) {
for(state = part->boids->states.first; state; state=state->next) {
for(rule = state->rules.first; rule; rule=rule->next) {
@@ -2217,7 +2201,7 @@ void DAG_id_flush_update(ID *id, short flag)
/* set flags & pointcache for object */
if(GS(id->name) == ID_OB) {
ob= (Object*)id;
- ob->recalc |= flag;
+ ob->recalc |= (flag & OB_RECALC);
BKE_ptcache_object_reset(sce, ob, PTCACHE_RESET_DEPSGRAPH);
if(flag & OB_RECALC_DATA) {
@@ -2255,6 +2239,20 @@ void DAG_id_flush_update(ID *id, short flag)
}
}
+ /* set flags based on particle settings */
+ if(idtype == ID_PA) {
+ ParticleSystem *psys;
+ for(obt=bmain->object.first; obt; obt= obt->id.next) {
+ for(psys=obt->particlesystem.first; psys; psys=psys->next) {
+ if(&psys->part->id == id) {
+ BKE_ptcache_object_reset(sce, obt, PTCACHE_RESET_DEPSGRAPH);
+ obt->recalc |= (flag & OB_RECALC);
+ psys->recalc |= (flag & PSYS_RECALC);
+ }
+ }
+ }
+ }
+
/* update editors */
dag_editors_update(bmain, id);
}
diff --git a/source/blender/blenkernel/intern/effect.c b/source/blender/blenkernel/intern/effect.c
index acf906e3163..7cc65de827a 100644
--- a/source/blender/blenkernel/intern/effect.c
+++ b/source/blender/blenkernel/intern/effect.c
@@ -48,12 +48,15 @@
#include "DNA_material_types.h"
#include "DNA_object_types.h"
#include "DNA_object_force.h"
+#include "DNA_particle_types.h"
#include "DNA_texture_types.h"
#include "DNA_scene_types.h"
#include "BLI_arithb.h"
#include "BLI_blenlib.h"
#include "BLI_jitter.h"
+#include "BLI_listbase.h"
+#include "BLI_noise.h"
#include "BLI_rand.h"
#include "PIL_time.h"
@@ -68,6 +71,7 @@
#include "BKE_depsgraph.h"
#include "BKE_displist.h"
#include "BKE_DerivedMesh.h"
+#include "BKE_cdderivedmesh.h"
#include "BKE_effect.h"
#include "BKE_global.h"
#include "BKE_group.h"
@@ -79,11 +83,13 @@
#include "BKE_main.h"
#include "BKE_modifier.h"
#include "BKE_object.h"
+#include "BKE_particle.h"
#include "BKE_scene.h"
#include "BKE_screen.h"
#include "BKE_utildefines.h"
#include "RE_render_ext.h"
+#include "RE_shader_ext.h"
/* fluid sim particle import */
#ifndef DISABLE_ELBEEM
@@ -95,17 +101,46 @@
//XXX #include "BIF_screen.h"
-PartDeflect *object_add_collision_fields(void)
+EffectorWeights *BKE_add_effector_weights(Group *group)
+{
+ EffectorWeights *weights = MEM_callocN(sizeof(EffectorWeights), "EffectorWeights");
+ int i;
+
+ for(i=0; i<NUM_PFIELD_TYPES; i++)
+ weights->weight[i] = 1.0f;
+
+ weights->global_gravity = 1.0f;
+
+ weights->group = group;
+
+ return weights;
+}
+PartDeflect *object_add_collision_fields(int type)
{
PartDeflect *pd;
pd= MEM_callocN(sizeof(PartDeflect), "PartDeflect");
+ pd->forcefield = type;
pd->pdef_sbdamp = 0.1f;
pd->pdef_sbift = 0.2f;
pd->pdef_sboft = 0.02f;
pd->seed = ((unsigned int)(ceil(PIL_check_seconds_timer()))+1) % 128;
pd->f_strength = 1.0f;
+ pd->f_damp = 1.0f;
+ pd->f_size = 1.0f;
+
+ /* set sensible defaults based on type */
+ switch(type) {
+ case PFIELD_VORTEX:
+ pd->shape = PFIELD_SHAPE_PLANE;
+ break;
+ case PFIELD_WIND:
+ pd->shape = PFIELD_SHAPE_PLANE;
+ pd->f_flow = 1.0f; /* realistic wind behavior */
+ break;
+ }
+ pd->flag = PFIELD_DO_LOCATION|PFIELD_DO_ROTATION;
return pd;
}
@@ -156,93 +191,216 @@ void free_effects(ListBase *lb)
}
/* -------------------------- Effectors ------------------ */
+void free_partdeflect(PartDeflect *pd)
+{
+ if(!pd)
+ return;
+
+ if(pd->tex)
+ pd->tex->id.us--;
-static void add_to_effectorcache(ListBase *lb, Scene *scene, Object *ob, Object *obsrc)
+ if(pd->rng)
+ rng_free(pd->rng);
+
+ MEM_freeN(pd);
+}
+
+static void precalculate_effector(EffectorCache *eff)
{
- pEffectorCache *ec;
- PartDeflect *pd= ob->pd;
-
- if(pd->forcefield == PFIELD_GUIDE) {
- if(ob->type==OB_CURVE && obsrc->type==OB_MESH) { /* guides only do mesh particles */
- Curve *cu= ob->data;
- if(cu->flag & CU_PATH) {
- if(cu->path==NULL || cu->path->data==NULL)
- makeDispListCurveTypes(scene, ob, 0);
- if(cu->path && cu->path->data) {
- ec= MEM_callocN(sizeof(pEffectorCache), "effector cache");
- ec->ob= ob;
- BLI_addtail(lb, ec);
- }
+ unsigned int cfra = (unsigned int)(eff->scene->r.cfra >= 0 ? eff->scene->r.cfra : -eff->scene->r.cfra);
+ if(!eff->pd->rng)
+ eff->pd->rng = rng_new(eff->pd->seed + cfra);
+ else
+ rng_srandom(eff->pd->rng, eff->pd->seed + cfra);
+
+ if(eff->pd->forcefield == PFIELD_GUIDE && eff->ob->type==OB_CURVE) {
+ Curve *cu= eff->ob->data;
+ if(cu->flag & CU_PATH) {
+ if(cu->path==NULL || cu->path->data==NULL)
+ makeDispListCurveTypes(eff->scene, eff->ob, 0);
+
+ if(cu->path && cu->path->data) {
+ where_on_path(eff->ob, 0.0, eff->guide_loc, eff->guide_dir, NULL, &eff->guide_radius);
+ Mat4MulVecfl(eff->ob->obmat, eff->guide_loc);
+ Mat4Mul3Vecfl(eff->ob->obmat, eff->guide_dir);
}
}
}
- else if(pd->forcefield) {
-
- if(pd->forcefield == PFIELD_WIND)
- {
- pd->rng = rng_new(pd->seed);
- }
-
- ec= MEM_callocN(sizeof(pEffectorCache), "effector cache");
- ec->ob= ob;
- BLI_addtail(lb, ec);
+ else if(eff->pd->shape == PFIELD_SHAPE_SURFACE) {
+ eff->surmd = (SurfaceModifierData *)modifiers_findByType ( eff->ob, eModifierType_Surface );
+ }
+ else if(eff->psys)
+ psys_update_particle_tree(eff->psys, eff->scene->r.cfra);
+}
+static EffectorCache *new_effector_cache(Scene *scene, Object *ob, ParticleSystem *psys, PartDeflect *pd)
+{
+ EffectorCache *eff = MEM_callocN(sizeof(EffectorCache), "EffectorCache");
+ eff->scene = scene;
+ eff->ob = ob;
+ eff->psys = psys;
+ eff->pd = pd;
+ eff->frame = -1;
+
+ precalculate_effector(eff);
+
+ return eff;
+}
+static void add_object_to_effectors(ListBase **effectors, Scene *scene, EffectorWeights *weights, Object *ob, Object *ob_src)
+{
+ EffectorCache *eff = NULL;
+
+ if( ob == ob_src || weights->weight[ob->pd->forcefield] == 0.0f )
+ return;
+
+ if (ob->pd->shape == PFIELD_SHAPE_POINTS && !ob->derivedFinal )
+ return;
+
+ if(*effectors == NULL)
+ *effectors = MEM_callocN(sizeof(ListBase), "effectors list");
+
+ eff = new_effector_cache(scene, ob, NULL, ob->pd);
+
+ BLI_addtail(*effectors, eff);
+}
+static void add_particles_to_effectors(ListBase **effectors, Scene *scene, EffectorWeights *weights, Object *ob, ParticleSystem *psys, ParticleSystem *psys_src)
+{
+ ParticleSettings *part= psys->part;
+
+ if( !psys_check_enabled(ob, psys) )
+ return;
+
+ if( psys == psys_src && (part->flag & PART_SELF_EFFECT) == 0)
+ return;
+
+ if( part->pd && part->pd->forcefield && weights->weight[part->pd->forcefield] != 0.0f) {
+ if(*effectors == NULL)
+ *effectors = MEM_callocN(sizeof(ListBase), "effectors list");
+
+ BLI_addtail(*effectors, new_effector_cache(scene, ob, psys, part->pd));
+ }
+
+ if (part->pd2 && part->pd2->forcefield && weights->weight[part->pd2->forcefield] != 0.0f) {
+ if(*effectors == NULL)
+ *effectors = MEM_callocN(sizeof(ListBase), "effectors list");
+
+ BLI_addtail(*effectors, new_effector_cache(scene, ob, psys, part->pd2));
}
}
/* returns ListBase handle with objects taking part in the effecting */
-ListBase *pdInitEffectors(Scene *scene, Object *obsrc, Group *group)
+ListBase *pdInitEffectors(Scene *scene, Object *ob_src, ParticleSystem *psys_src, EffectorWeights *weights)
{
- static ListBase listb={NULL, NULL};
- pEffectorCache *ec;
Base *base;
- unsigned int layer= obsrc->lay;
+ unsigned int layer= ob_src->lay;
+ ListBase *effectors = NULL;
- if(group) {
+ if(weights->group) {
GroupObject *go;
- for(go= group->gobject.first; go; go= go->next) {
- if( (go->ob->lay & layer) && go->ob->pd && go->ob!=obsrc) {
- add_to_effectorcache(&listb, scene, go->ob, obsrc);
+ for(go= weights->group->gobject.first; go; go= go->next) {
+ if( (go->ob->lay & layer) ) {
+ if( go->ob->pd && go->ob->pd->forcefield )
+ add_object_to_effectors(&effectors, scene, weights, go->ob, ob_src);
+
+ if( go->ob->particlesystem.first ) {
+ ParticleSystem *psys= go->ob->particlesystem.first;
+
+ for( ; psys; psys=psys->next )
+ add_particles_to_effectors(&effectors, scene, weights, go->ob, psys, psys_src);
+ }
}
}
}
else {
for(base = scene->base.first; base; base= base->next) {
- if( (base->lay & layer) && base->object->pd && base->object!=obsrc) {
- add_to_effectorcache(&listb, scene, base->object, obsrc);
+ if( (base->lay & layer) ) {
+ if( base->object->pd && base->object->pd->forcefield )
+ add_object_to_effectors(&effectors, scene, weights, base->object, ob_src);
+
+ if( base->object->particlesystem.first ) {
+ ParticleSystem *psys= base->object->particlesystem.first;
+
+ for( ; psys; psys=psys->next )
+ add_particles_to_effectors(&effectors, scene, weights, base->object, psys, psys_src);
+ }
}
}
}
-
- /* make a full copy */
- for(ec= listb.first; ec; ec= ec->next) {
- ec->obcopy= *(ec->ob);
- }
-
- if(listb.first)
- return &listb;
-
- return NULL;
+ return effectors;
}
-void pdEndEffectors(ListBase *lb)
+void pdEndEffectors(ListBase **effectors)
{
- if(lb) {
- pEffectorCache *ec;
- /* restore full copy */
- for(ec= lb->first; ec; ec= ec->next)
- {
- if(ec->ob->pd && (ec->ob->pd->forcefield == PFIELD_WIND))
- rng_free(ec->ob->pd->rng);
-
- *(ec->ob)= ec->obcopy;
+ if(*effectors) {
+ EffectorCache *eff = (*effectors)->first;
+
+ for(; eff; eff=eff->next) {
+ if(eff->guide_data)
+ MEM_freeN(eff->guide_data);
}
- BLI_freelistN(lb);
+ BLI_freelistN(*effectors);
+ MEM_freeN(*effectors);
+ *effectors = NULL;
}
}
+void pd_point_from_particle(ParticleSimulationData *sim, ParticleData *pa, ParticleKey *state, EffectedPoint *point)
+{
+ point->loc = state->co;
+ point->vel = state->vel;
+ point->index = pa - sim->psys->particles;
+ point->size = pa->size;
+ /* TODO: point->charge */
+ point->charge = 1.0f;
+
+ point->vel_to_sec = 1.0f;
+ point->vel_to_frame = psys_get_timestep(sim);
+
+ point->flag = 0;
+
+ if(sim->psys->part->flag & PART_ROT_DYN) {
+ point->ave = state->ave;
+ point->rot = state->rot;
+ }
+ else
+ point->ave = point->rot = NULL;
+
+ point->psys = sim->psys;
+}
+
+void pd_point_from_loc(Scene *scene, float *loc, float *vel, int index, EffectedPoint *point)
+{
+ point->loc = loc;
+ point->vel = vel;
+ point->index = index;
+ point->size = 0.0f;
+
+ point->vel_to_sec = (float)scene->r.frs_sec;
+ point->vel_to_frame = 1.0f;
+
+ point->flag = 0;
+
+ point->ave = point->rot = NULL;
+ point->psys = NULL;
+}
+void pd_point_from_soft(Scene *scene, float *loc, float *vel, int index, EffectedPoint *point)
+{
+ point->loc = loc;
+ point->vel = vel;
+ point->index = index;
+ point->size = 0.0f;
+
+ point->vel_to_sec = (float)scene->r.frs_sec;
+ point->vel_to_frame = 1.0f;
+
+ point->flag = PE_WIND_AS_SPEED;
+
+ point->ave = point->rot = NULL;
+
+ point->psys = NULL;
+}
/************************************************/
/* Effectors */
/************************************************/
@@ -256,27 +414,33 @@ static void eff_tri_ray_hit(void *userdata, int index, const BVHTreeRay *ray, BV
}
// get visibility of a wind ray
-static float eff_calc_visibility(Scene *scene, Object *ob, float *co, float *dir)
+static float eff_calc_visibility(ListBase *colliders, EffectorCache *eff, EffectorData *efd, EffectedPoint *point)
{
- Object **collobjs = NULL;
- int numcollobj = 0, i;
+ ListBase *colls = colliders;
+ ColliderCache *col;
float norm[3], len = 0.0;
float visibility = 1.0, absorption = 0.0;
- collobjs = get_collisionobjects(scene, ob, &numcollobj);
-
- if(!collobjs)
- return 0;
+ if(!(eff->pd->flag & PFIELD_VISIBILITY))
+ return visibility;
+
+ if(!colls)
+ colls = get_collider_cache(eff->scene, NULL);
+
+ if(!colls)
+ return visibility;
- VECCOPY(norm, dir);
+ VECCOPY(norm, efd->vec_to_point);
VecNegf(norm);
len = Normalize(norm);
// check all collision objects
- for(i = 0; i < numcollobj; i++)
+ for(col = colls->first; col; col = col->next)
{
- Object *collob= collobjs[i];
- CollisionModifierData *collmd = (CollisionModifierData*)modifiers_findByType(collob, eModifierType_Collision);
+ CollisionModifierData *collmd = col->collmd;
+
+ if(col->ob == eff->ob)
+ continue;
if(collmd->bvhtree)
{
@@ -286,9 +450,9 @@ static float eff_calc_visibility(Scene *scene, Object *ob, float *co, float *dir
hit.dist = len + FLT_EPSILON;
// check if the way is blocked
- if(BLI_bvhtree_ray_cast(collmd->bvhtree, co, norm, 0.0f, &hit, eff_tri_ray_hit, NULL)>=0)
+ if(BLI_bvhtree_ray_cast(collmd->bvhtree, point->loc, norm, 0.0f, &hit, eff_tri_ray_hit, NULL)>=0)
{
- absorption= (collob->pd)? collob->pd->absorption: 0.0f;
+ absorption= col->ob->pd->absorption;
// visibility is only between 0 and 1, calculated from 1-absorption
visibility *= CLAMPIS(1.0f-absorption, 0.0f, 1.0f);
@@ -298,8 +462,9 @@ static float eff_calc_visibility(Scene *scene, Object *ob, float *co, float *dir
}
}
}
-
- MEM_freeN(collobjs);
+
+ if(!colliders)
+ free_collider_cache(&colls);
return visibility;
}
@@ -347,43 +512,39 @@ static float falloff_func_rad(PartDeflect *pd, float fac)
return falloff_func(fac, pd->flag&PFIELD_USEMINR, pd->minrad, pd->flag&PFIELD_USEMAXR, pd->maxrad, pd->f_power_r);
}
-float effector_falloff(PartDeflect *pd, float *eff_velocity, float *vec_to_part)
+float effector_falloff(EffectorCache *eff, EffectorData *efd, EffectedPoint *point, EffectorWeights *weights)
{
- float eff_dir[3], temp[3];
- float falloff=1.0, fac, r_fac;
-
- if(pd->forcefield==PFIELD_LENNARDJ)
- return falloff; /* Lennard-Jones field has it's own falloff built in */
+ float temp[3];
+ float falloff = weights ? weights->weight[0] * weights->weight[eff->pd->forcefield] : 1.0f;
+ float fac, r_fac;
- VecCopyf(eff_dir,eff_velocity);
- Normalize(eff_dir);
+ fac = Inpf(efd->nor, efd->vec_to_point);
- if(pd->flag & PFIELD_POSZ && Inpf(eff_dir,vec_to_part)<0.0f)
+ if(eff->pd->zdir == PFIELD_Z_POS && fac < 0.0f)
falloff=0.0f;
- else switch(pd->falloff){
+ else if(eff->pd->zdir == PFIELD_Z_NEG && fac > 0.0f)
+ falloff=0.0f;
+ else switch(eff->pd->falloff){
case PFIELD_FALL_SPHERE:
- fac=VecLength(vec_to_part);
- falloff= falloff_func_dist(pd, fac);
+ falloff*= falloff_func_dist(eff->pd, efd->distance);
break;
case PFIELD_FALL_TUBE:
- fac=Inpf(vec_to_part,eff_dir);
- falloff= falloff_func_dist(pd, ABS(fac));
+ falloff*= falloff_func_dist(eff->pd, ABS(fac));
if(falloff == 0.0f)
break;
- VECADDFAC(temp,vec_to_part,eff_dir,-fac);
- r_fac=VecLength(temp);
- falloff*= falloff_func_rad(pd, r_fac);
+ VECADDFAC(temp, efd->vec_to_point, efd->nor, -fac);
+ r_fac= VecLength(temp);
+ falloff*= falloff_func_rad(eff->pd, r_fac);
break;
case PFIELD_FALL_CONE:
- fac=Inpf(vec_to_part,eff_dir);
- falloff= falloff_func_dist(pd, ABS(fac));
+ falloff*= falloff_func_dist(eff->pd, ABS(fac));
if(falloff == 0.0f)
break;
- r_fac=saacos(fac/VecLength(vec_to_part))*180.0f/(float)M_PI;
- falloff*= falloff_func_rad(pd, r_fac);
+ r_fac=saacos(fac/VecLength(efd->vec_to_point))*180.0f/(float)M_PI;
+ falloff*= falloff_func_rad(eff->pd, r_fac);
break;
}
@@ -391,127 +552,391 @@ float effector_falloff(PartDeflect *pd, float *eff_velocity, float *vec_to_part)
return falloff;
}
-void do_physical_effector(Scene *scene, Object *ob, float *opco, short type, float force_val, float distance, float falloff, float size, float damp, float *eff_velocity, float *vec_to_part, float *velocity, float *field, int planar, struct RNG *rng, float noise_factor, float charge, float pa_size)
+int closest_point_on_surface(SurfaceModifierData *surmd, float *co, float *surface_co, float *surface_nor, float *surface_vel)
{
- float mag_vec[3]={0,0,0};
- float temp[3], temp2[3];
- float eff_vel[3];
- float noise = 0, visibility;
-
- // calculate visibility
- visibility = eff_calc_visibility(scene, ob, opco, vec_to_part);
- if(visibility <= 0.0)
- return;
- falloff *= visibility;
+ BVHTreeNearest nearest;
- VecCopyf(eff_vel,eff_velocity);
- Normalize(eff_vel);
+ nearest.index = -1;
+ nearest.dist = FLT_MAX;
- switch(type){
- case PFIELD_WIND:
- VECCOPY(mag_vec,eff_vel);
-
- // add wind noise here, only if we have wind
- if((noise_factor > 0.0f) && (force_val > FLT_EPSILON))
- noise = wind_func(rng, noise_factor);
+ BLI_bvhtree_find_nearest(surmd->bvhtree->tree, co, &nearest, surmd->bvhtree->nearest_callback, surmd->bvhtree);
+
+ if(nearest.index != -1) {
+ VECCOPY(surface_co, nearest.co);
+
+ if(surface_nor) {
+ VECCOPY(surface_nor, nearest.no);
+ }
+
+ if(surface_vel) {
+ MFace *mface = CDDM_get_face(surmd->dm, nearest.index);
- VecMulf(mag_vec,(force_val+noise)*falloff);
- VecAddf(field,field,mag_vec);
- break;
+ VECCOPY(surface_vel, surmd->v[mface->v1].co);
+ VecAddf(surface_vel, surface_vel, surmd->v[mface->v2].co);
+ VecAddf(surface_vel, surface_vel, surmd->v[mface->v3].co);
+ if(mface->v4)
+ VecAddf(surface_vel, surface_vel, surmd->v[mface->v4].co);
- case PFIELD_FORCE:
- if(planar)
- Projf(mag_vec,vec_to_part,eff_vel);
- else
- VecCopyf(mag_vec,vec_to_part);
+ VecMulf(surface_vel, mface->v4 ? 0.25f : 0.333f);
+ }
+ return 1;
+ }
- Normalize(mag_vec);
+ return 0;
+}
+int get_effector_data(EffectorCache *eff, EffectorData *efd, EffectedPoint *point, int real_velocity)
+{
+ float cfra = eff->scene->r.cfra;
+ int ret = 0;
- VecMulf(mag_vec,force_val*falloff);
- VecAddf(field,field,mag_vec);
- break;
+ if(eff->pd->shape==PFIELD_SHAPE_SURFACE && eff->surmd) {
+ /* closest point in the object surface is an effector */
+ float vec[3];
- case PFIELD_VORTEX:
- Crossf(mag_vec,eff_vel,vec_to_part);
+ /* using velocity corrected location allows for easier sliding over effector surface */
+ VecCopyf(vec, point->vel);
+ VecMulf(vec, point->vel_to_frame);
+ VecAddf(vec, vec, point->loc);
- Normalize(mag_vec);
+ ret = closest_point_on_surface(eff->surmd, vec, efd->loc, efd->nor, real_velocity ? efd->vel : NULL);
- VecMulf(mag_vec,force_val*distance*falloff);
- VecAddf(field,field,mag_vec);
+ efd->size = 0.0f;
+ }
+ else if(eff->pd->shape==PFIELD_SHAPE_POINTS) {
- break;
- case PFIELD_MAGNET:
- if(planar)
- VecCopyf(temp,eff_vel);
- else
- /* magnetic field of a moving charge */
- Crossf(temp,eff_vel,vec_to_part);
+ if(eff->ob->derivedFinal) {
+ DerivedMesh *dm = eff->ob->derivedFinal;
- Normalize(temp);
+ dm->getVertCo(dm, *efd->index, efd->loc);
+ dm->getVertNo(dm, *efd->index, efd->nor);
- Crossf(temp2,velocity,temp);
- VecAddf(mag_vec,mag_vec,temp2);
+ Mat4MulVecfl(eff->ob->obmat, efd->loc);
+ Mat4Mul3Vecfl(eff->ob->obmat, efd->nor);
- VecMulf(mag_vec,force_val*falloff);
- VecAddf(field,field,mag_vec);
- break;
- case PFIELD_HARMONIC:
- if(planar)
- Projf(mag_vec,vec_to_part,eff_vel);
- else
- VecCopyf(mag_vec,vec_to_part);
+ Normalize(efd->nor);
- VecMulf(mag_vec,force_val*falloff);
- VecSubf(field,field,mag_vec);
+ efd->size = 0.0f;
- VecCopyf(mag_vec,velocity);
- VecMulf(mag_vec,damp*2.0f*(float)sqrt(force_val));
- VecSubf(field,field,mag_vec);
- break;
- case PFIELD_CHARGE:
- if(planar)
- Projf(mag_vec,vec_to_part,eff_vel);
- else
- VecCopyf(mag_vec,vec_to_part);
+ /**/
+ ret = 1;
+ }
+ }
+ else if(eff->psys) {
+ ParticleSimulationData sim = {eff->scene, eff->ob, eff->psys, NULL, NULL};
+ ParticleData *pa = eff->psys->particles + *efd->index;
+ ParticleKey state;
+
+ /* exclude the particle itself for self effecting particles */
+ if(eff->psys == point->psys && *efd->index == point->index)
+ ;
+ else {
+ /* TODO: time from actual previous calculated frame (step might not be 1) */
+ state.time = cfra - 1.0;
+ ret = psys_get_particle_state(&sim, *efd->index, &state, 0);
+
+ /* TODO */
+ //if(eff->pd->forcefiled == PFIELD_HARMONIC && ret==0) {
+ // if(pa->dietime < eff->psys->cfra)
+ // eff->flag |= PE_VELOCITY_TO_IMPULSE;
+ //}
+
+ VECCOPY(efd->loc, state.co);
+ VECCOPY(efd->nor, state.vel);
+ if(real_velocity) {
+ VECCOPY(efd->vel, state.vel);
+ }
- Normalize(mag_vec);
+ efd->size = pa->size;
+ }
+ }
+ else {
+ /* use center of object for distance calculus */
+ Object *ob = eff->ob;
+ Object obcopy = *ob;
+
+ where_is_object_time(eff->scene, ob, cfra);
+
+ /* use z-axis as normal*/
+ VECCOPY(efd->nor, ob->obmat[2]);
+ Normalize(efd->nor);
+
+ /* for vortex the shape chooses between old / new force */
+ if(eff->pd->shape == PFIELD_SHAPE_PLANE) {
+ /* efd->loc is closes point on effector xy-plane */
+ float temp[3];
+ VecSubf(temp, point->loc, ob->obmat[3]);
+ Projf(efd->loc, temp, efd->nor);
+ VecSubf(efd->loc, point->loc, efd->loc);
+ }
+ else {
+ VECCOPY(efd->loc, ob->obmat[3]);
+ }
- VecMulf(mag_vec,charge*force_val*falloff);
- VecAddf(field,field,mag_vec);
- break;
- case PFIELD_LENNARDJ:
- {
- float fac;
+ if(real_velocity) {
+ VECCOPY(efd->vel, ob->obmat[3]);
+
+ where_is_object_time(eff->scene, ob, cfra - 1.0);
+
+ VecSubf(efd->vel, efd->vel, ob->obmat[3]);
+ }
+
+ *eff->ob = obcopy;
+
+ efd->size = 0.0f;
+
+ ret = 1;
+ }
+
+ if(ret) {
+ VecSubf(efd->vec_to_point, point->loc, efd->loc);
+ efd->distance = VecLength(efd->vec_to_point);
+
+ /* for some effectors we need the object center every time */
+ VecSubf(efd->vec_to_point2, point->loc, eff->ob->obmat[3]);
+ VECCOPY(efd->nor2, eff->ob->obmat[2]);
+ Normalize(efd->nor2);
+ }
+
+ return ret;
+}
+static void get_effector_tot(EffectorCache *eff, EffectorData *efd, EffectedPoint *point, int *tot, int *p)
+{
+ if(eff->pd->shape == PFIELD_SHAPE_POINTS) {
+ efd->index = p;
+
+ *p = 0;
+ *tot = eff->ob->derivedFinal ? eff->ob->derivedFinal->numVertData : 1;
+
+ if(*tot && eff->pd->forcefield == PFIELD_HARMONIC && point->index >= 0) {
+ *p = point->index % *tot;
+ *tot = *p+1;
+ }
+ }
+ else if(eff->psys) {
+ efd->index = p;
+
+ *p = 0;
+ *tot = eff->psys->totpart;
+
+ if(eff->pd->forcefield == PFIELD_CHARGE) {
+ /* Only the charge of the effected particle is used for
+ interaction, not fall-offs. If the fall-offs aren't the
+ same this will be unphysical, but for animation this
+ could be the wanted behavior. If you want physical
+ correctness the fall-off should be spherical 2.0 anyways.
+ */
+ efd->charge = eff->pd->f_strength;
+ }
+ else if(eff->pd->forcefield == PFIELD_HARMONIC) {
+ /* every particle is mapped to only one harmonic effector particle */
+ *p= point->index % eff->psys->totpart;
+ *tot= *p + 1;
+ }
+ }
+ else {
+ *p = 0;
+ *tot = 1;
+ }
+}
+static void do_texture_effector(EffectorCache *eff, EffectorData *efd, EffectedPoint *point, float *total_force)
+{
+ TexResult result[4];
+ float tex_co[3], strength, force[3];
+ float nabla = eff->pd->tex_nabla;
+ int hasrgb;
+ short mode = eff->pd->tex_mode;
+
+ if(!eff->pd->tex)
+ return;
+
+ result[0].nor = result[1].nor = result[2].nor = result[3].nor = 0;
+
+ strength= eff->pd->f_strength * efd->falloff;
+
+ VECCOPY(tex_co,point->loc);
+
+ if(eff->pd->flag & PFIELD_TEX_2D) {
+ float fac=-Inpf(tex_co, efd->nor);
+ VECADDFAC(tex_co, tex_co, efd->nor, fac);
+ }
+
+ if(eff->pd->flag & PFIELD_TEX_OBJECT) {
+ Mat4Mul3Vecfl(eff->ob->obmat, tex_co);
+ }
+
+ hasrgb = multitex_ext(eff->pd->tex, tex_co, NULL,NULL, 1, result);
+
+ if(hasrgb && mode==PFIELD_TEX_RGB) {
+ force[0] = (0.5f - result->tr) * strength;
+ force[1] = (0.5f - result->tg) * strength;
+ force[2] = (0.5f - result->tb) * strength;
+ }
+ else {
+ strength/=nabla;
+
+ tex_co[0] += nabla;
+ multitex_ext(eff->pd->tex, tex_co, NULL, NULL, 1, result+1);
+
+ tex_co[0] -= nabla;
+ tex_co[1] += nabla;
+ multitex_ext(eff->pd->tex, tex_co, NULL, NULL, 1, result+2);
- if(planar) {
- Projf(mag_vec,vec_to_part,eff_vel);
- distance = VecLength(mag_vec);
+ tex_co[1] -= nabla;
+ tex_co[2] += nabla;
+ multitex_ext(eff->pd->tex, tex_co, NULL, NULL, 1, result+3);
+
+ if(mode == PFIELD_TEX_GRAD || !hasrgb) { /* if we dont have rgb fall back to grad */
+ force[0] = (result[0].tin - result[1].tin) * strength;
+ force[1] = (result[0].tin - result[2].tin) * strength;
+ force[2] = (result[0].tin - result[3].tin) * strength;
+ }
+ else { /*PFIELD_TEX_CURL*/
+ float dbdy, dgdz, drdz, dbdx, dgdx, drdy;
+
+ dbdy = result[2].tb - result[0].tb;
+ dgdz = result[3].tg - result[0].tg;
+ drdz = result[3].tr - result[0].tr;
+ dbdx = result[1].tb - result[0].tb;
+ dgdx = result[1].tg - result[0].tg;
+ drdy = result[2].tr - result[0].tr;
+
+ force[0] = (dbdy - dgdz) * strength;
+ force[1] = (drdz - dbdx) * strength;
+ force[2] = (dgdx - drdy) * strength;
+ }
+ }
+
+ if(eff->pd->flag & PFIELD_TEX_2D){
+ float fac = -Inpf(force, efd->nor);
+ VECADDFAC(force, force, efd->nor, fac);
+ }
+
+ VecAddf(total_force, total_force, force);
+}
+void do_physical_effector(EffectorCache *eff, EffectorData *efd, EffectedPoint *point, float *total_force)
+{
+ PartDeflect *pd = eff->pd;
+ RNG *rng = pd->rng;
+ float force[3]={0,0,0};
+ float temp[3];
+ float fac;
+ float strength = pd->f_strength;
+ float damp = pd->f_damp;
+ float noise_factor = pd->f_noise;
+
+ if(noise_factor > 0.0f) {
+ strength += wind_func(rng, noise_factor);
+
+ if(ELEM(pd->forcefield, PFIELD_HARMONIC, PFIELD_DRAG))
+ damp += wind_func(rng, noise_factor);
+ }
+
+ VECCOPY(force, efd->vec_to_point);
+
+ switch(pd->forcefield){
+ case PFIELD_WIND:
+ Normalize(force);
+ strength *= (Inpf(force, efd->nor) >= 0.0f ? 1.0f : -1.0f);
+ VecMulf(force, strength * efd->falloff);
+ break;
+ case PFIELD_FORCE:
+ Normalize(force);
+ VecMulf(force, strength * efd->falloff);
+ break;
+ case PFIELD_VORTEX:
+ /* old vortex force */
+ if(pd->shape == PFIELD_SHAPE_POINT) {
+ Crossf(force, efd->nor, efd->vec_to_point);
+ Normalize(force);
+ VecMulf(force, strength * efd->distance * efd->falloff);
}
+ else {
+ /* new vortex force */
+ Crossf(temp, efd->nor2, efd->vec_to_point2);
+ VecMulf(temp, strength * efd->falloff);
+
+ Crossf(force, efd->nor2, temp);
+ VecMulf(force, strength * efd->falloff);
+
+ VECADDFAC(temp, temp, point->vel, -point->vel_to_sec);
+ VecAddf(force, force, temp);
+ }
+ break;
+ case PFIELD_MAGNET:
+ if(eff->pd->shape == PFIELD_SHAPE_POINT)
+ /* magnetic field of a moving charge */
+ Crossf(temp, efd->nor, efd->vec_to_point);
else
- VecCopyf(mag_vec,vec_to_part);
-
- /* at this distance the field is 60 times weaker than maximum */
- if(distance > 2.22 * (size+pa_size))
- break;
+ VecCopyf(temp, efd->nor);
- fac = pow((size+pa_size)/distance,6.0);
+ Normalize(temp);
+ VecMulf(temp, strength * efd->falloff);
+ Crossf(force, point->vel, temp);
+ VecMulf(force, point->vel_to_sec);
+ break;
+ case PFIELD_HARMONIC:
+ VecMulf(force, -strength * efd->falloff);
+ VecCopyf(temp, point->vel);
+ VecMulf(temp, -damp * 2.0f * (float)sqrt(fabs(strength)) * point->vel_to_sec);
+ VecAddf(force, force, temp);
+ break;
+ case PFIELD_CHARGE:
+ VecMulf(force, point->charge * strength * efd->falloff);
+ break;
+ case PFIELD_LENNARDJ:
+ fac = pow((efd->size + point->size) / efd->distance, 6.0);
- fac = - fac * (1.0 - fac) / distance;
+ fac = - fac * (1.0 - fac) / efd->distance;
/* limit the repulsive term drastically to avoid huge forces */
fac = ((fac>2.0) ? 2.0 : fac);
- /* 0.003715 is the fac value at 2.22 times (size+pa_size),
- substracted to avoid discontinuity at the border
- */
- VecMulf(mag_vec, force_val * (fac-0.0037315));
- VecAddf(field,field,mag_vec);
+ VecMulf(force, strength * fac);
break;
- }
case PFIELD_BOID:
/* Boid field is handled completely in boids code. */
+ return;
+ case PFIELD_TURBULENCE:
+ if(pd->flag & PFIELD_GLOBAL_CO) {
+ VECCOPY(temp, point->loc);
+ }
+ else {
+ VECADD(temp, efd->vec_to_point2, efd->nor2);
+ }
+ force[0] = -1.0f + 2.0f * BLI_gTurbulence(pd->f_size, temp[0], temp[1], temp[2], 2,0,2);
+ force[1] = -1.0f + 2.0f * BLI_gTurbulence(pd->f_size, temp[1], temp[2], temp[0], 2,0,2);
+ force[2] = -1.0f + 2.0f * BLI_gTurbulence(pd->f_size, temp[2], temp[0], temp[1], 2,0,2);
+ VecMulf(force, strength * efd->falloff);
+ break;
+ case PFIELD_DRAG:
+ VECCOPY(force, point->vel);
+ fac = Normalize(force) * point->vel_to_sec;
+
+ strength = MIN2(strength, 2.0f);
+ damp = MIN2(damp, 2.0f);
+
+ VecMulf(force, -efd->falloff * fac * (strength * fac + damp));
break;
}
+
+ if(pd->flag & PFIELD_DO_LOCATION) {
+ VECADDFAC(total_force, total_force, force, 1.0f/point->vel_to_sec);
+
+ if(ELEM(pd->forcefield, PFIELD_HARMONIC, PFIELD_DRAG)==0 && pd->f_flow != 0.0f) {
+ VECADDFAC(total_force, total_force, point->vel, -pd->f_flow * efd->falloff);
+ }
+ }
+
+ if(pd->flag & PFIELD_DO_ROTATION && point->ave && point->rot) {
+ float xvec[3] = {1.0f, 0.0f, 0.0f};
+ float dave[3];
+ QuatMulVecf(point->rot, xvec);
+ Crossf(dave, xvec, force);
+ if(pd->f_flow != 0.0f) {
+ VECADDFAC(dave, dave, point->ave, -pd->f_flow * efd->falloff);
+ }
+ VecAddf(point->ave, point->ave, dave);
+ }
}
/* -------- pdDoEffectors() --------
@@ -528,7 +953,7 @@ void do_physical_effector(Scene *scene, Object *ob, float *opco, short type, flo
guide = old speed of particle
*/
-void pdDoEffectors(Scene *scene, ListBase *lb, float *opco, float *force, float *speed, float cur_time, float loc_time, unsigned int flags)
+void pdDoEffectors(ListBase *effectors, ListBase *colliders, EffectorWeights *weights, EffectedPoint *point, float *force, float *impulse)
{
/*
Modifies the force on a particle according to its
@@ -543,43 +968,45 @@ void pdDoEffectors(Scene *scene, ListBase *lb, float *opco, float *force, float
(particles are guided along a curve bezier or old nurbs)
(is independent of other effectors)
*/
- Object *ob;
- pEffectorCache *ec;
- PartDeflect *pd;
-
- float distance, vec_to_part[3];
- float falloff;
+ EffectorCache *eff;
+ EffectorData efd;
+ int p=0, tot = 1;
/* Cycle through collected objects, get total of (1/(gravity_strength * dist^gravity_power)) */
/* Check for min distance here? (yes would be cool to add that, ton) */
- for(ec = lb->first; ec; ec= ec->next) {
+ if(effectors) for(eff = effectors->first; eff; eff=eff->next) {
/* object effectors were fully checked to be OK to evaluate! */
- ob= ec->ob;
- pd= ob->pd;
-
- /* Get IPO force strength and fall off values here */
- where_is_object_time(scene, ob, cur_time);
-
- /* use center of object for distance calculus */
- VecSubf(vec_to_part, opco, ob->obmat[3]);
- distance = VecLength(vec_to_part);
- falloff=effector_falloff(pd,ob->obmat[2],vec_to_part);
-
- if(falloff<=0.0f)
- ; /* don't do anything */
- else {
- float field[3]={0,0,0}, tmp[3];
- VECCOPY(field, force);
- do_physical_effector(scene, ob, opco, pd->forcefield,pd->f_strength,distance,
- falloff, pd->f_dist, pd->f_damp, ob->obmat[2], vec_to_part,
- speed,force, pd->flag&PFIELD_PLANAR, pd->rng, pd->f_noise, 0.0f, 0.0f);
-
- // for softbody backward compatibility
- if(flags & PE_WIND_AS_SPEED){
- VECSUB(tmp, force, field);
- VECSUB(speed, speed, tmp);
+ get_effector_tot(eff, &efd, point, &tot, &p);
+
+ for(; p<tot; p++) {
+ if(get_effector_data(eff, &efd, point, 0)) {
+ efd.falloff= effector_falloff(eff, &efd, point, weights);
+
+ if(efd.falloff > 0.0f)
+ efd.falloff *= eff_calc_visibility(colliders, eff, &efd, point);
+
+ if(efd.falloff <= 0.0f)
+ ; /* don't do anything */
+ else if(eff->pd->forcefield == PFIELD_TEXTURE)
+ do_texture_effector(eff, &efd, point, force);
+ else {
+ float temp1[3]={0,0,0}, temp2[3];
+ VECCOPY(temp1, force);
+
+ do_physical_effector(eff, &efd, point, force);
+
+ // for softbody backward compatibility
+ if(point->flag & PE_WIND_AS_SPEED && impulse){
+ VECSUB(temp2, force, temp1);
+ VECSUB(impulse, impulse, temp2);
+ }
+ }
+ }
+ else if(eff->flag & PE_VELOCITY_TO_IMPULSE && impulse) {
+ /* special case for harmonic effector */
+ VECADD(impulse, impulse, efd.vel);
}
}
}
diff --git a/source/blender/blenkernel/intern/implicit.c b/source/blender/blenkernel/intern/implicit.c
index ae2acd6aef7..de215ae4af9 100644
--- a/source/blender/blenkernel/intern/implicit.c
+++ b/source/blender/blenkernel/intern/implicit.c
@@ -33,6 +33,7 @@
#include "DNA_cloth_types.h"
#include "DNA_scene_types.h"
+#include "DNA_object_force.h"
#include "BKE_effect.h"
#include "BKE_global.h"
@@ -1482,15 +1483,19 @@ static void cloth_calc_force(ClothModifierData *clmd, float frame, lfVector *lF,
Cloth *cloth = clmd->clothObject;
int i = 0;
float spring_air = clmd->sim_parms->Cvi * 0.01f; /* viscosity of air scaled in percent */
- float gravity[3];
+ float gravity[3] = {0.0f, 0.0f, 0.0f};
float tm2[3][3] = {{-spring_air,0,0}, {0,-spring_air,0},{0,0,-spring_air}};
MFace *mfaces = cloth->mfaces;
unsigned int numverts = cloth->numverts;
LinkNode *search = cloth->springs;
lfVector *winvec;
+ EffectedPoint epoint;
- VECCOPY(gravity, clmd->sim_parms->gravity);
- mul_fvector_S(gravity, gravity, 0.001f); /* scale gravity force */
+ /* global acceleration (gravitation) */
+ if(clmd->scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY) {
+ VECCOPY(gravity, clmd->scene->physics_settings.gravity);
+ mul_fvector_S(gravity, gravity, 0.001f * clmd->sim_parms->effector_weights->global_gravity); /* scale gravity force */
+ }
/* set dFdX jacobi matrix to zero */
init_bfmatrix(dFdX, ZERO);
@@ -1525,10 +1530,9 @@ static void cloth_calc_force(ClothModifierData *clmd, float frame, lfVector *lF,
// precalculate wind forces
for(i = 0; i < cloth->numverts; i++)
- {
- float speed[3] = {0.0f, 0.0f,0.0f};
-
- pdDoEffectors(clmd->scene, effectors, lX[i], winvec[i], speed, frame, 0.0f, 0);
+ {
+ pd_point_from_loc(clmd->scene, (float*)lX[i], (float*)lV[i], i, &epoint);
+ pdDoEffectors(effectors, NULL, clmd->sim_parms->effector_weights, &epoint, winvec[i], NULL);
}
for(i = 0; i < cloth->numfaces; i++)
@@ -1656,9 +1660,7 @@ int implicit_solver (Object *ob, float frame, ClothModifierData *clmd, ListBase
while(step < tf)
{
// calculate forces
- effectors= pdInitEffectors(clmd->scene, ob, NULL);
cloth_calc_force(clmd, frame, id->F, id->X, id->V, id->dFdV, id->dFdX, effectors, step, id->M);
- if(effectors) pdEndEffectors(effectors);
// calculate new velocity
simulate_implicit_euler(id->Vnew, id->X, id->V, id->F, id->dFdV, id->dFdX, dt, id->A, id->B, id->dV, id->S, id->z, id->olddV, id->P, id->Pinv, id->M, id->bigI);
@@ -1741,9 +1743,7 @@ int implicit_solver (Object *ob, float frame, ClothModifierData *clmd, ListBase
cp_lfvector(id->V, id->Vnew, numverts);
// calculate
- effectors= pdInitEffectors(clmd->scene, ob, NULL);
cloth_calc_force(clmd, frame, id->F, id->X, id->V, id->dFdV, id->dFdX, effectors, step+dt, id->M);
- if(effectors) pdEndEffectors(effectors);
simulate_implicit_euler(id->Vnew, id->X, id->V, id->F, id->dFdV, id->dFdX, dt / 2.0f, id->A, id->B, id->dV, id->S, id->z, id->olddV, id->P, id->Pinv, id->M, id->bigI);
}
diff --git a/source/blender/blenkernel/intern/modifier.c b/source/blender/blenkernel/intern/modifier.c
index b9b9ea6b4f3..3b47c2f1830 100644
--- a/source/blender/blenkernel/intern/modifier.c
+++ b/source/blender/blenkernel/intern/modifier.c
@@ -5971,6 +5971,8 @@ static void clothModifier_copyData(ModifierData *md, ModifierData *target)
tclmd->point_cache = NULL;
tclmd->sim_parms = MEM_dupallocN(clmd->sim_parms);
+ if(clmd->sim_parms->effector_weights)
+ tclmd->sim_parms->effector_weights = MEM_dupallocN(clmd->sim_parms->effector_weights);
tclmd->coll_parms = MEM_dupallocN(clmd->coll_parms);
tclmd->point_cache = BKE_ptcache_copy_list(&tclmd->ptcaches, &clmd->ptcaches);
tclmd->clothObject = NULL;
@@ -5992,8 +5994,11 @@ static void clothModifier_freeData(ModifierData *md)
cloth_free_modifier_extern (clmd);
- if(clmd->sim_parms)
+ if(clmd->sim_parms) {
+ if(clmd->sim_parms->effector_weights)
+ MEM_freeN(clmd->sim_parms->effector_weights);
MEM_freeN(clmd->sim_parms);
+ }
if(clmd->coll_parms)
MEM_freeN(clmd->coll_parms);
diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c
index 4c729845745..579466ea626 100644
--- a/source/blender/blenkernel/intern/object.c
+++ b/source/blender/blenkernel/intern/object.c
@@ -91,6 +91,7 @@
#include "BKE_constraint.h"
#include "BKE_curve.h"
#include "BKE_displist.h"
+#include "BKE_effect.h"
#include "BKE_fcurve.h"
#include "BKE_group.h"
#include "BKE_icons.h"
@@ -298,11 +299,8 @@ void free_object(Object *ob)
free_constraints(&ob->constraints);
- if(ob->pd){
- if(ob->pd->tex)
- ob->pd->tex->id.us--;
- MEM_freeN(ob->pd);
- }
+ free_partdeflect(ob->pd);
+
if(ob->soft) sbFree(ob->soft);
if(ob->bsoft) bsbFree(ob->bsoft);
if(ob->gpulamp.first) GPU_lamp_free(ob);
@@ -1069,6 +1067,9 @@ SoftBody *copy_softbody(SoftBody *sb)
sbn->pointcache= BKE_ptcache_copy_list(&sbn->ptcaches, &sb->ptcaches);
+ if(sb->effector_weights)
+ sbn->effector_weights = MEM_dupallocN(sb->effector_weights);
+
return sbn;
}
@@ -1129,11 +1130,9 @@ ParticleSystem *copy_particlesystem(ParticleSystem *psys)
psysn->pathcache= NULL;
psysn->childcache= NULL;
psysn->edit= NULL;
- psysn->effectors.first= psysn->effectors.last= 0;
psysn->pathcachebufs.first = psysn->pathcachebufs.last = NULL;
psysn->childcachebufs.first = psysn->childcachebufs.last = NULL;
- psysn->reactevents.first = psysn->reactevents.last = NULL;
psysn->renderdata = NULL;
psysn->pointcache= BKE_ptcache_copy_list(&psysn->ptcaches, &psys->ptcaches);
@@ -1278,6 +1277,8 @@ Object *copy_object(Object *ob)
obn->pd= MEM_dupallocN(ob->pd);
if(obn->pd->tex)
id_us_plus(&(obn->pd->tex->id));
+ if(obn->pd->rng)
+ obn->pd->rng = MEM_dupallocN(ob->pd->rng);
}
obn->soft= copy_softbody(ob->soft);
obn->bsoft = copy_bulletsoftbody(ob->bsoft);
diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c
index e18e7f54e49..e63b77a134e 100644
--- a/source/blender/blenkernel/intern/particle.c
+++ b/source/blender/blenkernel/intern/particle.c
@@ -53,7 +53,7 @@
#include "BLI_blenlib.h"
#include "BLI_dynstr.h"
#include "BLI_kdtree.h"
-#include "BLI_linklist.h"
+#include "BLI_listbase.h"
#include "BLI_rand.h"
#include "BLI_threads.h"
@@ -61,6 +61,7 @@
#include "BKE_boids.h"
#include "BKE_cloth.h"
+#include "BKE_effect.h"
#include "BKE_global.h"
#include "BKE_main.h"
#include "BKE_lattice.h"
@@ -96,8 +97,7 @@ int count_particles(ParticleSystem *psys){
int tot=0;
LOOP_SHOWN_PARTICLES {
- if(pa->alive == PARS_KILLED);
- else if(pa->alive == PARS_UNBORN && (part->flag & PART_UNBORN)==0);
+ if(pa->alive == PARS_UNBORN && (part->flag & PART_UNBORN)==0);
else if(pa->alive == PARS_DEAD && (part->flag & PART_DIED)==0);
else tot++;
}
@@ -109,8 +109,7 @@ int count_particles_mod(ParticleSystem *psys, int totgr, int cur){
int tot=0;
LOOP_SHOWN_PARTICLES {
- if(pa->alive == PARS_KILLED);
- else if(pa->alive == PARS_UNBORN && (part->flag & PART_UNBORN)==0);
+ if(pa->alive == PARS_UNBORN && (part->flag & PART_UNBORN)==0);
else if(pa->alive == PARS_DEAD && (part->flag & PART_DIED)==0);
else if(p%totgr==cur) tot++;
}
@@ -302,15 +301,11 @@ int psys_check_enabled(Object *ob, ParticleSystem *psys)
/************************************************/
void psys_free_settings(ParticleSettings *part)
{
- if(part->pd) {
- MEM_freeN(part->pd);
- part->pd = NULL;
- }
-
- if(part->pd2) {
- MEM_freeN(part->pd2);
- part->pd2 = NULL;
- }
+ free_partdeflect(part->pd);
+ free_partdeflect(part->pd2);
+
+ if(part->effector_weights)
+ MEM_freeN(part->effector_weights);
boid_free_settings(part->boids);
}
@@ -428,21 +423,23 @@ void psys_free_particles(ParticleSystem *psys)
}
void psys_free_pdd(ParticleSystem *psys)
{
- if(psys->pdd->cdata)
- MEM_freeN(psys->pdd->cdata);
- psys->pdd->cdata = NULL;
+ if(psys->pdd) {
+ if(psys->pdd->cdata)
+ MEM_freeN(psys->pdd->cdata);
+ psys->pdd->cdata = NULL;
- if(psys->pdd->vdata)
- MEM_freeN(psys->pdd->vdata);
- psys->pdd->vdata = NULL;
+ if(psys->pdd->vdata)
+ MEM_freeN(psys->pdd->vdata);
+ psys->pdd->vdata = NULL;
- if(psys->pdd->ndata)
- MEM_freeN(psys->pdd->ndata);
- psys->pdd->ndata = NULL;
+ if(psys->pdd->ndata)
+ MEM_freeN(psys->pdd->ndata);
+ psys->pdd->ndata = NULL;
- if(psys->pdd->vedata)
- MEM_freeN(psys->pdd->vedata);
- psys->pdd->vedata = NULL;
+ if(psys->pdd->vedata)
+ MEM_freeN(psys->pdd->vedata);
+ psys->pdd->vedata = NULL;
+ }
}
/* free everything */
void psys_free(Object *ob, ParticleSystem * psys)
@@ -465,9 +462,6 @@ void psys_free(Object *ob, ParticleSystem * psys)
psys->child = 0;
psys->totchild = 0;
}
-
- if(psys->effectors.first)
- psys_end_effectors(psys);
// check if we are last non-visible particle system
for(tpsys=ob->particlesystem.first; tpsys; tpsys=tpsys->next){
@@ -493,10 +487,11 @@ void psys_free(Object *ob, ParticleSystem * psys)
psys->pointcache = NULL;
BLI_freelistN(&psys->targets);
- BLI_freelistN(&psys->reactevents);
BLI_kdtree_free(psys->tree);
+ pdEndEffectors(&psys->effectors);
+
if(psys->frand)
MEM_freeN(psys->frand);
@@ -1896,124 +1891,135 @@ static void do_clump(ParticleKey *state, ParticleKey *par, float time, float clu
VecLerpf(state->co,state->co,par->co,clump);
}
}
+void precalc_guides(ParticleSimulationData *sim, ListBase *effectors)
+{
+ EffectedPoint point;
+ ParticleKey state;
+ EffectorData efd;
+ EffectorCache *eff;
+ ParticleSystem *psys = sim->psys;
+ EffectorWeights *weights = sim->psys->part->effector_weights;
+ GuideEffectorData *data;
+ PARTICLE_P;
+
+ if(!effectors)
+ return;
+
+ LOOP_PARTICLES {
+ psys_particle_on_emitter(sim->psmd,sim->psys->part->from,pa->num,pa->num_dmcache,pa->fuv,pa->foffset,state.co,0,0,0,0,0);
+ pd_point_from_particle(sim, pa, &state, &point);
+
+ for(eff = effectors->first; eff; eff=eff->next) {
+ if(eff->pd->forcefield != PFIELD_GUIDE)
+ continue;
-int do_guide(Scene *scene, ParticleKey *state, int pa_num, float time, ListBase *lb)
+ if(!eff->guide_data)
+ eff->guide_data = MEM_callocN(sizeof(GuideEffectorData)*psys->totpart, "GuideEffectorData");
+
+ data = eff->guide_data + p;
+
+ VECSUB(efd.vec_to_point, state.co, eff->guide_loc);
+ VECCOPY(efd.nor, eff->guide_dir);
+ efd.distance = VecLength(efd.vec_to_point);
+
+ VECCOPY(data->vec_to_point, efd.vec_to_point);
+ data->strength = effector_falloff(eff, &efd, &point, weights);
+ }
+ }
+}
+int do_guides(ListBase *effectors, ParticleKey *state, int index, float time)
{
+ EffectorCache *eff;
PartDeflect *pd;
- ParticleEffectorCache *ec;
- Object *eob;
Curve *cu;
ParticleKey key, par;
+ GuideEffectorData *data;
- float effect[3]={0.0,0.0,0.0}, distance, f_force, mindist, totforce=0.0;
- float guidevec[4], guidedir[3], rot2[4], radius, temp[3], angle, pa_loc[3], pa_zero[3]={0.0f,0.0f,0.0f};
- float veffect[3]={0.0,0.0,0.0}, guidetime;
+ float effect[3] = {0.0f, 0.0f, 0.0f}, veffect[3] = {0.0f, 0.0f, 0.0f};
+ float guidevec[4], guidedir[3], rot2[4], temp[3];
+ float guidetime, radius, angle, totstrength = 0.0f;
+ float vec_to_point[3];
- effect[0]=effect[1]=effect[2]=0.0;
+ if(effectors) for(eff = effectors->first; eff; eff=eff->next) {
+ pd = eff->pd;
- if(lb->first){
- for(ec = lb->first; ec; ec= ec->next){
- eob= ec->ob;
- if(ec->type & PSYS_EC_EFFECTOR){
- pd=eob->pd;
- if(pd->forcefield==PFIELD_GUIDE){
- cu = (Curve*)eob->data;
-
- distance=ec->distances[pa_num];
- mindist=pd->f_strength;
+ if(pd->forcefield != PFIELD_GUIDE)
+ continue;
- VECCOPY(pa_loc, ec->locations+3*pa_num);
- VECCOPY(pa_zero,pa_loc);
- VECADD(pa_zero,pa_zero,ec->firstloc);
+ data = eff->guide_data + index;
- guidetime=time/(1.0-pd->free_end);
+ if(data->strength <= 0.0f)
+ continue;
- /* WARNING: bails out with continue here */
- if(((pd->flag & PFIELD_USEMAX) && distance>pd->maxdist) || guidetime>1.0f) continue;
+ guidetime = time / (1.0 - pd->free_end);
- if(guidetime>1.0f) continue;
+ if(guidetime>1.0f)
+ continue;
- /* calculate contribution factor for this guide */
- f_force=1.0f;
- if(distance<=mindist);
- else if(pd->flag & PFIELD_USEMAX) {
- if(mindist>=pd->maxdist) f_force= 0.0f;
- else if(pd->f_power!=0.0f){
- f_force= 1.0f - (distance-mindist)/(pd->maxdist - mindist);
- f_force = (float)pow(f_force, pd->f_power);
- }
- }
- else if(pd->f_power!=0.0f){
- f_force= 1.0f/(1.0f + distance-mindist);
- f_force = (float)pow(f_force, pd->f_power);
- }
+ cu = (Curve*)eff->ob->data;
- if(pd->flag & PFIELD_GUIDE_PATH_ADD)
- where_on_path(eob, f_force*guidetime, guidevec, guidedir, NULL, &radius);
- else
- where_on_path(eob, guidetime, guidevec, guidedir, NULL, &radius);
+ if(pd->flag & PFIELD_GUIDE_PATH_ADD) {
+ if(where_on_path(eff->ob, data->strength * guidetime, guidevec, guidedir, NULL, &radius)==0)
+ return 0;
+ }
+ else {
+ if(where_on_path(eff->ob, guidetime, guidevec, guidedir, NULL, &radius)==0)
+ return 0;
+ }
- Mat4MulVecfl(ec->ob->obmat,guidevec);
- Mat4Mul3Vecfl(ec->ob->obmat,guidedir);
+ Mat4MulVecfl(eff->ob->obmat, guidevec);
+ Mat4Mul3Vecfl(eff->ob->obmat, guidedir);
- Normalize(guidedir);
+ Normalize(guidedir);
- if(guidetime!=0.0){
- /* curve direction */
- Crossf(temp, ec->firstdir, guidedir);
- angle=Inpf(ec->firstdir,guidedir)/(VecLength(ec->firstdir));
- angle=saacos(angle);
- VecRotToQuat(temp,angle,rot2);
- QuatMulVecf(rot2,pa_loc);
+ VECCOPY(vec_to_point, data->vec_to_point);
- /* curve tilt */
- VecRotToQuat(guidedir,guidevec[3]-ec->firstloc[3],rot2);
- QuatMulVecf(rot2,pa_loc);
+ if(guidetime != 0.0){
+ /* curve direction */
+ Crossf(temp, eff->guide_dir, guidedir);
+ angle = Inpf(eff->guide_dir, guidedir)/(VecLength(eff->guide_dir));
+ angle = saacos(angle);
+ VecRotToQuat(temp, angle, rot2);
+ QuatMulVecf(rot2, vec_to_point);
- //vectoquat(guidedir, pd->kink_axis, (pd->kink_axis+1)%3, q);
- //QuatMul(par.rot,rot2,q);
- }
- //else{
- // par.rot[0]=1.0f;
- // par.rot[1]=par.rot[2]=par.rot[3]=0.0f;
- //}
-
- /* curve taper */
- if(cu->taperobj)
- VecMulf(pa_loc, calc_taper(scene, cu->taperobj, (int)(f_force*guidetime*100.0), 100));
-
- else{ /* curve size*/
- if(cu->flag & CU_PATH_RADIUS) {
- VecMulf(pa_loc, radius);
- }
- }
- par.co[0]=par.co[1]=par.co[2]=0.0f;
- VECCOPY(key.co,pa_loc);
- do_prekink(&key, &par, 0, guidetime, pd->kink_freq, pd->kink_shape, pd->kink_amp, pd->kink, pd->kink_axis, 0);
- do_clump(&key, &par, guidetime, pd->clump_fac, pd->clump_pow, 1.0f);
- VECCOPY(pa_loc,key.co);
-
- VECADD(pa_loc,pa_loc,guidevec);
- VECSUB(pa_loc,pa_loc,pa_zero);
- VECADDFAC(effect,effect,pa_loc,f_force);
- VECADDFAC(veffect,veffect,guidedir,f_force);
- totforce+=f_force;
- }
- }
+ /* curve tilt */
+ VecRotToQuat(guidedir, guidevec[3] - eff->guide_loc[3], rot2);
+ QuatMulVecf(rot2, vec_to_point);
}
- if(totforce!=0.0){
- if(totforce>1.0)
- VecMulf(effect,1.0f/totforce);
- CLAMP(totforce,0.0,1.0);
- VECADD(effect,effect,pa_zero);
- VecLerpf(state->co,state->co,effect,totforce);
+ /* curve taper */
+ if(cu->taperobj)
+ VecMulf(vec_to_point, calc_taper(eff->scene, cu->taperobj, (int)(data->strength*guidetime*100.0), 100));
- Normalize(veffect);
- VecMulf(veffect,VecLength(state->vel));
- VECCOPY(state->vel,veffect);
- return 1;
+ else{ /* curve size*/
+ if(cu->flag & CU_PATH_RADIUS) {
+ VecMulf(vec_to_point, radius);
+ }
}
+ par.co[0] = par.co[1] = par.co[2] = 0.0f;
+ VECCOPY(key.co, vec_to_point);
+ do_prekink(&key, &par, 0, guidetime, pd->kink_freq, pd->kink_shape, pd->kink_amp, pd->kink, pd->kink_axis, 0);
+ do_clump(&key, &par, guidetime, pd->clump_fac, pd->clump_pow, 1.0f);
+ VECCOPY(vec_to_point, key.co);
+
+ VECADD(vec_to_point, vec_to_point, guidevec);
+ //VECSUB(pa_loc,pa_loc,pa_zero);
+ VECADDFAC(effect, effect, vec_to_point, data->strength);
+ VECADDFAC(veffect, veffect, guidedir, data->strength);
+ totstrength += data->strength;
+ }
+
+ if(totstrength != 0.0){
+ if(totstrength > 1.0)
+ VecMulf(effect, 1.0f / totstrength);
+ CLAMP(totstrength, 0.0, 1.0);
+ //VECADD(effect,effect,pa_zero);
+ VecLerpf(state->co, state->co, effect, totstrength);
+
+ Normalize(veffect);
+ VecMulf(veffect, VecLength(state->vel));
+ VECCOPY(state->vel, veffect);
+ return 1;
}
return 0;
}
@@ -2053,14 +2059,18 @@ static void do_path_effectors(ParticleSimulationData *sim, int i, ParticleCacheK
{
float force[3] = {0.0f,0.0f,0.0f}, vel[3] = {0.0f,0.0f,0.0f};
ParticleKey eff_key;
- ParticleData *pa;
+ EffectedPoint epoint;
+
+ /* Don't apply effectors for dynamic hair, otherwise the effectors don't get applied twice. */
+ if(sim->psys->flag & PSYS_HAIR_DYNAMICS)
+ return;
VECCOPY(eff_key.co,(ca-1)->co);
VECCOPY(eff_key.vel,(ca-1)->vel);
QUATCOPY(eff_key.rot,(ca-1)->rot);
- pa= sim->psys->particles+i;
- do_effectors(sim, i, pa, &eff_key, rootco, force, vel, dfra, cfra);
+ pd_point_from_particle(sim, sim->psys->particles+i, &eff_key, &epoint);
+ pdDoEffectors(sim->psys->effectors, sim->colliders, sim->psys->part->effector_weights, &epoint, force, NULL);
VecMulf(force, effector*pow((float)k / (float)steps, 100.0f * sim->psys->part->eff_hair) / (float)steps);
@@ -2777,9 +2787,9 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra)
do_path_effectors(sim, p, ca, k, steps, cache[p]->co, effector, dfra, cfra, &length, vec);
/* apply guide curves to path data */
- if(psys->effectors.first && (psys->part->flag & PART_CHILD_EFFECT)==0)
+ if(sim->psys->effectors && (psys->part->flag & PART_CHILD_EFFECT)==0)
/* ca is safe to cast, since only co and vel are used */
- do_guide(sim->scene, (ParticleKey*)ca, p, (float)k/(float)steps, &psys->effectors);
+ do_guides(sim->psys->effectors, (ParticleKey*)ca, p, (float)k/(float)steps);
/* apply lattice */
if(psys->lattice)
@@ -3187,8 +3197,6 @@ void object_remove_particle_system(Scene *scene, Object *ob)
}
static void default_particle_settings(ParticleSettings *part)
{
- int i;
-
part->type= PART_EMITTER;
part->distr= PART_DISTR_JIT;
part->draw_as = PART_DRAW_REND;
@@ -3199,7 +3207,7 @@ static void default_particle_settings(ParticleSettings *part)
part->flag=PART_REACT_MULTIPLE|PART_HAIR_GEOMETRY|PART_EDISTR|PART_TRAND;
part->sta= 1.0;
- part->end= 100.0;
+ part->end= 200.0;
part->lifetime= 50.0;
part->jitfac= 1.0;
part->totpart= 1000;
@@ -3249,10 +3257,6 @@ static void default_particle_settings(ParticleSettings *part)
part->keyed_loops = 1;
- for(i=0; i<10; i++)
- part->effector_weight[i]=1.0f;
-
-
#if 0 // XXX old animation system
part->ipo = NULL;
#endif // XXX old animation system
@@ -3261,6 +3265,9 @@ static void default_particle_settings(ParticleSettings *part)
part->simplify_rate= 1.0f;
part->simplify_transition= 0.1f;
part->simplify_viewport= 0.8;
+
+ if(!part->effector_weights)
+ part->effector_weights = BKE_add_effector_weights(NULL);
}
@@ -3348,24 +3355,6 @@ void make_local_particlesettings(ParticleSettings *part)
}
}
}
-void psys_flush_particle_settings(Scene *scene, ParticleSettings *part, int recalc)
-{
- Base *base = scene->base.first;
- ParticleSystem *psys;
- int flush;
-
- for(base = scene->base.first; base; base = base->next) {
- flush = 0;
- for(psys = base->object->particlesystem.first; psys; psys=psys->next) {
- if(psys->part == part) {
- psys->recalc |= recalc;
- flush++;
- }
- }
- if(flush)
- DAG_id_flush_update(&base->object->id, OB_RECALC_DATA);
- }
-}
/************************************************/
/* Textures */
@@ -3646,7 +3635,7 @@ static void do_child_modifiers(ParticleSimulationData *sim, ParticleTexture *pte
if(part->flag & PART_CHILD_EFFECT)
/* state is safe to cast, since only co and vel are used */
- guided = do_guide(sim->scene, (ParticleKey*)state, cpa->parent, t, &(sim->psys->effectors));
+ guided = do_guides(sim->psys->effectors, (ParticleKey*)state, cpa->parent, t);
if(guided==0){
if(part->kink)
@@ -3716,8 +3705,8 @@ void psys_get_particle_on_path(ParticleSimulationData *sim, int p, ParticleKey *
Mat4MulVecfl(hairmat, state->co);
Mat4Mul3Vecfl(hairmat, state->vel);
- if(psys->effectors.first && (part->flag & PART_CHILD_GUIDE)==0) {
- do_guide(sim->scene, state, p, state->time, &psys->effectors);
+ if(sim->psys->effectors && (part->flag & PART_CHILD_GUIDE)==0) {
+ do_guides(sim->psys->effectors, state, p, state->time);
/* TODO: proper velocity handling */
}
@@ -3905,8 +3894,6 @@ int psys_get_particle_state(ParticleSimulationData *sim, int p, ParticleKey *sta
}
if(pa) {
- if(pa->alive == PARS_KILLED) return 0;
-
if(!always)
if((pa->alive==PARS_UNBORN && (part->flag & PART_UNBORN)==0)
|| (pa->alive==PARS_DEAD && (part->flag & PART_DIED)==0))
diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c
index 1b6d56e6459..77cef689d09 100644
--- a/source/blender/blenkernel/intern/particle_system.c
+++ b/source/blender/blenkernel/intern/particle_system.c
@@ -58,7 +58,7 @@
#include "BLI_blenlib.h"
#include "BLI_kdtree.h"
#include "BLI_kdopbvh.h"
-#include "BLI_linklist.h"
+#include "BLI_listbase.h"
#include "BLI_threads.h"
#include "BKE_anim.h"
@@ -132,9 +132,6 @@ void psys_reset(ParticleSystem *psys, int mode)
psys->totkeyed= 0;
psys->flag &= ~(PSYS_HAIR_DONE|PSYS_KEYED);
- if(psys->reactevents.first)
- BLI_freelistN(&psys->reactevents);
-
if(psys->edit && psys->free_edit) {
psys->free_edit(psys->edit);
psys->edit = NULL;
@@ -1796,8 +1793,9 @@ void reset_particle(ParticleSimulationData *sim, ParticleData *pa, float dtime,
/* and gravity in r_ve */
bpa->gravity[0] = bpa->gravity[1] = 0.0f;
bpa->gravity[2] = -1.0f;
- if(part->acc[2]!=0.0f)
- bpa->gravity[2] = part->acc[2];
+ if((sim->scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY)
+ && sim->scene->physics_settings.gravity[2]!=0.0f)
+ bpa->gravity[2] = sim->scene->physics_settings.gravity[2];
/* calculate rotation matrix */
Projf(dvec, r_vel, pa->state.ave);
@@ -1936,8 +1934,12 @@ void reset_particle(ParticleSimulationData *sim, ParticleData *pa, float dtime,
pa->dietime = pa->time + pa->lifetime;
- if(pa->time >= cfra)
+ if(pa->time > cfra)
pa->alive = PARS_UNBORN;
+ else if(pa->dietime <= cfra)
+ pa->alive = PARS_DEAD;
+ else
+ pa->alive = PARS_ALIVE;
pa->state.time = cfra;
}
@@ -2203,12 +2205,12 @@ void psys_get_pointcache_start_end(Scene *scene, ParticleSystem *psys, int *sfra
/************************************************/
/* Effectors */
/************************************************/
-static void update_particle_tree(ParticleSystem *psys)
+void psys_update_particle_tree(ParticleSystem *psys, float cfra)
{
if(psys) {
PARTICLE_P;
- if(!psys->tree || psys->tree_frame != psys->cfra) {
+ if(!psys->tree || psys->tree_frame != cfra) {
BLI_kdtree_free(psys->tree);
@@ -2216,7 +2218,10 @@ static void update_particle_tree(ParticleSystem *psys)
LOOP_SHOWN_PARTICLES {
if(pa->alive == PARS_ALIVE)
- BLI_kdtree_insert(psys->tree, p, pa->state.co, NULL);
+ if(pa->state.time == cfra)
+ BLI_kdtree_insert(psys->tree, p, pa->prev_state.co, NULL);
+ else
+ BLI_kdtree_insert(psys->tree, p, pa->state.co, NULL);
}
BLI_kdtree_balance(psys->tree);
@@ -2224,535 +2229,12 @@ static void update_particle_tree(ParticleSystem *psys)
}
}
}
-static void do_texture_effector(Tex *tex, short mode, short is_2d, float nabla, short object, float *pa_co, float obmat[4][4], float force_val, float falloff, float *field)
-{
- TexResult result[4];
- float tex_co[3], strength, mag_vec[3];
- int hasrgb;
- if(tex==NULL) return;
-
- result[0].nor = result[1].nor = result[2].nor = result[3].nor = 0;
-
- strength= force_val*falloff;
-
- VECCOPY(tex_co,pa_co);
-
- if(is_2d){
- float fac=-Inpf(tex_co,obmat[2]);
- VECADDFAC(tex_co,tex_co,obmat[2],fac);
- }
-
- if(object){
- VecSubf(tex_co,tex_co,obmat[3]);
- Mat4Mul3Vecfl(obmat,tex_co);
- }
-
- hasrgb = multitex_ext(tex, tex_co, NULL,NULL, 1, result);
-
- if(hasrgb && mode==PFIELD_TEX_RGB){
- mag_vec[0]= (0.5f-result->tr)*strength;
- mag_vec[1]= (0.5f-result->tg)*strength;
- mag_vec[2]= (0.5f-result->tb)*strength;
- }
- else{
- strength/=nabla;
-
- tex_co[0]+= nabla;
- multitex_ext(tex, tex_co, NULL,NULL, 1, result+1);
-
- tex_co[0]-= nabla;
- tex_co[1]+= nabla;
- multitex_ext(tex, tex_co, NULL,NULL, 1, result+2);
-
- tex_co[1]-= nabla;
- tex_co[2]+= nabla;
- multitex_ext(tex, tex_co, NULL,NULL, 1, result+3);
-
- if(mode==PFIELD_TEX_GRAD || !hasrgb){ /* if we dont have rgb fall back to grad */
- mag_vec[0]= (result[0].tin-result[1].tin)*strength;
- mag_vec[1]= (result[0].tin-result[2].tin)*strength;
- mag_vec[2]= (result[0].tin-result[3].tin)*strength;
- }
- else{ /*PFIELD_TEX_CURL*/
- float dbdy,dgdz,drdz,dbdx,dgdx,drdy;
-
- dbdy= result[2].tb-result[0].tb;
- dgdz= result[3].tg-result[0].tg;
- drdz= result[3].tr-result[0].tr;
- dbdx= result[1].tb-result[0].tb;
- dgdx= result[1].tg-result[0].tg;
- drdy= result[2].tr-result[0].tr;
-
- mag_vec[0]=(dbdy-dgdz)*strength;
- mag_vec[1]=(drdz-dbdx)*strength;
- mag_vec[2]=(dgdx-drdy)*strength;
- }
- }
-
- if(is_2d){
- float fac=-Inpf(mag_vec,obmat[2]);
- VECADDFAC(mag_vec,mag_vec,obmat[2],fac);
- }
-
- VecAddf(field,field,mag_vec);
-}
-static void add_to_effectors(ParticleSimulationData *sim, ListBase *lb, Object *ob)
-{
- ParticleEffectorCache *ec;
- PartDeflect *pd= ob->pd;
- short type=0,i;
-
- if(pd && ob != sim->ob){
- if(pd->forcefield == PFIELD_GUIDE) {
- if(ob->type==OB_CURVE) {
- Curve *cu= ob->data;
- if(cu->flag & CU_PATH) {
- if(cu->path==NULL || cu->path->data==NULL)
- makeDispListCurveTypes(sim->scene, ob, 0);
- if(cu->path && cu->path->data) {
- type |= PSYS_EC_EFFECTOR;
- }
- }
- }
- }
- else if(pd->forcefield)
- {
- type |= PSYS_EC_EFFECTOR;
- }
- }
-
- if(pd && pd->deflect)
- type |= PSYS_EC_DEFLECT;
-
- if(type){
- ec= MEM_callocN(sizeof(ParticleEffectorCache), "effector cache");
- ec->ob= ob;
- ec->type=type;
- ec->distances=0;
- ec->locations=0;
- ec->rng = rng_new(1);
- rng_srandom(ec->rng, (unsigned int)(ceil(PIL_check_seconds_timer()))); // use better seed
-
- BLI_addtail(lb, ec);
- }
-
- type=0;
-
- /* add particles as different effectors */
- if(ob->particlesystem.first){
- ParticleSystem *epsys=ob->particlesystem.first;
- ParticleSettings *epart=0;
- //Object *tob;
-
- for(i=0; epsys; epsys=epsys->next,i++){
- if(!psys_check_enabled(ob, epsys))
- continue;
- type=0;
- if(epsys!=sim->psys || (sim->psys->part->flag & PART_SELF_EFFECT)){
- epart=epsys->part;
-
- if((epsys->part->pd && epsys->part->pd->forcefield)
- || (epsys->part->pd2 && epsys->part->pd2->forcefield))
- {
- type=PSYS_EC_PARTICLE;
- }
-
- //if(epart->type==PART_REACTOR) {
- // tob=epsys->target_ob;
- // if(tob==0)
- // tob=ob;
- // if(BLI_findlink(&tob->particlesystem,epsys->target_psys-1)==sim->psys)
- // type|=PSYS_EC_REACTOR;
- //}
-
- if(type){
- ec= MEM_callocN(sizeof(ParticleEffectorCache), "effector cache");
- ec->ob= ob;
- ec->type=type;
- ec->psys_nbr=i;
- ec->rng = rng_new(1);
- rng_srandom(ec->rng, (unsigned int)(ceil(PIL_check_seconds_timer())));
-
- BLI_addtail(lb, ec);
- }
- }
- }
-
- }
-}
-
-static void psys_init_effectors_recurs(ParticleSimulationData *sim, Object *ob, ListBase *listb, int level)
-{
- Group *group;
- GroupObject *go;
- unsigned int layer= sim->ob->lay;
-
- if(level>MAX_DUPLI_RECUR) return;
-
- if(ob->lay & layer) {
- if(ob->pd || ob->particlesystem.first)
- add_to_effectors(sim, listb, ob);
-
- if(ob->dup_group) {
- group= ob->dup_group;
- for(go= group->gobject.first; go; go= go->next)
- psys_init_effectors_recurs(sim, go->ob, listb, level+1);
- }
- }
-}
-
-static void psys_init_effectors(ParticleSimulationData *sim, Group *group)
-{
- ListBase *listb= &sim->psys->effectors;
- Base *base;
-
- listb->first=listb->last=0;
-
- if(group) {
- GroupObject *go;
-
- for(go= group->gobject.first; go; go= go->next)
- psys_init_effectors_recurs(sim, go->ob, listb, 0);
- }
- else {
- for(base = sim->scene->base.first; base; base= base->next)
- psys_init_effectors_recurs(sim, base->object, listb, 0);
- }
-}
-
-void psys_end_effectors(ParticleSystem *psys)
-{
- /* NOTE:
- ec->ob is not valid in here anymore! - dg
- */
- ParticleEffectorCache *ec = psys->effectors.first;
-
- for(; ec; ec= ec->next){
- if(ec->distances)
- MEM_freeN(ec->distances);
-
- if(ec->locations)
- MEM_freeN(ec->locations);
-
- if(ec->face_minmax)
- MEM_freeN(ec->face_minmax);
-
- if(ec->vert_cos)
- MEM_freeN(ec->vert_cos);
-
- if(ec->tree)
- BLI_kdtree_free(ec->tree);
-
- if(ec->rng)
- rng_free(ec->rng);
- }
-
- BLI_freelistN(&psys->effectors);
-}
-
-/* precalcs effectors and returns 1 if there were any collision object
- * so collision checks can be avoided as quickly as possible */
-static int precalc_effectors(ParticleSimulationData *sim, float cfra)
-{
- ParticleSystem *psys = sim->psys;
- ListBase *lb=&psys->effectors;
- ParticleEffectorCache *ec;
- ParticleSettings *part=psys->part;
- PARTICLE_P;
- int totpart, collision = 0;
- float vec2[3],loc[3],radius,*co=0;
-
- for(ec= lb->first; ec; ec= ec->next) {
- PartDeflect *pd= ec->ob->pd;
- co = NULL;
-
- if(ec->type==PSYS_EC_EFFECTOR && pd->forcefield==PFIELD_GUIDE && ec->ob->type==OB_CURVE
- && part->phystype!=PART_PHYS_BOIDS) {
- float vec[4];
-
- where_on_path(ec->ob, 0.0, vec, vec2, NULL, &radius);
-
- Mat4MulVecfl(ec->ob->obmat,vec);
- Mat4Mul3Vecfl(ec->ob->obmat,vec2);
-
- QUATCOPY(ec->firstloc,vec);
- VECCOPY(ec->firstdir,vec2);
-
- /* TODO - use 'radius' to adjust the effector */
-
- totpart=psys->totpart;
-
- if(totpart){
- ec->distances=MEM_callocN(totpart*sizeof(float),"particle distances");
- ec->locations=MEM_callocN(totpart*3*sizeof(float),"particle locations");
-
- LOOP_PARTICLES {
- if(part->from == PART_FROM_PARTICLE) {
- VECCOPY(loc, pa->fuv);
- }
- else
- psys_particle_on_emitter(sim->psmd,part->from,pa->num,pa->num_dmcache,pa->fuv,pa->foffset,loc,0,0,0,0,0);
-
- Mat4MulVecfl(sim->ob->obmat,loc);
- ec->distances[p]=VecLenf(loc,vec);
- VECSUB(loc,loc,vec);
- VECCOPY(ec->locations+3*p,loc);
- }
- }
- }
- else if(ec->type==PSYS_EC_PARTICLE){
- ParticleSimulationData esim = {sim->scene, ec->ob, BLI_findlink(&ec->ob->particlesystem, ec->psys_nbr), NULL};
- ParticleSettings *epart = esim.psys->part;
- ParticleData *epa;
- int p, totepart = esim.psys->totpart;
-
- if(psys->part->phystype==PART_PHYS_BOIDS){
- ParticleKey state;
- PartDeflect *pd;
-
- pd= epart->pd;
- if(pd->forcefield==PFIELD_FORCE && totepart){
- KDTree *tree;
-
- tree=BLI_kdtree_new(totepart);
- ec->tree=tree;
-
- for(p=0, epa=esim.psys->particles; p<totepart; p++,epa++)
- if(epa->alive==PARS_ALIVE && psys_get_particle_state(&esim,p,&state,0))
- BLI_kdtree_insert(tree, p, state.co, NULL);
-
- BLI_kdtree_balance(tree);
- }
- }
-
- }
- else if(ec->type==PSYS_EC_DEFLECT) {
- CollisionModifierData *collmd = ( CollisionModifierData * ) ( modifiers_findByType ( ec->ob, eModifierType_Collision ) );
- if(collmd) {
- collision_move_object(collmd, 1.0, 0.0);
- collision = 1;
- }
- }
- }
-
- return collision;
-}
-/* updates particle effectors and returns if any collision objects were found */
-int psys_update_effectors(ParticleSimulationData *sim, float cfra, int precalc)
-{
- psys_end_effectors(sim->psys);
- psys_init_effectors(sim, sim->psys->part->eff_group);
- return (precalc ? precalc_effectors(sim, cfra) : 0);
-}
-int effector_find_co(Scene *scene, float *pco, SurfaceModifierData *sur, Object *ob, PartDeflect *pd, float *co, float *nor, float *vel, int *index)
+static void psys_update_effectors(ParticleSimulationData *sim)
{
- SurfaceModifierData *surmd = NULL;
- int ret = 0;
-
- if(sur)
- surmd = sur;
- else if(pd && pd->flag&PFIELD_SURFACE)
- {
- surmd = (SurfaceModifierData *)modifiers_findByType ( ob, eModifierType_Surface );
- }
-
- if(surmd) {
- /* closest point in the object surface is an effector */
- BVHTreeNearest nearest;
-
- nearest.index = -1;
- nearest.dist = FLT_MAX;
-
- BLI_bvhtree_find_nearest(surmd->bvhtree->tree, pco, &nearest, surmd->bvhtree->nearest_callback, surmd->bvhtree);
-
- if(nearest.index != -1) {
- VECCOPY(co, nearest.co);
-
- if(nor) {
- VECCOPY(nor, nearest.no);
- }
-
- if(vel) {
- MFace *mface = CDDM_get_face(surmd->dm, nearest.index);
-
- VECCOPY(vel, surmd->v[mface->v1].co);
- VecAddf(vel, vel, surmd->v[mface->v2].co);
- VecAddf(vel, vel, surmd->v[mface->v3].co);
- if(mface->v4)
- VecAddf(vel, vel, surmd->v[mface->v4].co);
-
- VecMulf(vel, mface->v4 ? 0.25f : 0.333f);
- }
-
- if(index)
- *index = nearest.index;
-
- ret = 1;
- }
- else {
- co[0] = co[1] = co[2] = 0.0f;
-
- if(nor)
- nor[0] = nor[1] = nor[2] = 0.0f;
-
- if(vel)
- vel[0] = vel[1] = vel[2] = 0.0f;
- }
- }
- else {
- /* use center of object for distance calculus */
- VECCOPY(co, ob->obmat[3]);
-
- if(nor) {
- VECCOPY(nor, ob->obmat[2]);
- }
-
- if(vel) {
- Object obcopy = *ob;
-
- VECCOPY(vel, ob->obmat[3]);
-
- where_is_object_time(scene, ob, scene->r.cfra - 1.0);
-
- VecSubf(vel, vel, ob->obmat[3]);
-
- *ob = obcopy;
- }
- }
-
- return ret;
-}
-/* calculate forces that all effectors apply to a particle*/
-void do_effectors(ParticleSimulationData *sim, int pa_no, ParticleData *pa, ParticleKey *state, float *rootco, float *force_field, float *vel,float framestep, float cfra)
-{
- Object *eob;
- ParticleSystem *psys = sim->psys;
- ParticleSettings *epart;
- ParticleData *epa;
- ParticleKey estate;
- PartDeflect *pd;
- ListBase *lb=&psys->effectors;
- ParticleEffectorCache *ec;
- float distance, vec_to_part[3], pco[3], co[3];
- float falloff, charge = 0.0f, strength;
- int p, face_index=-1;
-
- /* check all effector objects for interaction */
- if(lb->first){
- if(psys->part->pd && psys->part->pd->forcefield==PFIELD_CHARGE){
- /* Only the charge of the effected particle is used for
- interaction, not fall-offs. If the fall-offs aren't the
- same this will be unphysical, but for animation this
- could be the wanted behavior. If you want physical
- correctness the fall-off should be spherical 2.0 anyways.
- */
- charge = psys->part->pd->f_strength;
- }
- if(psys->part->pd2 && psys->part->pd2->forcefield==PFIELD_CHARGE){
- charge += psys->part->pd2->f_strength;
- }
- for(ec = lb->first; ec; ec= ec->next){
- eob= ec->ob;
- if(ec->type & PSYS_EC_EFFECTOR){
- pd=eob->pd;
- if(psys->part->type!=PART_HAIR && psys->part->integrator)
- where_is_object_time(sim->scene, eob, cfra);
-
- if(pd && pd->flag&PFIELD_SURFACE) {
- float velocity[3];
- /* using velocity corrected location allows for easier sliding over effector surface */
- VecCopyf(velocity, state->vel);
- VecMulf(velocity, psys_get_timestep(sim));
- VecAddf(pco, state->co, velocity);
- }
- else
- VECCOPY(pco, state->co);
-
- effector_find_co(sim->scene, pco, NULL, eob, pd, co, NULL, NULL, &face_index);
-
- VecSubf(vec_to_part, state->co, co);
-
- distance = VecLength(vec_to_part);
-
- falloff=effector_falloff(pd,eob->obmat[2],vec_to_part);
-
- strength = pd->f_strength * psys->part->effector_weight[0] * psys->part->effector_weight[pd->forcefield];
-
- if(falloff<=0.0f)
- ; /* don't do anything */
- else if(pd->forcefield==PFIELD_TEXTURE) {
- do_texture_effector(pd->tex, pd->tex_mode, pd->flag&PFIELD_TEX_2D, pd->tex_nabla,
- pd->flag & PFIELD_TEX_OBJECT, (pd->flag & PFIELD_TEX_ROOTCO) ? rootco : state->co, eob->obmat,
- strength, falloff, force_field);
- } else {
- do_physical_effector(sim->scene, eob, state->co, pd->forcefield,strength,distance,
- falloff,0.0,pd->f_damp,eob->obmat[2],vec_to_part,
- state->vel,force_field,pd->flag&PFIELD_PLANAR,ec->rng,pd->f_noise,charge,pa->size);
- }
- }
- if(ec->type & PSYS_EC_PARTICLE){
- ParticleSimulationData esim = {sim->scene, eob, BLI_findlink(&eob->particlesystem,ec->psys_nbr), NULL};
- int totepart, i;
-
- epart = esim.psys->part;
- pd = epart->pd;
- totepart = esim.psys->totpart;
-
- if(totepart <= 0)
- continue;
-
- if(pd && pd->forcefield==PFIELD_HARMONIC){
- /* every particle is mapped to only one harmonic effector particle */
- p= pa_no%esim.psys->totpart;
- totepart= p+1;
- }
- else{
- p=0;
- }
-
- esim.psys->lattice= psys_get_lattice(sim);
-
- for(; p<totepart; p++){
- /* particle skips itself as effector */
- if(esim.psys == psys && p == pa_no) continue;
-
- epa = esim.psys->particles + p;
- estate.time = cfra;
- if(psys_get_particle_state(&esim, p, &estate, 0)){
- VECSUB(vec_to_part, state->co, estate.co);
- distance = VecLength(vec_to_part);
-
- for(i=0, pd = epart->pd; i<2; i++,pd = epart->pd2) {
- if(pd==NULL || pd->forcefield==0) continue;
-
- falloff = effector_falloff(pd, estate.vel, vec_to_part);
-
- strength = pd->f_strength * psys->part->effector_weight[0] * psys->part->effector_weight[pd->forcefield];
-
- if(falloff<=0.0f)
- ; /* don't do anything */
- else
- do_physical_effector(sim->scene, eob, state->co, pd->forcefield,strength,distance,
- falloff,epart->size,pd->f_damp,estate.vel,vec_to_part,
- state->vel,force_field,0, ec->rng, pd->f_noise,charge,pa->size);
- }
- }
- else if(pd && pd->forcefield==PFIELD_HARMONIC && cfra-framestep <= epa->dietime && cfra>epa->dietime){
- /* first step after key release */
- psys_get_particle_state(&esim, p, &estate, 1);
- VECADD(vel, vel, estate.vel);
- /* TODO: add rotation handling here too */
- }
- }
-
- if(esim.psys->lattice){
- end_latt_deform(esim.psys->lattice);
- esim.psys->lattice= NULL;
- }
- }
- }
- }
+ pdEndEffectors(&sim->psys->effectors);
+ sim->psys->effectors = pdInitEffectors(sim->scene, sim->ob, sim->psys, sim->psys->part->effector_weights);
+ precalc_guides(sim, sim->psys->effectors);
}
/************************************************/
@@ -2763,9 +2245,10 @@ static void apply_particle_forces(ParticleSimulationData *sim, int p, float dfra
{
ParticleSettings *part = sim->psys->part;
ParticleData *pa = sim->psys->particles + p;
+ EffectedPoint epoint;
ParticleKey states[5], tkey;
float timestep = psys_get_timestep(sim);
- float force[3],tvel[3],dx[4][3],dv[4][3];
+ float force[3],impulse[3],dx[4][3],dv[4][3];
float dtime=dfra*timestep, time, pa_mass=part->mass, fac, fra=sim->psys->cfra;
int i, steps=1;
@@ -2791,10 +2274,11 @@ static void apply_particle_forces(ParticleSimulationData *sim, int p, float dfra
for(i=0; i<steps; i++){
force[0]=force[1]=force[2]=0.0;
- tvel[0]=tvel[1]=tvel[2]=0.0;
+ impulse[0]=impulse[1]=impulse[2]=0.0;
/* add effectors */
- if(part->type != PART_HAIR)
- do_effectors(sim, p, pa, states+i, states->co, force, tvel, dfra, fra);
+ pd_point_from_particle(sim, pa, states+i, &epoint);
+ if(part->type != PART_HAIR || part->effector_weights->flag & EFF_WEIGHT_DO_HAIR)
+ pdDoEffectors(sim->psys->effectors, sim->colliders, part->effector_weights, &epoint, force, impulse);
/* calculate air-particle interaction */
if(part->dragfac!=0.0f){
@@ -2813,10 +2297,17 @@ static void apply_particle_forces(ParticleSimulationData *sim, int p, float dfra
VecMulf(force,1.0f/pa_mass);
/* add global acceleration (gravitation) */
- VECADD(force,force,part->acc);
+ if(sim->scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY
+ /* normal gravity is too strong for hair so it's disabled by default */
+ && (part->type != PART_HAIR || part->effector_weights->flag & EFF_WEIGHT_DO_HAIR)) {
+ float gravity[3];
+ VECCOPY(gravity, sim->scene->physics_settings.gravity);
+ VecMulf(gravity, part->effector_weights->global_gravity);
+ VECADD(force,force,gravity);
+ }
/* calculate next state */
- VECADD(states[i].vel,states[i].vel,tvel);
+ VECADD(states[i].vel,states[i].vel,impulse);
switch(part->integrator){
case PART_INT_EULER:
@@ -2889,6 +2380,8 @@ static void apply_particle_forces(ParticleSimulationData *sim, int p, float dfra
if(part->dampfac!=0.0)
VecMulf(pa->state.vel,1.0f-part->dampfac);
+ VECCOPY(pa->state.ave, states->ave);
+
/* finally we do guides */
time=(cfra-pa->time)/pa->lifetime;
CLAMP(time,0.0,1.0);
@@ -2898,7 +2391,7 @@ static void apply_particle_forces(ParticleSimulationData *sim, int p, float dfra
tkey.time=pa->state.time;
if(part->type != PART_HAIR) {
- if(do_guide(sim->scene, &tkey, p, time, &sim->psys->effectors)) {
+ if(do_guides(sim->psys->effectors, &tkey, p, time)) {
VECCOPY(pa->state.co,tkey.co);
/* guides don't produce valid velocity */
VECSUB(pa->state.vel,tkey.co,pa->prev_state.co);
@@ -3129,7 +2622,8 @@ void particle_intersect_face(void *userdata, int index, const BVHTreeRay *ray, B
VECCOPY(col->vel,vel);
- col->ob = col->ob_t;
+ col->hit_ob = col->ob;
+ col->hit_md = col->md;
}
}
}
@@ -3146,7 +2640,8 @@ void particle_intersect_face(void *userdata, int index, const BVHTreeRay *ray, B
VECCOPY(col->vel,vel);
- col->ob = col->ob_t;
+ col->hit_ob = col->ob;
+ col->hit_md = col->md;
}
}
}
@@ -3163,13 +2658,11 @@ void particle_intersect_face(void *userdata, int index, const BVHTreeRay *ray, B
/* 1. check for all possible deflectors for closest intersection on particle path */
/* 2. if deflection was found kill the particle or calculate new coordinates */
static void deflect_particle(ParticleSimulationData *sim, int p, float dfra, float cfra){
- Object *ob = NULL, *skip_ob = NULL;
+ Object *ground_ob = NULL;
ParticleSettings *part = sim->psys->part;
- ListBase *lb=&sim->psys->effectors;
- ParticleEffectorCache *ec;
- ParticleKey reaction_state;
- ParticleCollision col;
ParticleData *pa = sim->psys->particles + p;
+ ParticleCollision col;
+ ColliderCache *coll;
BVHTreeRayHit hit;
float ray_dir[3], zerovec[3]={0.0,0.0,0.0};
float radius = ((part->flag & PART_SIZE_DEFL)?pa->size:0.0f), boid_z = 0.0f;
@@ -3185,11 +2678,11 @@ static void deflect_particle(ParticleSimulationData *sim, int p, float dfra, flo
BoidParticle *bpa = pa->boid;
radius = pa->size;
boid_z = pa->state.co[2];
- skip_ob = bpa->ground;
+ ground_ob = bpa->ground;
}
/* 10 iterations to catch multiple deflections */
- if(lb->first) while(deflections < max_deflections){
+ if(sim->colliders) while(deflections < max_deflections){
/* 1. */
VECSUB(ray_dir, col.co2, col.co1);
@@ -3201,32 +2694,25 @@ static void deflect_particle(ParticleSimulationData *sim, int p, float dfra, flo
if(hit.dist == 0.0f)
hit.dist = col.ray_len = 0.000001f;
- for(ec=lb->first; ec; ec=ec->next){
- if(ec->type & PSYS_EC_DEFLECT){
- ob= ec->ob;
-
- /* for boids: don't check with current ground object */
- if(ob==skip_ob)
- continue;
-
- /* particles should not collide with emitter at birth */
- if(ob==sim->ob && pa->time < cfra && pa->time >= sim->psys->cfra)
- continue;
+ for(coll = sim->colliders->first; coll; coll=coll->next){
+ /* for boids: don't check with current ground object */
+ if(coll->ob == ground_ob)
+ continue;
- if(part->type!=PART_HAIR)
- where_is_object_time(sim->scene, sim->ob, cfra);
+ /* particles should not collide with emitter at birth */
+ if(coll->ob == sim->ob && pa->time < cfra && pa->time >= sim->psys->cfra)
+ continue;
- col.md = ( CollisionModifierData * ) ( modifiers_findByType ( ec->ob, eModifierType_Collision ) );
- col.ob_t = ob;
+ col.ob = coll->ob;
+ col.md = coll->collmd;
- if(col.md && col.md->bvhtree)
- BLI_bvhtree_ray_cast(col.md->bvhtree, col.co1, ray_dir, radius, &hit, particle_intersect_face, &col);
- }
+ if(col.md && col.md->bvhtree)
+ BLI_bvhtree_ray_cast(col.md->bvhtree, col.co1, ray_dir, radius, &hit, particle_intersect_face, &col);
}
/* 2. */
if(hit.index>=0) {
- PartDeflect *pd = col.ob->pd;
+ PartDeflect *pd = col.hit_ob->pd;
int through = (BLI_frand() < pd->pdef_perm) ? 1 : 0;
float co[3]; /* point of collision */
float vec[3]; /* movement through collision */
@@ -3253,9 +2739,6 @@ static void deflect_particle(ParticleSimulationData *sim, int p, float dfra, flo
/* particle is dead so we don't need to calculate further */
deflections=max_deflections;
-
- /* store for reactors */
- copy_particle_key(&reaction_state, &pa->state, 0);
}
else {
float nor_vec[3], tan_vec[3], tan_vel[3], vel[3];
@@ -3416,7 +2899,7 @@ static void psys_update_path_cache(ParticleSimulationData *sim, float cfra)
if((part->type==PART_HAIR || psys->flag&PSYS_KEYED || psys->pointcache->flag & PTCACHE_BAKED)==0)
skip = 1; /* only hair, keyed and baked stuff can have paths */
- else if(part->ren_as != PART_DRAW_PATH)
+ else if(part->ren_as != PART_DRAW_PATH && !(part->type==PART_HAIR && ELEM(part->ren_as, PART_DRAW_OB, PART_DRAW_GR)))
skip = 1; /* particle visualization must be set as path */
else if(!psys->renderdata) {
if(part->draw_as != PART_DRAW_REND)
@@ -3555,8 +3038,11 @@ static void do_hair_dynamics(ParticleSimulationData *sim)
psys->hair_out_dm->release(psys->hair_out_dm);
psys->clmd->point_cache = psys->pointcache;
+ psys->clmd->sim_parms->effector_weights = psys->part->effector_weights;
psys->hair_out_dm = clothModifier_do(psys->clmd, sim->scene, sim->ob, dm, 0, 0);
+
+ psys->clmd->sim_parms->effector_weights = NULL;
}
static void hair_step(ParticleSimulationData *sim, float cfra)
{
@@ -3586,7 +3072,7 @@ static void hair_step(ParticleSimulationData *sim, float cfra)
if(psys->part->type==PART_HAIR && psys->flag & PSYS_HAIR_DYNAMICS)
do_hair_dynamics(sim);
- psys_update_effectors(sim, cfra, 1);
+ psys_update_effectors(sim);
psys_update_path_cache(sim, cfra);
@@ -3653,7 +3139,7 @@ static void dynamics_step(ParticleSimulationData *sim, float cfra)
BoidBrainData bbd;
PARTICLE_P;
float timestep;
- int totpart, check_collisions = 0;
+ int totpart;
/* current time */
float ctime, ipotime; // XXX old animation system
/* frame & time changes */
@@ -3665,7 +3151,7 @@ static void dynamics_step(ParticleSimulationData *sim, float cfra)
totpart=psys->totpart;
- timestep=psys_get_timestep(sim);
+ timestep = psys_get_timestep(sim);
dtime= dfra*timestep;
ctime= cfra*timestep;
ipotime= cfra; // XXX old animation system
@@ -3703,15 +3189,6 @@ static void dynamics_step(ParticleSimulationData *sim, float cfra)
}
else{
pa->loop = 0;
- if(cfra <= pa->time)
- pa->alive = PARS_UNBORN;
- /* without dynamics the state is allways known so no need to kill */
- else if(ELEM(part->phystype, PART_PHYS_NO, PART_PHYS_KEYED)){
- if(cfra < pa->dietime)
- pa->alive = PARS_ALIVE;
- }
- else
- pa->alive = PARS_KILLED;
}
}
@@ -3721,7 +3198,10 @@ static void dynamics_step(ParticleSimulationData *sim, float cfra)
else{
BLI_srandom(31415926 + (int)cfra + psys->seed);
- psys_update_effectors(sim, cfra, 1);
+ psys_update_effectors(sim);
+
+ if(part->type != PART_HAIR)
+ sim->colliders = get_collider_cache(sim->scene, NULL);
if(part->phystype==PART_PHYS_BOIDS){
ParticleTarget *pt = psys->targets.first;
@@ -3731,13 +3211,13 @@ static void dynamics_step(ParticleSimulationData *sim, float cfra)
bbd.dfra = dfra;
bbd.timestep = timestep;
- update_particle_tree(psys);
+ psys_update_particle_tree(psys, cfra);
boids_precalc_rules(part, cfra);
for(; pt; pt=pt->next) {
if(pt->ob)
- update_particle_tree(BLI_findlink(&pt->ob->particlesystem, pt->psys-1));
+ psys_update_particle_tree(BLI_findlink(&pt->ob->particlesystem, pt->psys-1), cfra);
}
}
@@ -3798,7 +3278,7 @@ static void dynamics_step(ParticleSimulationData *sim, float cfra)
apply_particle_forces(sim, p, pa_dfra, cfra);
/* deflection */
- if(check_collisions)
+ if(sim->colliders)
deflect_particle(sim, p, pa_dfra, cfra);
/* rotations */
@@ -3812,7 +3292,8 @@ static void dynamics_step(ParticleSimulationData *sim, float cfra)
boid_body(&bbd, pa);
/* deflection */
- deflect_particle(sim, p, pa_dfra, cfra);
+ if(sim->colliders)
+ deflect_particle(sim, p, pa_dfra, cfra);
}
break;
}
@@ -3837,9 +3318,9 @@ static void dynamics_step(ParticleSimulationData *sim, float cfra)
//push_reaction(ob,psys,p,PART_EVENT_NEAR,&pa->state);
}
}
+
+ free_collider_cache(&sim->colliders);
}
- if(psys->reactevents.first)
- BLI_freelistN(&psys->reactevents);
if(tree)
BLI_kdtree_free(tree);
@@ -3860,7 +3341,7 @@ static void cached_step(ParticleSimulationData *sim, float cfra)
if(part->from!=PART_FROM_PARTICLE)
vg_size= psys_cache_vgroup(sim->psmd->dm,psys,PSYS_VG_SIZE);
- psys_update_effectors(sim, cfra, 1);
+ psys_update_effectors(sim);
disp= (float)get_current_display_percentage(psys)/100.0f;
@@ -4195,6 +3676,13 @@ static void system_step(ParticleSimulationData *sim, float cfra)
else if(framenr > endframe) {
framenr= endframe;
}
+
+ if(framenr == startframe) {
+ BKE_ptcache_id_reset(sim->scene, &pid, PTCACHE_RESET_OUTDATED);
+ cache->simframe= framenr;
+ cache->flag |= PTCACHE_SIMULATION_VALID;
+ cache->flag &= ~PTCACHE_REDO_NEEDED;
+ }
}
/* verify if we need to reallocate */
@@ -4226,7 +3714,7 @@ static void system_step(ParticleSimulationData *sim, float cfra)
if(alloc) {
realloc_particles(sim, totpart);
- if(usecache && !only_children_changed) {
+ if(oldtotpart && usecache && !only_children_changed) {
BKE_ptcache_id_clear(&pid, PTCACHE_CLEAR_ALL, 0);
BKE_ptcache_id_from_particles(&pid, sim->ob, psys);
}
@@ -4286,7 +3774,7 @@ static void system_step(ParticleSimulationData *sim, float cfra)
pa->alive = PARS_ALIVE;
}
}
- else if(sim->ob->id.lib || (cache->flag & PTCACHE_BAKED)) {
+ else if(cfra != startframe && (sim->ob->id.lib || (cache->flag & PTCACHE_BAKED))) {
psys_reset(psys, PSYS_RESET_CACHE_MISS);
psys->cfra=cfra;
psys->recalc = 0;
@@ -4383,7 +3871,7 @@ static int hair_needs_recalc(ParticleSystem *psys)
/* main particle update call, checks that things are ok on the large scale before actual particle calculations */
void particle_system_update(Scene *scene, Object *ob, ParticleSystem *psys)
{
- ParticleSimulationData sim = {scene, ob, psys, NULL};
+ ParticleSimulationData sim = {scene, ob, psys, NULL, NULL};
float cfra;
/* drawdata is outdated after ANY change */
diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c
index 3915a6901a0..bffe4566f74 100644
--- a/source/blender/blenkernel/intern/pointcache.c
+++ b/source/blender/blenkernel/intern/pointcache.c
@@ -292,6 +292,9 @@ static void ptcache_interpolate_particle(int index, void *psys_v, void **data, f
else
BKE_ptcache_make_particle_key(keys+2, 0, data, cfra2);
+ if(cfra > pa->time)
+ cfra1 = MAX2(cfra1, pa->time);
+
dfra = cfra2 - cfra1;
VecMulf(keys[1].vel, dfra / frs_sec);
@@ -2266,6 +2269,7 @@ void BKE_ptcache_make_cache(PTCacheBaker* baker)
}
}
}
+ BLI_freelistN(&pidlist2);
}
if(bake || cache->flag & PTCACHE_REDO_NEEDED)
diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c
index b3f00f884bc..4f72ca96f5f 100644
--- a/source/blender/blenkernel/intern/scene.c
+++ b/source/blender/blenkernel/intern/scene.c
@@ -400,6 +400,10 @@ Scene *add_scene(char *name)
sce->toolsettings->proportional_size = 1.0f;
+ sce->physics_settings.gravity[0] = 0.0f;
+ sce->physics_settings.gravity[1] = 0.0f;
+ sce->physics_settings.gravity[2] = -9.81f;
+ sce->physics_settings.flag = PHYS_GLOBAL_GRAVITY;
sce->unit.scale_length = 1.0f;
diff --git a/source/blender/blenkernel/intern/smoke.c b/source/blender/blenkernel/intern/smoke.c
index 62463b3d555..4f7a8cda81b 100644
--- a/source/blender/blenkernel/intern/smoke.c
+++ b/source/blender/blenkernel/intern/smoke.c
@@ -832,8 +832,7 @@ static void smoke_calc_domain(Scene *scene, Object *ob, SmokeModifierData *smd)
size_t i = 0;
size_t index = 0;
int badcell = 0;
- if(pa->alive == PARS_KILLED) continue;
- else if(pa->alive == PARS_UNBORN && (part->flag & PART_UNBORN)==0) continue;
+ if(pa->alive == PARS_UNBORN && (part->flag & PART_UNBORN)==0) continue;
else if(pa->alive == PARS_DEAD && (part->flag & PART_DIED)==0) continue;
else if(pa->flag & (PARS_UNEXIST+PARS_NO_DISP)) continue;
// VECCOPY(pos, pa->state.co);
diff --git a/source/blender/blenkernel/intern/softbody.c b/source/blender/blenkernel/intern/softbody.c
index 450a64d72eb..089f2a5ebfb 100644
--- a/source/blender/blenkernel/intern/softbody.c
+++ b/source/blender/blenkernel/intern/softbody.c
@@ -1550,11 +1550,14 @@ static void _scan_for_ext_spring_forces(Scene *scene, Object *ob, float timenow,
float f,windfactor = 0.25f;
/*see if we have wind*/
if(do_effector) {
+ EffectedPoint epoint;
float speed[3]={0.0f,0.0f,0.0f};
float pos[3];
VecMidf(pos, sb->bpoint[bs->v1].pos , sb->bpoint[bs->v2].pos);
VecMidf(vel, sb->bpoint[bs->v1].vec , sb->bpoint[bs->v2].vec);
- pdDoEffectors(scene, do_effector, pos, force, speed, (float)scene->r.cfra, 0.0f, PE_WIND_AS_SPEED);
+ pd_point_from_soft(scene, pos, vel, -1, &epoint);
+ pdDoEffectors(do_effector, NULL, sb->effector_weights, &epoint, force, speed);
+
VecMulf(speed,windfactor);
VecAddf(vel,vel,speed);
}
@@ -1589,14 +1592,13 @@ static void _scan_for_ext_spring_forces(Scene *scene, Object *ob, float timenow,
static void scan_for_ext_spring_forces(Scene *scene, Object *ob, float timenow)
{
SoftBody *sb = ob->soft;
- ListBase *do_effector= NULL;
+ ListBase *do_effector = NULL;
- do_effector= pdInitEffectors(scene, ob,NULL);
+ do_effector = pdInitEffectors(scene, ob, NULL, sb->effector_weights);
if (sb){
_scan_for_ext_spring_forces(scene, ob, timenow, 0, sb->totspring, do_effector);
}
- if(do_effector)
- pdEndEffectors(do_effector);
+ pdEndEffectors(&do_effector);
}
static void *exec_scan_for_ext_spring_forces(void *data)
@@ -1614,7 +1616,7 @@ static void sb_sfesf_threads_run(Scene *scene, struct Object *ob, float timenow,
int i, totthread,left,dec;
int lowsprings =100; /* wild guess .. may increase with better thread management 'above' or even be UI option sb->spawn_cf_threads_nopts */
- do_effector= pdInitEffectors(scene, ob,NULL);
+ do_effector= pdInitEffectors(scene, ob, NULL, ob->soft->effector_weights);
/* figure the number of threads while preventing pretty pointless threading overhead */
if(scene->r.mode & R_FIXED_THREADS)
@@ -1661,9 +1663,8 @@ static void sb_sfesf_threads_run(Scene *scene, struct Object *ob, float timenow,
exec_scan_for_ext_spring_forces(&sb_threads[0]);
/* clean up */
MEM_freeN(sb_threads);
-
- if(do_effector)
- pdEndEffectors(do_effector);
+
+ pdEndEffectors(&do_effector);
}
@@ -2226,19 +2227,22 @@ static int _softbody_calc_forces_slice_in_a_thread(Scene *scene, Object *ob, flo
/* done goal stuff */
/* gravitation */
- if (sb){
- float gravity = sb->grav * sb_grav_force_scale(ob);
- bp->force[2]-= gravity*bp->mass; /* individual mass of node here */
+ if (sb && scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY){
+ float gravity[3];
+ VECCOPY(gravity, scene->physics_settings.gravity);
+ VecMulf(gravity, sb_grav_force_scale(ob)*bp->mass*sb->effector_weights->global_gravity); /* individual mass of node here */
+ VecAddf(bp->force, bp->force, gravity);
}
/* particle field & vortex */
if(do_effector) {
+ EffectedPoint epoint;
float kd;
float force[3]= {0.0f, 0.0f, 0.0f};
float speed[3]= {0.0f, 0.0f, 0.0f};
float eval_sb_fric_force_scale = sb_fric_force_scale(ob); /* just for calling function once */
-
- pdDoEffectors(scene, do_effector, bp->pos, force, speed, (float)scene->r.cfra, 0.0f, PE_WIND_AS_SPEED);
+ pd_point_from_soft(scene, bp->pos, bp->vec, sb->bpoint-bp, &epoint);
+ pdDoEffectors(do_effector, NULL, sb->effector_weights, &epoint, force, speed);
/* apply forcefield*/
VecMulf(force,fieldfactor* eval_sb_fric_force_scale);
@@ -2341,6 +2345,7 @@ static void sb_cf_threads_run(Scene *scene, Object *ob, float forcetime, float t
left = totpoint;
dec = totpoint/totthread +1;
for(i=0; i<totthread; i++) {
+ sb_threads[i].scene = scene;
sb_threads[i].ob = ob;
sb_threads[i].forcetime = forcetime;
sb_threads[i].timenow = timenow;
@@ -2381,7 +2386,7 @@ static void softbody_calc_forcesEx(Scene *scene, Object *ob, float forcetime, fl
*/
SoftBody *sb= ob->soft; /* is supposed to be there */
BodyPoint *bproot;
- ListBase *do_effector;
+ ListBase *do_effector = NULL;
float iks, gravity;
float fieldfactor = -1.0f, windfactor = 0.25;
int do_deflector,do_selfcollision,do_springcollision,do_aero;
@@ -2401,7 +2406,7 @@ static void softbody_calc_forcesEx(Scene *scene, Object *ob, float forcetime, fl
sb_sfesf_threads_run(scene, ob, timenow,sb->totspring,NULL);
/* after spring scan because it uses Effoctors too */
- do_effector= pdInitEffectors(scene, ob,NULL);
+ do_effector= pdInitEffectors(scene, ob, NULL, sb->effector_weights);
if (do_deflector) {
float defforce[3];
@@ -2414,7 +2419,7 @@ static void softbody_calc_forcesEx(Scene *scene, Object *ob, float forcetime, fl
if (ob->softflag & OB_SB_FACECOLL) scan_for_ext_face_forces(ob,timenow);
/* finish matrix and solve */
- if(do_effector) pdEndEffectors(do_effector);
+ pdEndEffectors(&do_effector);
}
@@ -2443,8 +2448,8 @@ static void softbody_calc_forces(Scene *scene, Object *ob, float forcetime, floa
BodyPoint *bp;
BodyPoint *bproot;
BodySpring *bs;
- ListBase *do_effector;
- float iks, ks, kd, gravity;
+ ListBase *do_effector = NULL;
+ float iks, ks, kd, gravity[3] = {0.0f,0.0f,0.0f};
float fieldfactor = -1.0f, windfactor = 0.25f;
float tune = sb->ballstiff;
int a, b, do_deflector,do_selfcollision,do_springcollision,do_aero;
@@ -2460,7 +2465,10 @@ static void softbody_calc_forces(Scene *scene, Object *ob, float forcetime, floa
*/
- gravity = sb->grav * sb_grav_force_scale(ob);
+ if (scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY){
+ VECCOPY(gravity, scene->physics_settings.gravity);
+ VecMulf(gravity, sb_grav_force_scale(ob)*sb->effector_weights->global_gravity);
+ }
/* check conditions for various options */
do_deflector= query_external_colliders(scene, ob);
@@ -2473,7 +2481,7 @@ static void softbody_calc_forces(Scene *scene, Object *ob, float forcetime, floa
if (do_springcollision || do_aero) scan_for_ext_spring_forces(scene, ob, timenow);
/* after spring scan because it uses Effoctors too */
- do_effector= pdInitEffectors(scene, ob,NULL);
+ do_effector= pdInitEffectors(scene, ob, NULL, ob->soft->effector_weights);
if (do_deflector) {
float defforce[3];
@@ -2631,16 +2639,17 @@ static void softbody_calc_forces(Scene *scene, Object *ob, float forcetime, floa
/* gravitation */
- bp->force[2]-= gravity*bp->mass; /* individual mass of node here */
+ VECADDFAC(bp->force, bp->force, gravity, bp->mass); /* individual mass of node here */
/* particle field & vortex */
if(do_effector) {
+ EffectedPoint epoint;
float force[3]= {0.0f, 0.0f, 0.0f};
float speed[3]= {0.0f, 0.0f, 0.0f};
float eval_sb_fric_force_scale = sb_fric_force_scale(ob); /* just for calling function once */
-
- pdDoEffectors(scene, do_effector, bp->pos, force, speed, (float)scene->r.cfra, 0.0f, PE_WIND_AS_SPEED);
+ pd_point_from_soft(scene, bp->pos, bp->vec, sb->bpoint-bp, &epoint);
+ pdDoEffectors(do_effector, NULL, sb->effector_weights, &epoint, force, speed);
/* apply forcefield*/
VecMulf(force,fieldfactor* eval_sb_fric_force_scale);
@@ -2819,7 +2828,7 @@ static void softbody_calc_forces(Scene *scene, Object *ob, float forcetime, floa
}
/* cleanup */
#endif
- if(do_effector) pdEndEffectors(do_effector);
+ pdEndEffectors(&do_effector);
}
}
@@ -3635,6 +3644,9 @@ SoftBody *sbNew(Scene *scene)
sb->pointcache = BKE_ptcache_add(&sb->ptcaches);
+ if(!sb->effector_weights)
+ sb->effector_weights = BKE_add_effector_weights(NULL);
+
return sb;
}
@@ -3644,6 +3656,8 @@ void sbFree(SoftBody *sb)
free_softbody_intern(sb);
BKE_ptcache_free_list(&sb->ptcaches);
sb->pointcache = NULL;
+ if(sb->effector_weights)
+ MEM_freeN(sb->effector_weights);
MEM_freeN(sb);
}
@@ -3684,6 +3698,9 @@ static void softbody_update_positions(Object *ob, SoftBody *sb, float (*vertexCo
BodyPoint *bp;
int a;
+ if(!sb || !sb->bpoint)
+ return;
+
for(a=0,bp=sb->bpoint; a<numVerts; a++, bp++) {
/* store where goals are now */
VECCOPY(bp->origS, bp->origE);