[tuhopuu-devel] particle deflection experiments.....

Leon Turner tuhopuu-devel@blender.org
Sun, 8 Feb 2004 15:05:42 +0000 (GMT)


--0-392819529-1076252742=:54885
Content-Type: text/plain; charset=iso-8859-1
Content-Transfer-Encoding: 8bit
Content-Id: 
Content-Disposition: inline

hi,

As requested by Theeth in the blender.org forums ,
here's the patch for the particle deflectors I've been
playing with in Tuhopuu.

This is my first attempt at coding in Blender (and C
really!) so please let me know all the things I need
to fix / change!!

I've attached two text files, one is an explanation /
summary, and the other is the patch file.

Cheers

Leon


	
	
		
___________________________________________________________
BT Yahoo! Broadband - Free modem offer, sign up online today and save £80 http://btyahoo.yahoo.co.uk
--0-392819529-1076252742=:54885
Content-Type: text/plain; name="particle_patch.txt"
Content-Description: particle_patch.txt
Content-Disposition: inline; filename="particle_patch.txt"

? obj
? user-def.mk
Index: source/blender/blenkernel/intern/effect.c
===================================================================
RCS file: /cvsroot/tuhopuu/tuhopuu2/source/blender/blenkernel/intern/effect.c,v
retrieving revision 1.2
diff -r1.2 effect.c
1c1
< /*  effect.c 
---
> /*  effect.c
52a53
> #include "MTC_vectorops.h"
61a63
> #include "BKE_main.h"
356a359,408
> float mag_vect(float n[3])
> {
> /* Just a simple function to get the magnitude of a vector without */
> /* normalising it */
>       float d;
>       d= n[0]*n[0]+n[1]*n[1]+n[2]*n[2];
>       d = sqrt(d);
>       return d;
> }
> 
> float pointintriangle(float p[3], float v1[3], float v2[3], float v3[3])
> {
> /* This function checks whether a point (p) is within a triangle formed by */
> /* three other points (v1, v2, v3. */
> /* It does this by checking the area of the total triangle compared to the areas of */
> /* the three triangles formed by the point and the three points */
> /* It assumes the points are all in the same plane, it doesn't check this */
> /* I'm sure this isn't a very good method, but it just about works!!! */
> /* Check whether the result is below is below a very small */
> /* number to see if the point is inside, since it won't ever be zero */
>       float total_area;
>       float a1,a2,a3;
>       float vect1[3], vect2[3], wvect[3];
>       float result;
>       /*First total area, between v1 and v2 will do*/
>       MTC_diff3Float(vect1, v1,v2);
>       MTC_diff3Float(vect2, v2,v3);
>       MTC_cross3Float(wvect,vect1,vect2);
>       total_area = mag_vect(wvect) / 2;
>       /*Now area 1 - p/v1, p/v2*/
>       MTC_diff3Float(vect1,p,v1);
>       MTC_diff3Float(vect2,p,v2);
>       MTC_cross3Float(wvect,vect1,vect2);
>       a1 = mag_vect(wvect) / 2;
>       /*Now area 2 - p/v2, p/v3*/
>       MTC_diff3Float(vect1,p,v2);
>       MTC_diff3Float(vect2,p,v3);
>       MTC_cross3Float(wvect,vect1,vect2);
>       a2 = mag_vect(wvect) / 2;
>       /*Now area 2 - p/v3, p/v1*/
>       MTC_diff3Float(vect1,p,v3);
>       MTC_diff3Float(vect2,p,v1);
>       MTC_cross3Float(wvect,vect1,vect2);
>       a3 = mag_vect(wvect) / 2;
>       result = total_area - a1 - a2 - a3;
>       result = abs(result);
>       return result;
> }
> 
> 
361c413,426
< 	int b, rt1, rt2;
---
> 	float *v1, *v2, *v3, *v4;
> 	float nv1[3], nv2[3], nv3[3], nv4[3], edge1[3], edge2[3], intersect_vect[3];
> 	float nvect[3],nvect_unit[3], vect_to_int[3], intersect_co[3], refl_vel[3];
> 	float k_plane, k_point1, k_point2, k_point3, dist_to_plane;
> 	float icalctop, icalcbot, surface_damp, int_u, n_mag;
> 	float mag_intersect, mag_iv, x_m,y_m,z_m;
> 	int a, b, rt1, rt2, deflected;
> 	float mat[3][3];
> 	float time_before, time_after, pintri;
> 	Mesh *def_mesh, *deflection_mesh = NULL;;
> 	MVert *mvert;
> 	MFace *mface;
> 	Main *mn;
> 	Object *myobject, *deflection_object;
398a464,651
>                 /* Particle deflection code     */
>                 /* Code is in two parts - first establish if a collision  */
>                 /* has taken place, second work out the new co-ordinates */
>                 /* and speed of the particle*/
>                 /* This has the limitation you can only have one collision */
>                 /* per particle per key frame - so you do get "leaks" at */
>                 /* joints between deflecting meshes*/
>                 /* First part: loop through all meshes, and all faces of meshes*/
>                 mn= G.main;
>                 myobject = mn->object.first;
>                 deflected = 0;
>                 while (myobject) {
>                     def_mesh = get_mesh(myobject);
>                     /* Don't go any further if we've already got a collision */
>                     if (def_mesh!=0) {
>                         if(def_mesh->pdeflect && (deflected == 0)) {
>                             mface= def_mesh->mface;
>                             a = def_mesh->totface;
>                             object_to_mat3(myobject, mat);
>                             while (a--) {
>                                 if (deflected == 0) {
>                                                     	
>                                     /* Calculate the global co-ordinates of the vertices*/
>                                     v1= (def_mesh->mvert+(mface->v1))->co;
>                                     v2= (def_mesh->mvert+(mface->v2))->co;
>                                     v3= (def_mesh->mvert+(mface->v3))->co;
>                                     v4= (def_mesh->mvert+(mface->v4))->co;
> 
>                                     nv1[0]= v1[0];
>                                     nv1[1]= v1[1];
>                                     nv1[2]= v1[2];
>                                     nv2[0]= v2[0];
>                                     nv2[1]= v2[1];
>                                     nv2[2]= v2[2];
>                                     nv3[0]= v3[0];
>                                     nv3[1]= v3[1];
>                                     nv3[2]= v3[2];
>                                     nv4[0]= v4[0];
>                                     nv4[1]= v4[1];
>                                     nv4[2]= v4[2];
> 
>                                     /*Apply the objects deformation matrix*/
>                                     Mat3MulVecfl(mat, nv1);
>                                     Mat3MulVecfl(mat, nv2);
>                                     Mat3MulVecfl(mat, nv3);
>                                     Mat3MulVecfl(mat, nv4);
> 
>                                     nv1[0]= nv1[0] + myobject->loc[0];
>                                     nv1[1]= nv1[1] + myobject->loc[1];
>                                     nv1[2]= nv1[2] + myobject->loc[2];
>                                     nv2[0]= nv2[0] + myobject->loc[0];
>                                     nv2[1]= nv2[1] + myobject->loc[1];
>                                     nv2[2]= nv2[2] + myobject->loc[2];
>                                     nv3[0]= nv3[0] + myobject->loc[0];
>                                     nv3[1]= nv3[1] + myobject->loc[1];
>                                     nv3[2]= nv3[2] + myobject->loc[2];
>                                     nv4[0]= nv4[0] + myobject->loc[0];
>                                     nv4[1]= nv4[1] + myobject->loc[1];
>                                     nv4[2]= nv4[2] + myobject->loc[2];
> 
>                                     /* Now calculate the normal vector of the face */
>                                     /* Just use the first three points */
>                                     /* First the edges */
>                                     MTC_diff3Float(edge1, nv1, nv2);
>                                     MTC_diff3Float(edge2, nv3, nv2);
> 
>                                     /*Now cross product and normalise*/
>                                     MTC_cross3Float(nvect, edge1, edge2);
>                                     n_mag = MTC_normalise3DF(nvect);
> 
>                                     /* Now calculate K */
>                                     k_plane = MTC_dot3Float(nvect, nv1);
>                                     k_point1 = MTC_dot3Float(nvect,pa->co);
>                                     k_point2 = MTC_dot3Float(nvect,opa->co);
> 
>                                     /* If the old co-ordinates and new co-ordinates were the same side of */
>                                     /* the plane, we don't need to go any further, since no collision is possible */
>                                     if (((k_plane > k_point1) && (k_plane < k_point2))||((k_plane < k_point1) && (k_plane > k_point2))) {
> 
>                                         /* Now check if the intersection point lies within */
>                                         /* any of the triangles of the face */
>                                         /* So first get the intersection point */
>                                         icalctop = (k_plane - (MTC_dot3Float(pa->co,nvect)));
>                                         MTC_diff3Float(intersect_vect, pa->co, opa->co);
>                                         icalcbot = (MTC_dot3Float(intersect_vect,nvect));
>                                         int_u = icalctop / icalcbot;
>                                         intersect_co[0] = (pa->co[0] + (int_u * intersect_vect[0]));
>                                         intersect_co[1] = (pa->co[1] + (int_u * intersect_vect[1]));
>                                         intersect_co[2] = (pa->co[2] + (int_u * intersect_vect[2]));
> 
>                                         /* Now check if intersection point is inside first three vertices */
>                                         pintri = pointintriangle(intersect_co, nv1, nv2, nv3);
>                                         if (pintri < 0.00000001) {
>                                             deflected = 1;
>                                             deflection_mesh = def_mesh;
>                                             deflection_object = myobject;
>                                         }
>                                         else {
> 
>                                         /* Only check the other triangle if the face has 4 vertices */
>                                         if (mface->v4) {
>                                             pintri = pointintriangle(intersect_co, nv1, nv3, nv4);
>                                                 if (pintri < 0.00000001) {
>                                                     deflected = 1;
>                                                     deflection_mesh = def_mesh;
>                                                     deflection_object = myobject;
>                                                 }
>                                             }
>                                         }
>                                     }
>                                 }
>                             mface++;
>                             }
>                         }
>                     }
>                     myobject = myobject->id.next;
>                 }
> 
>                   /* Now for the second part of the deflection code - work out the new speed */
>                   /* and position of the particle if a collision occurred */
>                   if (deflected) {
>                       /* Just some preiliminary stuff*/
>                       mag_iv = MTC_normalise3DF(intersect_vect);
>                       MTC_diff3Float(vect_to_int, opa->co, intersect_co);
>                       mag_intersect = MTC_normalise3DF(vect_to_int);
>                       pa->co[0] = intersect_co[0];
>                       pa->co[1] = intersect_co[1];
>                       pa->co[2] = intersect_co[2];
> 
>                       /* Work out the lengths of time before and after collision*/
>                       time_before = (deltalife*(mag_intersect / (mag_iv)));
>                       time_after =  (deltalife*((mag_iv - mag_intersect) / (mag_iv)));
> 
>                       /* We have to recalculate what the speed would have been at the */
>                       /* point of collision, not the key frame time */
>                       pa->no[0]= opa->no[0] + time_before*force[0];
> 		      pa->no[1]= opa->no[1] + time_before*force[1];
> 		      pa->no[2]= opa->no[2] + time_before*force[2];
> 
>                       /* Reflect the speed vector in the face */
>                       x_m = (2 * pa->no[0] * nvect[0]);
>                       y_m = (2 * pa->no[1] * nvect[1]);
>                       z_m = (2 * pa->no[2] * nvect[2]);
>                       refl_vel[0] = pa->no[0] - (nvect[0] * (x_m + y_m + z_m));
>                       refl_vel[1] = pa->no[1] - (nvect[1] * (x_m + y_m + z_m));
>                       refl_vel[2] = pa->no[2] - (nvect[2] * (x_m + y_m + z_m));
> 
>                       /* Now add in the damping force - only damp in the direction of */
>                       /* the faces normal vector */
>                       pa->no[0] = (refl_vel[0] * (1 + (nvect[0] * deflection_mesh->pdef_damp)));
>                       pa->no[1] = (refl_vel[1] * (1 + (nvect[1] * deflection_mesh->pdef_damp)));
>                       pa->no[2] = (refl_vel[2] * (1 + (nvect[2] * deflection_mesh->pdef_damp)));
> 
>                       /* We have the particles speed at the point of collision    */
>                       /* Now we want the particles speed at the current key frame */
>                       pa->no[0]= pa->no[0] + time_after*force[0];
> 		      pa->no[1]= pa->no[1] + time_after*force[1];
> 		      pa->no[2]= pa->no[2] + time_after*force[2];
> 
>                       /* Now we have to recalculate pa->co for the remainder*/
>                       /* of the time since the intersect*/
> 		      pa->co[0]= pa->co[0] + time_after*pa->no[0];
> 		      pa->co[1]= pa->co[1] + time_after*pa->no[1];
> 		      pa->co[2]= pa->co[2] + time_after*pa->no[2];
> 
>                       /* The particle may have fallen through the face again by now!!*/
>                       /* So check if the particle has changed sides of the plane compared*/
>                       /* the co-ordinates at the last keyframe*/
>                       k_point3 = MTC_dot3Float(nvect,pa->co);
>                       if (((k_plane > k_point3) && (k_plane < k_point2))||((k_plane < k_point3) && (k_plane > k_point2))) {
>                           
>                           /* Yup, the pesky particle may have fallen through a hole!!! */
>                           /* So we'll cheat a bit and move the particle along the normal vector */
>                           /* until it's just the other side of the plane */
>                           icalctop = (k_plane - nvect[0]*pa->co[0] - nvect[1]*pa->co[1] - nvect[2]*pa->co[2]);
>                           icalcbot = (nvect[0]*nvect[0] + nvect[1]*nvect[1] + nvect[2]*nvect[2]);
>                           dist_to_plane = icalctop / icalcbot;
> 
>                           /*  Now just increase the distance a little to place */
>                           /* the point the other side of the plane */
>                           dist_to_plane *= 1.001;
>                           pa->co[0]= pa->co[0] + (dist_to_plane * nvect[0]);
>                           pa->co[1]= pa->co[1] + (dist_to_plane * nvect[1]);
>                           pa->co[2]= pa->co[2] + (dist_to_plane * nvect[2]);
>                           /* And hope it works!!! */
>                        }
>                 }
> 
408c661
< 	
---
> 
Index: source/blender/include/butspace.h
===================================================================
RCS file: /cvsroot/tuhopuu/tuhopuu2/source/blender/include/butspace.h,v
retrieving revision 1.5
diff -r1.5 butspace.h
338a339,340
> #define B_ISDEFLECTOR   2085
> #define B_PDEFDAMPING   2086
Index: source/blender/makesdna/DNA_mesh_types.h
===================================================================
RCS file: /cvsroot/tuhopuu/tuhopuu2/source/blender/makesdna/DNA_mesh_types.h,v
retrieving revision 1.7
diff -r1.7 DNA_mesh_types.h
134c134,137
< 	
---
> 
> 	int pdeflect;        /* Deflection flag - does mesh deflect particles*/
> 	float pdef_damp;     /* Damping factor for particle deflection       */
> 
Index: source/blender/src/buttons_editing.c
===================================================================
RCS file: /cvsroot/tuhopuu/tuhopuu2/source/blender/src/buttons_editing.c,v
retrieving revision 1.11
diff -r1.11 buttons_editing.c
1604a1605,1608
> 		case B_ISDEFLECTOR:      /*Not sure if this is needed!!!*/
> 		        break;
> 		case B_PDEFDAMPING:      /*Ditto!!!*/
> 		        break;
1752a1757,1781
> static void editing_panel_deflectors(Object *ob)
> {
> /* A new panel for particle interaction settings */
> 	uiBlock *block;
> 	ID *id, *idfrom;
> 	int *poin, xco=143;
> 	float min;
> 	char str[64];
> 	uiBut *but;
> 	Mesh *me;
> 
> 	block= uiNewBlock(&curarea->uiblocks, "editing_panel_deflectors", UI_EMBOSS, UI_HELV, curarea->win);
> 	if(uiNewPanel(curarea, block, "Particle Interaction", "Editing", 640, 0, 174, 204)==0) return;
> 
> 	buttons_active_id(&id, &idfrom);
> 
> 	/* vertex group... partially editmode... */
> 	if(ob->type==OB_MESH) {
> 	  me= get_mesh(ob);
>           uiDefButI(block, TOG|BIT|0, B_ISDEFLECTOR, "Deflection",	143,40,140,20, &me->pdeflect, 0, 0, 0, 0, "Deflects particles");
>           uiDefButF(block, NUM, B_PDEFDAMPING, "Surface damping",	143,15,140,20, &me->pdef_damp, 0, 1, 0, 0, "Amount of damping during particle collision");
>         }
> 
> 	
> }
2190c2219
< 			if(G.f & (G_VERTEXPAINT | G_TEXTUREPAINT | G_WEIGHTPAINT) )
---
> 			if(G.f & (G_VERTEXPAINT | G_TEXTUREPAINT | G_WEIGHTPAINT) ) {
2191a2221,2224
> 			}
> 			else if(!(G.f & G_FACESELECT)) {
> 			     editing_panel_deflectors(ob);  /* Particle deflectors */
> 			}

