Blender V2.61 - r43446
|
00001 /* 00002 * ***** BEGIN GPL LICENSE BLOCK ***** 00003 * 00004 * This program is free software; you can redistribute it and/or 00005 * modify it under the terms of the GNU General Public License 00006 * as published by the Free Software Foundation; either version 2 00007 * of the License, or (at your option) any later version. 00008 * 00009 * This program is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 * GNU General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU General Public License 00015 * along with this program; if not, write to the Free Software Foundation, 00016 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00017 * 00018 * The Original Code is Copyright (C) Blender Foundation 00019 * All rights reserved. 00020 * 00021 * The Original Code is: all of this file. 00022 * 00023 * Contributor(s): none yet. 00024 * 00025 * ***** END GPL LICENSE BLOCK ***** 00026 */ 00027 00033 /* 00034 ****** 00035 variables on the UI for now 00036 00037 float mediafrict; friction to env 00038 float nodemass; softbody mass of *vertex* 00039 float grav; softbody amount of gravitaion to apply 00040 00041 float goalspring; softbody goal springs 00042 float goalfrict; softbody goal springs friction 00043 float mingoal; quick limits for goal 00044 float maxgoal; 00045 00046 float inspring; softbody inner springs 00047 float infrict; softbody inner springs friction 00048 00049 ***** 00050 */ 00051 00052 00053 #include <math.h> 00054 #include <stdlib.h> 00055 #include <string.h> 00056 00057 #include "MEM_guardedalloc.h" 00058 00059 /* types */ 00060 #include "DNA_object_types.h" 00061 #include "DNA_scene_types.h" 00062 #include "DNA_lattice_types.h" 00063 #include "DNA_curve_types.h" 00064 #include "DNA_mesh_types.h" 00065 #include "DNA_meshdata_types.h" 00066 00067 #include "BLI_math.h" 00068 #include "BLI_utildefines.h" 00069 #include "BLI_listbase.h" 00070 #include "BLI_ghash.h" 00071 #include "BLI_threads.h" 00072 00073 #include "BKE_curve.h" 00074 #include "BKE_effect.h" 00075 #include "BKE_global.h" 00076 #include "BKE_modifier.h" 00077 #include "BKE_softbody.h" 00078 #include "BKE_DerivedMesh.h" 00079 #include "BKE_pointcache.h" 00080 #include "BKE_deform.h" 00081 //XXX #include "BIF_editdeform.h" 00082 //XXX #include "BIF_graphics.h" 00083 #include "PIL_time.h" 00084 // #include "ONL_opennl.h" remove linking to ONL for now 00085 00086 /* callbacks for errors and interrupts and some goo */ 00087 static int (*SB_localInterruptCallBack)(void) = NULL; 00088 00089 00090 /* ********** soft body engine ******* */ 00091 00092 typedef enum {SB_EDGE=1,SB_BEND=2,SB_STIFFQUAD=3,SB_HANDLE=4} type_spring; 00093 00094 typedef struct BodySpring { 00095 int v1, v2; 00096 float len,cf,load; 00097 float ext_force[3]; /* edges colliding and sailing */ 00098 type_spring springtype; 00099 short flag; 00100 } BodySpring; 00101 00102 typedef struct BodyFace { 00103 int v1, v2, v3 ,v4; 00104 float ext_force[3]; /* faces colliding */ 00105 short flag; 00106 } BodyFace; 00107 00108 typedef struct ReferenceVert { 00109 float pos[3]; /* position relative to com */ 00110 float mass; /* node mass */ 00111 } ReferenceVert; 00112 00113 typedef struct ReferenceState { 00114 float com[3]; /* center of mass*/ 00115 ReferenceVert *ivert; /* list of intial values */ 00116 }ReferenceState ; 00117 00118 00119 /*private scratch pad for caching and other data only needed when alive*/ 00120 typedef struct SBScratch { 00121 GHash *colliderhash; 00122 short needstobuildcollider; 00123 short flag; 00124 BodyFace *bodyface; 00125 int totface; 00126 float aabbmin[3],aabbmax[3]; 00127 ReferenceState Ref; 00128 }SBScratch; 00129 00130 typedef struct SB_thread_context { 00131 Scene *scene; 00132 Object *ob; 00133 float forcetime; 00134 float timenow; 00135 int ifirst; 00136 int ilast; 00137 ListBase *do_effector; 00138 int do_deflector; 00139 float fieldfactor; 00140 float windfactor; 00141 int nr; 00142 int tot; 00143 }SB_thread_context; 00144 00145 #define NLF_BUILD 1 00146 #define NLF_SOLVE 2 00147 00148 #define MID_PRESERVE 1 00149 00150 #define SOFTGOALSNAP 0.999f 00151 /* if bp-> goal is above make it a *forced follow original* and skip all ODE stuff for this bp 00152 removes *unnecessary* stiffnes from ODE system 00153 */ 00154 #define HEUNWARNLIMIT 1 /* 500 would be fine i think for detecting severe *stiff* stuff */ 00155 00156 00157 #define BSF_INTERSECT 1 /* edge intersects collider face */ 00158 00159 /* private definitions for bodypoint states */ 00160 #define SBF_DOFUZZY 1 /* Bodypoint do fuzzy */ 00161 #define SBF_OUTOFCOLLISION 2 /* Bodypoint does not collide */ 00162 00163 00164 #define BFF_INTERSECT 1 /* collider edge intrudes face */ 00165 #define BFF_CLOSEVERT 2 /* collider vertex repulses face */ 00166 00167 00168 static float SoftHeunTol = 1.0f; /* humm .. this should be calculated from sb parameters and sizes */ 00169 00170 /* local prototypes */ 00171 static void free_softbody_intern(SoftBody *sb); 00172 /* aye this belongs to arith.c */ 00173 static void Vec3PlusStVec(float *v, float s, float *v1); 00174 00175 /*+++ frame based timing +++*/ 00176 00177 /*physical unit of force is [kg * m / sec^2]*/ 00178 00179 static float sb_grav_force_scale(Object *UNUSED(ob)) 00180 /* since unit of g is [m/sec^2] and F = mass * g we rescale unit mass of node to 1 gramm 00181 put it to a function here, so we can add user options later without touching simulation code 00182 */ 00183 { 00184 return (0.001f); 00185 } 00186 00187 static float sb_fric_force_scale(Object *UNUSED(ob)) 00188 /* rescaling unit of drag [1 / sec] to somehow reasonable 00189 put it to a function here, so we can add user options later without touching simulation code 00190 */ 00191 { 00192 return (0.01f); 00193 } 00194 00195 static float sb_time_scale(Object *ob) 00196 /* defining the frames to *real* time relation */ 00197 { 00198 SoftBody *sb= ob->soft; /* is supposed to be there */ 00199 if (sb){ 00200 return(sb->physics_speed); 00201 /*hrms .. this could be IPO as well :) 00202 estimated range [0.001 sluggish slug - 100.0 very fast (i hope ODE solver can handle that)] 00203 1 approx = a unit 1 pendulum at g = 9.8 [earth conditions] has period 65 frames 00204 theory would give a 50 frames period .. so there must be something inaccurate .. looking for that (BM) 00205 */ 00206 } 00207 return (1.0f); 00208 /* 00209 this would be frames/sec independent timing assuming 25 fps is default 00210 but does not work very well with NLA 00211 return (25.0f/scene->r.frs_sec) 00212 */ 00213 } 00214 /*--- frame based timing ---*/ 00215 00216 /* helper functions for everything is animatable jow_go_for2_5 +++++++*/ 00217 /* introducing them here, because i know: steps in properties ( at frame timing ) 00218 will cause unwanted responses of the softbody system (which does inter frame calculations ) 00219 so first 'cure' would be: interpolate linear in time .. 00220 Q: why do i write this? 00221 A: because it happend once, that some eger coder 'streamlined' code to fail. 00222 We DO linear interpolation for goals .. and i think we should do on animated properties as well 00223 */ 00224 00225 /* animate sb->maxgoal,sb->mingoal */ 00226 static float _final_goal(Object *ob,BodyPoint *bp)/*jow_go_for2_5 */ 00227 { 00228 float f = -1999.99f; 00229 if (ob){ 00230 SoftBody *sb= ob->soft; /* is supposed to be there */ 00231 if(!(ob->softflag & OB_SB_GOAL)) return (0.0f); 00232 if (sb&&bp){ 00233 if (bp->goal < 0.0f) return (0.0f); 00234 f = sb->mingoal + bp->goal*ABS(sb->maxgoal - sb->mingoal); 00235 f = pow(f, 4.0f); 00236 return (f); 00237 } 00238 } 00239 printf("_final_goal failed! sb or bp ==NULL \n" ); 00240 return f; /*using crude but spot able values some times helps debuggin */ 00241 } 00242 00243 static float _final_mass(Object *ob,BodyPoint *bp) 00244 { 00245 if (ob){ 00246 SoftBody *sb= ob->soft; /* is supposed to be there */ 00247 if (sb&&bp){ 00248 return(bp->mass*sb->nodemass); 00249 } 00250 } 00251 printf("_final_mass failed! sb or bp ==NULL \n" ); 00252 return 1.0f; 00253 } 00254 /* helper functions for everything is animateble jow_go_for2_5 ------*/ 00255 00256 /*+++ collider caching and dicing +++*/ 00257 00258 /******************** 00259 for each target object/face the axis aligned bounding box (AABB) is stored 00260 faces parallel to global axes 00261 so only simple "value" in [min,max] ckecks are used 00262 float operations still 00263 */ 00264 00265 /* just an ID here to reduce the prob for killing objects 00266 ** ob->sumohandle points to we should not kill :) 00267 */ 00268 static const int CCD_SAVETY = 190561; 00269 00270 typedef struct ccdf_minmax{ 00271 float minx,miny,minz,maxx,maxy,maxz; 00272 }ccdf_minmax; 00273 00274 00275 00276 typedef struct ccd_Mesh { 00277 int totvert, totface; 00278 MVert *mvert; 00279 MVert *mprevvert; 00280 MFace *mface; 00281 int savety; 00282 ccdf_minmax *mima; 00283 /* Axis Aligned Bounding Box AABB */ 00284 float bbmin[3]; 00285 float bbmax[3]; 00286 }ccd_Mesh; 00287 00288 00289 00290 00291 static ccd_Mesh *ccd_mesh_make(Object *ob) 00292 { 00293 CollisionModifierData *cmd; 00294 ccd_Mesh *pccd_M = NULL; 00295 ccdf_minmax *mima =NULL; 00296 MFace *mface=NULL; 00297 float v[3],hull; 00298 int i; 00299 00300 cmd =(CollisionModifierData *)modifiers_findByType(ob, eModifierType_Collision); 00301 00302 /* first some paranoia checks */ 00303 if (!cmd) return NULL; 00304 if (!cmd->numverts || !cmd->numfaces) return NULL; 00305 00306 pccd_M = MEM_mallocN(sizeof(ccd_Mesh),"ccd_Mesh"); 00307 pccd_M->totvert = cmd->numverts; 00308 pccd_M->totface = cmd->numfaces; 00309 pccd_M->savety = CCD_SAVETY; 00310 pccd_M->bbmin[0]=pccd_M->bbmin[1]=pccd_M->bbmin[2]=1e30f; 00311 pccd_M->bbmax[0]=pccd_M->bbmax[1]=pccd_M->bbmax[2]=-1e30f; 00312 pccd_M->mprevvert=NULL; 00313 00314 00315 /* blow it up with forcefield ranges */ 00316 hull = MAX2(ob->pd->pdef_sbift,ob->pd->pdef_sboft); 00317 00318 /* alloc and copy verts*/ 00319 pccd_M->mvert = MEM_dupallocN(cmd->xnew); 00320 /* note that xnew coords are already in global space, */ 00321 /* determine the ortho BB */ 00322 for(i=0; i < pccd_M->totvert; i++){ 00323 /* evaluate limits */ 00324 copy_v3_v3(v,pccd_M->mvert[i].co); 00325 pccd_M->bbmin[0] = MIN2(pccd_M->bbmin[0],v[0]-hull); 00326 pccd_M->bbmin[1] = MIN2(pccd_M->bbmin[1],v[1]-hull); 00327 pccd_M->bbmin[2] = MIN2(pccd_M->bbmin[2],v[2]-hull); 00328 00329 pccd_M->bbmax[0] = MAX2(pccd_M->bbmax[0],v[0]+hull); 00330 pccd_M->bbmax[1] = MAX2(pccd_M->bbmax[1],v[1]+hull); 00331 pccd_M->bbmax[2] = MAX2(pccd_M->bbmax[2],v[2]+hull); 00332 00333 } 00334 /* alloc and copy faces*/ 00335 pccd_M->mface = MEM_dupallocN(cmd->mfaces); 00336 00337 /* OBBs for idea1 */ 00338 pccd_M->mima = MEM_mallocN(sizeof(ccdf_minmax)*pccd_M->totface,"ccd_Mesh_Faces_mima"); 00339 mima = pccd_M->mima; 00340 mface = pccd_M->mface; 00341 00342 00343 /* anyhoo we need to walk the list of faces and find OBB they live in */ 00344 for(i=0; i < pccd_M->totface; i++){ 00345 mima->minx=mima->miny=mima->minz=1e30f; 00346 mima->maxx=mima->maxy=mima->maxz=-1e30f; 00347 00348 copy_v3_v3(v,pccd_M->mvert[mface->v1].co); 00349 mima->minx = MIN2(mima->minx,v[0]-hull); 00350 mima->miny = MIN2(mima->miny,v[1]-hull); 00351 mima->minz = MIN2(mima->minz,v[2]-hull); 00352 mima->maxx = MAX2(mima->maxx,v[0]+hull); 00353 mima->maxy = MAX2(mima->maxy,v[1]+hull); 00354 mima->maxz = MAX2(mima->maxz,v[2]+hull); 00355 00356 copy_v3_v3(v,pccd_M->mvert[mface->v2].co); 00357 mima->minx = MIN2(mima->minx,v[0]-hull); 00358 mima->miny = MIN2(mima->miny,v[1]-hull); 00359 mima->minz = MIN2(mima->minz,v[2]-hull); 00360 mima->maxx = MAX2(mima->maxx,v[0]+hull); 00361 mima->maxy = MAX2(mima->maxy,v[1]+hull); 00362 mima->maxz = MAX2(mima->maxz,v[2]+hull); 00363 00364 copy_v3_v3(v,pccd_M->mvert[mface->v3].co); 00365 mima->minx = MIN2(mima->minx,v[0]-hull); 00366 mima->miny = MIN2(mima->miny,v[1]-hull); 00367 mima->minz = MIN2(mima->minz,v[2]-hull); 00368 mima->maxx = MAX2(mima->maxx,v[0]+hull); 00369 mima->maxy = MAX2(mima->maxy,v[1]+hull); 00370 mima->maxz = MAX2(mima->maxz,v[2]+hull); 00371 00372 if(mface->v4){ 00373 copy_v3_v3(v,pccd_M->mvert[mface->v4].co); 00374 mima->minx = MIN2(mima->minx,v[0]-hull); 00375 mima->miny = MIN2(mima->miny,v[1]-hull); 00376 mima->minz = MIN2(mima->minz,v[2]-hull); 00377 mima->maxx = MAX2(mima->maxx,v[0]+hull); 00378 mima->maxy = MAX2(mima->maxy,v[1]+hull); 00379 mima->maxz = MAX2(mima->maxz,v[2]+hull); 00380 } 00381 00382 00383 mima++; 00384 mface++; 00385 00386 } 00387 return pccd_M; 00388 } 00389 static void ccd_mesh_update(Object *ob,ccd_Mesh *pccd_M) 00390 { 00391 CollisionModifierData *cmd; 00392 ccdf_minmax *mima =NULL; 00393 MFace *mface=NULL; 00394 float v[3],hull; 00395 int i; 00396 00397 cmd =(CollisionModifierData *)modifiers_findByType(ob, eModifierType_Collision); 00398 00399 /* first some paranoia checks */ 00400 if (!cmd) return ; 00401 if (!cmd->numverts || !cmd->numfaces) return ; 00402 00403 if ((pccd_M->totvert != cmd->numverts) || 00404 (pccd_M->totface != cmd->numfaces)) return; 00405 00406 pccd_M->bbmin[0]=pccd_M->bbmin[1]=pccd_M->bbmin[2]=1e30f; 00407 pccd_M->bbmax[0]=pccd_M->bbmax[1]=pccd_M->bbmax[2]=-1e30f; 00408 00409 00410 /* blow it up with forcefield ranges */ 00411 hull = MAX2(ob->pd->pdef_sbift,ob->pd->pdef_sboft); 00412 00413 /* rotate current to previous */ 00414 if(pccd_M->mprevvert) MEM_freeN(pccd_M->mprevvert); 00415 pccd_M->mprevvert = pccd_M->mvert; 00416 /* alloc and copy verts*/ 00417 pccd_M->mvert = MEM_dupallocN(cmd->xnew); 00418 /* note that xnew coords are already in global space, */ 00419 /* determine the ortho BB */ 00420 for(i=0; i < pccd_M->totvert; i++){ 00421 /* evaluate limits */ 00422 copy_v3_v3(v,pccd_M->mvert[i].co); 00423 pccd_M->bbmin[0] = MIN2(pccd_M->bbmin[0],v[0]-hull); 00424 pccd_M->bbmin[1] = MIN2(pccd_M->bbmin[1],v[1]-hull); 00425 pccd_M->bbmin[2] = MIN2(pccd_M->bbmin[2],v[2]-hull); 00426 00427 pccd_M->bbmax[0] = MAX2(pccd_M->bbmax[0],v[0]+hull); 00428 pccd_M->bbmax[1] = MAX2(pccd_M->bbmax[1],v[1]+hull); 00429 pccd_M->bbmax[2] = MAX2(pccd_M->bbmax[2],v[2]+hull); 00430 00431 /* evaluate limits */ 00432 copy_v3_v3(v,pccd_M->mprevvert[i].co); 00433 pccd_M->bbmin[0] = MIN2(pccd_M->bbmin[0],v[0]-hull); 00434 pccd_M->bbmin[1] = MIN2(pccd_M->bbmin[1],v[1]-hull); 00435 pccd_M->bbmin[2] = MIN2(pccd_M->bbmin[2],v[2]-hull); 00436 00437 pccd_M->bbmax[0] = MAX2(pccd_M->bbmax[0],v[0]+hull); 00438 pccd_M->bbmax[1] = MAX2(pccd_M->bbmax[1],v[1]+hull); 00439 pccd_M->bbmax[2] = MAX2(pccd_M->bbmax[2],v[2]+hull); 00440 00441 } 00442 00443 mima = pccd_M->mima; 00444 mface = pccd_M->mface; 00445 00446 00447 /* anyhoo we need to walk the list of faces and find OBB they live in */ 00448 for(i=0; i < pccd_M->totface; i++){ 00449 mima->minx=mima->miny=mima->minz=1e30f; 00450 mima->maxx=mima->maxy=mima->maxz=-1e30f; 00451 00452 copy_v3_v3(v,pccd_M->mvert[mface->v1].co); 00453 mima->minx = MIN2(mima->minx,v[0]-hull); 00454 mima->miny = MIN2(mima->miny,v[1]-hull); 00455 mima->minz = MIN2(mima->minz,v[2]-hull); 00456 mima->maxx = MAX2(mima->maxx,v[0]+hull); 00457 mima->maxy = MAX2(mima->maxy,v[1]+hull); 00458 mima->maxz = MAX2(mima->maxz,v[2]+hull); 00459 00460 copy_v3_v3(v,pccd_M->mvert[mface->v2].co); 00461 mima->minx = MIN2(mima->minx,v[0]-hull); 00462 mima->miny = MIN2(mima->miny,v[1]-hull); 00463 mima->minz = MIN2(mima->minz,v[2]-hull); 00464 mima->maxx = MAX2(mima->maxx,v[0]+hull); 00465 mima->maxy = MAX2(mima->maxy,v[1]+hull); 00466 mima->maxz = MAX2(mima->maxz,v[2]+hull); 00467 00468 copy_v3_v3(v,pccd_M->mvert[mface->v3].co); 00469 mima->minx = MIN2(mima->minx,v[0]-hull); 00470 mima->miny = MIN2(mima->miny,v[1]-hull); 00471 mima->minz = MIN2(mima->minz,v[2]-hull); 00472 mima->maxx = MAX2(mima->maxx,v[0]+hull); 00473 mima->maxy = MAX2(mima->maxy,v[1]+hull); 00474 mima->maxz = MAX2(mima->maxz,v[2]+hull); 00475 00476 if(mface->v4){ 00477 copy_v3_v3(v,pccd_M->mvert[mface->v4].co); 00478 mima->minx = MIN2(mima->minx,v[0]-hull); 00479 mima->miny = MIN2(mima->miny,v[1]-hull); 00480 mima->minz = MIN2(mima->minz,v[2]-hull); 00481 mima->maxx = MAX2(mima->maxx,v[0]+hull); 00482 mima->maxy = MAX2(mima->maxy,v[1]+hull); 00483 mima->maxz = MAX2(mima->maxz,v[2]+hull); 00484 } 00485 00486 00487 copy_v3_v3(v,pccd_M->mprevvert[mface->v1].co); 00488 mima->minx = MIN2(mima->minx,v[0]-hull); 00489 mima->miny = MIN2(mima->miny,v[1]-hull); 00490 mima->minz = MIN2(mima->minz,v[2]-hull); 00491 mima->maxx = MAX2(mima->maxx,v[0]+hull); 00492 mima->maxy = MAX2(mima->maxy,v[1]+hull); 00493 mima->maxz = MAX2(mima->maxz,v[2]+hull); 00494 00495 copy_v3_v3(v,pccd_M->mprevvert[mface->v2].co); 00496 mima->minx = MIN2(mima->minx,v[0]-hull); 00497 mima->miny = MIN2(mima->miny,v[1]-hull); 00498 mima->minz = MIN2(mima->minz,v[2]-hull); 00499 mima->maxx = MAX2(mima->maxx,v[0]+hull); 00500 mima->maxy = MAX2(mima->maxy,v[1]+hull); 00501 mima->maxz = MAX2(mima->maxz,v[2]+hull); 00502 00503 copy_v3_v3(v,pccd_M->mprevvert[mface->v3].co); 00504 mima->minx = MIN2(mima->minx,v[0]-hull); 00505 mima->miny = MIN2(mima->miny,v[1]-hull); 00506 mima->minz = MIN2(mima->minz,v[2]-hull); 00507 mima->maxx = MAX2(mima->maxx,v[0]+hull); 00508 mima->maxy = MAX2(mima->maxy,v[1]+hull); 00509 mima->maxz = MAX2(mima->maxz,v[2]+hull); 00510 00511 if(mface->v4){ 00512 copy_v3_v3(v,pccd_M->mprevvert[mface->v4].co); 00513 mima->minx = MIN2(mima->minx,v[0]-hull); 00514 mima->miny = MIN2(mima->miny,v[1]-hull); 00515 mima->minz = MIN2(mima->minz,v[2]-hull); 00516 mima->maxx = MAX2(mima->maxx,v[0]+hull); 00517 mima->maxy = MAX2(mima->maxy,v[1]+hull); 00518 mima->maxz = MAX2(mima->maxz,v[2]+hull); 00519 } 00520 00521 00522 mima++; 00523 mface++; 00524 00525 } 00526 return ; 00527 } 00528 00529 static void ccd_mesh_free(ccd_Mesh *ccdm) 00530 { 00531 if(ccdm && (ccdm->savety == CCD_SAVETY )){ /*make sure we're not nuking objects we don't know*/ 00532 MEM_freeN(ccdm->mface); 00533 MEM_freeN(ccdm->mvert); 00534 if (ccdm->mprevvert) MEM_freeN(ccdm->mprevvert); 00535 MEM_freeN(ccdm->mima); 00536 MEM_freeN(ccdm); 00537 ccdm = NULL; 00538 } 00539 } 00540 00541 static void ccd_build_deflector_hash(Scene *scene, Object *vertexowner, GHash *hash) 00542 { 00543 Base *base= scene->base.first; 00544 Object *ob; 00545 00546 if (!hash) return; 00547 while (base) { 00548 /*Only proceed for mesh object in same layer */ 00549 if(base->object->type==OB_MESH && (base->lay & vertexowner->lay)) { 00550 ob= base->object; 00551 if((vertexowner) && (ob == vertexowner)) { 00552 /* if vertexowner is given we don't want to check collision with owner object */ 00553 base = base->next; 00554 continue; 00555 } 00556 00557 /*+++ only with deflecting set */ 00558 if(ob->pd && ob->pd->deflect && BLI_ghash_lookup(hash, ob) == NULL) { 00559 ccd_Mesh *ccdmesh = ccd_mesh_make(ob); 00560 BLI_ghash_insert(hash, ob, ccdmesh); 00561 }/*--- only with deflecting set */ 00562 00563 }/* mesh && layer*/ 00564 base = base->next; 00565 } /* while (base) */ 00566 } 00567 00568 static void ccd_update_deflector_hash(Scene *scene, Object *vertexowner, GHash *hash) 00569 { 00570 Base *base= scene->base.first; 00571 Object *ob; 00572 00573 if ((!hash) || (!vertexowner)) return; 00574 while (base) { 00575 /*Only proceed for mesh object in same layer */ 00576 if(base->object->type==OB_MESH && (base->lay & vertexowner->lay)) { 00577 ob= base->object; 00578 if(ob == vertexowner){ 00579 /* if vertexowner is given we don't want to check collision with owner object */ 00580 base = base->next; 00581 continue; 00582 } 00583 00584 /*+++ only with deflecting set */ 00585 if(ob->pd && ob->pd->deflect) { 00586 ccd_Mesh *ccdmesh = BLI_ghash_lookup(hash,ob); 00587 if (ccdmesh) 00588 ccd_mesh_update(ob,ccdmesh); 00589 }/*--- only with deflecting set */ 00590 00591 }/* mesh && layer*/ 00592 base = base->next; 00593 } /* while (base) */ 00594 } 00595 00596 00597 00598 00599 /*--- collider caching and dicing ---*/ 00600 00601 00602 static int count_mesh_quads(Mesh *me) 00603 { 00604 int a,result = 0; 00605 MFace *mface= me->mface; 00606 00607 if(mface) { 00608 for(a=me->totface; a>0; a--, mface++) { 00609 if(mface->v4) result++; 00610 } 00611 } 00612 return result; 00613 } 00614 00615 static void add_mesh_quad_diag_springs(Object *ob) 00616 { 00617 Mesh *me= ob->data; 00618 MFace *mface= me->mface; 00619 /*BodyPoint *bp;*/ /*UNUSED*/ 00620 BodySpring *bs, *bs_new; 00621 int a ; 00622 00623 if (ob->soft){ 00624 int nofquads; 00625 //float s_shear = ob->soft->shearstiff*ob->soft->shearstiff; 00626 00627 nofquads = count_mesh_quads(me); 00628 if (nofquads) { 00629 /* resize spring-array to hold additional quad springs */ 00630 bs_new= MEM_callocN( (ob->soft->totspring + nofquads *2 )*sizeof(BodySpring), "bodyspring"); 00631 memcpy(bs_new,ob->soft->bspring,(ob->soft->totspring )*sizeof(BodySpring)); 00632 00633 if(ob->soft->bspring) 00634 MEM_freeN(ob->soft->bspring); /* do this before reassigning the pointer or have a 1st class memory leak */ 00635 ob->soft->bspring = bs_new; 00636 00637 /* fill the tail */ 00638 a = 0; 00639 bs = bs_new+ob->soft->totspring; 00640 /*bp= ob->soft->bpoint; */ /*UNUSED*/ 00641 if(mface ) { 00642 for(a=me->totface; a>0; a--, mface++) { 00643 if(mface->v4) { 00644 bs->v1= mface->v1; 00645 bs->v2= mface->v3; 00646 bs->springtype =SB_STIFFQUAD; 00647 bs++; 00648 bs->v1= mface->v2; 00649 bs->v2= mface->v4; 00650 bs->springtype =SB_STIFFQUAD; 00651 bs++; 00652 00653 } 00654 } 00655 } 00656 00657 /* now we can announce new springs */ 00658 ob->soft->totspring += nofquads *2; 00659 } 00660 } 00661 } 00662 00663 static void add_2nd_order_roller(Object *ob,float UNUSED(stiffness), int *counter, int addsprings) 00664 { 00665 /*assume we have a softbody*/ 00666 SoftBody *sb= ob->soft; /* is supposed to be there */ 00667 BodyPoint *bp,*bpo; 00668 BodySpring *bs,*bs2,*bs3= NULL; 00669 int a,b,c,notthis= 0,v0; 00670 if (!sb->bspring){return;} /* we are 2nd order here so 1rst should have been build :) */ 00671 /* first run counting second run adding */ 00672 *counter = 0; 00673 if (addsprings) bs3 = ob->soft->bspring+ob->soft->totspring; 00674 for(a=sb->totpoint, bp= sb->bpoint; a>0; a--, bp++) { 00675 /*scan for neighborhood*/ 00676 bpo = NULL; 00677 v0 = (sb->totpoint-a); 00678 for(b=bp->nofsprings;b>0;b--){ 00679 bs = sb->bspring + bp->springs[b-1]; 00680 /*nasty thing here that springs have two ends 00681 so here we have to make sure we examine the other */ 00682 if (v0 == bs->v1){ 00683 bpo =sb->bpoint+bs->v2; 00684 notthis = bs->v2; 00685 } 00686 else { 00687 if (v0 == bs->v2){ 00688 bpo =sb->bpoint+bs->v1; 00689 notthis = bs->v1; 00690 } 00691 else {printf("oops we should not get here - add_2nd_order_springs");} 00692 } 00693 if (bpo){/* so now we have a 2nd order humpdidump */ 00694 for(c=bpo->nofsprings;c>0;c--){ 00695 bs2 = sb->bspring + bpo->springs[c-1]; 00696 if ((bs2->v1 != notthis) && (bs2->v1 > v0)){ 00697 (*counter)++;/*hit */ 00698 if (addsprings){ 00699 bs3->v1= v0; 00700 bs3->v2= bs2->v1; 00701 bs3->springtype =SB_BEND; 00702 bs3++; 00703 } 00704 } 00705 if ((bs2->v2 !=notthis)&&(bs2->v2 > v0)){ 00706 (*counter)++;/*hit */ 00707 if (addsprings){ 00708 bs3->v1= v0; 00709 bs3->v2= bs2->v2; 00710 bs3->springtype =SB_BEND; 00711 bs3++; 00712 } 00713 00714 } 00715 } 00716 00717 } 00718 00719 } 00720 /*scan for neighborhood done*/ 00721 } 00722 } 00723 00724 00725 static void add_2nd_order_springs(Object *ob,float stiffness) 00726 { 00727 int counter = 0; 00728 BodySpring *bs_new; 00729 stiffness *=stiffness; 00730 00731 add_2nd_order_roller(ob,stiffness,&counter,0); /* counting */ 00732 if (counter) { 00733 /* resize spring-array to hold additional springs */ 00734 bs_new= MEM_callocN( (ob->soft->totspring + counter )*sizeof(BodySpring), "bodyspring"); 00735 memcpy(bs_new,ob->soft->bspring,(ob->soft->totspring )*sizeof(BodySpring)); 00736 00737 if(ob->soft->bspring) 00738 MEM_freeN(ob->soft->bspring); 00739 ob->soft->bspring = bs_new; 00740 00741 add_2nd_order_roller(ob,stiffness,&counter,1); /* adding */ 00742 ob->soft->totspring +=counter ; 00743 } 00744 } 00745 00746 static void add_bp_springlist(BodyPoint *bp,int springID) 00747 { 00748 int *newlist; 00749 00750 if (bp->springs == NULL) { 00751 bp->springs = MEM_callocN( sizeof(int), "bpsprings"); 00752 bp->springs[0] = springID; 00753 bp->nofsprings = 1; 00754 } 00755 else { 00756 bp->nofsprings++; 00757 newlist = MEM_callocN(bp->nofsprings * sizeof(int), "bpsprings"); 00758 memcpy(newlist,bp->springs,(bp->nofsprings-1)* sizeof(int)); 00759 MEM_freeN(bp->springs); 00760 bp->springs = newlist; 00761 bp->springs[bp->nofsprings-1] = springID; 00762 } 00763 } 00764 00765 /* do this once when sb is build 00766 it is O(N^2) so scanning for springs every iteration is too expensive 00767 */ 00768 static void build_bps_springlist(Object *ob) 00769 { 00770 SoftBody *sb= ob->soft; /* is supposed to be there */ 00771 BodyPoint *bp; 00772 BodySpring *bs; 00773 int a,b; 00774 00775 if (sb==NULL) return; /* paranoya check */ 00776 00777 for(a=sb->totpoint, bp= sb->bpoint; a>0; a--, bp++) { 00778 /* throw away old list */ 00779 if (bp->springs) { 00780 MEM_freeN(bp->springs); 00781 bp->springs=NULL; 00782 } 00783 /* scan for attached inner springs */ 00784 for(b=sb->totspring, bs= sb->bspring; b>0; b--, bs++) { 00785 if (( (sb->totpoint-a) == bs->v1) ){ 00786 add_bp_springlist(bp,sb->totspring -b); 00787 } 00788 if (( (sb->totpoint-a) == bs->v2) ){ 00789 add_bp_springlist(bp,sb->totspring -b); 00790 } 00791 }/*for springs*/ 00792 }/*for bp*/ 00793 } 00794 00795 static void calculate_collision_balls(Object *ob) 00796 { 00797 SoftBody *sb= ob->soft; /* is supposed to be there */ 00798 BodyPoint *bp; 00799 BodySpring *bs; 00800 int a,b,akku_count; 00801 float min,max,akku; 00802 00803 if (sb==NULL) return; /* paranoya check */ 00804 00805 for(a=sb->totpoint, bp= sb->bpoint; a>0; a--, bp++) { 00806 bp->colball=0; 00807 akku =0.0f; 00808 akku_count=0; 00809 min = 1e22f; 00810 max = -1e22f; 00811 /* first estimation based on attached */ 00812 for(b=bp->nofsprings;b>0;b--){ 00813 bs = sb->bspring + bp->springs[b-1]; 00814 if (bs->springtype == SB_EDGE){ 00815 akku += bs->len; 00816 akku_count++, 00817 min = MIN2(bs->len,min); 00818 max = MAX2(bs->len,max); 00819 } 00820 } 00821 00822 if (akku_count > 0) { 00823 if (sb->sbc_mode == SBC_MODE_MANUAL){ 00824 bp->colball=sb->colball; 00825 } 00826 if (sb->sbc_mode == SBC_MODE_AVG){ 00827 bp->colball = akku/(float)akku_count*sb->colball; 00828 } 00829 if (sb->sbc_mode == SBC_MODE_MIN){ 00830 bp->colball=min*sb->colball; 00831 } 00832 if (sb->sbc_mode == SBC_MODE_MAX){ 00833 bp->colball=max*sb->colball; 00834 } 00835 if (sb->sbc_mode == SBC_MODE_AVGMINMAX){ 00836 bp->colball = (min + max)/2.0f*sb->colball; 00837 } 00838 } 00839 else bp->colball=0; 00840 }/*for bp*/ 00841 } 00842 00843 00844 /* creates new softbody if didn't exist yet, makes new points and springs arrays */ 00845 static void renew_softbody(Scene *scene, Object *ob, int totpoint, int totspring) 00846 { 00847 SoftBody *sb; 00848 int i; 00849 short softflag; 00850 if(ob->soft==NULL) ob->soft= sbNew(scene); 00851 else free_softbody_intern(ob->soft); 00852 sb= ob->soft; 00853 softflag=ob->softflag; 00854 00855 if(totpoint) { 00856 sb->totpoint= totpoint; 00857 sb->totspring= totspring; 00858 00859 sb->bpoint= MEM_mallocN( totpoint*sizeof(BodyPoint), "bodypoint"); 00860 if(totspring) 00861 sb->bspring= MEM_mallocN( totspring*sizeof(BodySpring), "bodyspring"); 00862 00863 /* initialise BodyPoint array */ 00864 for (i=0; i<totpoint; i++) { 00865 BodyPoint *bp = &sb->bpoint[i]; 00866 00867 00868 /* hum as far as i see this is overridden by _final_goal() now jow_go_for2_5 */ 00869 /* sadly breaks compatibility with older versions */ 00870 /* but makes goals behave the same for meshes, lattices and curves */ 00871 if(softflag & OB_SB_GOAL) { 00872 bp->goal= sb->defgoal; 00873 } 00874 else { 00875 bp->goal= 0.0f; 00876 /* so this will definily be below SOFTGOALSNAP */ 00877 } 00878 00879 bp->nofsprings= 0; 00880 bp->springs= NULL; 00881 bp->choke = 0.0f; 00882 bp->choke2 = 0.0f; 00883 bp->frozen = 1.0f; 00884 bp->colball = 0.0f; 00885 bp->loc_flag = 0; 00886 bp->springweight = 1.0f; 00887 bp->mass = 1.0f; 00888 } 00889 } 00890 } 00891 00892 static void free_softbody_baked(SoftBody *sb) 00893 { 00894 SBVertex *key; 00895 int k; 00896 00897 for(k=0; k<sb->totkey; k++) { 00898 key= *(sb->keys + k); 00899 if(key) MEM_freeN(key); 00900 } 00901 if(sb->keys) MEM_freeN(sb->keys); 00902 00903 sb->keys= NULL; 00904 sb->totkey= 0; 00905 } 00906 static void free_scratch(SoftBody *sb) 00907 { 00908 if(sb->scratch){ 00909 /* todo make sure everything is cleaned up nicly */ 00910 if (sb->scratch->colliderhash){ 00911 BLI_ghash_free(sb->scratch->colliderhash, NULL, 00912 (GHashValFreeFP) ccd_mesh_free); /*this hoepfully will free all caches*/ 00913 sb->scratch->colliderhash = NULL; 00914 } 00915 if (sb->scratch->bodyface){ 00916 MEM_freeN(sb->scratch->bodyface); 00917 } 00918 if (sb->scratch->Ref.ivert){ 00919 MEM_freeN(sb->scratch->Ref.ivert); 00920 } 00921 MEM_freeN(sb->scratch); 00922 sb->scratch = NULL; 00923 } 00924 00925 } 00926 00927 /* only frees internal data */ 00928 static void free_softbody_intern(SoftBody *sb) 00929 { 00930 if(sb) { 00931 int a; 00932 BodyPoint *bp; 00933 00934 if(sb->bpoint){ 00935 for(a=sb->totpoint, bp= sb->bpoint; a>0; a--, bp++) { 00936 /* free spring list */ 00937 if (bp->springs != NULL) { 00938 MEM_freeN(bp->springs); 00939 } 00940 } 00941 MEM_freeN(sb->bpoint); 00942 } 00943 00944 if(sb->bspring) MEM_freeN(sb->bspring); 00945 00946 sb->totpoint= sb->totspring= 0; 00947 sb->bpoint= NULL; 00948 sb->bspring= NULL; 00949 00950 free_scratch(sb); 00951 free_softbody_baked(sb); 00952 } 00953 } 00954 00955 00956 /* ************ dynamics ********** */ 00957 00958 /* the most general (micro physics correct) way to do collision 00959 ** (only needs the current particle position) 00960 ** 00961 ** it actually checks if the particle intrudes a short range force field generated 00962 ** by the faces of the target object and returns a force to drive the particel out 00963 ** the strenght of the field grows exponetially if the particle is on the 'wrong' side of the face 00964 ** 'wrong' side : projection to the face normal is negative (all referred to a vertex in the face) 00965 ** 00966 ** flaw of this: 'fast' particles as well as 'fast' colliding faces 00967 ** give a 'tunnel' effect such that the particle passes through the force field 00968 ** without ever 'seeing' it 00969 ** this is fully compliant to heisenberg: h >= fuzzy(location) * fuzzy(time) 00970 ** besides our h is way larger than in QM because forces propagate way slower here 00971 ** we have to deal with fuzzy(time) in the range of 1/25 seconds (typical frame rate) 00972 ** yup collision targets are not known here any better 00973 ** and 1/25 second is looong compared to real collision events 00974 ** Q: why not use 'simple' collision here like bouncing back a particle 00975 ** --> reverting is velocity on the face normal 00976 ** A: because our particles are not alone here 00977 ** and need to tell their neighbours exactly what happens via spring forces 00978 ** unless sbObjectStep( .. ) is called on sub frame timing level 00979 ** BTW that also questions the use of a 'implicit' solvers on softbodies 00980 ** since that would only valid for 'slow' moving collision targets and dito particles 00981 */ 00982 00983 /* aye this belongs to arith.c */ 00984 static void Vec3PlusStVec(float *v, float s, float *v1) 00985 { 00986 v[0] += s*v1[0]; 00987 v[1] += s*v1[1]; 00988 v[2] += s*v1[2]; 00989 } 00990 00991 /* +++ dependancy information functions*/ 00992 00993 static int are_there_deflectors(Scene *scene, unsigned int layer) 00994 { 00995 Base *base; 00996 00997 for(base = scene->base.first; base; base= base->next) { 00998 if( (base->lay & layer) && base->object->pd) { 00999 if(base->object->pd->deflect) 01000 return 1; 01001 } 01002 } 01003 return 0; 01004 } 01005 01006 static int query_external_colliders(Scene *scene, Object *me) 01007 { 01008 return(are_there_deflectors(scene, me->lay)); 01009 } 01010 /* --- dependancy information functions*/ 01011 01012 01013 /* +++ the aabb "force" section*/ 01014 static int sb_detect_aabb_collisionCached( float UNUSED(force[3]), unsigned int UNUSED(par_layer),struct Object *vertexowner,float UNUSED(time)) 01015 { 01016 Object *ob; 01017 SoftBody *sb=vertexowner->soft; 01018 GHash *hash; 01019 GHashIterator *ihash; 01020 float aabbmin[3],aabbmax[3]; 01021 int deflected=0; 01022 #if 0 01023 int a; 01024 #endif 01025 01026 if ((sb == NULL) || (sb->scratch ==NULL)) return 0; 01027 copy_v3_v3(aabbmin,sb->scratch->aabbmin); 01028 copy_v3_v3(aabbmax,sb->scratch->aabbmax); 01029 01030 hash = vertexowner->soft->scratch->colliderhash; 01031 ihash = BLI_ghashIterator_new(hash); 01032 while (!BLI_ghashIterator_isDone(ihash) ) { 01033 01034 ccd_Mesh *ccdm = BLI_ghashIterator_getValue (ihash); 01035 ob = BLI_ghashIterator_getKey (ihash); 01036 /* only with deflecting set */ 01037 if(ob->pd && ob->pd->deflect) { 01038 #if 0 /* UNUSED */ 01039 MFace *mface= NULL; 01040 MVert *mvert= NULL; 01041 MVert *mprevvert= NULL; 01042 ccdf_minmax *mima= NULL; 01043 #endif 01044 if(ccdm){ 01045 #if 0 /* UNUSED */ 01046 mface= ccdm->mface; 01047 mvert= ccdm->mvert; 01048 mprevvert= ccdm->mprevvert; 01049 mima= ccdm->mima; 01050 a = ccdm->totface; 01051 #endif 01052 if ((aabbmax[0] < ccdm->bbmin[0]) || 01053 (aabbmax[1] < ccdm->bbmin[1]) || 01054 (aabbmax[2] < ccdm->bbmin[2]) || 01055 (aabbmin[0] > ccdm->bbmax[0]) || 01056 (aabbmin[1] > ccdm->bbmax[1]) || 01057 (aabbmin[2] > ccdm->bbmax[2]) ) { 01058 /* boxes dont intersect */ 01059 BLI_ghashIterator_step(ihash); 01060 continue; 01061 } 01062 01063 /* so now we have the 2 boxes overlapping */ 01064 /* forces actually not used */ 01065 deflected = 2; 01066 01067 } 01068 else{ 01069 /*aye that should be cached*/ 01070 printf("missing cache error \n"); 01071 BLI_ghashIterator_step(ihash); 01072 continue; 01073 } 01074 } /* if(ob->pd && ob->pd->deflect) */ 01075 BLI_ghashIterator_step(ihash); 01076 } /* while () */ 01077 BLI_ghashIterator_free(ihash); 01078 return deflected; 01079 } 01080 /* --- the aabb section*/ 01081 01082 01083 /* +++ the face external section*/ 01084 static int sb_detect_face_pointCached(float face_v1[3],float face_v2[3],float face_v3[3],float *damp, 01085 float force[3], unsigned int UNUSED(par_layer),struct Object *vertexowner,float time) 01086 { 01087 Object *ob; 01088 GHash *hash; 01089 GHashIterator *ihash; 01090 float nv1[3], edge1[3], edge2[3], d_nvect[3], aabbmin[3],aabbmax[3]; 01091 float facedist,outerfacethickness,tune = 10.f; 01092 int a, deflected=0; 01093 01094 aabbmin[0] = MIN3(face_v1[0],face_v2[0],face_v3[0]); 01095 aabbmin[1] = MIN3(face_v1[1],face_v2[1],face_v3[1]); 01096 aabbmin[2] = MIN3(face_v1[2],face_v2[2],face_v3[2]); 01097 aabbmax[0] = MAX3(face_v1[0],face_v2[0],face_v3[0]); 01098 aabbmax[1] = MAX3(face_v1[1],face_v2[1],face_v3[1]); 01099 aabbmax[2] = MAX3(face_v1[2],face_v2[2],face_v3[2]); 01100 01101 /* calculate face normal once again SIGH */ 01102 sub_v3_v3v3(edge1, face_v1, face_v2); 01103 sub_v3_v3v3(edge2, face_v3, face_v2); 01104 cross_v3_v3v3(d_nvect, edge2, edge1); 01105 normalize_v3(d_nvect); 01106 01107 01108 hash = vertexowner->soft->scratch->colliderhash; 01109 ihash = BLI_ghashIterator_new(hash); 01110 while (!BLI_ghashIterator_isDone(ihash) ) { 01111 01112 ccd_Mesh *ccdm = BLI_ghashIterator_getValue (ihash); 01113 ob = BLI_ghashIterator_getKey (ihash); 01114 /* only with deflecting set */ 01115 if(ob->pd && ob->pd->deflect) { 01116 MVert *mvert= NULL; 01117 MVert *mprevvert= NULL; 01118 if(ccdm){ 01119 mvert= ccdm->mvert; 01120 a = ccdm->totvert; 01121 mprevvert= ccdm->mprevvert; 01122 outerfacethickness =ob->pd->pdef_sboft; 01123 if ((aabbmax[0] < ccdm->bbmin[0]) || 01124 (aabbmax[1] < ccdm->bbmin[1]) || 01125 (aabbmax[2] < ccdm->bbmin[2]) || 01126 (aabbmin[0] > ccdm->bbmax[0]) || 01127 (aabbmin[1] > ccdm->bbmax[1]) || 01128 (aabbmin[2] > ccdm->bbmax[2]) ) { 01129 /* boxes dont intersect */ 01130 BLI_ghashIterator_step(ihash); 01131 continue; 01132 } 01133 01134 } 01135 else{ 01136 /*aye that should be cached*/ 01137 printf("missing cache error \n"); 01138 BLI_ghashIterator_step(ihash); 01139 continue; 01140 } 01141 01142 01143 /* use mesh*/ 01144 if (mvert) { 01145 while(a){ 01146 copy_v3_v3(nv1,mvert[a-1].co); 01147 if(mprevvert){ 01148 mul_v3_fl(nv1,time); 01149 Vec3PlusStVec(nv1,(1.0f-time),mprevvert[a-1].co); 01150 } 01151 /* origin to face_v2*/ 01152 sub_v3_v3(nv1, face_v2); 01153 facedist = dot_v3v3(nv1,d_nvect); 01154 if (ABS(facedist)<outerfacethickness){ 01155 if (isect_point_tri_prism_v3(nv1, face_v1,face_v2,face_v3) ){ 01156 float df; 01157 if (facedist > 0){ 01158 df = (outerfacethickness-facedist)/outerfacethickness; 01159 } 01160 else { 01161 df = (outerfacethickness+facedist)/outerfacethickness; 01162 } 01163 01164 *damp=df*tune*ob->pd->pdef_sbdamp; 01165 01166 df = 0.01f*exp(- 100.0f*df); 01167 Vec3PlusStVec(force,-df,d_nvect); 01168 deflected = 3; 01169 } 01170 } 01171 a--; 01172 }/* while(a)*/ 01173 } /* if (mvert) */ 01174 } /* if(ob->pd && ob->pd->deflect) */ 01175 BLI_ghashIterator_step(ihash); 01176 } /* while () */ 01177 BLI_ghashIterator_free(ihash); 01178 return deflected; 01179 } 01180 01181 01182 static int sb_detect_face_collisionCached(float face_v1[3],float face_v2[3],float face_v3[3],float *damp, 01183 float force[3], unsigned int UNUSED(par_layer),struct Object *vertexowner,float time) 01184 { 01185 Object *ob; 01186 GHash *hash; 01187 GHashIterator *ihash; 01188 float nv1[3], nv2[3], nv3[3], nv4[3], edge1[3], edge2[3], d_nvect[3], aabbmin[3],aabbmax[3]; 01189 float t,tune = 10.0f; 01190 int a, deflected=0; 01191 01192 aabbmin[0] = MIN3(face_v1[0],face_v2[0],face_v3[0]); 01193 aabbmin[1] = MIN3(face_v1[1],face_v2[1],face_v3[1]); 01194 aabbmin[2] = MIN3(face_v1[2],face_v2[2],face_v3[2]); 01195 aabbmax[0] = MAX3(face_v1[0],face_v2[0],face_v3[0]); 01196 aabbmax[1] = MAX3(face_v1[1],face_v2[1],face_v3[1]); 01197 aabbmax[2] = MAX3(face_v1[2],face_v2[2],face_v3[2]); 01198 01199 hash = vertexowner->soft->scratch->colliderhash; 01200 ihash = BLI_ghashIterator_new(hash); 01201 while (!BLI_ghashIterator_isDone(ihash) ) { 01202 01203 ccd_Mesh *ccdm = BLI_ghashIterator_getValue (ihash); 01204 ob = BLI_ghashIterator_getKey (ihash); 01205 /* only with deflecting set */ 01206 if(ob->pd && ob->pd->deflect) { 01207 MFace *mface= NULL; 01208 MVert *mvert= NULL; 01209 MVert *mprevvert= NULL; 01210 ccdf_minmax *mima= NULL; 01211 if(ccdm){ 01212 mface= ccdm->mface; 01213 mvert= ccdm->mvert; 01214 mprevvert= ccdm->mprevvert; 01215 mima= ccdm->mima; 01216 a = ccdm->totface; 01217 01218 if ((aabbmax[0] < ccdm->bbmin[0]) || 01219 (aabbmax[1] < ccdm->bbmin[1]) || 01220 (aabbmax[2] < ccdm->bbmin[2]) || 01221 (aabbmin[0] > ccdm->bbmax[0]) || 01222 (aabbmin[1] > ccdm->bbmax[1]) || 01223 (aabbmin[2] > ccdm->bbmax[2]) ) { 01224 /* boxes dont intersect */ 01225 BLI_ghashIterator_step(ihash); 01226 continue; 01227 } 01228 01229 } 01230 else{ 01231 /*aye that should be cached*/ 01232 printf("missing cache error \n"); 01233 BLI_ghashIterator_step(ihash); 01234 continue; 01235 } 01236 01237 01238 /* use mesh*/ 01239 while (a--) { 01240 if ( 01241 (aabbmax[0] < mima->minx) || 01242 (aabbmin[0] > mima->maxx) || 01243 (aabbmax[1] < mima->miny) || 01244 (aabbmin[1] > mima->maxy) || 01245 (aabbmax[2] < mima->minz) || 01246 (aabbmin[2] > mima->maxz) 01247 ) { 01248 mface++; 01249 mima++; 01250 continue; 01251 } 01252 01253 01254 if (mvert){ 01255 01256 copy_v3_v3(nv1,mvert[mface->v1].co); 01257 copy_v3_v3(nv2,mvert[mface->v2].co); 01258 copy_v3_v3(nv3,mvert[mface->v3].co); 01259 if (mface->v4){ 01260 copy_v3_v3(nv4,mvert[mface->v4].co); 01261 } 01262 if (mprevvert){ 01263 mul_v3_fl(nv1,time); 01264 Vec3PlusStVec(nv1,(1.0f-time),mprevvert[mface->v1].co); 01265 01266 mul_v3_fl(nv2,time); 01267 Vec3PlusStVec(nv2,(1.0f-time),mprevvert[mface->v2].co); 01268 01269 mul_v3_fl(nv3,time); 01270 Vec3PlusStVec(nv3,(1.0f-time),mprevvert[mface->v3].co); 01271 01272 if (mface->v4){ 01273 mul_v3_fl(nv4,time); 01274 Vec3PlusStVec(nv4,(1.0f-time),mprevvert[mface->v4].co); 01275 } 01276 } 01277 } 01278 01279 /* switch origin to be nv2*/ 01280 sub_v3_v3v3(edge1, nv1, nv2); 01281 sub_v3_v3v3(edge2, nv3, nv2); 01282 cross_v3_v3v3(d_nvect, edge2, edge1); 01283 normalize_v3(d_nvect); 01284 if ( 01285 isect_line_tri_v3(nv1, nv2, face_v1, face_v2, face_v3, &t, NULL) || 01286 isect_line_tri_v3(nv2, nv3, face_v1, face_v2, face_v3, &t, NULL) || 01287 isect_line_tri_v3(nv3, nv1, face_v1, face_v2, face_v3, &t, NULL) ){ 01288 Vec3PlusStVec(force,-0.5f,d_nvect); 01289 *damp=tune*ob->pd->pdef_sbdamp; 01290 deflected = 2; 01291 } 01292 if (mface->v4){ /* quad */ 01293 /* switch origin to be nv4 */ 01294 sub_v3_v3v3(edge1, nv3, nv4); 01295 sub_v3_v3v3(edge2, nv1, nv4); 01296 cross_v3_v3v3(d_nvect, edge2, edge1); 01297 normalize_v3(d_nvect); 01298 if ( 01299 /* isect_line_tri_v3(nv1, nv3, face_v1, face_v2, face_v3, &t, NULL) || 01300 we did that edge already */ 01301 isect_line_tri_v3(nv3, nv4, face_v1, face_v2, face_v3, &t, NULL) || 01302 isect_line_tri_v3(nv4, nv1, face_v1, face_v2, face_v3, &t, NULL) ){ 01303 Vec3PlusStVec(force,-0.5f,d_nvect); 01304 *damp=tune*ob->pd->pdef_sbdamp; 01305 deflected = 2; 01306 } 01307 } 01308 mface++; 01309 mima++; 01310 }/* while a */ 01311 } /* if(ob->pd && ob->pd->deflect) */ 01312 BLI_ghashIterator_step(ihash); 01313 } /* while () */ 01314 BLI_ghashIterator_free(ihash); 01315 return deflected; 01316 } 01317 01318 01319 01320 static void scan_for_ext_face_forces(Object *ob,float timenow) 01321 { 01322 SoftBody *sb = ob->soft; 01323 BodyFace *bf; 01324 int a; 01325 float damp=0.0f,choke=1.0f; 01326 float tune = -10.0f; 01327 float feedback[3]; 01328 01329 if (sb && sb->scratch->totface){ 01330 01331 01332 bf = sb->scratch->bodyface; 01333 for(a=0; a<sb->scratch->totface; a++, bf++) { 01334 bf->ext_force[0]=bf->ext_force[1]=bf->ext_force[2]=0.0f; 01335 /*+++edges intruding*/ 01336 bf->flag &= ~BFF_INTERSECT; 01337 feedback[0]=feedback[1]=feedback[2]=0.0f; 01338 if (sb_detect_face_collisionCached(sb->bpoint[bf->v1].pos,sb->bpoint[bf->v2].pos, sb->bpoint[bf->v3].pos, 01339 &damp, feedback, ob->lay ,ob , timenow)){ 01340 Vec3PlusStVec(sb->bpoint[bf->v1].force,tune,feedback); 01341 Vec3PlusStVec(sb->bpoint[bf->v2].force,tune,feedback); 01342 Vec3PlusStVec(sb->bpoint[bf->v3].force,tune,feedback); 01343 // Vec3PlusStVec(bf->ext_force,tune,feedback); 01344 bf->flag |= BFF_INTERSECT; 01345 choke = MIN2(MAX2(damp,choke),1.0f); 01346 } 01347 01348 feedback[0]=feedback[1]=feedback[2]=0.0f; 01349 if ((bf->v4) && (sb_detect_face_collisionCached(sb->bpoint[bf->v1].pos,sb->bpoint[bf->v3].pos, sb->bpoint[bf->v4].pos, 01350 &damp, feedback, ob->lay ,ob , timenow))){ 01351 Vec3PlusStVec(sb->bpoint[bf->v1].force,tune,feedback); 01352 Vec3PlusStVec(sb->bpoint[bf->v3].force,tune,feedback); 01353 Vec3PlusStVec(sb->bpoint[bf->v4].force,tune,feedback); 01354 // Vec3PlusStVec(bf->ext_force,tune,feedback); 01355 bf->flag |= BFF_INTERSECT; 01356 choke = MIN2(MAX2(damp,choke),1.0f); 01357 } 01358 /*---edges intruding*/ 01359 01360 /*+++ close vertices*/ 01361 if (( bf->flag & BFF_INTERSECT)==0){ 01362 bf->flag &= ~BFF_CLOSEVERT; 01363 tune = -1.0f; 01364 feedback[0]=feedback[1]=feedback[2]=0.0f; 01365 if (sb_detect_face_pointCached(sb->bpoint[bf->v1].pos,sb->bpoint[bf->v2].pos, sb->bpoint[bf->v3].pos, 01366 &damp, feedback, ob->lay ,ob , timenow)){ 01367 Vec3PlusStVec(sb->bpoint[bf->v1].force,tune,feedback); 01368 Vec3PlusStVec(sb->bpoint[bf->v2].force,tune,feedback); 01369 Vec3PlusStVec(sb->bpoint[bf->v3].force,tune,feedback); 01370 // Vec3PlusStVec(bf->ext_force,tune,feedback); 01371 bf->flag |= BFF_CLOSEVERT; 01372 choke = MIN2(MAX2(damp,choke),1.0f); 01373 } 01374 01375 feedback[0]=feedback[1]=feedback[2]=0.0f; 01376 if ((bf->v4) && (sb_detect_face_pointCached(sb->bpoint[bf->v1].pos,sb->bpoint[bf->v3].pos, sb->bpoint[bf->v4].pos, 01377 &damp, feedback, ob->lay ,ob , timenow))){ 01378 Vec3PlusStVec(sb->bpoint[bf->v1].force,tune,feedback); 01379 Vec3PlusStVec(sb->bpoint[bf->v3].force,tune,feedback); 01380 Vec3PlusStVec(sb->bpoint[bf->v4].force,tune,feedback); 01381 // Vec3PlusStVec(bf->ext_force,tune,feedback); 01382 bf->flag |= BFF_CLOSEVERT; 01383 choke = MIN2(MAX2(damp,choke),1.0f); 01384 } 01385 } 01386 /*--- close vertices*/ 01387 } 01388 bf = sb->scratch->bodyface; 01389 for(a=0; a<sb->scratch->totface; a++, bf++) { 01390 if (( bf->flag & BFF_INTERSECT) || ( bf->flag & BFF_CLOSEVERT)) 01391 { 01392 sb->bpoint[bf->v1].choke2=MAX2(sb->bpoint[bf->v1].choke2,choke); 01393 sb->bpoint[bf->v2].choke2=MAX2(sb->bpoint[bf->v2].choke2,choke); 01394 sb->bpoint[bf->v3].choke2=MAX2(sb->bpoint[bf->v3].choke2,choke); 01395 if (bf->v4){ 01396 sb->bpoint[bf->v2].choke2=MAX2(sb->bpoint[bf->v2].choke2,choke); 01397 } 01398 } 01399 } 01400 } 01401 } 01402 01403 /* --- the face external section*/ 01404 01405 01406 /* +++ the spring external section*/ 01407 01408 static int sb_detect_edge_collisionCached(float edge_v1[3],float edge_v2[3],float *damp, 01409 float force[3], unsigned int UNUSED(par_layer),struct Object *vertexowner,float time) 01410 { 01411 Object *ob; 01412 GHash *hash; 01413 GHashIterator *ihash; 01414 float nv1[3], nv2[3], nv3[3], nv4[3], edge1[3], edge2[3], d_nvect[3], aabbmin[3],aabbmax[3]; 01415 float t,el; 01416 int a, deflected=0; 01417 01418 aabbmin[0] = MIN2(edge_v1[0],edge_v2[0]); 01419 aabbmin[1] = MIN2(edge_v1[1],edge_v2[1]); 01420 aabbmin[2] = MIN2(edge_v1[2],edge_v2[2]); 01421 aabbmax[0] = MAX2(edge_v1[0],edge_v2[0]); 01422 aabbmax[1] = MAX2(edge_v1[1],edge_v2[1]); 01423 aabbmax[2] = MAX2(edge_v1[2],edge_v2[2]); 01424 01425 el = len_v3v3(edge_v1,edge_v2); 01426 01427 hash = vertexowner->soft->scratch->colliderhash; 01428 ihash = BLI_ghashIterator_new(hash); 01429 while (!BLI_ghashIterator_isDone(ihash) ) { 01430 01431 ccd_Mesh *ccdm = BLI_ghashIterator_getValue (ihash); 01432 ob = BLI_ghashIterator_getKey (ihash); 01433 /* only with deflecting set */ 01434 if(ob->pd && ob->pd->deflect) { 01435 MFace *mface= NULL; 01436 MVert *mvert= NULL; 01437 MVert *mprevvert= NULL; 01438 ccdf_minmax *mima= NULL; 01439 if(ccdm){ 01440 mface= ccdm->mface; 01441 mvert= ccdm->mvert; 01442 mprevvert= ccdm->mprevvert; 01443 mima= ccdm->mima; 01444 a = ccdm->totface; 01445 01446 if ((aabbmax[0] < ccdm->bbmin[0]) || 01447 (aabbmax[1] < ccdm->bbmin[1]) || 01448 (aabbmax[2] < ccdm->bbmin[2]) || 01449 (aabbmin[0] > ccdm->bbmax[0]) || 01450 (aabbmin[1] > ccdm->bbmax[1]) || 01451 (aabbmin[2] > ccdm->bbmax[2]) ) { 01452 /* boxes dont intersect */ 01453 BLI_ghashIterator_step(ihash); 01454 continue; 01455 } 01456 01457 } 01458 else{ 01459 /*aye that should be cached*/ 01460 printf("missing cache error \n"); 01461 BLI_ghashIterator_step(ihash); 01462 continue; 01463 } 01464 01465 01466 /* use mesh*/ 01467 while (a--) { 01468 if ( 01469 (aabbmax[0] < mima->minx) || 01470 (aabbmin[0] > mima->maxx) || 01471 (aabbmax[1] < mima->miny) || 01472 (aabbmin[1] > mima->maxy) || 01473 (aabbmax[2] < mima->minz) || 01474 (aabbmin[2] > mima->maxz) 01475 ) { 01476 mface++; 01477 mima++; 01478 continue; 01479 } 01480 01481 01482 if (mvert){ 01483 01484 copy_v3_v3(nv1,mvert[mface->v1].co); 01485 copy_v3_v3(nv2,mvert[mface->v2].co); 01486 copy_v3_v3(nv3,mvert[mface->v3].co); 01487 if (mface->v4){ 01488 copy_v3_v3(nv4,mvert[mface->v4].co); 01489 } 01490 if (mprevvert){ 01491 mul_v3_fl(nv1,time); 01492 Vec3PlusStVec(nv1,(1.0f-time),mprevvert[mface->v1].co); 01493 01494 mul_v3_fl(nv2,time); 01495 Vec3PlusStVec(nv2,(1.0f-time),mprevvert[mface->v2].co); 01496 01497 mul_v3_fl(nv3,time); 01498 Vec3PlusStVec(nv3,(1.0f-time),mprevvert[mface->v3].co); 01499 01500 if (mface->v4){ 01501 mul_v3_fl(nv4,time); 01502 Vec3PlusStVec(nv4,(1.0f-time),mprevvert[mface->v4].co); 01503 } 01504 } 01505 } 01506 01507 /* switch origin to be nv2*/ 01508 sub_v3_v3v3(edge1, nv1, nv2); 01509 sub_v3_v3v3(edge2, nv3, nv2); 01510 01511 cross_v3_v3v3(d_nvect, edge2, edge1); 01512 normalize_v3(d_nvect); 01513 if ( isect_line_tri_v3(edge_v1, edge_v2, nv1, nv2, nv3, &t, NULL)){ 01514 float v1[3],v2[3]; 01515 float intrusiondepth,i1,i2; 01516 sub_v3_v3v3(v1, edge_v1, nv2); 01517 sub_v3_v3v3(v2, edge_v2, nv2); 01518 i1 = dot_v3v3(v1,d_nvect); 01519 i2 = dot_v3v3(v2,d_nvect); 01520 intrusiondepth = -MIN2(i1,i2)/el; 01521 Vec3PlusStVec(force,intrusiondepth,d_nvect); 01522 *damp=ob->pd->pdef_sbdamp; 01523 deflected = 2; 01524 } 01525 if (mface->v4){ /* quad */ 01526 /* switch origin to be nv4 */ 01527 sub_v3_v3v3(edge1, nv3, nv4); 01528 sub_v3_v3v3(edge2, nv1, nv4); 01529 01530 cross_v3_v3v3(d_nvect, edge2, edge1); 01531 normalize_v3(d_nvect); 01532 if (isect_line_tri_v3( edge_v1, edge_v2,nv1, nv3, nv4, &t, NULL)){ 01533 float v1[3],v2[3]; 01534 float intrusiondepth,i1,i2; 01535 sub_v3_v3v3(v1, edge_v1, nv4); 01536 sub_v3_v3v3(v2, edge_v2, nv4); 01537 i1 = dot_v3v3(v1,d_nvect); 01538 i2 = dot_v3v3(v2,d_nvect); 01539 intrusiondepth = -MIN2(i1,i2)/el; 01540 01541 01542 Vec3PlusStVec(force,intrusiondepth,d_nvect); 01543 *damp=ob->pd->pdef_sbdamp; 01544 deflected = 2; 01545 } 01546 } 01547 mface++; 01548 mima++; 01549 }/* while a */ 01550 } /* if(ob->pd && ob->pd->deflect) */ 01551 BLI_ghashIterator_step(ihash); 01552 } /* while () */ 01553 BLI_ghashIterator_free(ihash); 01554 return deflected; 01555 } 01556 01557 static void _scan_for_ext_spring_forces(Scene *scene, Object *ob, float timenow, int ifirst, int ilast, struct ListBase *do_effector) 01558 { 01559 SoftBody *sb = ob->soft; 01560 int a; 01561 float damp; 01562 float feedback[3]; 01563 01564 if (sb && sb->totspring){ 01565 for(a=ifirst; a<ilast; a++) { 01566 BodySpring *bs = &sb->bspring[a]; 01567 bs->ext_force[0]=bs->ext_force[1]=bs->ext_force[2]=0.0f; 01568 feedback[0]=feedback[1]=feedback[2]=0.0f; 01569 bs->flag &= ~BSF_INTERSECT; 01570 01571 if (bs->springtype == SB_EDGE){ 01572 /* +++ springs colliding */ 01573 if (ob->softflag & OB_SB_EDGECOLL){ 01574 if ( sb_detect_edge_collisionCached (sb->bpoint[bs->v1].pos , sb->bpoint[bs->v2].pos, 01575 &damp,feedback,ob->lay,ob,timenow)){ 01576 add_v3_v3(bs->ext_force, feedback); 01577 bs->flag |= BSF_INTERSECT; 01578 //bs->cf=damp; 01579 bs->cf=sb->choke*0.01f; 01580 01581 } 01582 } 01583 /* ---- springs colliding */ 01584 01585 /* +++ springs seeing wind ... n stuff depending on their orientation*/ 01586 /* note we don't use sb->mediafrict but use sb->aeroedge for magnitude of effect*/ 01587 if(sb->aeroedge){ 01588 float vel[3],sp[3],pr[3],force[3]; 01589 float f,windfactor = 0.25f; 01590 /*see if we have wind*/ 01591 if(do_effector) { 01592 EffectedPoint epoint; 01593 float speed[3]={0.0f,0.0f,0.0f}; 01594 float pos[3]; 01595 mid_v3_v3v3(pos, sb->bpoint[bs->v1].pos , sb->bpoint[bs->v2].pos); 01596 mid_v3_v3v3(vel, sb->bpoint[bs->v1].vec , sb->bpoint[bs->v2].vec); 01597 pd_point_from_soft(scene, pos, vel, -1, &epoint); 01598 pdDoEffectors(do_effector, NULL, sb->effector_weights, &epoint, force, speed); 01599 01600 mul_v3_fl(speed,windfactor); 01601 add_v3_v3(vel, speed); 01602 } 01603 /* media in rest */ 01604 else{ 01605 add_v3_v3v3(vel, sb->bpoint[bs->v1].vec , sb->bpoint[bs->v2].vec); 01606 } 01607 f = normalize_v3(vel); 01608 f = -0.0001f*f*f*sb->aeroedge; 01609 /* (todo) add a nice angle dependant function done for now BUT */ 01610 /* still there could be some nice drag/lift function, but who needs it */ 01611 01612 sub_v3_v3v3(sp, sb->bpoint[bs->v1].pos , sb->bpoint[bs->v2].pos); 01613 project_v3_v3v3(pr,vel,sp); 01614 sub_v3_v3(vel, pr); 01615 normalize_v3(vel); 01616 if (ob->softflag & OB_SB_AERO_ANGLE){ 01617 normalize_v3(sp); 01618 Vec3PlusStVec(bs->ext_force,f*(1.0f-ABS(dot_v3v3(vel,sp))),vel); 01619 } 01620 else{ 01621 Vec3PlusStVec(bs->ext_force,f,vel); // to keep compatible with 2.45 release files 01622 } 01623 } 01624 /* --- springs seeing wind */ 01625 } 01626 } 01627 } 01628 } 01629 01630 01631 static void scan_for_ext_spring_forces(Scene *scene, Object *ob, float timenow) 01632 { 01633 SoftBody *sb = ob->soft; 01634 ListBase *do_effector = NULL; 01635 01636 do_effector = pdInitEffectors(scene, ob, NULL, sb->effector_weights); 01637 _scan_for_ext_spring_forces(scene, ob, timenow, 0, sb->totspring, do_effector); 01638 pdEndEffectors(&do_effector); 01639 } 01640 01641 static void *exec_scan_for_ext_spring_forces(void *data) 01642 { 01643 SB_thread_context *pctx = (SB_thread_context*)data; 01644 _scan_for_ext_spring_forces(pctx->scene, pctx->ob, pctx->timenow, pctx->ifirst, pctx->ilast, pctx->do_effector); 01645 return NULL; 01646 } 01647 01648 static void sb_sfesf_threads_run(Scene *scene, struct Object *ob, float timenow,int totsprings,int *UNUSED(ptr_to_break_func(void))) 01649 { 01650 ListBase *do_effector = NULL; 01651 ListBase threads; 01652 SB_thread_context *sb_threads; 01653 int i, totthread,left,dec; 01654 int lowsprings =100; /* wild guess .. may increase with better thread management 'above' or even be UI option sb->spawn_cf_threads_nopts */ 01655 01656 do_effector= pdInitEffectors(scene, ob, NULL, ob->soft->effector_weights); 01657 01658 /* figure the number of threads while preventing pretty pointless threading overhead */ 01659 if(scene->r.mode & R_FIXED_THREADS) 01660 totthread= scene->r.threads; 01661 else 01662 totthread= BLI_system_thread_count(); 01663 /* what if we got zillions of CPUs running but less to spread*/ 01664 while ((totsprings/totthread < lowsprings) && (totthread > 1)) { 01665 totthread--; 01666 } 01667 01668 sb_threads= MEM_callocN(sizeof(SB_thread_context)*totthread, "SBSpringsThread"); 01669 memset(sb_threads, 0, sizeof(SB_thread_context)*totthread); 01670 left = totsprings; 01671 dec = totsprings/totthread +1; 01672 for(i=0; i<totthread; i++) { 01673 sb_threads[i].scene = scene; 01674 sb_threads[i].ob = ob; 01675 sb_threads[i].forcetime = 0.0; // not used here 01676 sb_threads[i].timenow = timenow; 01677 sb_threads[i].ilast = left; 01678 left = left - dec; 01679 if (left >0){ 01680 sb_threads[i].ifirst = left; 01681 } 01682 else 01683 sb_threads[i].ifirst = 0; 01684 sb_threads[i].do_effector = do_effector; 01685 sb_threads[i].do_deflector = 0;// not used here 01686 sb_threads[i].fieldfactor = 0.0f;// not used here 01687 sb_threads[i].windfactor = 0.0f;// not used here 01688 sb_threads[i].nr= i; 01689 sb_threads[i].tot= totthread; 01690 } 01691 if(totthread > 1) { 01692 BLI_init_threads(&threads, exec_scan_for_ext_spring_forces, totthread); 01693 01694 for(i=0; i<totthread; i++) 01695 BLI_insert_thread(&threads, &sb_threads[i]); 01696 01697 BLI_end_threads(&threads); 01698 } 01699 else 01700 exec_scan_for_ext_spring_forces(&sb_threads[0]); 01701 /* clean up */ 01702 MEM_freeN(sb_threads); 01703 01704 pdEndEffectors(&do_effector); 01705 } 01706 01707 01708 /* --- the spring external section*/ 01709 01710 static int choose_winner(float*w, float* pos,float*a,float*b,float*c,float*ca,float*cb,float*cc) 01711 { 01712 float mindist,cp; 01713 int winner =1; 01714 mindist = ABS(dot_v3v3(pos,a)); 01715 01716 cp = ABS(dot_v3v3(pos,b)); 01717 if ( mindist < cp ){ 01718 mindist = cp; 01719 winner =2; 01720 } 01721 01722 cp = ABS(dot_v3v3(pos,c)); 01723 if (mindist < cp ){ 01724 mindist = cp; 01725 winner =3; 01726 } 01727 switch (winner){ 01728 case 1: copy_v3_v3(w,ca); break; 01729 case 2: copy_v3_v3(w,cb); break; 01730 case 3: copy_v3_v3(w,cc); 01731 } 01732 return(winner); 01733 } 01734 01735 01736 01737 static int sb_detect_vertex_collisionCached(float opco[3], float facenormal[3], float *damp, 01738 float force[3], unsigned int UNUSED(par_layer), struct Object *vertexowner, 01739 float time,float vel[3], float *intrusion) 01740 { 01741 Object *ob= NULL; 01742 GHash *hash; 01743 GHashIterator *ihash; 01744 float nv1[3], nv2[3], nv3[3], nv4[3], edge1[3], edge2[3],d_nvect[3], dv1[3],ve[3],avel[3]={0.0,0.0,0.0}, 01745 vv1[3], vv2[3], vv3[3], vv4[3], coledge[3]={0.0f, 0.0f, 0.0f}, mindistedge = 1000.0f, 01746 outerforceaccu[3], innerforceaccu[3], 01747 facedist, /* n_mag, */ /* UNUSED */ force_mag_norm, minx, miny, minz, maxx, maxy, maxz, 01748 innerfacethickness = -0.5f, outerfacethickness = 0.2f, 01749 ee = 5.0f, ff = 0.1f, fa=1; 01750 int a, deflected=0, cavel=0, ci=0; 01751 /* init */ 01752 *intrusion = 0.0f; 01753 hash = vertexowner->soft->scratch->colliderhash; 01754 ihash = BLI_ghashIterator_new(hash); 01755 outerforceaccu[0]=outerforceaccu[1]=outerforceaccu[2]=0.0f; 01756 innerforceaccu[0]=innerforceaccu[1]=innerforceaccu[2]=0.0f; 01757 /* go */ 01758 while (!BLI_ghashIterator_isDone(ihash) ) { 01759 01760 ccd_Mesh *ccdm = BLI_ghashIterator_getValue (ihash); 01761 ob = BLI_ghashIterator_getKey (ihash); 01762 /* only with deflecting set */ 01763 if(ob->pd && ob->pd->deflect) { 01764 MFace *mface= NULL; 01765 MVert *mvert= NULL; 01766 MVert *mprevvert= NULL; 01767 ccdf_minmax *mima= NULL; 01768 01769 if(ccdm){ 01770 mface= ccdm->mface; 01771 mvert= ccdm->mvert; 01772 mprevvert= ccdm->mprevvert; 01773 mima= ccdm->mima; 01774 a = ccdm->totface; 01775 01776 minx =ccdm->bbmin[0]; 01777 miny =ccdm->bbmin[1]; 01778 minz =ccdm->bbmin[2]; 01779 01780 maxx =ccdm->bbmax[0]; 01781 maxy =ccdm->bbmax[1]; 01782 maxz =ccdm->bbmax[2]; 01783 01784 if ((opco[0] < minx) || 01785 (opco[1] < miny) || 01786 (opco[2] < minz) || 01787 (opco[0] > maxx) || 01788 (opco[1] > maxy) || 01789 (opco[2] > maxz) ) { 01790 /* outside the padded boundbox --> collision object is too far away */ 01791 BLI_ghashIterator_step(ihash); 01792 continue; 01793 } 01794 } 01795 else{ 01796 /*aye that should be cached*/ 01797 printf("missing cache error \n"); 01798 BLI_ghashIterator_step(ihash); 01799 continue; 01800 } 01801 01802 /* do object level stuff */ 01803 /* need to have user control for that since it depends on model scale */ 01804 innerfacethickness =-ob->pd->pdef_sbift; 01805 outerfacethickness =ob->pd->pdef_sboft; 01806 fa = (ff*outerfacethickness-outerfacethickness); 01807 fa *= fa; 01808 fa = 1.0f/fa; 01809 avel[0]=avel[1]=avel[2]=0.0f; 01810 /* use mesh*/ 01811 while (a--) { 01812 if ( 01813 (opco[0] < mima->minx) || 01814 (opco[0] > mima->maxx) || 01815 (opco[1] < mima->miny) || 01816 (opco[1] > mima->maxy) || 01817 (opco[2] < mima->minz) || 01818 (opco[2] > mima->maxz) 01819 ) { 01820 mface++; 01821 mima++; 01822 continue; 01823 } 01824 01825 if (mvert){ 01826 01827 copy_v3_v3(nv1,mvert[mface->v1].co); 01828 copy_v3_v3(nv2,mvert[mface->v2].co); 01829 copy_v3_v3(nv3,mvert[mface->v3].co); 01830 if (mface->v4){ 01831 copy_v3_v3(nv4,mvert[mface->v4].co); 01832 } 01833 01834 if (mprevvert){ 01835 /* grab the average speed of the collider vertices 01836 before we spoil nvX 01837 humm could be done once a SB steps but then we' need to store that too 01838 since the AABB reduced propabitlty to get here drasticallly 01839 it might be a nice tradeof CPU <--> memory 01840 */ 01841 sub_v3_v3v3(vv1,nv1,mprevvert[mface->v1].co); 01842 sub_v3_v3v3(vv2,nv2,mprevvert[mface->v2].co); 01843 sub_v3_v3v3(vv3,nv3,mprevvert[mface->v3].co); 01844 if (mface->v4){ 01845 sub_v3_v3v3(vv4,nv4,mprevvert[mface->v4].co); 01846 } 01847 01848 mul_v3_fl(nv1,time); 01849 Vec3PlusStVec(nv1,(1.0f-time),mprevvert[mface->v1].co); 01850 01851 mul_v3_fl(nv2,time); 01852 Vec3PlusStVec(nv2,(1.0f-time),mprevvert[mface->v2].co); 01853 01854 mul_v3_fl(nv3,time); 01855 Vec3PlusStVec(nv3,(1.0f-time),mprevvert[mface->v3].co); 01856 01857 if (mface->v4){ 01858 mul_v3_fl(nv4,time); 01859 Vec3PlusStVec(nv4,(1.0f-time),mprevvert[mface->v4].co); 01860 } 01861 } 01862 } 01863 01864 /* switch origin to be nv2*/ 01865 sub_v3_v3v3(edge1, nv1, nv2); 01866 sub_v3_v3v3(edge2, nv3, nv2); 01867 sub_v3_v3v3(dv1,opco,nv2); /* abuse dv1 to have vertex in question at *origin* of triangle */ 01868 01869 cross_v3_v3v3(d_nvect, edge2, edge1); 01870 /* n_mag = */ /* UNUSED */ normalize_v3(d_nvect); 01871 facedist = dot_v3v3(dv1,d_nvect); 01872 // so rules are 01873 // 01874 01875 if ((facedist > innerfacethickness) && (facedist < outerfacethickness)){ 01876 if (isect_point_tri_prism_v3(opco, nv1, nv2, nv3) ){ 01877 force_mag_norm =(float)exp(-ee*facedist); 01878 if (facedist > outerfacethickness*ff) 01879 force_mag_norm =(float)force_mag_norm*fa*(facedist - outerfacethickness)*(facedist - outerfacethickness); 01880 *damp=ob->pd->pdef_sbdamp; 01881 if (facedist > 0.0f){ 01882 *damp *= (1.0f - facedist/outerfacethickness); 01883 Vec3PlusStVec(outerforceaccu,force_mag_norm,d_nvect); 01884 deflected = 3; 01885 01886 } 01887 else { 01888 Vec3PlusStVec(innerforceaccu,force_mag_norm,d_nvect); 01889 if (deflected < 2) deflected = 2; 01890 } 01891 if ((mprevvert) && (*damp > 0.0f)){ 01892 choose_winner(ve,opco,nv1,nv2,nv3,vv1,vv2,vv3); 01893 add_v3_v3(avel, ve); 01894 cavel ++; 01895 } 01896 *intrusion += facedist; 01897 ci++; 01898 } 01899 } 01900 if (mface->v4){ /* quad */ 01901 /* switch origin to be nv4 */ 01902 sub_v3_v3v3(edge1, nv3, nv4); 01903 sub_v3_v3v3(edge2, nv1, nv4); 01904 sub_v3_v3v3(dv1,opco,nv4); /* abuse dv1 to have vertex in question at *origin* of triangle */ 01905 01906 cross_v3_v3v3(d_nvect, edge2, edge1); 01907 /* n_mag = */ /* UNUSED */ normalize_v3(d_nvect); 01908 facedist = dot_v3v3(dv1,d_nvect); 01909 01910 if ((facedist > innerfacethickness) && (facedist < outerfacethickness)){ 01911 if (isect_point_tri_prism_v3(opco, nv1, nv3, nv4) ){ 01912 force_mag_norm =(float)exp(-ee*facedist); 01913 if (facedist > outerfacethickness*ff) 01914 force_mag_norm =(float)force_mag_norm*fa*(facedist - outerfacethickness)*(facedist - outerfacethickness); 01915 *damp=ob->pd->pdef_sbdamp; 01916 if (facedist > 0.0f){ 01917 *damp *= (1.0f - facedist/outerfacethickness); 01918 Vec3PlusStVec(outerforceaccu,force_mag_norm,d_nvect); 01919 deflected = 3; 01920 01921 } 01922 else { 01923 Vec3PlusStVec(innerforceaccu,force_mag_norm,d_nvect); 01924 if (deflected < 2) deflected = 2; 01925 } 01926 01927 if ((mprevvert) && (*damp > 0.0f)){ 01928 choose_winner(ve,opco,nv1,nv3,nv4,vv1,vv3,vv4); 01929 add_v3_v3(avel, ve); 01930 cavel ++; 01931 } 01932 *intrusion += facedist; 01933 ci++; 01934 } 01935 01936 } 01937 if ((deflected < 2)&& (G.rt != 444)) // we did not hit a face until now 01938 { // see if 'outer' hits an edge 01939 float dist; 01940 01941 closest_to_line_segment_v3(ve, opco, nv1, nv2); 01942 sub_v3_v3v3(ve,opco,ve); 01943 dist = normalize_v3(ve); 01944 if ((dist < outerfacethickness)&&(dist < mindistedge )){ 01945 copy_v3_v3(coledge,ve); 01946 mindistedge = dist, 01947 deflected=1; 01948 } 01949 01950 closest_to_line_segment_v3(ve, opco, nv2, nv3); 01951 sub_v3_v3v3(ve,opco,ve); 01952 dist = normalize_v3(ve); 01953 if ((dist < outerfacethickness)&&(dist < mindistedge )){ 01954 copy_v3_v3(coledge,ve); 01955 mindistedge = dist, 01956 deflected=1; 01957 } 01958 01959 closest_to_line_segment_v3(ve, opco, nv3, nv1); 01960 sub_v3_v3v3(ve,opco,ve); 01961 dist = normalize_v3(ve); 01962 if ((dist < outerfacethickness)&&(dist < mindistedge )){ 01963 copy_v3_v3(coledge,ve); 01964 mindistedge = dist, 01965 deflected=1; 01966 } 01967 if (mface->v4){ /* quad */ 01968 closest_to_line_segment_v3(ve, opco, nv3, nv4); 01969 sub_v3_v3v3(ve,opco,ve); 01970 dist = normalize_v3(ve); 01971 if ((dist < outerfacethickness)&&(dist < mindistedge )){ 01972 copy_v3_v3(coledge,ve); 01973 mindistedge = dist, 01974 deflected=1; 01975 } 01976 01977 closest_to_line_segment_v3(ve, opco, nv1, nv4); 01978 sub_v3_v3v3(ve,opco,ve); 01979 dist = normalize_v3(ve); 01980 if ((dist < outerfacethickness)&&(dist < mindistedge )){ 01981 copy_v3_v3(coledge,ve); 01982 mindistedge = dist, 01983 deflected=1; 01984 } 01985 01986 } 01987 01988 01989 } 01990 } 01991 mface++; 01992 mima++; 01993 }/* while a */ 01994 } /* if(ob->pd && ob->pd->deflect) */ 01995 BLI_ghashIterator_step(ihash); 01996 } /* while () */ 01997 01998 if (deflected == 1){ // no face but 'outer' edge cylinder sees vert 01999 force_mag_norm =(float)exp(-ee*mindistedge); 02000 if (mindistedge > outerfacethickness*ff) 02001 force_mag_norm =(float)force_mag_norm*fa*(mindistedge - outerfacethickness)*(mindistedge - outerfacethickness); 02002 Vec3PlusStVec(force,force_mag_norm,coledge); 02003 *damp=ob->pd->pdef_sbdamp; 02004 if (mindistedge > 0.0f){ 02005 *damp *= (1.0f - mindistedge/outerfacethickness); 02006 } 02007 02008 } 02009 if (deflected == 2){ // face inner detected 02010 add_v3_v3(force, innerforceaccu); 02011 } 02012 if (deflected == 3){ // face outer detected 02013 add_v3_v3(force, outerforceaccu); 02014 } 02015 02016 BLI_ghashIterator_free(ihash); 02017 if (cavel) mul_v3_fl(avel,1.0f/(float)cavel); 02018 copy_v3_v3(vel,avel); 02019 if (ci) *intrusion /= ci; 02020 if (deflected){ 02021 normalize_v3_v3(facenormal, force); 02022 } 02023 return deflected; 02024 } 02025 02026 02027 /* sandbox to plug in various deflection algos */ 02028 static int sb_deflect_face(Object *ob,float *actpos,float *facenormal,float *force,float *cf,float time,float *vel,float *intrusion) 02029 { 02030 float s_actpos[3]; 02031 int deflected; 02032 copy_v3_v3(s_actpos,actpos); 02033 deflected= sb_detect_vertex_collisionCached(s_actpos, facenormal, cf, force , ob->lay, ob,time,vel,intrusion); 02034 //deflected= sb_detect_vertex_collisionCachedEx(s_actpos, facenormal, cf, force , ob->lay, ob,time,vel,intrusion); 02035 return(deflected); 02036 } 02037 02038 /* hiding this for now .. but the jacobian may pop up on other tasks .. so i'd like to keep it 02039 static void dfdx_spring(int ia, int ic, int op, float dir[3],float L,float len,float factor) 02040 { 02041 float m,delta_ij; 02042 int i ,j; 02043 if (L < len){ 02044 for(i=0;i<3;i++) 02045 for(j=0;j<3;j++){ 02046 delta_ij = (i==j ? (1.0f): (0.0f)); 02047 m=factor*(dir[i]*dir[j] + (1-L/len)*(delta_ij - dir[i]*dir[j])); 02048 nlMatrixAdd(ia+i,op+ic+j,m); 02049 } 02050 } 02051 else{ 02052 for(i=0;i<3;i++) 02053 for(j=0;j<3;j++){ 02054 m=factor*dir[i]*dir[j]; 02055 nlMatrixAdd(ia+i,op+ic+j,m); 02056 } 02057 } 02058 } 02059 02060 02061 static void dfdx_goal(int ia, int ic, int op, float factor) 02062 { 02063 int i; 02064 for(i=0;i<3;i++) nlMatrixAdd(ia+i,op+ic+i,factor); 02065 } 02066 02067 static void dfdv_goal(int ia, int ic,float factor) 02068 { 02069 int i; 02070 for(i=0;i<3;i++) nlMatrixAdd(ia+i,ic+i,factor); 02071 } 02072 */ 02073 static void sb_spring_force(Object *ob,int bpi,BodySpring *bs,float iks,float UNUSED(forcetime), int nl_flags) 02074 { 02075 SoftBody *sb= ob->soft; /* is supposed to be there */ 02076 BodyPoint *bp1,*bp2; 02077 02078 float dir[3],dvel[3]; 02079 float distance,forcefactor,kd,absvel,projvel,kw; 02080 #if 0 /* UNUSED */ 02081 int ia,ic; 02082 #endif 02083 /* prepare depending on which side of the spring we are on */ 02084 if (bpi == bs->v1){ 02085 bp1 = &sb->bpoint[bs->v1]; 02086 bp2 = &sb->bpoint[bs->v2]; 02087 #if 0 /* UNUSED */ 02088 ia =3*bs->v1; 02089 ic =3*bs->v2; 02090 #endif 02091 } 02092 else if (bpi == bs->v2){ 02093 bp1 = &sb->bpoint[bs->v2]; 02094 bp2 = &sb->bpoint[bs->v1]; 02095 #if 0 /* UNUSED */ 02096 ia =3*bs->v2; 02097 ic =3*bs->v1; 02098 #endif 02099 } 02100 else{ 02101 /* TODO make this debug option */ 02102 02103 printf("bodypoint <bpi> is not attached to spring <*bs> --> sb_spring_force()\n"); 02104 return; 02105 } 02106 02107 /* do bp1 <--> bp2 elastic */ 02108 sub_v3_v3v3(dir,bp1->pos,bp2->pos); 02109 distance = normalize_v3(dir); 02110 if (bs->len < distance) 02111 iks = 1.0f/(1.0f-sb->inspring)-1.0f ;/* inner spring constants function */ 02112 else 02113 iks = 1.0f/(1.0f-sb->inpush)-1.0f ;/* inner spring constants function */ 02114 02115 if(bs->len > 0.0f) /* check for degenerated springs */ 02116 forcefactor = iks/bs->len; 02117 else 02118 forcefactor = iks; 02119 kw = (bp1->springweight+bp2->springweight)/2.0f; 02120 kw = kw * kw; 02121 kw = kw * kw; 02122 switch (bs->springtype){ 02123 case SB_EDGE: 02124 case SB_HANDLE: 02125 forcefactor *= kw; 02126 break; 02127 case SB_BEND: 02128 forcefactor *=sb->secondspring*kw; 02129 break; 02130 case SB_STIFFQUAD: 02131 forcefactor *=sb->shearstiff*sb->shearstiff* kw; 02132 break; 02133 default: 02134 break; 02135 } 02136 02137 02138 Vec3PlusStVec(bp1->force,(bs->len - distance)*forcefactor,dir); 02139 02140 /* do bp1 <--> bp2 viscous */ 02141 sub_v3_v3v3(dvel,bp1->vec,bp2->vec); 02142 kd = sb->infrict * sb_fric_force_scale(ob); 02143 absvel = normalize_v3(dvel); 02144 projvel = dot_v3v3(dir,dvel); 02145 kd *= absvel * projvel; 02146 Vec3PlusStVec(bp1->force,-kd,dir); 02147 02148 /* do jacobian stuff if needed */ 02149 if(nl_flags & NLF_BUILD){ 02150 //int op =3*sb->totpoint; 02151 //float mvel = -forcetime*kd; 02152 //float mpos = -forcetime*forcefactor; 02153 /* depending on my pos */ 02154 // dfdx_spring(ia,ia,op,dir,bs->len,distance,-mpos); 02155 /* depending on my vel */ 02156 // dfdv_goal(ia,ia,mvel); // well that ignores geometie 02157 if(bp2->goal < SOFTGOALSNAP){ /* ommit this bp when it snaps */ 02158 /* depending on other pos */ 02159 // dfdx_spring(ia,ic,op,dir,bs->len,distance,mpos); 02160 /* depending on other vel */ 02161 // dfdv_goal(ia,ia,-mvel); // well that ignores geometie 02162 } 02163 } 02164 } 02165 02166 02167 /* since this is definitely the most CPU consuming task here .. try to spread it */ 02168 /* core function _softbody_calc_forces_slice_in_a_thread */ 02169 /* result is int to be able to flag user break */ 02170 static int _softbody_calc_forces_slice_in_a_thread(Scene *scene, Object *ob, float forcetime, float timenow,int ifirst,int ilast,int *UNUSED(ptr_to_break_func(void)),ListBase *do_effector,int do_deflector,float fieldfactor, float windfactor) 02171 { 02172 float iks; 02173 int bb,do_selfcollision,do_springcollision,do_aero; 02174 int number_of_points_here = ilast - ifirst; 02175 SoftBody *sb= ob->soft; /* is supposed to be there */ 02176 BodyPoint *bp; 02177 02178 /* intitialize */ 02179 if (sb) { 02180 /* check conditions for various options */ 02181 /* +++ could be done on object level to squeeze out the last bits of it */ 02182 do_selfcollision=((ob->softflag & OB_SB_EDGES) && (sb->bspring)&& (ob->softflag & OB_SB_SELF)); 02183 do_springcollision=do_deflector && (ob->softflag & OB_SB_EDGES) &&(ob->softflag & OB_SB_EDGECOLL); 02184 do_aero=((sb->aeroedge)&& (ob->softflag & OB_SB_EDGES)); 02185 /* --- could be done on object level to squeeze out the last bits of it */ 02186 } 02187 else { 02188 printf("Error expected a SB here \n"); 02189 return (999); 02190 } 02191 02192 /* debugerin */ 02193 if (sb->totpoint < ifirst) { 02194 printf("Aye 998"); 02195 return (998); 02196 } 02197 /* debugerin */ 02198 02199 02200 bp = &sb->bpoint[ifirst]; 02201 for(bb=number_of_points_here; bb>0; bb--, bp++) { 02202 /* clear forces accumulator */ 02203 bp->force[0]= bp->force[1]= bp->force[2]= 0.0; 02204 /* naive ball self collision */ 02205 /* needs to be done if goal snaps or not */ 02206 if(do_selfcollision){ 02207 int attached; 02208 BodyPoint *obp; 02209 BodySpring *bs; 02210 int c,b; 02211 float velcenter[3],dvel[3],def[3]; 02212 float distance; 02213 float compare; 02214 float bstune = sb->ballstiff; 02215 02216 for(c=sb->totpoint, obp= sb->bpoint; c>=ifirst+bb; c--, obp++) { 02217 compare = (obp->colball + bp->colball); 02218 sub_v3_v3v3(def, bp->pos, obp->pos); 02219 /* rather check the AABBoxes before ever calulating the real distance */ 02220 /* mathematically it is completly nuts, but performace is pretty much (3) times faster */ 02221 if ((ABS(def[0]) > compare) || (ABS(def[1]) > compare) || (ABS(def[2]) > compare)) continue; 02222 distance = normalize_v3(def); 02223 if (distance < compare ){ 02224 /* exclude body points attached with a spring */ 02225 attached = 0; 02226 for(b=obp->nofsprings;b>0;b--){ 02227 bs = sb->bspring + obp->springs[b-1]; 02228 if (( ilast-bb == bs->v2) || ( ilast-bb == bs->v1)){ 02229 attached=1; 02230 continue;} 02231 } 02232 if (!attached){ 02233 float f = bstune/(distance) + bstune/(compare*compare)*distance - 2.0f*bstune/compare ; 02234 02235 mid_v3_v3v3(velcenter, bp->vec, obp->vec); 02236 sub_v3_v3v3(dvel,velcenter,bp->vec); 02237 mul_v3_fl(dvel,_final_mass(ob,bp)); 02238 02239 Vec3PlusStVec(bp->force,f*(1.0f-sb->balldamp),def); 02240 Vec3PlusStVec(bp->force,sb->balldamp,dvel); 02241 02242 /* exploit force(a,b) == -force(b,a) part2/2 */ 02243 sub_v3_v3v3(dvel,velcenter,obp->vec); 02244 mul_v3_fl(dvel,_final_mass(ob,bp)); 02245 02246 Vec3PlusStVec(obp->force,sb->balldamp,dvel); 02247 Vec3PlusStVec(obp->force,-f*(1.0f-sb->balldamp),def); 02248 } 02249 } 02250 } 02251 } 02252 /* naive ball self collision done */ 02253 02254 if(_final_goal(ob,bp) < SOFTGOALSNAP){ /* ommit this bp when it snaps */ 02255 float auxvect[3]; 02256 float velgoal[3]; 02257 02258 /* do goal stuff */ 02259 if(ob->softflag & OB_SB_GOAL) { 02260 /* true elastic goal */ 02261 float ks,kd; 02262 sub_v3_v3v3(auxvect,bp->pos,bp->origT); 02263 ks = 1.0f/(1.0f- _final_goal(ob,bp)*sb->goalspring)-1.0f ; 02264 bp->force[0]+= -ks*(auxvect[0]); 02265 bp->force[1]+= -ks*(auxvect[1]); 02266 bp->force[2]+= -ks*(auxvect[2]); 02267 02268 /* calulate damping forces generated by goals*/ 02269 sub_v3_v3v3(velgoal,bp->origS, bp->origE); 02270 kd = sb->goalfrict * sb_fric_force_scale(ob) ; 02271 add_v3_v3v3(auxvect,velgoal,bp->vec); 02272 02273 if (forcetime > 0.0f) { /* make sure friction does not become rocket motor on time reversal */ 02274 bp->force[0]-= kd * (auxvect[0]); 02275 bp->force[1]-= kd * (auxvect[1]); 02276 bp->force[2]-= kd * (auxvect[2]); 02277 } 02278 else { 02279 bp->force[0]-= kd * (velgoal[0] - bp->vec[0]); 02280 bp->force[1]-= kd * (velgoal[1] - bp->vec[1]); 02281 bp->force[2]-= kd * (velgoal[2] - bp->vec[2]); 02282 } 02283 } 02284 /* done goal stuff */ 02285 02286 /* gravitation */ 02287 if (sb && scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY){ 02288 float gravity[3]; 02289 copy_v3_v3(gravity, scene->physics_settings.gravity); 02290 mul_v3_fl(gravity, sb_grav_force_scale(ob)*_final_mass(ob,bp)*sb->effector_weights->global_gravity); /* individual mass of node here */ 02291 add_v3_v3(bp->force, gravity); 02292 } 02293 02294 /* particle field & vortex */ 02295 if(do_effector) { 02296 EffectedPoint epoint; 02297 float kd; 02298 float force[3]= {0.0f, 0.0f, 0.0f}; 02299 float speed[3]= {0.0f, 0.0f, 0.0f}; 02300 float eval_sb_fric_force_scale = sb_fric_force_scale(ob); /* just for calling function once */ 02301 pd_point_from_soft(scene, bp->pos, bp->vec, sb->bpoint-bp, &epoint); 02302 pdDoEffectors(do_effector, NULL, sb->effector_weights, &epoint, force, speed); 02303 02304 /* apply forcefield*/ 02305 mul_v3_fl(force,fieldfactor* eval_sb_fric_force_scale); 02306 add_v3_v3(bp->force, force); 02307 02308 /* BP friction in moving media */ 02309 kd= sb->mediafrict* eval_sb_fric_force_scale; 02310 bp->force[0] -= kd * (bp->vec[0] + windfactor*speed[0]/eval_sb_fric_force_scale); 02311 bp->force[1] -= kd * (bp->vec[1] + windfactor*speed[1]/eval_sb_fric_force_scale); 02312 bp->force[2] -= kd * (bp->vec[2] + windfactor*speed[2]/eval_sb_fric_force_scale); 02313 /* now we'll have nice centrifugal effect for vortex */ 02314 02315 } 02316 else { 02317 /* BP friction in media (not) moving*/ 02318 float kd = sb->mediafrict* sb_fric_force_scale(ob); 02319 /* assume it to be proportional to actual velocity */ 02320 bp->force[0]-= bp->vec[0]*kd; 02321 bp->force[1]-= bp->vec[1]*kd; 02322 bp->force[2]-= bp->vec[2]*kd; 02323 /* friction in media done */ 02324 } 02325 /* +++cached collision targets */ 02326 bp->choke = 0.0f; 02327 bp->choke2 = 0.0f; 02328 bp->loc_flag &= ~SBF_DOFUZZY; 02329 if(do_deflector && !(bp->loc_flag & SBF_OUTOFCOLLISION) ) { 02330 float cfforce[3],defforce[3] ={0.0f,0.0f,0.0f}, vel[3] = {0.0f,0.0f,0.0f}, facenormal[3], cf = 1.0f,intrusion; 02331 float kd = 1.0f; 02332 02333 if (sb_deflect_face(ob,bp->pos,facenormal,defforce,&cf,timenow,vel,&intrusion)){ 02334 if (intrusion < 0.0f){ 02335 sb->scratch->flag |= SBF_DOFUZZY; 02336 bp->loc_flag |= SBF_DOFUZZY; 02337 bp->choke = sb->choke*0.01f; 02338 } 02339 02340 sub_v3_v3v3(cfforce,bp->vec,vel); 02341 Vec3PlusStVec(bp->force,-cf*50.0f,cfforce); 02342 02343 Vec3PlusStVec(bp->force,kd,defforce); 02344 } 02345 02346 } 02347 /* ---cached collision targets */ 02348 02349 /* +++springs */ 02350 iks = 1.0f/(1.0f-sb->inspring)-1.0f ;/* inner spring constants function */ 02351 if(ob->softflag & OB_SB_EDGES) { 02352 if (sb->bspring){ /* spring list exists at all ? */ 02353 int b; 02354 BodySpring *bs; 02355 for(b=bp->nofsprings;b>0;b--){ 02356 bs = sb->bspring + bp->springs[b-1]; 02357 if (do_springcollision || do_aero){ 02358 add_v3_v3(bp->force, bs->ext_force); 02359 if (bs->flag & BSF_INTERSECT) 02360 bp->choke = bs->cf; 02361 02362 } 02363 // sb_spring_force(Object *ob,int bpi,BodySpring *bs,float iks,float forcetime,int nl_flags) 02364 sb_spring_force(ob,ilast-bb,bs,iks,forcetime,0); 02365 }/* loop springs */ 02366 }/* existing spring list */ 02367 }/*any edges*/ 02368 /* ---springs */ 02369 }/*omit on snap */ 02370 }/*loop all bp's*/ 02371 return 0; /*done fine*/ 02372 } 02373 02374 static void *exec_softbody_calc_forces(void *data) 02375 { 02376 SB_thread_context *pctx = (SB_thread_context*)data; 02377 _softbody_calc_forces_slice_in_a_thread(pctx->scene, pctx->ob, pctx->forcetime, pctx->timenow, pctx->ifirst, pctx->ilast, NULL, pctx->do_effector,pctx->do_deflector,pctx->fieldfactor,pctx->windfactor); 02378 return NULL; 02379 } 02380 02381 static void sb_cf_threads_run(Scene *scene, Object *ob, float forcetime, float timenow,int totpoint,int *UNUSED(ptr_to_break_func(void)),struct ListBase *do_effector,int do_deflector,float fieldfactor, float windfactor) 02382 { 02383 ListBase threads; 02384 SB_thread_context *sb_threads; 02385 int i, totthread,left,dec; 02386 int lowpoints =100; /* wild guess .. may increase with better thread management 'above' or even be UI option sb->spawn_cf_threads_nopts */ 02387 02388 /* figure the number of threads while preventing pretty pointless threading overhead */ 02389 if(scene->r.mode & R_FIXED_THREADS) 02390 totthread= scene->r.threads; 02391 else 02392 totthread= BLI_system_thread_count(); 02393 /* what if we got zillions of CPUs running but less to spread*/ 02394 while ((totpoint/totthread < lowpoints) && (totthread > 1)) { 02395 totthread--; 02396 } 02397 02398 /* printf("sb_cf_threads_run spawning %d threads \n",totthread); */ 02399 02400 sb_threads= MEM_callocN(sizeof(SB_thread_context)*totthread, "SBThread"); 02401 memset(sb_threads, 0, sizeof(SB_thread_context)*totthread); 02402 left = totpoint; 02403 dec = totpoint/totthread +1; 02404 for(i=0; i<totthread; i++) { 02405 sb_threads[i].scene = scene; 02406 sb_threads[i].ob = ob; 02407 sb_threads[i].forcetime = forcetime; 02408 sb_threads[i].timenow = timenow; 02409 sb_threads[i].ilast = left; 02410 left = left - dec; 02411 if (left >0){ 02412 sb_threads[i].ifirst = left; 02413 } 02414 else 02415 sb_threads[i].ifirst = 0; 02416 sb_threads[i].do_effector = do_effector; 02417 sb_threads[i].do_deflector = do_deflector; 02418 sb_threads[i].fieldfactor = fieldfactor; 02419 sb_threads[i].windfactor = windfactor; 02420 sb_threads[i].nr= i; 02421 sb_threads[i].tot= totthread; 02422 } 02423 02424 02425 if(totthread > 1) { 02426 BLI_init_threads(&threads, exec_softbody_calc_forces, totthread); 02427 02428 for(i=0; i<totthread; i++) 02429 BLI_insert_thread(&threads, &sb_threads[i]); 02430 02431 BLI_end_threads(&threads); 02432 } 02433 else 02434 exec_softbody_calc_forces(&sb_threads[0]); 02435 /* clean up */ 02436 MEM_freeN(sb_threads); 02437 } 02438 02439 static void softbody_calc_forcesEx(Scene *scene, Object *ob, float forcetime, float timenow, int UNUSED(nl_flags)) 02440 { 02441 /* rule we never alter free variables :bp->vec bp->pos in here ! 02442 * this will ruin adaptive stepsize AKA heun! (BM) 02443 */ 02444 SoftBody *sb= ob->soft; /* is supposed to be there */ 02445 /*BodyPoint *bproot;*/ /* UNUSED */ 02446 ListBase *do_effector = NULL; 02447 /* float gravity; */ /* UNUSED */ 02448 /* float iks; */ 02449 float fieldfactor = -1.0f, windfactor = 0.25; 02450 int do_deflector /*,do_selfcollision*/ ,do_springcollision,do_aero; 02451 02452 /* gravity = sb->grav * sb_grav_force_scale(ob); */ /* UNUSED */ 02453 02454 /* check conditions for various options */ 02455 do_deflector= query_external_colliders(scene, ob); 02456 /* do_selfcollision=((ob->softflag & OB_SB_EDGES) && (sb->bspring)&& (ob->softflag & OB_SB_SELF)); */ /* UNUSED */ 02457 do_springcollision=do_deflector && (ob->softflag & OB_SB_EDGES) &&(ob->softflag & OB_SB_EDGECOLL); 02458 do_aero=((sb->aeroedge)&& (ob->softflag & OB_SB_EDGES)); 02459 02460 /* iks = 1.0f/(1.0f-sb->inspring)-1.0f; */ /* inner spring constants function */ /* UNUSED */ 02461 /* bproot= sb->bpoint; */ /* need this for proper spring addressing */ /* UNUSED */ 02462 02463 if (do_springcollision || do_aero) 02464 sb_sfesf_threads_run(scene, ob, timenow,sb->totspring,NULL); 02465 02466 /* after spring scan because it uses Effoctors too */ 02467 do_effector= pdInitEffectors(scene, ob, NULL, sb->effector_weights); 02468 02469 if (do_deflector) { 02470 float defforce[3]; 02471 do_deflector = sb_detect_aabb_collisionCached(defforce,ob->lay,ob,timenow); 02472 } 02473 02474 sb_cf_threads_run(scene, ob, forcetime, timenow, sb->totpoint, NULL, do_effector, do_deflector, fieldfactor, windfactor); 02475 02476 /* finally add forces caused by face collision */ 02477 if (ob->softflag & OB_SB_FACECOLL) scan_for_ext_face_forces(ob,timenow); 02478 02479 /* finish matrix and solve */ 02480 pdEndEffectors(&do_effector); 02481 } 02482 02483 02484 02485 02486 static void softbody_calc_forces(Scene *scene, Object *ob, float forcetime, float timenow, int nl_flags) 02487 { 02488 /* redirection to the new threaded Version */ 02489 if (!(G.rt & 0x10)){ // 16 02490 softbody_calc_forcesEx(scene, ob, forcetime, timenow, nl_flags); 02491 return; 02492 } 02493 else{ 02494 /* so the following will die */ 02495 /* |||||||||||||||||||||||||| */ 02496 /* VVVVVVVVVVVVVVVVVVVVVVVVVV */ 02497 /*backward compatibility note: 02498 fixing bug [17428] which forces adaptive step size to tiny steps 02499 in some situations 02500 .. keeping G.rt==17 0x11 option for old files 'needing' the bug*/ 02501 02502 /* rule we never alter free variables :bp->vec bp->pos in here ! 02503 * this will ruin adaptive stepsize AKA heun! (BM) 02504 */ 02505 SoftBody *sb= ob->soft; /* is supposed to be there */ 02506 BodyPoint *bp; 02507 /* BodyPoint *bproot; */ /* UNUSED */ 02508 BodySpring *bs; 02509 ListBase *do_effector = NULL; 02510 float iks, ks, kd, gravity[3] = {0.0f,0.0f,0.0f}; 02511 float fieldfactor = -1.0f, windfactor = 0.25f; 02512 float tune = sb->ballstiff; 02513 int a, b, do_deflector,do_selfcollision,do_springcollision,do_aero; 02514 02515 02516 /* jacobian 02517 NLboolean success; 02518 02519 if(nl_flags){ 02520 nlBegin(NL_SYSTEM); 02521 nlBegin(NL_MATRIX); 02522 } 02523 */ 02524 02525 02526 if (scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY){ 02527 copy_v3_v3(gravity, scene->physics_settings.gravity); 02528 mul_v3_fl(gravity, sb_grav_force_scale(ob)*sb->effector_weights->global_gravity); 02529 } 02530 02531 /* check conditions for various options */ 02532 do_deflector= query_external_colliders(scene, ob); 02533 do_selfcollision=((ob->softflag & OB_SB_EDGES) && (sb->bspring)&& (ob->softflag & OB_SB_SELF)); 02534 do_springcollision=do_deflector && (ob->softflag & OB_SB_EDGES) &&(ob->softflag & OB_SB_EDGECOLL); 02535 do_aero=((sb->aeroedge)&& (ob->softflag & OB_SB_EDGES)); 02536 02537 iks = 1.0f/(1.0f-sb->inspring)-1.0f ;/* inner spring constants function */ 02538 /* bproot= sb->bpoint; */ /* need this for proper spring addressing */ /* UNUSED */ 02539 02540 if (do_springcollision || do_aero) scan_for_ext_spring_forces(scene, ob, timenow); 02541 /* after spring scan because it uses Effoctors too */ 02542 do_effector= pdInitEffectors(scene, ob, NULL, ob->soft->effector_weights); 02543 02544 if (do_deflector) { 02545 float defforce[3]; 02546 do_deflector = sb_detect_aabb_collisionCached(defforce,ob->lay,ob,timenow); 02547 } 02548 02549 for(a=sb->totpoint, bp= sb->bpoint; a>0; a--, bp++) { 02550 /* clear forces accumulator */ 02551 bp->force[0]= bp->force[1]= bp->force[2]= 0.0; 02552 if(nl_flags & NLF_BUILD){ 02553 //int ia =3*(sb->totpoint-a); 02554 //int op =3*sb->totpoint; 02555 /* dF/dV = v */ 02556 /* jacobioan 02557 nlMatrixAdd(op+ia,ia,-forcetime); 02558 nlMatrixAdd(op+ia+1,ia+1,-forcetime); 02559 nlMatrixAdd(op+ia+2,ia+2,-forcetime); 02560 02561 nlMatrixAdd(ia,ia,1); 02562 nlMatrixAdd(ia+1,ia+1,1); 02563 nlMatrixAdd(ia+2,ia+2,1); 02564 02565 nlMatrixAdd(op+ia,op+ia,1); 02566 nlMatrixAdd(op+ia+1,op+ia+1,1); 02567 nlMatrixAdd(op+ia+2,op+ia+2,1); 02568 */ 02569 02570 02571 } 02572 02573 /* naive ball self collision */ 02574 /* needs to be done if goal snaps or not */ 02575 if(do_selfcollision){ 02576 int attached; 02577 BodyPoint *obp; 02578 int c,b; 02579 float velcenter[3],dvel[3],def[3]; 02580 float distance; 02581 float compare; 02582 02583 for(c=sb->totpoint, obp= sb->bpoint; c>=a; c--, obp++) { 02584 02585 //if ((bp->octantflag & obp->octantflag) == 0) continue; 02586 02587 compare = (obp->colball + bp->colball); 02588 sub_v3_v3v3(def, bp->pos, obp->pos); 02589 02590 /* rather check the AABBoxes before ever calulating the real distance */ 02591 /* mathematically it is completly nuts, but performace is pretty much (3) times faster */ 02592 if ((ABS(def[0]) > compare) || (ABS(def[1]) > compare) || (ABS(def[2]) > compare)) continue; 02593 02594 distance = normalize_v3(def); 02595 if (distance < compare ){ 02596 /* exclude body points attached with a spring */ 02597 attached = 0; 02598 for(b=obp->nofsprings;b>0;b--){ 02599 bs = sb->bspring + obp->springs[b-1]; 02600 if (( sb->totpoint-a == bs->v2) || ( sb->totpoint-a == bs->v1)){ 02601 attached=1; 02602 continue;} 02603 } 02604 if (!attached){ 02605 float f = tune/(distance) + tune/(compare*compare)*distance - 2.0f*tune/compare ; 02606 02607 mid_v3_v3v3(velcenter, bp->vec, obp->vec); 02608 sub_v3_v3v3(dvel,velcenter,bp->vec); 02609 mul_v3_fl(dvel,_final_mass(ob,bp)); 02610 02611 Vec3PlusStVec(bp->force,f*(1.0f-sb->balldamp),def); 02612 Vec3PlusStVec(bp->force,sb->balldamp,dvel); 02613 02614 if(nl_flags & NLF_BUILD){ 02615 //int ia =3*(sb->totpoint-a); 02616 //int ic =3*(sb->totpoint-c); 02617 //int op =3*sb->totpoint; 02618 //float mvel = forcetime*sb->nodemass*sb->balldamp; 02619 //float mpos = forcetime*tune*(1.0f-sb->balldamp); 02620 /*some quick and dirty entries to the jacobian*/ 02621 //dfdx_goal(ia,ia,op,mpos); 02622 //dfdv_goal(ia,ia,mvel); 02623 /* exploit force(a,b) == -force(b,a) part1/2 */ 02624 //dfdx_goal(ic,ic,op,mpos); 02625 //dfdv_goal(ic,ic,mvel); 02626 02627 02628 /*TODO sit down an X-out the true jacobian entries*/ 02629 /*well does not make to much sense because the eigenvalues 02630 of the jacobian go negative; and negative eigenvalues 02631 on a complex iterative system z(n+1)=A * z(n) 02632 give imaginary roots in the charcateristic polynom 02633 --> solutions that to z(t)=u(t)* exp ( i omega t) --> oscilations we don't want here 02634 where u(t) is a unknown amplitude function (worst case rising fast) 02635 */ 02636 } 02637 02638 /* exploit force(a,b) == -force(b,a) part2/2 */ 02639 sub_v3_v3v3(dvel,velcenter,obp->vec); 02640 mul_v3_fl(dvel,(_final_mass(ob,bp)+_final_mass(ob,obp))/2.0f); 02641 02642 Vec3PlusStVec(obp->force,sb->balldamp,dvel); 02643 Vec3PlusStVec(obp->force,-f*(1.0f-sb->balldamp),def); 02644 02645 02646 } 02647 } 02648 } 02649 } 02650 /* naive ball self collision done */ 02651 02652 if(_final_goal(ob,bp) < SOFTGOALSNAP){ /* ommit this bp when it snaps */ 02653 float auxvect[3]; 02654 float velgoal[3]; 02655 02656 /* do goal stuff */ 02657 if(ob->softflag & OB_SB_GOAL) { 02658 /* true elastic goal */ 02659 sub_v3_v3v3(auxvect,bp->pos,bp->origT); 02660 ks = 1.0f/(1.0f- _final_goal(ob,bp)*sb->goalspring)-1.0f ; 02661 bp->force[0]+= -ks*(auxvect[0]); 02662 bp->force[1]+= -ks*(auxvect[1]); 02663 bp->force[2]+= -ks*(auxvect[2]); 02664 02665 if(nl_flags & NLF_BUILD){ 02666 //int ia =3*(sb->totpoint-a); 02667 //int op =3*(sb->totpoint); 02668 /* depending on my pos */ 02669 //dfdx_goal(ia,ia,op,ks*forcetime); 02670 } 02671 02672 02673 /* calulate damping forces generated by goals*/ 02674 sub_v3_v3v3(velgoal,bp->origS, bp->origE); 02675 kd = sb->goalfrict * sb_fric_force_scale(ob) ; 02676 add_v3_v3v3(auxvect,velgoal,bp->vec); 02677 02678 if (forcetime > 0.0f) { /* make sure friction does not become rocket motor on time reversal */ 02679 bp->force[0]-= kd * (auxvect[0]); 02680 bp->force[1]-= kd * (auxvect[1]); 02681 bp->force[2]-= kd * (auxvect[2]); 02682 if(nl_flags & NLF_BUILD){ 02683 //int ia =3*(sb->totpoint-a); 02684 normalize_v3(auxvect); 02685 /* depending on my vel */ 02686 //dfdv_goal(ia,ia,kd*forcetime); 02687 } 02688 02689 } 02690 else { 02691 bp->force[0]-= kd * (velgoal[0] - bp->vec[0]); 02692 bp->force[1]-= kd * (velgoal[1] - bp->vec[1]); 02693 bp->force[2]-= kd * (velgoal[2] - bp->vec[2]); 02694 } 02695 } 02696 /* done goal stuff */ 02697 02698 02699 /* gravitation */ 02700 madd_v3_v3fl(bp->force, gravity, _final_mass(ob,bp)); /* individual mass of node here */ 02701 02702 02703 /* particle field & vortex */ 02704 if(do_effector) { 02705 EffectedPoint epoint; 02706 float force[3]= {0.0f, 0.0f, 0.0f}; 02707 float speed[3]= {0.0f, 0.0f, 0.0f}; 02708 float eval_sb_fric_force_scale = sb_fric_force_scale(ob); /* just for calling function once */ 02709 pd_point_from_soft(scene, bp->pos, bp->vec, sb->bpoint-bp, &epoint); 02710 pdDoEffectors(do_effector, NULL, sb->effector_weights, &epoint, force, speed); 02711 02712 /* apply forcefield*/ 02713 mul_v3_fl(force,fieldfactor* eval_sb_fric_force_scale); 02714 add_v3_v3(bp->force, force); 02715 02716 /* BP friction in moving media */ 02717 kd= sb->mediafrict* eval_sb_fric_force_scale; 02718 bp->force[0] -= kd * (bp->vec[0] + windfactor*speed[0]/eval_sb_fric_force_scale); 02719 bp->force[1] -= kd * (bp->vec[1] + windfactor*speed[1]/eval_sb_fric_force_scale); 02720 bp->force[2] -= kd * (bp->vec[2] + windfactor*speed[2]/eval_sb_fric_force_scale); 02721 /* now we'll have nice centrifugal effect for vortex */ 02722 02723 } 02724 else { 02725 /* BP friction in media (not) moving*/ 02726 kd= sb->mediafrict* sb_fric_force_scale(ob); 02727 /* assume it to be proportional to actual velocity */ 02728 bp->force[0]-= bp->vec[0]*kd; 02729 bp->force[1]-= bp->vec[1]*kd; 02730 bp->force[2]-= bp->vec[2]*kd; 02731 /* friction in media done */ 02732 if(nl_flags & NLF_BUILD){ 02733 //int ia =3*(sb->totpoint-a); 02734 /* da/dv = */ 02735 02736 // nlMatrixAdd(ia,ia,forcetime*kd); 02737 // nlMatrixAdd(ia+1,ia+1,forcetime*kd); 02738 // nlMatrixAdd(ia+2,ia+2,forcetime*kd); 02739 } 02740 02741 } 02742 /* +++cached collision targets */ 02743 bp->choke = 0.0f; 02744 bp->choke2 = 0.0f; 02745 bp->loc_flag &= ~SBF_DOFUZZY; 02746 if(do_deflector) { 02747 float cfforce[3],defforce[3] ={0.0f,0.0f,0.0f}, vel[3] = {0.0f,0.0f,0.0f}, facenormal[3], cf = 1.0f,intrusion; 02748 kd = 1.0f; 02749 02750 if (sb_deflect_face(ob,bp->pos,facenormal,defforce,&cf,timenow,vel,&intrusion)){ 02751 if ((!nl_flags)&&(intrusion < 0.0f)){ 02752 if(G.rt & 0x01){ // 17 we did check for bit 0x10 before 02753 /*fixing bug [17428] this forces adaptive step size to tiny steps 02754 in some situations .. keeping G.rt==17 option for old files 'needing' the bug 02755 */ 02756 /*bjornmose: uugh.. what an evil hack 02757 violation of the 'don't touch bp->pos in here' rule 02758 but works nice, like this--> 02759 we predict the solution beeing out of the collider 02760 in heun step No1 and leave the heun step No2 adapt to it 02761 so we kind of introduced a implicit solver for this case 02762 */ 02763 Vec3PlusStVec(bp->pos,-intrusion,facenormal); 02764 } 02765 else{ 02766 02767 sub_v3_v3v3(cfforce,bp->vec,vel); 02768 Vec3PlusStVec(bp->force,-cf*50.0f,cfforce); 02769 } 02770 02771 02772 sb->scratch->flag |= SBF_DOFUZZY; 02773 bp->loc_flag |= SBF_DOFUZZY; 02774 bp->choke = sb->choke*0.01f; 02775 } 02776 else{ 02777 sub_v3_v3v3(cfforce,bp->vec,vel); 02778 Vec3PlusStVec(bp->force,-cf*50.0f,cfforce); 02779 } 02780 Vec3PlusStVec(bp->force,kd,defforce); 02781 if (nl_flags & NLF_BUILD){ 02782 // int ia =3*(sb->totpoint-a); 02783 // int op =3*sb->totpoint; 02784 //dfdx_goal(ia,ia,op,mpos); // don't do unless you know 02785 //dfdv_goal(ia,ia,-cf); 02786 02787 } 02788 02789 } 02790 02791 } 02792 /* ---cached collision targets */ 02793 02794 /* +++springs */ 02795 if(ob->softflag & OB_SB_EDGES) { 02796 if (sb->bspring){ /* spring list exists at all ? */ 02797 for(b=bp->nofsprings;b>0;b--){ 02798 bs = sb->bspring + bp->springs[b-1]; 02799 if (do_springcollision || do_aero){ 02800 add_v3_v3(bp->force, bs->ext_force); 02801 if (bs->flag & BSF_INTERSECT) 02802 bp->choke = bs->cf; 02803 02804 } 02805 // sb_spring_force(Object *ob,int bpi,BodySpring *bs,float iks,float forcetime,int nl_flags) 02806 // rather remove nl_falgs from code .. will make things a lot cleaner 02807 sb_spring_force(ob,sb->totpoint-a,bs,iks,forcetime,0); 02808 }/* loop springs */ 02809 }/* existing spring list */ 02810 }/*any edges*/ 02811 /* ---springs */ 02812 }/*omit on snap */ 02813 }/*loop all bp's*/ 02814 02815 02816 /* finally add forces caused by face collision */ 02817 if (ob->softflag & OB_SB_FACECOLL) scan_for_ext_face_forces(ob,timenow); 02818 02819 /* finish matrix and solve */ 02820 #if (0) // remove onl linking for now .. still i am not sure .. the jacobian can be useful .. so keep that BM 02821 if(nl_flags & NLF_SOLVE){ 02822 //double sct,sst=PIL_check_seconds_timer(); 02823 for(a=sb->totpoint, bp= sb->bpoint; a>0; a--, bp++) { 02824 int iv =3*(sb->totpoint-a); 02825 int ip =3*(2*sb->totpoint-a); 02826 int n; 02827 for (n=0;n<3;n++) {nlRightHandSideSet(0, iv+n, bp->force[0+n]);} 02828 for (n=0;n<3;n++) {nlRightHandSideSet(0, ip+n, bp->vec[0+n]);} 02829 } 02830 nlEnd(NL_MATRIX); 02831 nlEnd(NL_SYSTEM); 02832 02833 if ((G.rt == 32) && (nl_flags & NLF_BUILD)) 02834 { 02835 printf("####MEE#####\n"); 02836 nlPrintMatrix(); 02837 } 02838 02839 success= nlSolveAdvanced(NULL, 1); 02840 02841 // nlPrintMatrix(); /* for debug purpose .. anyhow cropping B vector looks like working */ 02842 if(success){ 02843 float f; 02844 int index =0; 02845 /* for debug purpose .. anyhow cropping B vector looks like working */ 02846 if (G.rt ==32) 02847 for(a=2*sb->totpoint, bp= sb->bpoint; a>0; a--, bp++) { 02848 f=nlGetVariable(0,index); 02849 printf("(%f ",f);index++; 02850 f=nlGetVariable(0,index); 02851 printf("%f ",f);index++; 02852 f=nlGetVariable(0,index); 02853 printf("%f)",f);index++; 02854 } 02855 02856 index =0; 02857 for(a=sb->totpoint, bp= sb->bpoint; a>0; a--, bp++) { 02858 f=nlGetVariable(0,index); 02859 bp->impdv[0] = f; index++; 02860 f=nlGetVariable(0,index); 02861 bp->impdv[1] = f; index++; 02862 f=nlGetVariable(0,index); 02863 bp->impdv[2] = f; index++; 02864 } 02865 /* 02866 for(a=sb->totpoint, bp= sb->bpoint; a>0; a--, bp++) { 02867 f=nlGetVariable(0,index); 02868 bp->impdx[0] = f; index++; 02869 f=nlGetVariable(0,index); 02870 bp->impdx[1] = f; index++; 02871 f=nlGetVariable(0,index); 02872 bp->impdx[2] = f; index++; 02873 } 02874 */ 02875 } 02876 else{ 02877 printf("Matrix inversion failed \n"); 02878 for(a=sb->totpoint, bp= sb->bpoint; a>0; a--, bp++) { 02879 copy_v3_v3(bp->impdv,bp->force); 02880 } 02881 02882 } 02883 02884 //sct=PIL_check_seconds_timer(); 02885 //if (sct-sst > 0.01f) printf(" implicit solver time %f %s \r",sct-sst,ob->id.name); 02886 } 02887 /* cleanup */ 02888 #endif 02889 pdEndEffectors(&do_effector); 02890 } 02891 } 02892 02893 static void softbody_apply_forces(Object *ob, float forcetime, int mode, float *err, int mid_flags) 02894 { 02895 /* time evolution */ 02896 /* actually does an explicit euler step mode == 0 */ 02897 /* or heun ~ 2nd order runge-kutta steps, mode 1,2 */ 02898 SoftBody *sb= ob->soft; /* is supposed to be there */ 02899 BodyPoint *bp; 02900 float dx[3]={0},dv[3],aabbmin[3],aabbmax[3],cm[3]={0.0f,0.0f,0.0f}; 02901 float timeovermass/*,freezeloc=0.00001f,freezeforce=0.00000000001f*/; 02902 float maxerrpos= 0.0f,maxerrvel = 0.0f; 02903 int a,fuzzy=0; 02904 02905 forcetime *= sb_time_scale(ob); 02906 02907 aabbmin[0]=aabbmin[1]=aabbmin[2] = 1e20f; 02908 aabbmax[0]=aabbmax[1]=aabbmax[2] = -1e20f; 02909 02910 /* old one with homogenous masses */ 02911 /* claim a minimum mass for vertex */ 02912 /* 02913 if (sb->nodemass > 0.009999f) timeovermass = forcetime/sb->nodemass; 02914 else timeovermass = forcetime/0.009999f; 02915 */ 02916 02917 for(a=sb->totpoint, bp= sb->bpoint; a>0; a--, bp++) { 02918 /* now we have individual masses */ 02919 /* claim a minimum mass for vertex */ 02920 if (_final_mass(ob,bp) > 0.009999f) timeovermass = forcetime/_final_mass(ob,bp); 02921 else timeovermass = forcetime/0.009999f; 02922 02923 02924 if(_final_goal(ob,bp) < SOFTGOALSNAP){ 02925 /* this makes t~ = t */ 02926 if(mid_flags & MID_PRESERVE) copy_v3_v3(dx,bp->vec); 02927 02928 /* so here is (v)' = a(cceleration) = sum(F_springs)/m + gravitation + some friction forces + more forces*/ 02929 /* the ( ... )' operator denotes derivate respective time */ 02930 /* the euler step for velocity then becomes */ 02931 /* v(t + dt) = v(t) + a(t) * dt */ 02932 mul_v3_fl(bp->force,timeovermass);/* individual mass of node here */ 02933 /* some nasty if's to have heun in here too */ 02934 copy_v3_v3(dv,bp->force); 02935 02936 if (mode == 1){ 02937 copy_v3_v3(bp->prevvec, bp->vec); 02938 copy_v3_v3(bp->prevdv, dv); 02939 } 02940 02941 if (mode ==2){ 02942 /* be optimistic and execute step */ 02943 bp->vec[0] = bp->prevvec[0] + 0.5f * (dv[0] + bp->prevdv[0]); 02944 bp->vec[1] = bp->prevvec[1] + 0.5f * (dv[1] + bp->prevdv[1]); 02945 bp->vec[2] = bp->prevvec[2] + 0.5f * (dv[2] + bp->prevdv[2]); 02946 /* compare euler to heun to estimate error for step sizing */ 02947 maxerrvel = MAX2(maxerrvel,ABS(dv[0] - bp->prevdv[0])); 02948 maxerrvel = MAX2(maxerrvel,ABS(dv[1] - bp->prevdv[1])); 02949 maxerrvel = MAX2(maxerrvel,ABS(dv[2] - bp->prevdv[2])); 02950 } 02951 else { add_v3_v3(bp->vec, bp->force); } 02952 02953 /* this makes t~ = t+dt */ 02954 if(!(mid_flags & MID_PRESERVE)) copy_v3_v3(dx,bp->vec); 02955 02956 /* so here is (x)'= v(elocity) */ 02957 /* the euler step for location then becomes */ 02958 /* x(t + dt) = x(t) + v(t~) * dt */ 02959 mul_v3_fl(dx,forcetime); 02960 02961 /* the freezer coming sooner or later */ 02962 /* 02963 if ((dot_v3v3(dx,dx)<freezeloc )&&(dot_v3v3(bp->force,bp->force)<freezeforce )){ 02964 bp->frozen /=2; 02965 } 02966 else{ 02967 bp->frozen =MIN2(bp->frozen*1.05f,1.0f); 02968 } 02969 mul_v3_fl(dx,bp->frozen); 02970 */ 02971 /* again some nasty if's to have heun in here too */ 02972 if (mode ==1){ 02973 copy_v3_v3(bp->prevpos,bp->pos); 02974 copy_v3_v3(bp->prevdx ,dx); 02975 } 02976 02977 if (mode ==2){ 02978 bp->pos[0] = bp->prevpos[0] + 0.5f * ( dx[0] + bp->prevdx[0]); 02979 bp->pos[1] = bp->prevpos[1] + 0.5f * ( dx[1] + bp->prevdx[1]); 02980 bp->pos[2] = bp->prevpos[2] + 0.5f * ( dx[2] + bp->prevdx[2]); 02981 maxerrpos = MAX2(maxerrpos,ABS(dx[0] - bp->prevdx[0])); 02982 maxerrpos = MAX2(maxerrpos,ABS(dx[1] - bp->prevdx[1])); 02983 maxerrpos = MAX2(maxerrpos,ABS(dx[2] - bp->prevdx[2])); 02984 02985 /* bp->choke is set when we need to pull a vertex or edge out of the collider. 02986 the collider object signals to get out by pushing hard. on the other hand 02987 we don't want to end up in deep space so we add some <viscosity> 02988 to balance that out */ 02989 if (bp->choke2 > 0.0f){ 02990 mul_v3_fl(bp->vec,(1.0f - bp->choke2)); 02991 } 02992 if (bp->choke > 0.0f){ 02993 mul_v3_fl(bp->vec,(1.0f - bp->choke)); 02994 } 02995 02996 } 02997 else { add_v3_v3(bp->pos, dx);} 02998 }/*snap*/ 02999 /* so while we are looping BPs anyway do statistics on the fly */ 03000 aabbmin[0] = MIN2(aabbmin[0],bp->pos[0]); 03001 aabbmin[1] = MIN2(aabbmin[1],bp->pos[1]); 03002 aabbmin[2] = MIN2(aabbmin[2],bp->pos[2]); 03003 aabbmax[0] = MAX2(aabbmax[0],bp->pos[0]); 03004 aabbmax[1] = MAX2(aabbmax[1],bp->pos[1]); 03005 aabbmax[2] = MAX2(aabbmax[2],bp->pos[2]); 03006 if (bp->loc_flag & SBF_DOFUZZY) fuzzy =1; 03007 } /*for*/ 03008 03009 if (sb->totpoint) mul_v3_fl(cm,1.0f/sb->totpoint); 03010 if (sb->scratch){ 03011 copy_v3_v3(sb->scratch->aabbmin,aabbmin); 03012 copy_v3_v3(sb->scratch->aabbmax,aabbmax); 03013 } 03014 03015 if (err){ /* so step size will be controlled by biggest difference in slope */ 03016 if (sb->solverflags & SBSO_OLDERR) 03017 *err = MAX2(maxerrpos,maxerrvel); 03018 else 03019 *err = maxerrpos; 03020 //printf("EP %f EV %f \n",maxerrpos,maxerrvel); 03021 if (fuzzy){ 03022 *err /= sb->fuzzyness; 03023 } 03024 } 03025 } 03026 03027 /* used by heun when it overshoots */ 03028 static void softbody_restore_prev_step(Object *ob) 03029 { 03030 SoftBody *sb= ob->soft; /* is supposed to be there*/ 03031 BodyPoint *bp; 03032 int a; 03033 03034 for(a=sb->totpoint, bp= sb->bpoint; a>0; a--, bp++) { 03035 copy_v3_v3(bp->vec, bp->prevvec); 03036 copy_v3_v3(bp->pos, bp->prevpos); 03037 } 03038 } 03039 03040 #if 0 03041 static void softbody_store_step(Object *ob) 03042 { 03043 SoftBody *sb= ob->soft; /* is supposed to be there*/ 03044 BodyPoint *bp; 03045 int a; 03046 03047 for(a=sb->totpoint, bp= sb->bpoint; a>0; a--, bp++) { 03048 copy_v3_v3(bp->prevvec,bp->vec); 03049 copy_v3_v3(bp->prevpos,bp->pos); 03050 } 03051 } 03052 03053 03054 /* used by predictors and correctors */ 03055 static void softbody_store_state(Object *ob,float *ppos,float *pvel) 03056 { 03057 SoftBody *sb= ob->soft; /* is supposed to be there*/ 03058 BodyPoint *bp; 03059 int a; 03060 float *pp=ppos,*pv=pvel; 03061 03062 for(a=sb->totpoint, bp= sb->bpoint; a>0; a--, bp++) { 03063 03064 copy_v3_v3(pv, bp->vec); 03065 pv+=3; 03066 03067 copy_v3_v3(pp, bp->pos); 03068 pp+=3; 03069 } 03070 } 03071 03072 /* used by predictors and correctors */ 03073 static void softbody_retrieve_state(Object *ob,float *ppos,float *pvel) 03074 { 03075 SoftBody *sb= ob->soft; /* is supposed to be there*/ 03076 BodyPoint *bp; 03077 int a; 03078 float *pp=ppos,*pv=pvel; 03079 03080 for(a=sb->totpoint, bp= sb->bpoint; a>0; a--, bp++) { 03081 03082 copy_v3_v3(bp->vec,pv); 03083 pv+=3; 03084 03085 copy_v3_v3(bp->pos,pp); 03086 pp+=3; 03087 } 03088 } 03089 03090 /* used by predictors and correctors */ 03091 static void softbody_swap_state(Object *ob,float *ppos,float *pvel) 03092 { 03093 SoftBody *sb= ob->soft; /* is supposed to be there*/ 03094 BodyPoint *bp; 03095 int a; 03096 float *pp=ppos,*pv=pvel; 03097 float temp[3]; 03098 03099 for(a=sb->totpoint, bp= sb->bpoint; a>0; a--, bp++) { 03100 03101 copy_v3_v3(temp, bp->vec); 03102 copy_v3_v3(bp->vec,pv); 03103 copy_v3_v3(pv,temp); 03104 pv+=3; 03105 03106 copy_v3_v3(temp, bp->pos); 03107 copy_v3_v3(bp->pos,pp); 03108 copy_v3_v3(pp,temp); 03109 pp+=3; 03110 } 03111 } 03112 #endif 03113 03114 03115 /* care for bodypoints taken out of the 'ordinary' solver step 03116 ** because they are screwed to goal by bolts 03117 ** they just need to move along with the goal in time 03118 ** we need to adjust them on sub frame timing in solver 03119 ** so now when frame is done .. put 'em to the position at the end of frame 03120 */ 03121 static void softbody_apply_goalsnap(Object *ob) 03122 { 03123 SoftBody *sb= ob->soft; /* is supposed to be there */ 03124 BodyPoint *bp; 03125 int a; 03126 03127 for(a=sb->totpoint, bp= sb->bpoint; a>0; a--, bp++) { 03128 if (_final_goal(ob,bp) >= SOFTGOALSNAP){ 03129 copy_v3_v3(bp->prevpos,bp->pos); 03130 copy_v3_v3(bp->pos,bp->origT); 03131 } 03132 } 03133 } 03134 03135 03136 static void apply_spring_memory(Object *ob) 03137 { 03138 SoftBody *sb = ob->soft; 03139 BodySpring *bs; 03140 BodyPoint *bp1, *bp2; 03141 int a; 03142 float b,l,r; 03143 03144 if (sb && sb->totspring){ 03145 b = sb->plastic; 03146 for(a=0; a<sb->totspring; a++) { 03147 bs = &sb->bspring[a]; 03148 bp1 =&sb->bpoint[bs->v1]; 03149 bp2 =&sb->bpoint[bs->v2]; 03150 l = len_v3v3(bp1->pos,bp2->pos); 03151 r = bs->len/l; 03152 if (( r > 1.05f) || (r < 0.95f)){ 03153 bs->len = ((100.0f - b) * bs->len + b*l)/100.0f; 03154 } 03155 } 03156 } 03157 } 03158 03159 /* expects full initialized softbody */ 03160 static void interpolate_exciter(Object *ob, int timescale, int time) 03161 { 03162 SoftBody *sb= ob->soft; 03163 BodyPoint *bp; 03164 float f; 03165 int a; 03166 03167 f = (float)time/(float)timescale; 03168 03169 for(a=sb->totpoint, bp= sb->bpoint; a>0; a--, bp++) { 03170 bp->origT[0] = bp->origS[0] + f*(bp->origE[0] - bp->origS[0]); 03171 bp->origT[1] = bp->origS[1] + f*(bp->origE[1] - bp->origS[1]); 03172 bp->origT[2] = bp->origS[2] + f*(bp->origE[2] - bp->origS[2]); 03173 if (_final_goal(ob,bp) >= SOFTGOALSNAP){ 03174 bp->vec[0] = bp->origE[0] - bp->origS[0]; 03175 bp->vec[1] = bp->origE[1] - bp->origS[1]; 03176 bp->vec[2] = bp->origE[2] - bp->origS[2]; 03177 } 03178 } 03179 03180 } 03181 03182 03183 /* ************ convertors ********** */ 03184 03185 /* for each object type we need; 03186 - xxxx_to_softbody(Object *ob) : a full (new) copy, creates SB geometry 03187 */ 03188 03189 static void get_scalar_from_vertexgroup(Object *ob, int vertID, short groupindex, float *target) 03190 /* result 0 on success, else indicates error number 03191 -- kind of *inverse* result defintion, 03192 -- but this way we can signal error condition to caller 03193 -- and yes this function must not be here but in a *vertex group module* 03194 */ 03195 { 03196 MDeformVert *dv= NULL; 03197 int i; 03198 03199 /* spot the vert in deform vert list at mesh */ 03200 if(ob->type==OB_MESH) { 03201 Mesh *me= ob->data; 03202 if (me->dvert) 03203 dv = me->dvert + vertID; 03204 } 03205 else if(ob->type==OB_LATTICE) { /* not yet supported in softbody btw */ 03206 Lattice *lt= ob->data; 03207 if (lt->dvert) 03208 dv = lt->dvert + vertID; 03209 } 03210 if(dv) { 03211 /* Lets see if this vert is in the weight group */ 03212 for (i=0; i<dv->totweight; i++){ 03213 if (dv->dw[i].def_nr == groupindex){ 03214 *target= dv->dw[i].weight; /* got it ! */ 03215 break; 03216 } 03217 } 03218 } 03219 } 03220 03221 /* Resetting a Mesh SB object's springs */ 03222 /* Spring length are caculted from'raw' mesh vertices that are NOT altered by modifier stack. */ 03223 static void springs_from_mesh(Object *ob) 03224 { 03225 SoftBody *sb; 03226 Mesh *me= ob->data; 03227 BodyPoint *bp; 03228 int a; 03229 float scale =1.0f; 03230 03231 sb= ob->soft; 03232 if (me && sb) 03233 { 03234 /* using bp->origS as a container for spring calcualtions here 03235 ** will be overwritten sbObjectStep() to receive 03236 ** actual modifier stack positions 03237 */ 03238 if(me->totvert) { 03239 bp= ob->soft->bpoint; 03240 for(a=0; a<me->totvert; a++, bp++) { 03241 copy_v3_v3(bp->origS, me->mvert[a].co); 03242 mul_m4_v3(ob->obmat, bp->origS); 03243 } 03244 03245 } 03246 /* recalculate spring length for meshes here */ 03247 /* public version shrink to fit */ 03248 if (sb->springpreload != 0 ){ 03249 scale = sb->springpreload / 100.0f; 03250 } 03251 for(a=0; a<sb->totspring; a++) { 03252 BodySpring *bs = &sb->bspring[a]; 03253 bs->len= scale*len_v3v3(sb->bpoint[bs->v1].origS, sb->bpoint[bs->v2].origS); 03254 } 03255 } 03256 } 03257 03258 03259 03260 03261 /* makes totally fresh start situation */ 03262 static void mesh_to_softbody(Scene *scene, Object *ob) 03263 { 03264 SoftBody *sb; 03265 Mesh *me= ob->data; 03266 MEdge *medge= me->medge; 03267 BodyPoint *bp; 03268 BodySpring *bs; 03269 int a, totedge; 03270 if (ob->softflag & OB_SB_EDGES) totedge= me->totedge; 03271 else totedge= 0; 03272 03273 /* renew ends with ob->soft with points and edges, also checks & makes ob->soft */ 03274 renew_softbody(scene, ob, me->totvert, totedge); 03275 03276 /* we always make body points */ 03277 sb= ob->soft; 03278 bp= sb->bpoint; 03279 03280 for(a=0; a<me->totvert; a++, bp++) { 03281 /* get scalar values needed *per vertex* from vertex group functions, 03282 so we can *paint* them nicly .. 03283 they are normalized [0.0..1.0] so may be we need amplitude for scale 03284 which can be done by caller but still .. i'd like it to go this way 03285 */ 03286 03287 if((ob->softflag & OB_SB_GOAL) && sb->vertgroup) { /* even this is a deprecated evil hack */ 03288 /* I'd like to have it .. if (sb->namedVG_Goal[0]) */ 03289 03290 get_scalar_from_vertexgroup(ob, a,(short) (sb->vertgroup-1), &bp->goal); 03291 /* do this always, regardless successfull read from vertex group */ 03292 /* this is where '2.5 every thing is animateable' goes wrong in the first place jow_go_for2_5 */ 03293 /* 1st coding action to take : move this to frame level */ 03294 /* reads: leave the bp->goal as it was read from vertex group / or default .. we will need it at per frame call */ 03295 /* should be fixed for meshes */ 03296 // bp->goal= sb->mingoal + bp->goal*goalfac; /* do not do here jow_go_for2_5 */ 03297 } 03298 else{ 03299 /* in consequence if no group was set .. but we want to animate it laters */ 03300 /* logically attach to goal with default first */ 03301 if(ob->softflag & OB_SB_GOAL){bp->goal =sb->defgoal;} 03302 } 03303 03304 /* to proove the concept 03305 this enables per vertex *mass painting* 03306 */ 03307 03308 if (sb->namedVG_Mass[0]) 03309 { 03310 int grp= defgroup_name_index (ob,sb->namedVG_Mass); 03311 /* printf("VGN %s %d \n",sb->namedVG_Mass,grp); */ 03312 if(grp > -1){ 03313 get_scalar_from_vertexgroup(ob, a,(short) (grp), &bp->mass); 03314 /* 2.5 bp->mass = bp->mass * sb->nodemass; */ 03315 /* printf("bp->mass %f \n",bp->mass); */ 03316 03317 } 03318 } 03319 /* first set the default */ 03320 bp->springweight = 1.0f; 03321 03322 if (sb->namedVG_Spring_K[0]) 03323 { 03324 int grp= defgroup_name_index (ob,sb->namedVG_Spring_K); 03325 //printf("VGN %s %d \n",sb->namedVG_Spring_K,grp); 03326 if(grp > -1){ 03327 get_scalar_from_vertexgroup(ob, a,(short) (grp), &bp->springweight); 03328 //printf("bp->springweight %f \n",bp->springweight); 03329 03330 } 03331 } 03332 03333 03334 } 03335 03336 /* but we only optionally add body edge springs */ 03337 if (ob->softflag & OB_SB_EDGES) { 03338 if(medge) { 03339 bs= sb->bspring; 03340 for(a=me->totedge; a>0; a--, medge++, bs++) { 03341 bs->v1= medge->v1; 03342 bs->v2= medge->v2; 03343 bs->springtype=SB_EDGE; 03344 } 03345 03346 03347 /* insert *diagonal* springs in quads if desired */ 03348 if (ob->softflag & OB_SB_QUADS) { 03349 add_mesh_quad_diag_springs(ob); 03350 } 03351 03352 build_bps_springlist(ob); /* scan for springs attached to bodypoints ONCE */ 03353 /* insert *other second order* springs if desired */ 03354 if (sb->secondspring > 0.0000001f) { 03355 add_2nd_order_springs(ob,sb->secondspring); /* exploits the the first run of build_bps_springlist(ob);*/ 03356 build_bps_springlist(ob); /* yes we need to do it again*/ 03357 } 03358 springs_from_mesh(ob); /* write the 'rest'-length of the springs */ 03359 if (ob->softflag & OB_SB_SELF) {calculate_collision_balls(ob);} 03360 03361 } 03362 03363 } 03364 03365 } 03366 03367 static void mesh_faces_to_scratch(Object *ob) 03368 { 03369 SoftBody *sb= ob->soft; 03370 Mesh *me= ob->data; 03371 MFace *mface; 03372 BodyFace *bodyface; 03373 int a; 03374 /* alloc and copy faces*/ 03375 03376 bodyface = sb->scratch->bodyface = MEM_mallocN(sizeof(BodyFace)*me->totface,"SB_body_Faces"); 03377 //memcpy(sb->scratch->mface,me->mface,sizeof(MFace)*me->totface); 03378 mface = me->mface; 03379 for(a=0; a<me->totface; a++, mface++, bodyface++) { 03380 bodyface->v1 = mface->v1; 03381 bodyface->v2 = mface->v2; 03382 bodyface->v3 = mface->v3; 03383 bodyface->v4 = mface->v4; 03384 bodyface->ext_force[0] = bodyface->ext_force[1] = bodyface->ext_force[2] = 0.0f; 03385 bodyface->flag =0; 03386 } 03387 sb->scratch->totface = me->totface; 03388 } 03389 static void reference_to_scratch(Object *ob) 03390 { 03391 SoftBody *sb= ob->soft; 03392 ReferenceVert *rp; 03393 BodyPoint *bp; 03394 float accu_pos[3] ={0.f,0.f,0.f}; 03395 float accu_mass = 0.f; 03396 int a; 03397 03398 sb->scratch->Ref.ivert = MEM_mallocN(sizeof(ReferenceVert)*sb->totpoint,"SB_Reference"); 03399 bp= ob->soft->bpoint; 03400 rp= sb->scratch->Ref.ivert; 03401 for(a=0; a<sb->totpoint; a++, rp++, bp++) { 03402 copy_v3_v3(rp->pos,bp->pos); 03403 add_v3_v3(accu_pos, bp->pos); 03404 accu_mass += _final_mass(ob,bp); 03405 } 03406 mul_v3_fl(accu_pos,1.0f/accu_mass); 03407 copy_v3_v3(sb->scratch->Ref.com,accu_pos); 03408 /* printf("reference_to_scratch \n"); */ 03409 } 03410 03411 /* 03412 helper function to get proper spring length 03413 when object is rescaled 03414 */ 03415 static float globallen(float *v1,float *v2,Object *ob) 03416 { 03417 float p1[3],p2[3]; 03418 copy_v3_v3(p1,v1); 03419 mul_m4_v3(ob->obmat, p1); 03420 copy_v3_v3(p2,v2); 03421 mul_m4_v3(ob->obmat, p2); 03422 return len_v3v3(p1,p2); 03423 } 03424 03425 static void makelatticesprings(Lattice *lt, BodySpring *bs, int dostiff,Object *ob) 03426 { 03427 BPoint *bp=lt->def, *bpu; 03428 int u, v, w, dv, dw, bpc=0, bpuc; 03429 03430 dv= lt->pntsu; 03431 dw= dv*lt->pntsv; 03432 03433 for(w=0; w<lt->pntsw; w++) { 03434 03435 for(v=0; v<lt->pntsv; v++) { 03436 03437 for(u=0, bpuc=0, bpu=NULL; u<lt->pntsu; u++, bp++, bpc++) { 03438 03439 if(w) { 03440 bs->v1 = bpc; 03441 bs->v2 = bpc-dw; 03442 bs->springtype=SB_EDGE; 03443 bs->len= globallen((bp-dw)->vec, bp->vec,ob); 03444 bs++; 03445 } 03446 if(v) { 03447 bs->v1 = bpc; 03448 bs->v2 = bpc-dv; 03449 bs->springtype=SB_EDGE; 03450 bs->len= globallen((bp-dv)->vec, bp->vec,ob); 03451 bs++; 03452 } 03453 if(u) { 03454 bs->v1 = bpuc; 03455 bs->v2 = bpc; 03456 bs->springtype=SB_EDGE; 03457 bs->len= globallen((bpu)->vec, bp->vec,ob); 03458 bs++; 03459 } 03460 03461 if (dostiff) { 03462 03463 if(w){ 03464 if( v && u ) { 03465 bs->v1 = bpc; 03466 bs->v2 = bpc-dw-dv-1; 03467 bs->springtype=SB_BEND; 03468 bs->len= globallen((bp-dw-dv-1)->vec, bp->vec,ob); 03469 bs++; 03470 } 03471 if( (v < lt->pntsv-1) && (u != 0) ) { 03472 bs->v1 = bpc; 03473 bs->v2 = bpc-dw+dv-1; 03474 bs->springtype=SB_BEND; 03475 bs->len= globallen((bp-dw+dv-1)->vec, bp->vec,ob); 03476 bs++; 03477 } 03478 } 03479 03480 if(w < lt->pntsw -1){ 03481 if( v && u ) { 03482 bs->v1 = bpc; 03483 bs->v2 = bpc+dw-dv-1; 03484 bs->springtype=SB_BEND; 03485 bs->len= globallen((bp+dw-dv-1)->vec, bp->vec,ob); 03486 bs++; 03487 } 03488 if( (v < lt->pntsv-1) && (u != 0) ) { 03489 bs->v1 = bpc; 03490 bs->v2 = bpc+dw+dv-1; 03491 bs->springtype=SB_BEND; 03492 bs->len= globallen((bp+dw+dv-1)->vec, bp->vec,ob); 03493 bs++; 03494 } 03495 } 03496 } 03497 bpu = bp; 03498 bpuc = bpc; 03499 } 03500 } 03501 } 03502 } 03503 03504 03505 /* makes totally fresh start situation */ 03506 static void lattice_to_softbody(Scene *scene, Object *ob) 03507 { 03508 Lattice *lt= ob->data; 03509 SoftBody *sb; 03510 int totvert, totspring = 0; 03511 03512 totvert= lt->pntsu*lt->pntsv*lt->pntsw; 03513 03514 if (ob->softflag & OB_SB_EDGES){ 03515 totspring = ((lt->pntsu -1) * lt->pntsv 03516 + (lt->pntsv -1) * lt->pntsu) * lt->pntsw 03517 +lt->pntsu*lt->pntsv*(lt->pntsw -1); 03518 if (ob->softflag & OB_SB_QUADS){ 03519 totspring += 4*(lt->pntsu -1) * (lt->pntsv -1) * (lt->pntsw-1); 03520 } 03521 } 03522 03523 03524 /* renew ends with ob->soft with points and edges, also checks & makes ob->soft */ 03525 renew_softbody(scene, ob, totvert, totspring); 03526 sb= ob->soft; /* can be created in renew_softbody() */ 03527 03528 /* weights from bpoints, same code used as for mesh vertices */ 03529 /* if((ob->softflag & OB_SB_GOAL) && sb->vertgroup) { 2.4x one*/ 03530 /* new! take the weights from lattice vertex anyhow */ 03531 if(ob->softflag & OB_SB_GOAL){ 03532 BodyPoint *bp= sb->bpoint; 03533 BPoint *bpnt= lt->def; 03534 /* jow_go_for2_5 */ 03535 int a; 03536 03537 for(a=0; a<totvert; a++, bp++, bpnt++) { 03538 bp->goal= bpnt->weight; 03539 } 03540 } 03541 03542 /* create some helper edges to enable SB lattice to be useful at all */ 03543 if (ob->softflag & OB_SB_EDGES){ 03544 makelatticesprings(lt,ob->soft->bspring,ob->softflag & OB_SB_QUADS,ob); 03545 build_bps_springlist(ob); /* link bps to springs */ 03546 } 03547 } 03548 03549 /* makes totally fresh start situation */ 03550 static void curve_surf_to_softbody(Scene *scene, Object *ob) 03551 { 03552 Curve *cu= ob->data; 03553 SoftBody *sb; 03554 BodyPoint *bp; 03555 BodySpring *bs; 03556 Nurb *nu; 03557 BezTriple *bezt; 03558 BPoint *bpnt; 03559 int a, curindex=0; 03560 int totvert, totspring = 0, setgoal=0; 03561 03562 totvert= count_curveverts(&cu->nurb); 03563 03564 if (ob->softflag & OB_SB_EDGES){ 03565 if(ob->type==OB_CURVE) { 03566 totspring= totvert - BLI_countlist(&cu->nurb); 03567 } 03568 } 03569 03570 /* renew ends with ob->soft with points and edges, also checks & makes ob->soft */ 03571 renew_softbody(scene, ob, totvert, totspring); 03572 sb= ob->soft; /* can be created in renew_softbody() */ 03573 03574 /* set vars now */ 03575 bp= sb->bpoint; 03576 bs= sb->bspring; 03577 03578 /* weights from bpoints, same code used as for mesh vertices */ 03579 /* if((ob->softflag & OB_SB_GOAL) && sb->vertgroup) 2.4x hack*/ 03580 /* new! take the weights from curve vertex anyhow */ 03581 if(ob->softflag & OB_SB_GOAL) 03582 setgoal= 1; 03583 03584 for(nu= cu->nurb.first; nu; nu= nu->next) { 03585 if(nu->bezt) { 03586 /* bezier case ; this is nicly said naive; who ever wrote this part, it was not me (JOW) :) */ 03587 /* a: never ever make tangent handles (sub) and or (ob)ject to collision */ 03588 /* b: rather calculate them using some C2 (C2= continous in second derivate -> no jump in bending ) condition */ 03589 /* not too hard to do, but needs some more code to care for; some one may want look at it JOW 2010/06/12*/ 03590 for(bezt=nu->bezt, a=0; a<nu->pntsu; a++, bezt++, bp+=3, curindex+=3) { 03591 if(setgoal) { 03592 bp->goal= bezt->weight; 03593 03594 /* all three triples */ 03595 (bp+1)->goal= bp->goal; 03596 (bp+2)->goal= bp->goal; 03597 /*do not collide handles */ 03598 (bp+1)->loc_flag |= SBF_OUTOFCOLLISION; 03599 (bp+2)->loc_flag |= SBF_OUTOFCOLLISION; 03600 } 03601 03602 if(totspring) { 03603 if(a>0) { 03604 bs->v1= curindex-3; 03605 bs->v2= curindex; 03606 bs->springtype=SB_HANDLE; 03607 bs->len= globallen( (bezt-1)->vec[0], bezt->vec[0], ob ); 03608 bs++; 03609 } 03610 bs->v1= curindex; 03611 bs->v2= curindex+1; 03612 bs->springtype=SB_HANDLE; 03613 bs->len= globallen( bezt->vec[0], bezt->vec[1], ob ); 03614 bs++; 03615 03616 bs->v1= curindex+1; 03617 bs->v2= curindex+2; 03618 bs->springtype=SB_HANDLE; 03619 bs->len= globallen( bezt->vec[1], bezt->vec[2], ob ); 03620 bs++; 03621 } 03622 } 03623 } 03624 else { 03625 for(bpnt=nu->bp, a=0; a<nu->pntsu*nu->pntsv; a++, bpnt++, bp++, curindex++) { 03626 if(setgoal) { 03627 bp->goal= bpnt->weight; 03628 } 03629 if(totspring && a>0) { 03630 bs->v1= curindex-1; 03631 bs->v2= curindex; 03632 bs->springtype=SB_EDGE; 03633 bs->len= globallen( (bpnt-1)->vec, bpnt->vec , ob ); 03634 bs++; 03635 } 03636 } 03637 } 03638 } 03639 03640 if(totspring) 03641 { 03642 build_bps_springlist(ob); /* link bps to springs */ 03643 if (ob->softflag & OB_SB_SELF) {calculate_collision_balls(ob);} 03644 } 03645 } 03646 03647 /* copies softbody result back in object */ 03648 static void softbody_to_object(Object *ob, float (*vertexCos)[3], int numVerts, int local) 03649 { 03650 SoftBody *sb= ob->soft; 03651 if(sb){ 03652 BodyPoint *bp= sb->bpoint; 03653 int a; 03654 if(sb->solverflags & SBSO_ESTIMATEIPO){SB_estimate_transform(ob,sb->lcom,sb->lrot,sb->lscale);} 03655 /* inverse matrix is not uptodate... */ 03656 invert_m4_m4(ob->imat, ob->obmat); 03657 03658 for(a=0; a<numVerts; a++, bp++) { 03659 copy_v3_v3(vertexCos[a], bp->pos); 03660 if(local==0) 03661 mul_m4_v3(ob->imat, vertexCos[a]); /* softbody is in global coords, baked optionally not */ 03662 } 03663 } 03664 } 03665 03666 /* +++ ************ maintaining scratch *************** */ 03667 static void sb_new_scratch(SoftBody *sb) 03668 { 03669 if (!sb) return; 03670 sb->scratch = MEM_callocN(sizeof(SBScratch), "SBScratch"); 03671 sb->scratch->colliderhash = BLI_ghash_new(BLI_ghashutil_ptrhash,BLI_ghashutil_ptrcmp, "sb_new_scratch gh"); 03672 sb->scratch->bodyface = NULL; 03673 sb->scratch->totface = 0; 03674 sb->scratch->aabbmax[0]=sb->scratch->aabbmax[1]=sb->scratch->aabbmax[2] = 1.0e30f; 03675 sb->scratch->aabbmin[0]=sb->scratch->aabbmin[1]=sb->scratch->aabbmin[2] = -1.0e30f; 03676 sb->scratch->Ref.ivert = NULL; 03677 03678 } 03679 /* --- ************ maintaining scratch *************** */ 03680 03681 /* ************ Object level, exported functions *************** */ 03682 03683 /* allocates and initializes general main data */ 03684 SoftBody *sbNew(Scene *scene) 03685 { 03686 SoftBody *sb; 03687 03688 sb= MEM_callocN(sizeof(SoftBody), "softbody"); 03689 03690 sb->mediafrict= 0.5f; 03691 sb->nodemass= 1.0f; 03692 sb->grav= 9.8f; 03693 sb->physics_speed= 1.0f; 03694 sb->rklimit= 0.1f; 03695 03696 sb->goalspring= 0.5f; 03697 sb->goalfrict= 0.0f; 03698 sb->mingoal= 0.0f; 03699 sb->maxgoal= 1.0f; 03700 sb->defgoal= 0.7f; 03701 03702 sb->inspring= 0.5f; 03703 sb->infrict= 0.5f; 03704 /*todo backward file compat should copy inspring to inpush while reading old files*/ 03705 sb->inpush = 0.5f; 03706 03707 sb->interval= 10; 03708 sb->sfra= scene->r.sfra; 03709 sb->efra= scene->r.efra; 03710 03711 sb->colball = 0.49f; 03712 sb->balldamp = 0.50f; 03713 sb->ballstiff= 1.0f; 03714 sb->sbc_mode = 1; 03715 03716 03717 sb->minloops = 10; 03718 sb->maxloops = 300; 03719 03720 sb->choke = 3; 03721 sb_new_scratch(sb); 03722 /*todo backward file compat should set sb->shearstiff = 1.0f while reading old files*/ 03723 sb->shearstiff = 1.0f; 03724 sb->solverflags |= SBSO_OLDERR; 03725 03726 sb->pointcache = BKE_ptcache_add(&sb->ptcaches); 03727 03728 if(!sb->effector_weights) 03729 sb->effector_weights = BKE_add_effector_weights(NULL); 03730 03731 sb->last_frame= MINFRAME-1; 03732 03733 return sb; 03734 } 03735 03736 /* frees all */ 03737 void sbFree(SoftBody *sb) 03738 { 03739 free_softbody_intern(sb); 03740 BKE_ptcache_free_list(&sb->ptcaches); 03741 sb->pointcache = NULL; 03742 if(sb->effector_weights) 03743 MEM_freeN(sb->effector_weights); 03744 MEM_freeN(sb); 03745 } 03746 03747 void sbFreeSimulation(SoftBody *sb) 03748 { 03749 free_softbody_intern(sb); 03750 } 03751 03752 /* makes totally fresh start situation */ 03753 void sbObjectToSoftbody(Object *ob) 03754 { 03755 //ob->softflag |= OB_SB_REDO; 03756 03757 free_softbody_intern(ob->soft); 03758 } 03759 03760 static int object_has_edges(Object *ob) 03761 { 03762 if(ob->type==OB_MESH) { 03763 return ((Mesh*) ob->data)->totedge; 03764 } 03765 else if(ob->type==OB_LATTICE) { 03766 return 1; 03767 } 03768 else { 03769 return 0; 03770 } 03771 } 03772 03773 /* SB global visible functions */ 03774 void sbSetInterruptCallBack(int (*f)(void)) 03775 { 03776 SB_localInterruptCallBack = f; 03777 } 03778 03779 static void softbody_update_positions(Object *ob, SoftBody *sb, float (*vertexCos)[3], int numVerts) 03780 { 03781 BodyPoint *bp; 03782 int a; 03783 03784 if(!sb || !sb->bpoint) 03785 return; 03786 03787 for(a=0,bp=sb->bpoint; a<numVerts; a++, bp++) { 03788 /* store where goals are now */ 03789 copy_v3_v3(bp->origS, bp->origE); 03790 /* copy the position of the goals at desired end time */ 03791 copy_v3_v3(bp->origE, vertexCos[a]); 03792 /* vertexCos came from local world, go global */ 03793 mul_m4_v3(ob->obmat, bp->origE); 03794 /* just to be save give bp->origT a defined value 03795 will be calulated in interpolate_exciter()*/ 03796 copy_v3_v3(bp->origT, bp->origE); 03797 } 03798 } 03799 03800 03801 /* void SB_estimate_transform */ 03802 /* input Object *ob out (says any object that can do SB like mesh,lattice,curve ) 03803 output float lloc[3],float lrot[3][3],float lscale[3][3] 03804 that is: 03805 a precise position vector denoting the motion of the center of mass 03806 give a rotation/scale matrix using averaging method, that's why estimate and not calculate 03807 see: this is kind of reverse engeneering: having to states of a point cloud and recover what happend 03808 our advantage here we know the identity of the vertex 03809 there are others methods giving other results. 03810 lloc,lrot,lscale are allowed to be NULL, just in case you don't need it. 03811 should be pretty useful for pythoneers :) 03812 not! velocity .. 2nd order stuff 03813 vcloud_estimate_transform see 03814 */ 03815 03816 void SB_estimate_transform(Object *ob,float lloc[3],float lrot[3][3],float lscale[3][3]) 03817 { 03818 BodyPoint *bp; 03819 ReferenceVert *rp; 03820 SoftBody *sb = NULL; 03821 float (*opos)[3]; 03822 float (*rpos)[3]; 03823 float com[3],rcom[3]; 03824 int a; 03825 03826 if(!ob ||!ob->soft) return; /* why did we get here ? */ 03827 sb= ob->soft; 03828 if(!sb || !sb->bpoint) return; 03829 opos= MEM_callocN( (sb->totpoint)*3*sizeof(float), "SB_OPOS"); 03830 rpos= MEM_callocN( (sb->totpoint)*3*sizeof(float), "SB_RPOS"); 03831 /* might filter vertex selection with a vertex group */ 03832 for(a=0, bp=sb->bpoint, rp=sb->scratch->Ref.ivert; a<sb->totpoint; a++, bp++, rp++) { 03833 copy_v3_v3(rpos[a],rp->pos); 03834 copy_v3_v3(opos[a],bp->pos); 03835 } 03836 03837 vcloud_estimate_transform(sb->totpoint, opos, NULL, rpos, NULL, com, rcom,lrot,lscale); 03838 //sub_v3_v3(com,rcom); 03839 if (lloc) copy_v3_v3(lloc,com); 03840 copy_v3_v3(sb->lcom,com); 03841 if (lscale) copy_m3_m3(sb->lscale,lscale); 03842 if (lrot) copy_m3_m3(sb->lrot,lrot); 03843 03844 03845 MEM_freeN(opos); 03846 MEM_freeN(rpos); 03847 } 03848 03849 static void softbody_reset(Object *ob, SoftBody *sb, float (*vertexCos)[3], int numVerts) 03850 { 03851 BodyPoint *bp; 03852 int a; 03853 03854 for(a=0,bp=sb->bpoint; a<numVerts; a++, bp++) { 03855 copy_v3_v3(bp->pos, vertexCos[a]); 03856 mul_m4_v3(ob->obmat, bp->pos); /* yep, sofbody is global coords*/ 03857 copy_v3_v3(bp->origS, bp->pos); 03858 copy_v3_v3(bp->origE, bp->pos); 03859 copy_v3_v3(bp->origT, bp->pos); 03860 bp->vec[0]= bp->vec[1]= bp->vec[2]= 0.0f; 03861 03862 /* the bp->prev*'s are for rolling back from a canceled try to propagate in time 03863 adaptive step size algo in a nutshell: 03864 1. set sheduled time step to new dtime 03865 2. try to advance the sheduled time step, beeing optimistic execute it 03866 3. check for success 03867 3.a we 're fine continue, may be we can increase sheduled time again ?? if so, do so! 03868 3.b we did exceed error limit --> roll back, shorten the sheduled time and try again at 2. 03869 4. check if we did reach dtime 03870 4.a nope we need to do some more at 2. 03871 4.b yup we're done 03872 */ 03873 03874 copy_v3_v3(bp->prevpos, bp->pos); 03875 copy_v3_v3(bp->prevvec, bp->vec); 03876 copy_v3_v3(bp->prevdx, bp->vec); 03877 copy_v3_v3(bp->prevdv, bp->vec); 03878 } 03879 03880 /* make a nice clean scratch struc */ 03881 free_scratch(sb); /* clear if any */ 03882 sb_new_scratch(sb); /* make a new */ 03883 sb->scratch->needstobuildcollider=1; 03884 zero_v3(sb->lcom); 03885 unit_m3(sb->lrot); 03886 unit_m3(sb->lscale); 03887 03888 03889 03890 /* copy some info to scratch */ 03891 /* we only need that if we want to reconstruct IPO */ 03892 if(1) { 03893 reference_to_scratch(ob); 03894 SB_estimate_transform(ob,NULL,NULL,NULL); 03895 SB_estimate_transform(ob,NULL,NULL,NULL); 03896 } 03897 switch(ob->type) { 03898 case OB_MESH: 03899 if (ob->softflag & OB_SB_FACECOLL) mesh_faces_to_scratch(ob); 03900 break; 03901 case OB_LATTICE: 03902 break; 03903 case OB_CURVE: 03904 case OB_SURF: 03905 break; 03906 default: 03907 break; 03908 } 03909 } 03910 03911 static void softbody_step(Scene *scene, Object *ob, SoftBody *sb, float dtime) 03912 { 03913 /* the simulator */ 03914 float forcetime; 03915 double sct,sst; 03916 03917 03918 sst=PIL_check_seconds_timer(); 03919 /* Integration back in time is possible in theory, but pretty useless here. 03920 So we refuse to do so. Since we do not know anything about 'outside' canges 03921 especially colliders we refuse to go more than 10 frames. 03922 */ 03923 if(dtime < 0 || dtime > 10.5f) return; 03924 03925 ccd_update_deflector_hash(scene, ob, sb->scratch->colliderhash); 03926 03927 if(sb->scratch->needstobuildcollider){ 03928 if (query_external_colliders(scene, ob)){ 03929 ccd_build_deflector_hash(scene, ob, sb->scratch->colliderhash); 03930 } 03931 sb->scratch->needstobuildcollider=0; 03932 } 03933 03934 if (sb->solver_ID < 2) { 03935 /* special case of 2nd order Runge-Kutta type AKA Heun */ 03936 int mid_flags=0; 03937 float err = 0; 03938 float forcetimemax = 1.0f; /* set defaults guess we shall do one frame */ 03939 float forcetimemin = 0.01f; /* set defaults guess 1/100 is tight enough */ 03940 float timedone =0.0; /* how far did we get without violating error condition */ 03941 /* loops = counter for emergency brake 03942 * we don't want to lock up the system if physics fail 03943 */ 03944 int loops =0 ; 03945 03946 SoftHeunTol = sb->rklimit; /* humm .. this should be calculated from sb parameters and sizes */ 03947 /* adjust loop limits */ 03948 if (sb->minloops > 0) forcetimemax = dtime / sb->minloops; 03949 if (sb->maxloops > 0) forcetimemin = dtime / sb->maxloops; 03950 03951 if(sb->solver_ID>0) mid_flags |= MID_PRESERVE; 03952 03953 forcetime =forcetimemax; /* hope for integrating in one step */ 03954 while ( (ABS(timedone) < ABS(dtime)) && (loops < 2000) ) 03955 { 03956 /* set goals in time */ 03957 interpolate_exciter(ob,200,(int)(200.0f*(timedone/dtime))); 03958 03959 sb->scratch->flag &= ~SBF_DOFUZZY; 03960 /* do predictive euler step */ 03961 softbody_calc_forces(scene, ob, forcetime,timedone/dtime,0); 03962 03963 softbody_apply_forces(ob, forcetime, 1, NULL,mid_flags); 03964 03965 /* crop new slope values to do averaged slope step */ 03966 softbody_calc_forces(scene, ob, forcetime,timedone/dtime,0); 03967 03968 softbody_apply_forces(ob, forcetime, 2, &err,mid_flags); 03969 softbody_apply_goalsnap(ob); 03970 03971 if (err > SoftHeunTol) { /* error needs to be scaled to some quantity */ 03972 03973 if (forcetime > forcetimemin){ 03974 forcetime = MAX2(forcetime / 2.0f,forcetimemin); 03975 softbody_restore_prev_step(ob); 03976 //printf("down,"); 03977 } 03978 else { 03979 timedone += forcetime; 03980 } 03981 } 03982 else { 03983 float newtime = forcetime * 1.1f; /* hope for 1.1 times better conditions in next step */ 03984 03985 if (sb->scratch->flag & SBF_DOFUZZY){ 03986 //if (err > SoftHeunTol/(2.0f*sb->fuzzyness)) { /* stay with this stepsize unless err really small */ 03987 newtime = forcetime; 03988 //} 03989 } 03990 else { 03991 if (err > SoftHeunTol/2.0f) { /* stay with this stepsize unless err really small */ 03992 newtime = forcetime; 03993 } 03994 } 03995 timedone += forcetime; 03996 newtime=MIN2(forcetimemax,MAX2(newtime,forcetimemin)); 03997 //if (newtime > forcetime) printf("up,"); 03998 if (forcetime > 0.0f) 03999 forcetime = MIN2(dtime - timedone,newtime); 04000 else 04001 forcetime = MAX2(dtime - timedone,newtime); 04002 } 04003 loops++; 04004 if(sb->solverflags & SBSO_MONITOR ){ 04005 sct=PIL_check_seconds_timer(); 04006 if (sct-sst > 0.5f) printf("%3.0f%% \r",100.0f*timedone/dtime); 04007 } 04008 /* ask for user break */ 04009 if (SB_localInterruptCallBack && SB_localInterruptCallBack()) break; 04010 04011 } 04012 /* move snapped to final position */ 04013 interpolate_exciter(ob, 2, 2); 04014 softbody_apply_goalsnap(ob); 04015 04016 // if(G.f & G_DEBUG){ 04017 if(sb->solverflags & SBSO_MONITOR ){ 04018 if (loops > HEUNWARNLIMIT) /* monitor high loop counts */ 04019 printf("\r needed %d steps/frame",loops); 04020 } 04021 04022 } 04023 else if (sb->solver_ID == 2) 04024 {/* do semi "fake" implicit euler */ 04025 //removed 04026 }/*SOLVER SELECT*/ 04027 else if (sb->solver_ID == 4) 04028 { 04029 /* do semi "fake" implicit euler */ 04030 }/*SOLVER SELECT*/ 04031 else if (sb->solver_ID == 3){ 04032 /* do "stupid" semi "fake" implicit euler */ 04033 //removed 04034 04035 }/*SOLVER SELECT*/ 04036 else{ 04037 printf("softbody no valid solver ID!"); 04038 }/*SOLVER SELECT*/ 04039 if(sb->plastic){ apply_spring_memory(ob);} 04040 04041 if(sb->solverflags & SBSO_MONITOR ){ 04042 sct=PIL_check_seconds_timer(); 04043 if ((sct-sst > 0.5f) || (G.f & G_DEBUG)) printf(" solver time %f sec %s \n",sct-sst,ob->id.name); 04044 } 04045 } 04046 04047 /* simulates one step. framenr is in frames */ 04048 void sbObjectStep(Scene *scene, Object *ob, float cfra, float (*vertexCos)[3], int numVerts) 04049 { 04050 SoftBody *sb= ob->soft; 04051 PointCache *cache; 04052 PTCacheID pid; 04053 float dtime, timescale; 04054 int framedelta, framenr, startframe, endframe; 04055 int cache_result; 04056 04057 cache= sb->pointcache; 04058 04059 framenr= (int)cfra; 04060 framedelta= framenr - cache->simframe; 04061 04062 BKE_ptcache_id_from_softbody(&pid, ob, sb); 04063 BKE_ptcache_id_time(&pid, scene, framenr, &startframe, &endframe, ×cale); 04064 04065 /* check for changes in mesh, should only happen in case the mesh 04066 * structure changes during an animation */ 04067 if(sb->bpoint && numVerts != sb->totpoint) { 04068 BKE_ptcache_invalidate(cache); 04069 return; 04070 } 04071 04072 /* clamp frame ranges */ 04073 if(framenr < startframe) { 04074 BKE_ptcache_invalidate(cache); 04075 return; 04076 } 04077 else if(framenr > endframe) { 04078 framenr = endframe; 04079 } 04080 04081 /* verify if we need to create the softbody data */ 04082 if(sb->bpoint == NULL || 04083 ((ob->softflag & OB_SB_EDGES) && !ob->soft->bspring && object_has_edges(ob))) { 04084 04085 switch(ob->type) { 04086 case OB_MESH: 04087 mesh_to_softbody(scene, ob); 04088 break; 04089 case OB_LATTICE: 04090 lattice_to_softbody(scene, ob); 04091 break; 04092 case OB_CURVE: 04093 case OB_SURF: 04094 curve_surf_to_softbody(scene, ob); 04095 break; 04096 default: 04097 renew_softbody(scene, ob, numVerts, 0); 04098 break; 04099 } 04100 04101 softbody_update_positions(ob, sb, vertexCos, numVerts); 04102 softbody_reset(ob, sb, vertexCos, numVerts); 04103 } 04104 04105 /* continue physics special case */ 04106 if(BKE_ptcache_get_continue_physics()) { 04107 BKE_ptcache_invalidate(cache); 04108 /* do simulation */ 04109 dtime = timescale; 04110 softbody_update_positions(ob, sb, vertexCos, numVerts); 04111 softbody_step(scene, ob, sb, dtime); 04112 softbody_to_object(ob, vertexCos, numVerts, 0); 04113 sb->last_frame = framenr; 04114 return; 04115 } 04116 04117 /* still no points? go away */ 04118 if(sb->totpoint==0) { 04119 return; 04120 } 04121 if(framenr == startframe) { 04122 BKE_ptcache_id_reset(scene, &pid, PTCACHE_RESET_OUTDATED); 04123 04124 /* first frame, no simulation to do, just set the positions */ 04125 softbody_update_positions(ob, sb, vertexCos, numVerts); 04126 04127 BKE_ptcache_validate(cache, framenr); 04128 cache->flag &= ~PTCACHE_REDO_NEEDED; 04129 04130 sb->last_frame = framenr; 04131 04132 return; 04133 } 04134 04135 /* try to read from cache */ 04136 cache_result = BKE_ptcache_read(&pid, framenr); 04137 04138 if(cache_result == PTCACHE_READ_EXACT || cache_result == PTCACHE_READ_INTERPOLATED) { 04139 softbody_to_object(ob, vertexCos, numVerts, sb->local); 04140 04141 BKE_ptcache_validate(cache, framenr); 04142 04143 if(cache_result == PTCACHE_READ_INTERPOLATED && cache->flag & PTCACHE_REDO_NEEDED) 04144 BKE_ptcache_write(&pid, framenr); 04145 04146 sb->last_frame = framenr; 04147 04148 return; 04149 } 04150 else if(cache_result==PTCACHE_READ_OLD) { 04151 ; /* do nothing */ 04152 } 04153 else if(/*ob->id.lib || */(cache->flag & PTCACHE_BAKED)) { /* "library linking & pointcaches" has to be solved properly at some point */ 04154 /* if baked and nothing in cache, do nothing */ 04155 BKE_ptcache_invalidate(cache); 04156 return; 04157 } 04158 04159 if(framenr!=sb->last_frame+1) 04160 return; 04161 04162 /* if on second frame, write cache for first frame */ 04163 if(cache->simframe == startframe && (cache->flag & PTCACHE_OUTDATED || cache->last_exact==0)) 04164 BKE_ptcache_write(&pid, startframe); 04165 04166 softbody_update_positions(ob, sb, vertexCos, numVerts); 04167 04168 /* checking time: */ 04169 dtime = framedelta*timescale; 04170 04171 /* do simulation */ 04172 softbody_step(scene, ob, sb, dtime); 04173 04174 softbody_to_object(ob, vertexCos, numVerts, 0); 04175 04176 BKE_ptcache_validate(cache, framenr); 04177 BKE_ptcache_write(&pid, framenr); 04178 04179 sb->last_frame = framenr; 04180 } 04181