Revision: 16507
          
http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-blender&revision=16507
Author:   jhk
Date:     2008-09-13 20:09:41 +0200 (Sat, 13 Sep 2008)

Log Message:
-----------
Particle collisions upgrade:

- Particle now use the deflector objects collision modifier data to collide 
with deflectors and as a result can now use the velocity of the colliding 
object for more realistic collisions.
- Dynamic rotations are also quite a bit more realistic and are related to the 
friction setting of the deflector (to get any dynamic rotations there has to be 
some friction). This is largely due to the separate handling of rolling 
friction (approximated to be 1% of normal sliding friction).
- Collisions should be a bit faster on complex deflectors due to the tree 
structure used by the collision modifier.
- Collision should also generally be a bit more accurate.

To be noted: Only the average velocity of individual deflector faces is used, 
so collisions with rotating or deforming objects can't be handled accurately - 
this would require much more complex calculations. Subdividing the deflector 
object surface to smaller faces can help with this as the individual face 
velocities become more linear.

Modified Paths:
--------------
    trunk/blender/source/blender/blenkernel/intern/effect.c
    trunk/blender/source/blender/blenkernel/intern/particle_system.c
    trunk/blender/source/blender/blenkernel/intern/shrinkwrap.c
    trunk/blender/source/blender/blenlib/BLI_kdopbvh.h
    trunk/blender/source/blender/blenlib/intern/BLI_kdopbvh.c
    trunk/blender/source/blender/makesdna/DNA_particle_types.h

Modified: trunk/blender/source/blender/blenkernel/intern/effect.c
===================================================================
--- trunk/blender/source/blender/blenkernel/intern/effect.c     2008-09-13 
16:03:11 UTC (rev 16506)
+++ trunk/blender/source/blender/blenkernel/intern/effect.c     2008-09-13 
18:09:41 UTC (rev 16507)
@@ -267,7 +267,7 @@
                        hit.dist = len + FLT_EPSILON;
                        
                        // check if the way is blocked
-                       if(BLI_bvhtree_ray_cast(collmd->bvhtree, co, norm, 
&hit, eff_tri_ray_hit, NULL)>=0)
+                       if(BLI_bvhtree_ray_cast(collmd->bvhtree, co, norm, 
0.0f, &hit, eff_tri_ray_hit, NULL)>=0)
                        {
                                // visibility is only between 0 and 1, 
calculated from 1-absorption
                                visibility *= MAX2(0.0, MIN2(1.0, 
(1.0-((float)collmd->absorption)*0.01)));

Modified: trunk/blender/source/blender/blenkernel/intern/particle_system.c
===================================================================
--- trunk/blender/source/blender/blenkernel/intern/particle_system.c    
2008-09-13 16:03:11 UTC (rev 16506)
+++ trunk/blender/source/blender/blenkernel/intern/particle_system.c    
2008-09-13 18:09:41 UTC (rev 16507)
@@ -53,12 +53,14 @@
 #include "BLI_arithb.h"
 #include "BLI_blenlib.h"
 #include "BLI_kdtree.h"
+#include "BLI_kdopbvh.h"
 #include "BLI_linklist.h"
 #include "BLI_threads.h"
 
 #include "BKE_anim.h"
 #include "BKE_bad_level_calls.h"
 #include "BKE_cdderivedmesh.h"
+#include "BKE_collision.h"
 #include "BKE_displist.h"
 #include "BKE_effect.h"
 #include "BKE_particle.h"
@@ -2432,7 +2434,7 @@
        }
 }
 
-static void precalc_effectors(Object *ob, ParticleSystem *psys, 
ParticleSystemModifierData *psmd)
+static void precalc_effectors(Object *ob, ParticleSystem *psys, 
ParticleSystemModifierData *psmd, float cfra)
 {
        ListBase *lb=&psys->effectors;
        ParticleEffectorCache *ec;
@@ -2472,96 +2474,20 @@
                                }
                        }
                }
