Integration stage of Softbody project

User level notes are in Wiki here;
http://wiki.blender.org/bin/view.pl/Blenderdev/Softbodies
And will be added in blender3d.org CMS later.

Tech level notes are still pending, but here's the most relevant ones;

- made ob->soft struct SoftBody to hold all settings, and read/save in
  files
- added (temporal!) conversion for the old settings. So: read old files
  with softbody experiments now, and save over!
- cleaned API calls for softbody, which are only 5 of them now:
  sbNew()
  sbFree()
  sbObjectStep()          (animation steps)
  sbObjectToSoftbody()    (full re-initialize data)
  sbObjectReset()         (only reset motion)
- API calls accepts time in frames now, within softbody.c it converts

Further, internally code was cleaned some (missing tabs etc). Also tried
to keep a well defined structure with hints how to add support for more
objects. Can write notes about that...
This commit is contained in:
Ton Roosendaal
2005-04-02 13:57:23 +00:00
parent 02d3ad0b34
commit bdb86d7c67
13 changed files with 559 additions and 496 deletions

View File

@@ -46,29 +46,23 @@ typedef struct BodySpring {
float len, strength;
} BodySpring;
typedef struct SoftBody {
int totpoint, totspring;
BodyPoint *bpoint;
BodySpring *bspring;
float ctime; // last time calculated
} SoftBody;
struct Object;
struct SoftBody;
/* temporal data, nothing saved in file */
extern void free_softbody(SoftBody *sb);
/* allocates and initializes general main data */
extern struct SoftBody *sbNew(void);
/* makes totally fresh start situation */
extern void object_to_softbody(Object *ob,float ctime);
/* frees internal data and softbody itself */
extern void sbFree(struct SoftBody *sb);
/* copy original (but new) situation in softbody, as result of matrices or deform */
void object_update_softbody(Object *ob);
/* go one step in simulation, copy result in displist vertices */
extern void sbObjectStep(struct Object *ob, float framnr);
/* copies softbody result back to object (in displist) */
extern void softbody_to_object(Object *ob);
/* makes totally fresh start situation, resets time */
extern void sbObjectToSoftbody(struct Object *ob);
/* go one step in simulation */
extern void object_softbody_step(Object *ob, float ctime);
/* resets all motion and time */
extern void sbObjectReset(struct Object *ob);
#endif

View File