--0-392819529-1076252742=:54885
Content-Type: text/plain; name="pdeflection.txt"
Content-Description: pdeflection.txt
Content-Disposition: inline; filename="pdeflection.txt"

Particle deflection 
===================


Notes
=====

The code adds an extra panel "Particle interaction" to the edit buttons which is only shown when in edit mode on a mesh.

It has two buttons currently, a toggle button "Deflection" to indicate whether the mesh should deflect particles and a value "Surface Damping" which controls how much the particles bounce.

It's still very experimental so it doesn't work perfectly - things to remember are:

- You need to set the "number of keys" in your particle effect as high as possible (32).

- It really only produces good results for large simple meshes (i.e. reasonably big planes!). Hopefully the triangle intersection calculation can be improved later!!!

- It sometimes produces strange results depending on the direction of the face normal. If it's not giving the results you expect, try reversing the face, or doing a "recalculate face normals outside".

- Particles will often "leak" if you have two close or intersecting deflectors. Since it can only calculate one collision per particle per key frame, the collision with the first mesh can move a particle through the second mesh. Not sure how to fix this yet! But depending on the scene it may not be too important.

- Best results seem to be with reasonably big damping settings (0.5-1).

- If you change the position or damping settings of a deflector, you need to do a "recalc all" on your particle effect.

- It doesn't support animated deflectors (yet!).



Summary of code changes
=======================

The code changes were to the following files, see the patch for details:

/cvsroot/tuhopuu/tuhopuu2/source/blender/blenkernel/intern/effect.c
        - Added two includes (BKE_main and and MTC_vectorops)
        - Two new functions (mag_vect and pointintriangle)
        - Modified function make_particle_keys (the main changes!)

/cvsroot/tuhopuu/tuhopuu2/source/blender/include/butspace.h
        - Added definitions for two buttons, B_ISDEFLECTOR and B_PDEFDAMPING

/cvsroot/tuhopuu/tuhopuu2/source/blender/makesdna/DNA_mesh_types.h
        - Added two new variables to Mesh structure, pdeflect and pdef_damp

/cvsroot/tuhopuu/tuhopuu2/source/blender/src/buttons_editing.c
        - Added case statements to function do_meshbuts, for B_ISDEFLECTOR and B_PDEFDAMPING
        - New function editing_panel_deflector for particle interactions with new buttons
        - Modified function editing_panels to display particle interaction panel

--0-392819529-1076252742=:54885--