-               else if(ec->type==PSYS_EC_DEFLECT){
-                       DerivedMesh *dm;
-                       MFace *mface=0;
-                       MVert *mvert=0;
-                       int i, totface;
-                       float v1[3],v2[3],v3[3],v4[4], *min, *max;
-
-                       if(ob==ec->ob)
-                               dm=psmd->dm;
-                       else{
-                               psys_disable_all(ec->ob);
-
-                               dm=mesh_get_derived_final(ec->ob,0);
-                               
-                               psys_enable_all(ec->ob);
-                       }
-
-                       if(dm){
-                               totvert=dm->getNumVerts(dm);
-                               totface=dm->getNumFaces(dm);
-                               mface=dm->getFaceDataArray(dm,CD_MFACE);
-                               mvert=dm->getVertDataArray(dm,CD_MVERT);
-
-                               /* Decide which is faster to calculate by the 
amount of*/
-                               /* matrice multiplications needed to convert 
spaces. */
-                               /* With size deflect we have to convert allways 
because */
-                               /* the object can be scaled nonuniformly 
(sphere->ellipsoid). */
-                               if(totvert<2*psys->totpart || part->flag & 
PART_SIZE_DEFL){
-                                       
co=ec->vert_cos=MEM_callocN(sizeof(float)*3*totvert,"Particle deflection vert 
cos");
-                                       /* convert vert coordinates to global 
(particle) coordinates */
-                                       for(i=0; i<totvert; i++, co+=3){
-                                               VECCOPY(co,mvert[i].co);
-                                               Mat4MulVecfl(ec->ob->obmat,co);
-                                       }
-                                       co=ec->vert_cos;
-                               }
-                               else
-                                       ec->vert_cos=0;
-
-                               INIT_MINMAX(ec->ob_minmax,ec->ob_minmax+3);
-
-                               
min=ec->face_minmax=MEM_callocN(sizeof(float)*6*totface,"Particle deflection 
face minmax");
-                               max=min+3;
-
-                               for(i=0; i<totface; i++,mface++,min+=6,max+=6){
-                                       if(co){
-                                               VECCOPY(v1,co+3*mface->v1);
-                                               VECCOPY(v2,co+3*mface->v2);
-                                               VECCOPY(v3,co+3*mface->v3);
-                                       }
-                                       else{
-                                               VECCOPY(v1,mvert[mface->v1].co);
-                                               VECCOPY(v2,mvert[mface->v2].co);
-                                               VECCOPY(v3,mvert[mface->v3].co);
-                                       }
-                                       INIT_MINMAX(min,max);
-                                       DO_MINMAX(v1,min,max);
-                                       DO_MINMAX(v2,min,max);
-                                       DO_MINMAX(v3,min,max);
-
-                                       if(mface->v4){
-                                               if(co){
-                                                       
VECCOPY(v4,co+3*mface->v4);
-                                               }
-                                               else{
-                                                       
VECCOPY(v4,mvert[mface->v4].co);
-                                               }
-                                               DO_MINMAX(v4,min,max);
-                                       }
-
-                                       
DO_MINMAX(min,ec->ob_minmax,ec->ob_minmax+3);
-                                       
DO_MINMAX(max,ec->ob_minmax,ec->ob_minmax+3);
-                               }
-                       }
-                       else
-                               ec->face_minmax=0;
-               }
                else if(ec->type==PSYS_EC_PARTICLE){
+                       Object *eob = ec->ob;
+                       ParticleSystem *epsys = 
BLI_findlink(&eob->particlesystem,ec->psys_nbr);
+                       ParticleSettings *epart = epsys->part;
+                       ParticleData *epa = epsys->particles;
+                       int totepart = epsys->totpart;
+
                        if(psys->part->phystype==PART_PHYS_BOIDS){
-                               Object *eob = ec->ob;
-                               ParticleSystem *epsys;
-                               ParticleSettings *epart;
                                ParticleData *epa;
                                ParticleKey state;
                                PartDeflect *pd;
-                               int totepart, p;
-                               epsys= 
BLI_findlink(&eob->particlesystem,ec->psys_nbr);
-                               epart= epsys->part;
+                               int p;
+                               
                                pd= epart->pd;
-                               totepart= epsys->totpart;
                                if(pd->forcefield==PFIELD_FORCE && totepart){
                                        KDTree *tree;
 
@@ -2576,6 +2502,11 @@
                                }
                        }
                }
+               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);
+               }
        }
 }
 
@@ -3024,37 +2955,124 @@
        }
        return intersect;
 }