@@ -264,19 +264,17 @@ int mesh_modifier(Object *ob, char mode)
if(ob->effect.first) done |= object_wave(ob);
if((ob->softflag & 0x01) && !(ob->softflag & 0x08)) {
float ctime= bsystem_time(ob, NULL, (float)G.scene->r.cfra, 0.0);
if((ob->softflag & OB_SB_ENABLE) && !(ob->softflag & OB_SB_POSTDEF)) {
done= 1;
object_softbody_step(ob, ctime);
sbObjectStep(ob, (float)G.scene->r.cfra);
}
/* deform: input mesh, output ob dl_verts. is used by subsurf (output should be in mesh ton!) */
/* object_deform: output for mesh is in mesh->mvert */
done |= object_deform(ob);
if((ob->softflag & 0x01) && (ob->softflag & 0x08)) {
float ctime= bsystem_time(ob, NULL, (float)G.scene->r.cfra, 0.0);
if((ob->softflag & OB_SB_ENABLE) && (ob->softflag & OB_SB_POSTDEF)) {
done= 1;
object_softbody_step(ob, ctime);
sbObjectStep(ob, (float)G.scene->r.cfra);
}
/* put deformed vertices in dl->verts, optional subsurf will replace that */

View File

@@ -507,7 +507,7 @@ static void calc_curve_deform(Object *par, float *co, short axis, CurveDeform *c
}
/* Mesh now applies on mesh itself, others do displist */
static int _object_deform(Object *ob, int applyflag)
{
Mesh *me;

View File

@@ -222,7 +222,7 @@ void free_object(Object *ob)
BPY_free_scriptlink(&ob->scriptlink);
if(ob->pd) MEM_freeN(ob->pd);
if(ob->soft) free_softbody(ob->soft);
if(ob->soft) sbFree(ob->soft);
}
void unlink_object(Object *ob)

View File

@@ -34,22 +34,18 @@
/*
******
variables on the UI for now
typedef struct Object {
.....
float formfactor, softtime; softtime = #euler integrations steps per frame
.....
float sb_goalspring; softbody goal springs
float sb_goalfrict; softbody goal springs friction
float sb_inspring; softbody inner springs
float sb_infrict; softbody inner springs friction
float sb_nodemass; softbody mass of *vertex*
float sb_grav; softbody amount of gravitaion to apply
float sb_mingoal; quick limits for goal
float sb_maxgoal;
float sb_mediafrict; friction to env
float sb_pad1; free
float mediafrict; friction to env
float nodemass; softbody mass of *vertex*
float grav; softbody amount of gravitaion to apply
float goalspring; softbody goal springs
float goalfrict; softbody goal springs friction
float mingoal; quick limits for goal
float maxgoal;
float inspring; softbody inner springs
float infrict; softbody inner springs friction
*****
*/
@@ -62,7 +58,6 @@ typedef struct Object {
#include "MEM_guardedalloc.h"
/* types */
#include "DNA_ika_types.h"
#include "DNA_object_types.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
@@ -71,10 +66,11 @@ typedef struct Object {
#include "BLI_blenlib.h"
#include "BLI_arithb.h"
#include "BKE_global.h"
#include "BKE_utildefines.h"
#include "BKE_softbody.h"
#include "BKE_displist.h"
#include "BKE_global.h"
#include "BKE_object.h"
#include "BKE_softbody.h"
#include "BKE_utildefines.h"
#include "BIF_editdeform.h"
@@ -93,30 +89,32 @@ float steptime = 1.0f/25.0f; // translate framerate to *real* time
float rescale_grav_to_framerate = 1.0f; // since unit of g is [m/sec^2] we need translation from frames to physics time
float rescale_friction_to_framerate = 1.0f; // since unit of drag is [kg/sec] we need translation from frames to physics time
short SB_ENABLE = 0; // quick hack to switch sb integration in 3d header
/* local prototypes */
void softbody_scale_time(float steptime);
int get_scalar_from_named_vertexgroup(Object *ob, char *name, int vertID, float *target);
static void softbody_scale_time(float steptime);
static int get_scalar_from_named_vertexgroup(Object *ob, char *name, int vertID, float *target);
static void free_softbody_intern(SoftBody *sb);
void softbody_scale_time(float steptime)
static void softbody_scale_time(float steptime)
{
rescale_grav_to_framerate = steptime*steptime;
rescale_friction_to_framerate = steptime;
}
static int count_quads( Mesh *me)
static int count_mesh_quads(Mesh *me)
{
int a,result = 0;
MFace *mface= me->mface;
if(mface ) {
for(a=me->totface; a>0; a--, mface++) {if(mface->v4) result++;}
if(mface) {
for(a=me->totface; a>0; a--, mface++) {
if(mface->v4) result++;
}
}
return result;
}
static void add_quad_diag_springs(Object *ob)
static void add_mesh_quad_diag_springs(Object *ob)
{
Mesh *me= ob->data;
MFace *mface= me->mface;
@@ -125,22 +123,23 @@ static void add_quad_diag_springs(Object *ob)
int a ;
if (ob->soft){
int nofquads;
nofquads = count_quads(me);
int nofquads;
nofquads = count_mesh_quads(me);
if (nofquads) {
/* resize spring-array to hold additional quad springs */
bs_new= MEM_callocN( (ob->soft->totspring + nofquads *2 )*sizeof(BodySpring), "bodyspring");
memcpy(bs_new,ob->soft->bspring,(ob->soft->totspring )*sizeof(BodySpring));
MEM_freeN(ob->soft->bspring); /* do this before reassigning the pointer or have a 1st class memory leak */
ob->soft->bspring = bs_new;
ob->soft->bspring = bs_new;
/* fill the tail */
a = 0;
bs = bs_new+ob->soft->totspring;
bp= ob->soft->bpoint;
if(mface ) {
for(a=me->totface; a>0; a--, mface++) {
if(mface->v4)
{
if(mface->v4) {
bs->v1= mface->v1;
bs->v2= mface->v3;
bs->strength= 1.0;
@@ -158,15 +157,15 @@ static void add_quad_diag_springs(Object *ob)
/* now we can announce new springs */
ob->soft->totspring += nofquads *2;
}
}
}
static void add_bp_springlist(BodyPoint *bp,int springID)
static void add_bp_springlist(BodyPoint *bp,int springID)
{
int *newlist;
if (bp->springs == NULL) {
bp->springs = MEM_callocN( sizeof(int), "bpsprings");
bp->springs[0] = springID;
@@ -185,14 +184,15 @@ static void add_bp_springlist(BodyPoint *bp,int springID)
/* do this once when sb is build
it is O(N^2) so scanning for springs every iteration is too expensive
*/
static void build_bps_springlist(Object *ob)
static void build_bps_springlist(Object *ob)
{
SoftBody *sb= ob->soft; // is supposed to be there
BodyPoint *bp;
BodySpring *bs;
int a,b;
if (!sb) return; // paranoya check
if (sb==NULL) return; // paranoya check
for(a=sb->totpoint, bp= sb->bpoint; a>0; a--, bp++) {
/* scan for attached inner springs */
for(b=sb->totspring, bs= sb->bspring; b>0; b--, bs++) {
@@ -203,18 +203,22 @@ static void build_bps_springlist(Object *ob)
add_bp_springlist(bp,sb->totspring -b);
}
}//for springs
if (bp->nofsprings) printf(" node %d has %d spring links\n",a,bp->nofsprings);
// if (bp->nofsprings) printf(" node %d has %d spring links\n",a,bp->nofsprings);
}//for bp
}
static SoftBody *new_softbody(int totpoint, int totspring)
/* creates new softbody if didn't exist yet, makes new points and springs arrays */
/* called in mesh_to_softbody */
static void renew_softbody(Object *ob, int totpoint, int totspring)
{
SoftBody *sb= NULL;
SoftBody *sb;
if(ob->soft==NULL) ob->soft= sbNew();
else free_softbody_intern(ob->soft);
sb= ob->soft;
if(totpoint) {
sb= MEM_callocN(sizeof(SoftBody), "softbody");
sb->totpoint= totpoint;
sb->totspring= totspring;
@@ -222,14 +226,15 @@ static SoftBody *new_softbody(int totpoint, int totspring)
if(totspring)
sb->bspring= MEM_mallocN( totspring*sizeof(BodySpring), "bodyspring");
}
return sb;
}
void free_softbody(SoftBody *sb)
/* only frees internal data */
static void free_softbody_intern(SoftBody *sb)
{
if(sb) {
int a;
BodyPoint *bp;
if(sb->bpoint){
for(a=sb->totpoint, bp= sb->bpoint; a>0; a--, bp++) {
/* free spring list */
@@ -239,10 +244,16 @@ void free_softbody(SoftBody *sb)
}
MEM_freeN(sb->bpoint);
}
if(sb->bspring) MEM_freeN(sb->bspring);
MEM_freeN(sb);
sb->totpoint= sb->totspring= 0;
sb->bpoint= NULL;
sb->bspring= NULL;
}
}
/* ************ dynamics ********** */
/* aye this belongs to arith.c */
@@ -258,17 +269,18 @@ static void softbody_calc_forces(Object *ob, float dtime)
{
SoftBody *sb= ob->soft; // is supposed to be there
BodyPoint *bp;
float iks,ks,kd,gravity,actspringlen,forcefactor,sd[3];
int a,b;
BodyPoint *bproot;
BodySpring *bs;
float iks, ks, kd, gravity, actspringlen, forcefactor, sd[3];
int a, b;
/* clear forces */
for(a=sb->totpoint, bp= sb->bpoint; a>0; a--, bp++) {
bp->force[0]= bp->force[1]= bp->force[2]= 0.0;
}
gravity = ob->sb_nodemass * ob->sb_grav * rescale_grav_to_framerate;
iks = 1.0f/(1.0f-ob->sb_inspring)-1.0f ;/* inner spring constants function */
gravity = sb->nodemass * sb->grav * rescale_grav_to_framerate;
iks = 1.0f/(1.0f-sb->inspring)-1.0f ;/* inner spring constants function */
bproot= sb->bpoint; /* need this for proper spring addressing */
for(a=sb->totpoint, bp= sb->bpoint; a>0; a--, bp++) {
@@ -278,34 +290,36 @@ static void softbody_calc_forces(Object *ob, float dtime)
float absvel =0, projvel= 0;
/* do goal stuff */
/* true elastic goal */
VecSubf(auxvect,bp->origT,bp->pos);
ks = 1.0f/(1.0f- bp->goal*ob->sb_goalspring)-1.0f ;
bp->force[0]= ks*(auxvect[0]);
bp->force[1]= ks*(auxvect[1]);
bp->force[2]= ks*(auxvect[2]);
/* calulate damping forces generated by goals*/
VecSubf(velgoal,bp->origS, bp->origE);
kd = ob->sb_goalfrict * rescale_friction_to_framerate ;
if(ob->softflag & OB_SB_GOAL) {
/* true elastic goal */
VecSubf(auxvect,bp->origT,bp->pos);
ks = 1.0f/(1.0f- bp->goal*sb->goalspring)-1.0f ;
bp->force[0]= ks*(auxvect[0]);
bp->force[1]= ks*(auxvect[1]);
bp->force[2]= ks*(auxvect[2]);
/* calulate damping forces generated by goals*/
VecSubf(velgoal,bp->origS, bp->origE);
kd = sb->goalfrict * rescale_friction_to_framerate ;
if (dtime > 0.0 ) { // make sure friction does not become rocket motor on time reversal
bp->force[0]-= kd * (velgoal[0] + bp->vec[0]);
bp->force[1]-= kd * (velgoal[1] + bp->vec[1]);
bp->force[2]-= kd * (velgoal[2] + bp->vec[2]);
}
else {
bp->force[0]-= kd * (velgoal[0] - bp->vec[0]);
bp->force[1]-= kd * (velgoal[1] - bp->vec[1]);
bp->force[2]-= kd * (velgoal[2] - bp->vec[2]);
if (dtime > 0.0 ) { // make sure friction does not become rocket motor on time reversal
bp->force[0]-= kd * (velgoal[0] + bp->vec[0]);
bp->force[1]-= kd * (velgoal[1] + bp->vec[1]);
bp->force[2]-= kd * (velgoal[2] + bp->vec[2]);
}
else {
bp->force[0]-= kd * (velgoal[0] - bp->vec[0]);
bp->force[1]-= kd * (velgoal[1] - bp->vec[1]);
bp->force[2]-= kd * (velgoal[2] - bp->vec[2]);
}
}
/* done goal stuff */
/* gravitation */
bp->force[2]-= gravity*ob->sb_nodemass; /* individual mass of node here */
bp->force[2]-= gravity*sb->nodemass; /* individual mass of node here */
/* friction in media */
kd= ob->sb_mediafrict* rescale_friction_to_framerate;
kd= sb->mediafrict* rescale_friction_to_framerate;
/* assume it to be proportional to actual velocity */
bp->force[0]-= bp->vec[0]*kd;
bp->force[1]-= bp->vec[1]*kd;
@@ -326,85 +340,87 @@ static void softbody_calc_forces(Object *ob, float dtime)
hrms .. may be a rough one could be used as well .. let's see
*/
if (1){ /* big mesh optimization */
/* run over attached inner spring list */
if (sb->bspring){ // spring list exists at all ?
for(b=bp->nofsprings;b>0;b--){
bs = sb->bspring + bp->springs[b-1];
if(ob->softflag & OB_SB_EDGES) {
if (1){ /* big mesh optimization */
/* run over attached inner spring list */
if (sb->bspring){ // spring list exists at all ?
for(b=bp->nofsprings;b>0;b--){
bs = sb->bspring + bp->springs[b-1];
if (( (sb->totpoint-a) == bs->v1) ){
actspringlen= VecLenf( (bproot+bs->v2)->pos, bp->pos);
VecSubf(sd,(bproot+bs->v2)->pos, bp->pos);
Normalise(sd);
// friction stuff V1
VecSubf(velgoal,bp->vec,(bproot+bs->v2)->vec);
kd = sb->infrict * rescale_friction_to_framerate ;
absvel = Normalise(velgoal);
projvel = ABS(Inpf(sd,velgoal));
kd *= absvel * projvel;
Vec3PlusStVec(bp->force,-kd,velgoal);
if(bs->len > 0.0) /* check for degenerated springs */
forcefactor = (bs->len - actspringlen)/bs->len * iks;
else
forcefactor = actspringlen * iks;
Vec3PlusStVec(bp->force,-forcefactor,sd);
}
if (( (sb->totpoint-a) == bs->v2) ){
actspringlen= VecLenf( (bproot+bs->v1)->pos, bp->pos);
VecSubf(sd,bp->pos,(bproot+bs->v1)->pos);
Normalise(sd);
// friction stuff V2
VecSubf(velgoal,bp->vec,(bproot+bs->v1)->vec);
kd = sb->infrict * rescale_friction_to_framerate ;
absvel = Normalise(velgoal);
projvel = ABS(Inpf(sd,velgoal));
kd *= absvel * projvel;
Vec3PlusStVec(bp->force,-kd,velgoal);
if(bs->len > 0.0)
forcefactor = (bs->len - actspringlen)/bs->len * iks;
else
forcefactor = actspringlen * iks;
Vec3PlusStVec(bp->force,+forcefactor,sd);
}
}
} //if spring list exists at all ?
}
else{ // this branch is not completly uptaded for friction stuff
/* scan for attached inner springs makes it a O(N^2) thing = bad !*/
/* obsolete .. but if someone wants to try the effect :) */
for(b=sb->totspring, bs= sb->bspring; b>0; b--, bs++) {
if (( (sb->totpoint-a) == bs->v1) ){
actspringlen= VecLenf( (bproot+bs->v2)->pos, bp->pos);
VecSubf(sd,(bproot+bs->v2)->pos, bp->pos);
Normalise(sd);
// friction stuff V1
VecSubf(velgoal,bp->vec,(bproot+bs->v2)->vec);
kd = ob->sb_infrict * rescale_friction_to_framerate ;
absvel = Normalise(velgoal);
projvel = ABS(Inpf(sd,velgoal));
kd *= absvel * projvel;
Vec3PlusStVec(bp->force,-kd,velgoal);
if(bs->len > 0.0) /* check for degenerated springs */
forcefactor = (bs->len - actspringlen)/bs->len * iks;
else
forcefactor = actspringlen * iks;
Vec3PlusStVec(bp->force,-forcefactor,sd);
}
if (( (sb->totpoint-a) == bs->v2) ){
actspringlen= VecLenf( (bproot+bs->v1)->pos, bp->pos);
VecSubf(sd,bp->pos,(bproot+bs->v1)->pos);
Normalise(sd);
// friction stuff V2
VecSubf(velgoal,bp->vec,(bproot+bs->v1)->vec);
kd = ob->sb_infrict * rescale_friction_to_framerate ;
absvel = Normalise(velgoal);
projvel = ABS(Inpf(sd,velgoal));
kd *= absvel * projvel;
Vec3PlusStVec(bp->force,-kd,velgoal);
if(bs->len > 0.0)
forcefactor = (bs->len - actspringlen)/bs->len * iks;
else
forcefactor = actspringlen * iks;
Vec3PlusStVec(bp->force,+forcefactor,sd);
Vec3PlusStVec(bp->force,+forcefactor,sd);
}
}
} //if spring list exists at all ?
}
else{ // this branch is not completly uptaded for friction stuff
/* scan for attached inner springs makes it a O(N^2) thing = bad !*/
/* obsolete .. but if someone wants to try the effect :) */
for(b=sb->totspring, bs= sb->bspring; b>0; b--, bs++) {
if (( (sb->totpoint-a) == bs->v1) ){
actspringlen= VecLenf( (bproot+bs->v2)->pos, bp->pos);
VecSubf(sd,(bproot+bs->v2)->pos, bp->pos);
Normalise(sd);
if(bs->len > 0.0) /* check for degenerated springs */
forcefactor = (bs->len - actspringlen)/bs->len * iks;
else
forcefactor = actspringlen * iks;
Vec3PlusStVec(bp->force,-forcefactor,sd);
}
if (( (sb->totpoint-a) == bs->v2) ){
actspringlen= VecLenf( (bproot+bs->v1)->pos, bp->pos);
VecSubf(sd,bp->pos,(bproot+bs->v1)->pos);
Normalise(sd);
if(bs->len > 0.0)
forcefactor = (bs->len - actspringlen)/bs->len * iks;
else
forcefactor = actspringlen * iks;
Vec3PlusStVec(bp->force,+forcefactor,sd);
}
}// no snap
}//for
}// no snap
}//for
}// if use edges
}
}
}
@@ -417,11 +433,11 @@ static void softbody_apply_forces(Object *ob, float dtime, int mode, float *err)
SoftBody *sb= ob->soft; // is supposed to be there
BodyPoint *bp;
float dx[3],dv[3];
int a;
float timeovermass;
float maxerr = 0.0;
int a;
if (ob->sb_nodemass > 0.09999f) timeovermass = dtime/ob->sb_nodemass;
if (sb->nodemass > 0.09999f) timeovermass = dtime/sb->nodemass;
else timeovermass = dtime/0.09999f;
for(a=sb->totpoint, bp= sb->bpoint; a>0; a--, bp++) {
@@ -436,8 +452,8 @@ static void softbody_apply_forces(Object *ob, float dtime, int mode, float *err)
/* some nasty if's to have heun in here too */
VECCOPY(dv,bp->force);
if (mode == 1){
VECCOPY(bp->prevvec,bp->vec);
VECCOPY(bp->prevdv ,dv);
VECCOPY(bp->prevvec, bp->vec);
VECCOPY(bp->prevdv, dv);
}
if (mode ==2){
/* be optimistic and execute step */
@@ -488,41 +504,14 @@ static void softbody_restore_prev_step(Object *ob)
{
SoftBody *sb= ob->soft; // is supposed to be there
BodyPoint *bp;
int a;
for(a=sb->totpoint, bp= sb->bpoint; a>0; a--, bp++) {
VECCOPY(bp->vec,bp->prevvec);
VECCOPY(bp->pos,bp->prevpos);
}
}
/* unused */
#if 0
static void softbody_apply_goal(Object *ob, float dtime)
{
SoftBody *sb= ob->soft; // is supposed to be there
BodyPoint *bp;
float vec[3], ks;
int a;
for(a=sb->totpoint, bp= sb->bpoint; a>0; a--, bp++) {
ks= bp->goal*dtime;
// this is hackish, screws up physics but stabilizes
vec[0]= ks*(bp->origT[0]-bp->pos[0]);
vec[1]= ks*(bp->origT[1]-bp->pos[1]);
vec[2]= ks*(bp->origT[2]-bp->pos[2]);
VECADD(bp->pos, bp->pos, vec);
ks= 1.0f-ks;
bp->vec[0]*= ks;
bp->vec[1]*= ks;
bp->vec[2]*= ks;
VECCOPY(bp->vec, bp->prevvec);
VECCOPY(bp->pos, bp->prevpos);
}
}
#endif
static void softbody_apply_goalsnap(Object *ob)
{
@@ -538,6 +527,8 @@ static void softbody_apply_goalsnap(Object *ob)
}
}
/* unused */
#if 0
static void softbody_force_goal(Object *ob)
{
SoftBody *sb= ob->soft; // is supposed to be there
@@ -551,44 +542,67 @@ static void softbody_force_goal(Object *ob)
bp->vec[2] = bp->origE[2] - bp->origS[2];
}
}
#endif
/* expects full initialized softbody */
static void interpolate_exciter(Object *ob, int timescale, int time)
{
Mesh *me= ob->data;
//MEdge *medge= me->medge;
int a;
SoftBody *sb= ob->soft;
BodyPoint *bp;
float f;
int a;
// note: i removed Mesh usage here, softbody should remain generic! (ton)
if(ob->soft) {
f = (float)time/(float)timescale;
bp= ob->soft->bpoint;
for(a=0; a<me->totvert; a++, bp++) {
bp->origT[0] = bp->origS[0] + f*(bp->origE[0] - bp->origS[0]);
bp->origT[1] = bp->origS[1] + f*(bp->origE[1] - bp->origS[1]);
bp->origT[2] = bp->origS[2] + f*(bp->origE[2] - bp->origS[2]);
if (bp->goal >= SOFTGOALSNAP){
bp->vec[0] = bp->origE[0] - bp->origS[0];
bp->vec[1] = bp->origE[1] - bp->origS[1];
bp->vec[2] = bp->origE[2] - bp->origS[2];
}
f = (float)time/(float)timescale;
for(a=sb->totpoint, bp= sb->bpoint; a>0; a--, bp++) {
bp->origT[0] = bp->origS[0] + f*(bp->origE[0] - bp->origS[0]);
bp->origT[1] = bp->origS[1] + f*(bp->origE[1] - bp->origS[1]);
bp->origT[2] = bp->origS[2] + f*(bp->origE[2] - bp->origS[2]);
if (bp->goal >= SOFTGOALSNAP){
bp->vec[0] = bp->origE[0] - bp->origS[0];
bp->vec[1] = bp->origE[1] - bp->origS[1];
bp->vec[2] = bp->origE[2] - bp->origS[2];
}
}
if(ob->softflag & OB_SB_EDGES) {
/* hrms .. do springs alter their lenght ?
if(medge) {
bs= ob->soft->bspring;
bp= ob->soft->bpoint;
for(a=0; (a<me->totedge && a < ob->soft->totspring ); a++, medge++, bs++) {
bs->len= VecLenf( (bp+bs->v1)->origT, (bp+bs->v2)->origT);
}
for(a=0; (a<me->totedge && a < ob->soft->totspring ); a++, bs++) {
bs->len= VecLenf( (bp+bs->v1)->origT, (bp+bs->v2)->origT);
}
*/
}
}
}
/* ************ convertors ********** */
/* for each object type we need;
- xxxx_to_softbody(Object *ob) : a full (new) copy
- xxxx_update_softbody(Object *ob) : update refreshes current positions
- softbody_to_xxxx(Object *ob) : after simulation, copy vertex locations back
*/
static int object_has_edges(Object *ob)
{
if(ob->type==OB_MESH) {
Mesh *me= ob->data;
if(me->medge) return 1;
}
else if(ob->type==OB_LATTICE) {
;
}
return 0;
}
/* copy original (new) situation in softbody, as result of matrices or deform */
/* is assumed to enter function with ob->soft, but can be without points */
static void mesh_update_softbody(Object *ob)
{
Mesh *me= ob->data;
@@ -596,7 +610,11 @@ static void mesh_update_softbody(Object *ob)
/* MEdge *medge= me->medge; */ /*unused*/
BodyPoint *bp;
int a;
if(ob->soft) {
/* possible after a file read... */
if(ob->soft->totpoint!=me->totvert) sbObjectToSoftbody(ob);
if(me->totvert) {
bp= ob->soft->bpoint;
for(a=0; a<me->totvert; a++, mvert++, bp++) {
@@ -605,30 +623,39 @@ static void mesh_update_softbody(Object *ob)
Mat4MulVecfl(ob->obmat, bp->origE);
VECCOPY(bp->origT, bp->origE);
}
/* hrms .. do springs alter their lenght ?
if(medge) {
bs= ob->soft->bspring;
bp= ob->soft->bpoint;
for(a=0; (a<me->totedge && a < ob->soft->totspring ); a++, medge++, bs++) {
bs->len= VecLenf( (bp+bs->v1)->origE, (bp+bs->v2)->origE);
if(ob->softflag & OB_SB_EDGES) {
/* happens when in UI edges was set */
if(ob->soft->bspring==NULL)
if(object_has_edges(ob)) sbObjectToSoftbody(ob);
/* hrms .. do springs alter their lenght ?
if(medge) {
bs= ob->soft->bspring;
bp= ob->soft->bpoint;
for(a=0; (a<me->totedge && a < ob->soft->totspring ); a++, medge++, bs++) {
bs->len= VecLenf( (bp+bs->v1)->origE, (bp+bs->v2)->origE);
}
}
*/
}
*/
}
}
int get_scalar_from_named_vertexgroup(Object *ob, char *name, int vertID, float *target)
static int get_scalar_from_named_vertexgroup(Object *ob, char *name, int vertID, float *target)
/* result 0 on success, else indicates error number
-- kind of *inverse* result defintion,
-- but this way we can signal error condition to caller
-- and yes this function must not be here but in a *vertex group module*
*/
{
int i,groupindex;
bDeformGroup *locGroup = NULL;
MDeformVert *dv;
int i, groupindex;
locGroup = get_named_vertexgroup(ob,name);
if(locGroup){
/* retrieve index for that group */
@@ -654,61 +681,65 @@ int get_scalar_from_named_vertexgroup(Object *ob, char *name, int vertID, float
/* makes totally fresh start situation */
static void mesh_to_softbody(Object *ob)
{
SoftBody *sb;
Mesh *me= ob->data;
MVert *mvert= me->mvert;
MEdge *medge= me->medge;
/* MFace *mface= me->mface; */ /*unused*/
BodyPoint *bp;
BodySpring *bs;
int a;
ob->soft= new_softbody(me->totvert, me->totedge);
if(ob->soft) {
bp= ob->soft->bpoint;
for(a=me->totvert; a>0; a--, mvert++, bp++) {
VECCOPY(bp->pos, mvert->co);
Mat4MulVecfl(ob->obmat, bp->pos); // yep, sofbody is global coords
VECCOPY(bp->origS, bp->pos);
VECCOPY(bp->origE, bp->pos);
VECCOPY(bp->origT, bp->pos);
bp->vec[0]= bp->vec[1]= bp->vec[2]= 0.0;
bp->weight= 1.0;
bp->goal= 0.5;
bp->nofsprings=0;
bp->springs=NULL;
if (1) { /* switch to vg scalars*/
/* get scalar values needed *per vertex* from vertex group functions,
so we can *paint* them nicly ..
they are normalized [0.0..1.0] so may be we need amplitude for scale
which can be done by caller
but still .. i'd like it to go this way
*/
int error;
char name[32] = "SOFTGOAL";
float temp;
error = get_scalar_from_named_vertexgroup(ob,name,me->totvert - a,&temp);
if (!error) bp->goal = temp;
if (bp->goal < ob->sb_mingoal) bp->goal = ob->sb_mingoal;
if (bp->goal > ob->sb_maxgoal) bp->goal = ob->sb_maxgoal;
/* a little ad hoc changing the goal control to be less *sharp* */
bp->goal = (float)pow(bp->goal,4.0f);
/* to proove the concept
this would enable per vertex *mass painting*
strcpy(name,"SOFTMASS");
error = get_scalar_from_named_vertexgroup(ob,name,me->totvert - a,&temp);
if (!error) bp->mass = temp * ob->rangeofmass;
*/
/* renew ends with ob->soft with points and edges, also checks & makes ob->soft */
renew_softbody(ob, me->totvert, me->totedge);
/* we always make body points */
sb= ob->soft;
bp= sb->bpoint;
for(a=me->totvert; a>0; a--, mvert++, bp++) {
VECCOPY(bp->pos, mvert->co);
Mat4MulVecfl(ob->obmat, bp->pos); // yep, sofbody is global coords
VECCOPY(bp->origS, bp->pos);
VECCOPY(bp->origE, bp->pos);
VECCOPY(bp->origT, bp->pos);
bp->vec[0]= bp->vec[1]= bp->vec[2]= 0.0;
bp->weight= 1.0;
bp->goal= 0.5;
bp->nofsprings=0;
bp->springs=NULL;
if (1) { /* switch to vg scalars*/
/* get scalar values needed *per vertex* from vertex group functions,
so we can *paint* them nicly ..
they are normalized [0.0..1.0] so may be we need amplitude for scale
which can be done by caller
but still .. i'd like it to go this way
*/
int error;
char name[32] = "SOFTGOAL";
float temp;
error = get_scalar_from_named_vertexgroup(ob,name,me->totvert - a,&temp);
if (!error) bp->goal = temp;
if (bp->goal < sb->mingoal) bp->goal = sb->mingoal;
if (bp->goal > sb->maxgoal) bp->goal = sb->maxgoal;
/* a little ad hoc changing the goal control to be less *sharp* */
bp->goal = (float)pow(bp->goal,4.0f);
/* to proove the concept
this would enable per vertex *mass painting*
strcpy(name,"SOFTMASS");
error = get_scalar_from_named_vertexgroup(ob,name,me->totvert - a,&temp);
if (!error) bp->mass = temp * ob->rangeofmass;
*/
} /* switch to vg scalars */
}
} /* switch to vg scalars */
}
/* but we only optionally add body edge springs */
if (ob->softflag & OB_SB_EDGES) {
if(medge) {
bs= ob->soft->bspring;
bp= ob->soft->bpoint;
bs= sb->bspring;
bp= sb->bpoint;
for(a=me->totedge; a>0; a--, medge++, bs++) {
bs->v1= medge->v1;
bs->v2= medge->v2;
@@ -718,44 +749,11 @@ this would enable per vertex *mass painting*
}
/* insert *diagonal* springs in quads if desired */
if (ob->softflag & 0x02) {
add_quad_diag_springs(ob);
if (ob->softflag & OB_SB_QUADS) {
add_mesh_quad_diag_springs(ob);
}
build_bps_springlist(ob); /* big mesh optimization */
/* vertex colors are abused as weights here, however they're stored in faces... uhh */
/* naah .. we don't do it any more bjornmose :-)
if(mface && me->mcol) {
char *mcol= (char *)me->mcol;
for(a=me->totface; a>0; a--, mface++, mcol+=16) {
bp= ob->soft->bpoint+mface->v1;
if(bp->goal==0.5) {
bp->goal= ( (float)( (mcol + 0)[1] ) )/255.0;
}
bp= ob->soft->bpoint+mface->v2;
if(bp->goal==0.5) {
bp->goal= ( (float)( (mcol + 4)[1] ) )/255.0;
}
bp= ob->soft->bpoint+mface->v3;
if(bp->goal==0.5) {
bp->goal= ( (float)( (mcol + 8)[1]) )/255.0;
}
if(mface->v4) {
bp= ob->soft->bpoint+mface->v4;
if(bp->goal==0.5) {
bp->goal= ( (float)( (mcol + 12)[1]) )/255.0;
}
}
}
}
*/
bp= ob->soft->bpoint;
for(a=me->totvert; a>0; a--, bp++) {
//printf("a %d goal %f\n", a, bp->goal);
}
}
}
@@ -790,142 +788,174 @@ static void softbody_to_lattice(Object *ob)
}
/* copies softbody result back in object */
/* only used in sbObjectStep() */
static void softbody_to_object(Object *ob)
{
if(ob->soft==NULL) return;
switch(ob->type) {
case OB_MESH:
softbody_to_mesh(ob);
break;
case OB_LATTICE:
softbody_to_lattice(ob);
break;
}
}
/* copy original (new) situation in softbody, as result of matrices or deform */
/* used in sbObjectStep() and sbObjectReset() */
/* assumes to have ob->soft, but can be entered without points */
static void object_update_softbody(Object *ob)
{
switch(ob->type) {
case OB_MESH:
mesh_update_softbody(ob);
break;
case OB_LATTICE:
//lattice_update_softbody(ob);
break;
}
}
/* ************ Object level, exported functions *************** */
/* copy original (new) situation in softbody, as result of matrices or deform */
void object_update_softbody(Object *ob)
/* allocates and initializes general main data */
SoftBody *sbNew(void)
{
switch(ob->type) {
case OB_MESH:
mesh_update_softbody(ob);
break;
case OB_LATTICE:
//lattice_update_softbody(ob);
break;
}
SoftBody *sb;
sb= MEM_callocN(sizeof(SoftBody), "softbody");
sb->mediafrict= 1.0;
sb->nodemass= 1.0;
sb->grav= 0.0;
sb->goalspring= 1.0;
sb->goalfrict= 1.0;
sb->mingoal= 0.0;
sb->maxgoal= 1.0;
sb->inspring= 1.0;
sb->infrict= 1.0;
return sb;
}
/* makes totally fresh start situation */
void object_to_softbody(Object *ob,float ctime)
/* frees all */
void sbFree(SoftBody *sb)
{
free_softbody_intern(sb);
MEM_freeN(sb);
}
/* makes totally fresh start situation */
void sbObjectToSoftbody(Object *ob)
{
if(ob->soft) free_softbody(ob->soft);
ob->soft= NULL;
switch(ob->type) {
case OB_MESH:
mesh_to_softbody(ob);
ob->soft->ctime = ctime;
break;
case OB_LATTICE:
lattice_to_softbody(ob);
break;
}
if(ob->soft) ob->soft->ctime= bsystem_time(ob, NULL, (float)G.scene->r.cfra, 0.0);
}
/* copies softbody result back in object */
void softbody_to_object(Object *ob)
/* reset all motion */
void sbObjectReset(Object *ob)
{
if(ob->soft==NULL) return;
SoftBody *sb= ob->soft;
BodyPoint *bp;
int a;
switch(ob->type) {
case OB_MESH:
softbody_to_mesh(ob);
break;
case OB_LATTICE:
softbody_to_lattice(ob);
break;
if(sb==NULL) return;
sb->ctime= bsystem_time(ob, NULL, (float)G.scene->r.cfra, 0.0);
object_update_softbody(ob);
for(a=sb->totpoint, bp= sb->bpoint; a>0; a--, bp++) {
// origS is previous timestep
VECCOPY(bp->origS, bp->origE);
VECCOPY(bp->pos, bp->origE);
bp->vec[0]= bp->vec[1]= bp->vec[2]= 0.0f;
// no idea about the Heun stuff! (ton)
}
}
/* simulates one step. ctime is in frames not seconds */
void object_softbody_step(Object *ob, float ctime)
/* simulates one step. framenr is in frames */
/* copies result back to object, displist */
void sbObjectStep(Object *ob, float framenr)
{
SoftBody *sb;
float dtime;
int timescale,t;
float forcetime;
float ctime, forcetime;
float err;
/* this is a NO! NO!
==========================
if(ob->soft==NULL) {
object_to_softbody(ob);
if(ob->soft==NULL) return;
ob->soft->ctime= ctime;
}
// you can't create a soft object on the fly
// 1. inner spings need a *default* length for crinkles/wrinkles,
// surface area and volume preservation
// 2. initial conditions for velocities and positions need to be defined
// for a certain point of time .. say t0
// 3. and since we have friction and *outer* movement
// the history of the *outer* movements will affect where we end up
// sooo atm going to edit mode and back ( back calls object_to_softbody(ob,1.0f)
is the only way to create softbody data
*/
/* first attempt to set initial conditions for softbodies
rules
1. ODE solving is disabled / via button in 3dview header /otherways do regular softbody stuff
2. set SB positions to *goal*
3. set SB velocities to match *goal* movement
*/
if (SB_ENABLE == 0){
if(ob->soft==NULL) {
return; /* nothing to do */
}
object_update_softbody(ob);
ob->soft->ctime= ctime;
interpolate_exciter(ob,200,200);
softbody_force_goal(ob);
softbody_to_object(ob);
return; /* no dynamics wanted */
}
if(ob->soft==NULL) {
/* aye no soft object created bail out here */
printf("Softbody Zombie \n");
/* just to be nice we allow full init */
if(ob->soft==NULL) sbObjectToSoftbody(ob);
/* this is after reading new file, or acceptable as signal to refresh */
else if(ob->soft->totpoint==0) sbObjectToSoftbody(ob);
sb= ob->soft;
/* still no points? go away */
if(sb->totpoint==0) return;
/* checking time: */
ctime= bsystem_time(ob, NULL, framenr, 0.0);
softbody_scale_time(steptime); // translate frames/sec and lenghts unit to SI system
dtime= ctime - sb->ctime;
// dtime= ABS(dtime); no no we want to go back in time with IPOs
timescale = (int)(sb->rklimit * ABS(dtime));
// bail out for negative or for large steps
if(dtime<0.0 || dtime >= 9.9*G.scene->r.framelen) {
sbObjectReset(ob);
return;
}
softbody_scale_time(steptime); // translate frames/sec and lenghts unit to SI system
dtime= ctime - ob->soft->ctime;
// dtime= ABS(dtime); no no we want to go back in time with IPOs
timescale = (int)(ob->softtime * ABS(dtime));
if(ABS(dtime) > 0.0) {
/* the simulator */
if(ABS(dtime) > 0.0) { // note: what does this mean now? (ton)
object_update_softbody(ob);
if (ob->softflag & 0x04){
if (TRUE) { // RSOL1 always true now (ton)
/* special case of 2nd order Runge-Kutta type AKA Heun */
float timedone =0.0;
/* counter for emergency brake
* we don't want to lock up the system if physics fail
*/
int loops =0 ;
SoftHeunTol = ob->softtime; // humm .. this should be calculated from sb parameters and sizes
SoftHeunTol = sb->rklimit; // humm .. this should be calculated from sb parameters and sizes
forcetime = dtime; /* hope for integrating in one step */
while ( (ABS(timedone) < ABS(dtime)) && (loops < 2000) )
{
if (ABS(dtime) > 3.0 ){
printf("SB_STEPSIZE \n");
if(G.f & G_DEBUG) printf("SB_STEPSIZE \n");
break; // sorry but i must assume goal movement can't be interpolated any more
}
//set goals in time
interpolate_exciter(ob,200,(int)(200.0*(timedone/dtime)));
// do predictive euler step
softbody_calc_forces(ob,forcetime);
softbody_apply_forces(ob,forcetime,1, NULL);
softbody_calc_forces(ob, forcetime);
softbody_apply_forces(ob, forcetime, 1, NULL);
// crop new slope values to do averaged slope step
softbody_calc_forces(ob,forcetime);
softbody_apply_forces(ob,forcetime,2, &err);
softbody_calc_forces(ob, forcetime);
softbody_apply_forces(ob, forcetime, 2, &err);
softbody_apply_goalsnap(ob);
if (err > SoftHeunTol){ // error needs to be scaled to some quantity
@@ -933,24 +963,27 @@ void object_softbody_step(Object *ob, float ctime)
forcetime /= 2.0;
}
else {
float newtime = forcetime * 1.1f; // hope for 1.1 times better conditions in next step
if (err > SoftHeunTol/2.0){ // stay with this stepsize unless err really small
newtime = forcetime;
}
timedone += forcetime;
if (forcetime > 0.0)
forcetime = MIN2(dtime - timedone,newtime);
forcetime = MIN2(dtime - timedone,newtime);
else
forcetime = MAX2(dtime - timedone,newtime);
forcetime = MAX2(dtime - timedone,newtime);
}
loops++;
}
// move snapped to final position
interpolate_exciter(ob,2,2);
interpolate_exciter(ob, 2, 2);
softbody_apply_goalsnap(ob);
if (loops > HEUNWARNLIMIT) /* monitor high loop counts say 1000 after testing */
printf("%d heun integration loops/frame \n",loops);
if(G.f & G_DEBUG) {
if (loops > HEUNWARNLIMIT) /* monitor high loop counts say 1000 after testing */
printf("%d heun integration loops/frame \n",loops);
}
}
else
/* do brute force explicit euler */
@@ -965,44 +998,42 @@ void object_softbody_step(Object *ob, float ctime)
/* the *goal* mesh must use the n*h timing too !
use *cheap* linear intepolation for that */
interpolate_exciter(ob,timescale,t);
if (timescale > 0 )
{
forcetime = dtime/timescale;
if (timescale > 0 ) {
forcetime = dtime/timescale;
/* does not fit the concept sloving ODEs :) */
/* softbody_apply_goal(ob,forcetime ); */
/* explicit Euler integration */
/* we are not controling a nuclear power plant!
so rought *almost* physical behaviour is acceptable.
in cases of *mild* stiffnes cranking up timscale -> decreasing stepsize *h*
avoids instability */
softbody_calc_forces(ob,forcetime);
softbody_apply_forces(ob,forcetime,0, NULL);
softbody_apply_goalsnap(ob);
/* does not fit the concept sloving ODEs :) */
/* softbody_apply_goal(ob,forcetime ); */
/* explicit Euler integration */
/* we are not controling a nuclear power plant!
so rought *almost* physical behaviour is acceptable.
in cases of *mild* stiffnes cranking up timscale -> decreasing stepsize *h*
avoids instability */
softbody_calc_forces(ob,forcetime);
softbody_apply_forces(ob,forcetime,0, NULL);
softbody_apply_goalsnap(ob);
// if (0){
/* ok here comes the <20>berhammer
use a semi implicit euler integration to tackle *all* stiff conditions
but i doubt the cost/benifit holds for most of the cases
-- to be coded*/
// }
// if (0){
/* ok here comes the <20>berhammer
use a semi implicit euler integration to tackle *all* stiff conditions
but i doubt the cost/benifit holds for most of the cases
-- to be coded*/
// }
}
}
/* and apply to vertices */
softbody_to_object(ob);
ob->soft->ctime= ctime;
sb->ctime= ctime;
} // if(ABS(dtime) > 0.0)
else {
// rule : you have asked for the current state of the softobject
// since dtime= ctime - ob->soft->ctime;
// and we were not notifified about any other time changes
// so here it is !
softbody_to_object(ob);
// rule : you have asked for the current state of the softobject
// since dtime= ctime - ob->soft->ctime;
// and we were not notifified about any other time changes
// so here it is !
softbody_to_object(ob);
}
}

View File

@@ -119,6 +119,7 @@
#include "BKE_object.h"
#include "BKE_sca.h" // for init_actuator
#include "BKE_scene.h"
#include "BKE_softbody.h" // sbNew()
#include "BKE_texture.h" // for open_plugin_tex
#include "BKE_utildefines.h" // SWITCH_INT DATA ENDB DNA1 O_BINARY GLOB USER TEST REND
@@ -2316,7 +2317,13 @@ static void direct_link_object(FileData *fd, Object *ob)
}
ob->pd= newdataadr(fd, ob->pd);
ob->soft= NULL;
ob->soft= newdataadr(fd, ob->soft);
if(ob->soft) {
SoftBody *sb= ob->soft; // init all stuff so it gets rebuilt nicely
sb->totpoint= sb->totspring= 0;
sb->bpoint= NULL;
sb->bspring= NULL;
}
link_list(fd, &ob->prop);
prop= ob->prop.first;
@@ -4625,6 +4632,7 @@ static void do_versions(Main *main)
}
}
if(main->versionfile <= 236) {
Object *ob;
Scene *sce= main->scene.first;
Camera *cam= main->camera.first;
bScreen *sc;
@@ -4653,6 +4661,26 @@ static void do_versions(Main *main)
}
}
}
/* temporal copy */
for(ob= main->object.first; ob; ob= ob->id.next) {
if(ob->softflag && ob->soft==NULL) {
SoftBody *sb;
ob->soft=sb= sbNew();
sb->goalspring= ob->sb_goalspring;
sb->goalfrict= ob->sb_goalfrict;
sb->inspring= ob->sb_inspring;
sb->infrict= ob->sb_infrict;
sb->nodemass= ob->sb_nodemass;
sb->grav= ob->sb_grav;
sb->mingoal= ob->sb_mingoal;
sb->maxgoal= ob->sb_maxgoal;
sb->mediafrict= ob->sb_mediafrict;
sb->rklimit= ob->softtime;
ob->softflag |= OB_SB_GOAL|OB_SB_EDGES;
}
}
}
/* don't forget to set version number in blender.c! */

View File

@@ -683,6 +683,7 @@ static void write_objects(WriteData *wd, ListBase *idbase)
write_nlastrips(wd, &ob->nlastrips);
writestruct(wd, DATA, "PartDeflect", 1, ob->pd);
writestruct(wd, DATA, "SoftBody", 1, ob->soft);
for(hook= ob->hooks.first; hook; hook= hook->next) {
writestruct(wd, DATA, "ObHook", 1, hook);

View File

@@ -51,7 +51,8 @@ struct BoundBox;
struct Path;
struct Material;
struct bConstraintChannel;
struct SoftBody;
struct BodyPoint;
struct BodySpring;
typedef struct bDeformGroup {
struct bDeformGroup *next, *prev;
@@ -90,6 +91,31 @@ typedef struct PartDeflect {
float f_power; /* The power law - real gravitation is 2 (square) */
} PartDeflect;
typedef struct SoftBody {
/* dynamic data */
int totpoint, totspring;
struct BodyPoint *bpoint; /* not saved in file */
struct BodySpring *bspring; /* not saved in file */
float ctime; /* last time calculated */
/* part of UI: */
float nodemass; /* softbody mass of *vertex* */
float grav; /* softbody amount of gravitaion to apply */
float mediafrict; /* friction to env */
float rklimit; /* error limit for ODE solver */
float goalspring; /* softbody goal springs */
float goalfrict; /* softbody goal springs friction */
float mingoal; /* quick limits for goal */
float maxgoal;
float inspring; /* softbody inner springs */
float infrict; /* softbody inner springs friction */
float pad;
} SoftBody;
typedef struct Object {
ID id;
@@ -150,7 +176,7 @@ typedef struct Object {
* For a Sphere, the form factor is by default = 0.4
*/
float formfactor, softtime; /* springf temp for softbody */
float formfactor, softtime; /* softtime temp for softbody, remove it before release! */
float rdamping, sizefac;
char dt, dtx;
@@ -194,7 +220,7 @@ typedef struct Object {
ListBase hooks;
PartDeflect *pd; /* particle deflector/attractor/collision data */
struct SoftBody *soft; /* only runtime, not saved in file! */
struct SoftBody *soft; /* if exists, saved in file */
struct Life *life;
LBuf lbuf;
@@ -387,6 +413,14 @@ extern Object workob;
#define OB_ADDACT 1024
#define OB_SHOWCONT 2048
/* ob->softflag */
#define OB_SB_ENABLE 1
#define OB_SB_GOAL 2
#define OB_SB_EDGES 4
#define OB_SB_QUADS 8
#define OB_SB_POSTDEF 16
#ifdef __cplusplus
}
#endif

View File

@@ -47,6 +47,7 @@
#include "BKE_global.h"
#include "BKE_main.h"
#include "BKE_library.h"
#include "BKE_softbody.h"
#include "BLI_blenlib.h"
#include "BLI_arithb.h"
@@ -1439,34 +1440,6 @@ static void object_panel_deflectors(Object *ob)
}
uiBlockEndAlign(block);
}
/*
if(strncmp(ob->id.name+2, "soft", 4)==0) {
int ypos = 220;
uiBlockBeginAlign(block);
uiDefButS(block, TOG|BIT|0, B_DIFF, "Soft Body", 220,ypos,200,20, &ob->softflag, 0, 0, 0, 0, "Sets object to become soft body");
uiDefButS(block, TOG|BIT|1, B_DIFF, "Stiff Quads", 220,ypos -= 20,100,20, &ob->softflag, 0, 0, 0, 0, "Sets object to have diagonal springs on 4-gons");
uiDefButS(block, TOG|BIT|2, B_DIFF, "R sol 1", 320,ypos,100,20, &ob->softflag, 0, 0, 0, 0, "Use Robust 2nd order solver");
uiDefButF(block, NUMSLI, B_DIFF, "GSpring:", 220,ypos -= 20,200,20, &ob->sb_goalspring, 0.0, 0.999, 10, 0, "Goal Spring Constant");
uiDefButF(block, NUM, B_DIFF, "GFrict:", 220,ypos -= 20,200,20, &ob->sb_goalfrict , 0.0, 10.0, 10, 0, "Goal Friction Constant");
uiDefButF(block, NUMSLI, B_DIFF, "ISpring:", 220,ypos -= 20,200,20, &ob->sb_inspring, 0.0, 0.999, 10, 0, "Inner Spring Constant");
uiDefButF(block, NUM, B_DIFF, "IFrict:", 220,ypos -= 20,200,20, &ob->sb_infrict, 0.0, 10.0, 10, 0, "Inner Friction Constant");
uiDefButF(block, NUM, B_DIFF, "MFrict:", 220,ypos -= 20,200,20, &ob->sb_mediafrict, 0.0, 10.0, 10, 0, "Friction in media");
if (ob->softflag & 0x4)
uiDefButF(block, NUMSLI, B_DIFF, "RKL:", 220,ypos -= 20,200,20, &ob->softtime , 0.01, 1.0, 10, 0, "ODE solver error limit");
else
uiDefButF(block, NUM, B_DIFF, "Steps:", 220,ypos -= 20,200,20, &ob->softtime , 1.0, 500.0, 10, 0, "Softbody time");
uiDefButF(block, NUM, B_DIFF, "NMass:", 220,ypos -= 20,200,20, &ob->sb_nodemass , 0.001, 50.0, 10, 0, "Node Mass");
uiDefButF(block, NUM, B_DIFF, "Grav:", 220,ypos -= 20,200,20, &ob->sb_grav , 0.0, 10.0, 10, 0, "Gravitation");
uiDefButF(block, NUMSLI, B_DIFF, "GMin:", 220,ypos -= 20,200,20, &ob->sb_mingoal, 0.0, 1.0, 10, 0, "Min Goal bound");
uiDefButF(block, NUMSLI, B_DIFF, "GMax:", 220,ypos -= 20,200,20, &ob->sb_maxgoal, 0.0, 1.0, 10, 0, "Max Goal bound");
uiDefButS(block, TOG|BIT|3, B_DIFF, "PostDef",220,ypos-= 20,100,20, &ob->softflag, 0, 0, 0, 0, "Apply Soft AFTER Deform");
uiBlockEndAlign(block);
}
*/
}
/* Panel for softbodies */
@@ -1474,36 +1447,50 @@ static void object_panel_deflectors(Object *ob)
static void object_softbodies(Object *ob)
{
uiBlock *block;
int ypos = 220;
if(strncmp(ob->id.name+2, "soft", 4)!=0) {return;}
block= uiNewBlock(&curarea->uiblocks, "object_softbodies", UI_EMBOSS, UI_HELV, curarea->win);
uiNewPanelTabbed("Constraints", "Object");
if(uiNewPanel(curarea, block, "Softbodies", "Object", 640, 0, 318, 204)==0) return;
if(uiNewPanel(curarea, block, "Softbody", "Object", 640, 0, 318, 204)==0) return;
uiBlockBeginAlign(block);
uiDefButS(block, TOG|BIT|0, REDRAWBUTSOBJECT, "Soft Body", 220,ypos,200,20, &ob->softflag, 0, 0, 0, 0, "Sets object to become soft body");
if ( ob->softflag & 0x01) {
uiDefButS(block, TOG|BIT|1, B_DIFF, "Stiff Quads", 220,ypos -= 20,100,20, &ob->softflag, 0, 0, 0, 0, "Sets object to have diagonal springs on 4-gons");
uiDefButS(block, TOG|BIT|2, B_DIFF, "R sol 1", 320,ypos,100,20, &ob->softflag, 0, 0, 0, 0, "Use Robust 2nd order solver");
uiDefButBitS(block, TOG, OB_SB_ENABLE, REDRAWBUTSOBJECT, "Enable Soft Body", 10,200,150,20, &ob->softflag, 0, 0, 0, 0, "Sets object to become soft body");
uiDefBut(block, LABEL, 0, "", 160, 200,150,20, NULL, 0.0, 0.0, 0, 0, ""); // alignment reason
if(ob->softflag & OB_SB_ENABLE) {
SoftBody *sb= ob->soft;
uiDefButF(block, NUMSLI, B_DIFF, "GSpring:", 220,ypos -= 20,200,20, &ob->sb_goalspring, 0.0, 0.999, 10, 0, "Goal Spring Constant");
uiDefButF(block, NUM, B_DIFF, "GFrict:", 220,ypos -= 20,200,20, &ob->sb_goalfrict , 0.0, 10.0, 10, 0, "Goal Friction Constant");
uiDefButF(block, NUMSLI, B_DIFF, "ISpring:", 220,ypos -= 20,200,20, &ob->sb_inspring, 0.0, 0.999, 10, 0, "Inner Spring Constant");
uiDefButF(block, NUM, B_DIFF, "IFrict:", 220,ypos -= 20,200,20, &ob->sb_infrict, 0.0, 10.0, 10, 0, "Inner Friction Constant");
uiDefButF(block, NUM, B_DIFF, "MFrict:", 220,ypos -= 20,200,20, &ob->sb_mediafrict, 0.0, 10.0, 10, 0, "Friction in media");
if (ob->softflag & 0x4)
uiDefButF(block, NUMSLI, B_DIFF, "RKL:", 220,ypos -= 20,200,20, &ob->softtime , 0.01, 1.0, 10, 0, "ODE solver error limit");
else
uiDefButF(block, NUM, B_DIFF, "Steps:", 220,ypos -= 20,200,20, &ob->softtime , 1.0, 500.0, 10, 0, "Softbody time");
uiDefButF(block, NUM, B_DIFF, "NMass:", 220,ypos -= 20,200,20, &ob->sb_nodemass , 0.001, 50.0, 10, 0, "Node Mass");
uiDefButF(block, NUM, B_DIFF, "Grav:", 220,ypos -= 20,200,20, &ob->sb_grav , 0.0, 10.0, 10, 0, "Gravitation");
uiDefButF(block, NUMSLI, B_DIFF, "GMin:", 220,ypos -= 20,200,20, &ob->sb_mingoal, 0.0, 1.0, 10, 0, "Min Goal bound");
uiDefButF(block, NUMSLI, B_DIFF, "GMax:", 220,ypos -= 20,200,20, &ob->sb_maxgoal, 0.0, 1.0, 10, 0, "Max Goal bound");
uiDefButS(block, TOG|BIT|3, B_DIFF, "PostDef",220,ypos-= 20,100,20, &ob->softflag, 0, 0, 0, 0, "Apply Soft AFTER Deform");
if(sb==NULL) {
sb= ob->soft= sbNew();
ob->softflag |= OB_SB_GOAL|OB_SB_EDGES;
}
/* GENERAL STUFF */
uiBlockBeginAlign(block);
uiDefButF(block, NUM, B_DIFF, "Friction:", 10, 170,150,20, &sb->mediafrict, 0.0, 10.0, 10, 0, "General Friction for point movements");
uiDefButF(block, NUM, B_DIFF, "Mass:", 160, 170,150,20, &sb->nodemass , 0.001, 50.0, 10, 0, "Point Mass, the heavier the slower");
uiDefButF(block, NUM, B_DIFF, "Grav:", 10,150,150,20, &sb->grav , 0.0, 10.0, 10, 0, "Apply gravitation to point movement");
uiDefButF(block, NUM, B_DIFF, "RKL:", 160,150,150,20, &sb->rklimit , 0.01, 1.0, 10, 0, "Runge-Kutta ODE solver error limit");
uiDefButBitS(block, TOG, OB_SB_POSTDEF, B_DIFF, "PostDef", 10,130,300,20, &ob->softflag, 0, 0, 0, 0, "Apply Soft AFTER Deform");
uiBlockEndAlign(block);
/* GOAL STUFF */
uiBlockBeginAlign(block);
uiDefButBitS(block, TOG, OB_SB_GOAL, B_DIFF, "Use Goal", 10,100,150,20, &ob->softflag, 0, 0, 0, 0, "Define forces for vertices to stick to animated position");
uiDefButF(block, NUM, B_DIFF, "GSpring:", 10,80,150,20, &sb->goalspring, 0.0, 0.999, 10, 0, "Goal (vertex target position) Spring Constant");
uiDefButF(block, NUM, B_DIFF, "GFrict:", 160,80,150,20, &sb->goalfrict , 0.0, 10.0, 10, 0, "Goal (vertex target position) Friction Constant");
uiDefButF(block, NUM, B_DIFF, "GMin:", 10,60,150,20, &sb->mingoal, 0.0, 1.0, 10, 0, "Min Goal bound");
uiDefButF(block, NUM, B_DIFF, "GMax:", 160,60,150,20, &sb->maxgoal, 0.0, 1.0, 10, 0, "Max Goal bound");
uiBlockEndAlign(block);
/* EDGE SPRING STUFF */
uiBlockBeginAlign(block);
uiDefButBitS(block, TOG, OB_SB_EDGES, B_DIFF, "Use Edges", 10,30,150,20, &ob->softflag, 0, 0, 0, 0, "Use Robust 2nd order solver");
uiDefButBitS(block, TOG, OB_SB_QUADS, B_DIFF, "Stiff Quads", 160,30,150,20, &ob->softflag, 0, 0, 0, 0, "Sets object to have diagonal springs on 4-gons");
uiDefButF(block, NUM, B_DIFF, "ESpring:", 10,10,150,20, &sb->inspring, 0.0, 0.999, 10, 0, "Edge Spring Constant");
uiDefButF(block, NUM, B_DIFF, "EFrict:", 160,10,150,20, &sb->infrict, 0.0, 10.0, 10, 0, "Edge Friction Constant");
uiBlockEndAlign(block);
}
uiBlockEndAlign(block);
}

View File

@@ -1426,7 +1426,6 @@ void swap_selectall_editipo()
}
else if(totipo_edit==0) {
ei= G.sipo->editipo;
printf("before totipo_sel %d\n", totipo_sel);
if (ei){
for(a=0; a<G.sipo->totipo; a++) {
if( ei->flag & IPO_VISIBLE ) {
@@ -1438,7 +1437,6 @@ void swap_selectall_editipo()
update_editipo_flags();
}
get_status_editipo();
printf("after totipo_sel %d\n", totipo_sel);
}
else {
ei= G.sipo->editipo;

View File

@@ -1537,13 +1537,8 @@ void exit_editmode(int freedata) /* freedata==0 at render, 1= freedata, 2= do un
/* displist make is different in editmode */
if(freedata) G.obedit= NULL;
// need to be here since
// makeDispList(ob); calls
// int mesh_modifier(Object *ob, char mode)..
// calling object_softbody_step(ob, ctime);
// needs a valid *up to date* softbody object or NULL pointer at "soft" member
// anyhow *new* dependacy graph should take care for that :)
if(ob->softflag & 0x01) object_to_softbody(ob,1.0f);
/* total remake of softbody data */
if(ob->softflag & OB_SB_ENABLE) sbObjectToSoftbody(ob);
makeDispList(ob);
@@ -1582,8 +1577,6 @@ void exit_editmode(int freedata) /* freedata==0 at render, 1= freedata, 2= do un
allqueue(REDRAWOOPS, 0);
}
scrarea_queue_headredraw(curarea);
// faaaaar to late
// if(ob->softflag & 0x01) object_to_softbody(ob);
if(G.obedit==NULL && freedata==2)
BIF_undo_push("Editmode");

View File

@@ -3361,6 +3361,7 @@ static uiBlock *view3d_faceselmenu(void *arg_unused)
static char *view3d_modeselect_pup(void)
{
Object *ob= OBACT;
static char string[1024];
char formatstr[1024];
char tempstr[1024];
@@ -3371,16 +3372,18 @@ static char *view3d_modeselect_pup(void)
sprintf(tempstr, formatstr, "Object Mode", V3D_OBJECTMODE_SEL, ICON_OBJECT);
strcat(string, tempstr);
if(ob==NULL) return string;
/* if active object is editable */
if (OBACT && ((OBACT->type == OB_MESH) || (OBACT->type == OB_ARMATURE)
|| (OBACT->type == OB_CURVE) || (OBACT->type == OB_SURF) || (OBACT->type == OB_FONT)
|| (OBACT->type == OB_MBALL) || (OBACT->type == OB_LATTICE))) {
if ( ((ob->type == OB_MESH) || (ob->type == OB_ARMATURE)
|| (ob->type == OB_CURVE) || (ob->type == OB_SURF) || (ob->type == OB_FONT)
|| (ob->type == OB_MBALL) || (ob->type == OB_LATTICE))) {
sprintf(tempstr, formatstr, "Edit Mode", V3D_EDITMODE_SEL, ICON_EDITMODE_HLT);
strcat(string, tempstr);
}
if (OBACT && OBACT->type == OB_MESH) {
if (ob->type == OB_MESH) {
sprintf(tempstr, formatstr, "UV Face Select", V3D_FACESELECTMODE_SEL, ICON_FACESEL_HLT);
strcat(string, tempstr);
@@ -3390,7 +3393,7 @@ static char *view3d_modeselect_pup(void)
strcat(string, tempstr);
if ( ((Mesh*)(OBACT->data))->dvert) {
if ( ((Mesh*)(ob->data))->dvert) {
sprintf(tempstr, formatstr, "Weight Paint", V3D_WEIGHTPAINTMODE_SEL, ICON_WPAINT_HLT);
strcat(string, tempstr);
}
@@ -3398,7 +3401,7 @@ static char *view3d_modeselect_pup(void)
/* if active object is an armature */
if (OBACT && OBACT->type==OB_ARMATURE) {
if (ob->type==OB_ARMATURE) {
sprintf(tempstr, formatstr, "Pose Mode", V3D_POSEMODE_SEL, ICON_POSE_HLT);
strcat(string, tempstr);
}
@@ -4088,11 +4091,6 @@ void view3d_buttons(void)
"Pastes the mirrored pose from the buffer");
}
}
{
extern short SB_ENABLE;
xco+= XIC+8;
uiDefButS(block, TOG|BIT|1, B_DIFF, "Soft", xco,0,XIC*3,YIC, &SB_ENABLE, 0, 0, 0, 0, "Force Softbodies to goal");
}
/* Always do this last */
curarea->headbutlen= xco+2*XIC;

View File

@@ -160,9 +160,10 @@ static void init_userdef_file(void)
}
/* transform widget settings */
if(U.tw_hotspot==0) {
U.tw_flag= U_TW_ABSOLUTE;
U.tw_hotspot= 14;
U.tw_size= 15; // percentage of window size
U.tw_handlesize= 25; // percentage of widget radius
U.tw_size= 20; // percentage of window size
U.tw_handlesize= 20; // percentage of widget radius
}
if (G.main->versionfile <= 191) {