+
+/* 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;
+       float nor[3]; // normal at collision point
+       float vel[3]; // velocity of collision point
+       float co1[3], co2[3]; // ray start and end points
+       float ray_len; // original length of co2-co1, needed for collision time 
evaluation
+       float t;        // time of previous collision, needed for substracting 
face velocity
+}
+ParticleCollision;
+
+static void particle_intersect_face(void *userdata, int index, const 
BVHTreeRay *ray, BVHTreeRayHit *hit)
+{
+       ParticleCollision *col = (ParticleCollision *) userdata;
+       MFace *face = col->md->mfaces + index;
+       MVert *x = col->md->x;
+       MVert *v = col->md->current_v;
+       float dir[3], vel[3], co1[3], co2[3], uv[2], ipoint[3], temp[3], dist, 
t, threshold;
+       int ret=0;
+
+       float *t0, *t1, *t2, *t3;
+       t0 = x[ face->v1 ].co;
+       t1 = x[ face->v2 ].co;
+       t2 = x[ face->v3 ].co;
+       t3 = face->v4 ? x[ face->v4].co : NULL;
+
+       /* calculate average velocity of face */
+       VECCOPY(vel, v[ face->v1 ].co);
+       VECADD(vel, vel, v[ face->v2 ].co);
+       VECADD(vel, vel, v[ face->v3 ].co);
+       VecMulf(vel, 0.33334f);
+
+       /* substract face velocity, in other words convert to 
+          a coordinate system where only the particle moves */
+       VECADDFAC(co1, col->co1, vel, -col->t);
+       VECSUB(co2, col->co2, vel);
+
+       do
+       {       
+               if(ray->radius == 0.0f) {
+                       if(LineIntersectsTriangle(co1, co2, t0, t1, t2, &t, 
uv)) {
+                               if(t >= 0.0f && t < hit->dist/col->ray_len) {
+                                       hit->dist = col->ray_len * t;
+                                       hit->index = index;
+
+                                       /* calculate normal that's facing the 
particle */
+                                       CalcNormFloat(t0, t1, t2, col->nor);
+                                       VECSUB(temp, co2, co1);
+                                       if(Inpf(col->nor, temp) > 0.0f)
+                                               VecMulf(col->nor, -1.0f);
+
+                                       VECCOPY(col->vel,vel);
+
+                                       col->ob = col->ob_t;
+                               }
+                       }
+               }
+               else {
+                       if(SweepingSphereIntersectsTriangleUV(co1, co2, 
ray->radius, t0, t1, t2, &t, ipoint)) {
+                               if(t >=0.0f && t < hit->dist/col->ray_len) {
+                                       hit->dist = col->ray_len * t;
+                                       hit->index = index;
+
+                                       VecLerpf(temp, co1, co2, t);
+                                       
+                                       VECSUB(col->nor, temp, ipoint);
+                                       Normalize(col->nor);
+
+                                       VECCOPY(col->vel,vel);
+
+                                       col->ob = col->ob_t;
+                               }
+                       }
+               }
+
+               t1 = t2;
+               t2 = t3;
+               t3 = NULL;
+
+       } while(t2);
+}
 /* particle - mesh collision code */
 /* in addition to basic point to surface collisions handles friction & 
damping,*/
 /* angular momentum <-> linear momentum and swept sphere - mesh collisions */
 /* 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(Object *pob, ParticleSystemModifierData *psmd, 
ParticleSystem *psys, ParticleSettings *part, ParticleData *pa, int p, float 
dfra, float cfra, ParticleKey *state, int *pa_die){
-       Object *ob, *min_ob;
-       MFace *mface;
-       MVert *mvert;
-       DerivedMesh *dm;
+static void deflect_particle(Object *pob, ParticleSystemModifierData *psmd, 
ParticleSystem *psys, ParticleSettings *part, ParticleData *pa, int p, float 
timestep, float dfra, float cfra, ParticleKey *state){
+       Object *ob;
        ListBase *lb=&psys->effectors;
        ParticleEffectorCache *ec;
-       ParticleKey cstate;
-       float imat[4][4];
-       float 
co1[3],co2[3],def_loc[3],def_nor[3],unit_nor[3],def_tan[3],dvec[3],def_vel[3],dave[3],dvel[3];
-       float pa_minmax[6];
-       float min_w[4], zerovec[3]={0.0,0.0,0.0}, ipoint[3];
-       float min_d,dotprod,damp,frict,o_len,d_len,radius=-1.0f;
-       int min_face=0, intersect=1, through=0;
-       short deflections=0, global=0;
+       ParticleKey reaction_state;
+       ParticleCollision col;
+       CollisionModifierData *collmd;
+       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);
+       int deflections=0, max_deflections=10;
 
-       VECCOPY(def_loc,pa->state.co);
-       VECCOPY(def_vel,pa->state.vel);
+       VECCOPY(col.co1, pa->state.co);
+       VECCOPY(col.co2, state->co);
+       col.t = 0.0f;
 
        /* 10 iterations to catch multiple deflections */
-       if(lb->first) while(deflections<10){
-               intersect=0;
-               global=0;
-               min_d=20000.0;
-               min_ob=NULL;
+       if(lb->first) while(deflections < max_deflections){
                /* 1. */
+
+               VECSUB(ray_dir, col.co2, col.co1);
+               hit.index = -1;
+               hit.dist = col.ray_len = VecLength(ray_dir);
+
+               /* even if particle is stationary we want to check for moving 
colliders */
+               /* if hit.dist is zero the bvhtree_ray_cast will just ignore 
everything */
+               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;
@@ -3062,263 +3080,165 @@
                                if(part->type!=PART_HAIR)
                                        where_is_object_time(ob,cfra);
 
-                               if(ob==pob){
-                                       dm=psmd->dm;
-                                       /* particles should not collide with 
emitter at birth */
-                                       if(pa->time < cfra && pa->time >= 
psys->cfra)
-                                               continue;
-                               }
-                               else
-                                       dm=0;
-                               
-                               VECCOPY(co1,def_loc);
-                               VECCOPY(co2,state->co);
+                               /* particles should not collide with emitter at 
birth */
+                               if(ob==pob && pa->time < cfra && pa->time >= 
psys->cfra)
+                                       continue;
 
-                               if(ec->vert_cos==0){
-                                       /* convert particle coordinates to 
object coordinates */
-                                       Mat4Invert(imat,ob->obmat);
-                                       Mat4MulVecfl(imat,co1);
-                                       Mat4MulVecfl(imat,co2);
-                               }
+                               col.md = ( CollisionModifierData * ) ( 
modifiers_findByType ( ec->ob, eModifierType_Collision ) );

@@ Diff output truncated at 10240 characters. @@

_______________________________________________
Bf-blender-cvs mailing list
[email protected]
http://lists.blender.org/mailman/listinfo/bf-blender-cvs

Reply via email to