forked from bartvdbraak/blender
Cloth: Collision improvements
This commit includes several performance, stability, and reliability improvements to cloth collisions. Most notably: * The implementation of a new self-collisions system. * Multithreading of collision detection. * Implementation of single sided collisions and normal overrides. * Replacement of the `plNearestPoints` function from Bullet with a dedicated solution. Further, this also includes several bug fixes, and algorithmic improvements. Reviewed By: brecht Differential Revision: http://developer.blender.org/D3712
This commit is contained in:
parent
a27d97d1b7
commit
0666ece2e2
@ -224,12 +224,33 @@ class PHYSICS_PT_cloth_shape(PhysicButtonsPanel, Panel):
|
||||
col.prop_search(cloth, "rest_shape_key", key, "key_blocks", text="Rest Shape Key")
|
||||
|
||||
|
||||
class PHYSICS_PT_cloth_object_collision(PhysicButtonsPanel, Panel):
|
||||
bl_label = "Object Collision"
|
||||
class PHYSICS_PT_cloth_collision(PhysicButtonsPanel, Panel):
|
||||
bl_label = "Collision"
|
||||
bl_parent_id = 'PHYSICS_PT_cloth'
|
||||
bl_options = {'DEFAULT_CLOSED'}
|
||||
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'}
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.use_property_split = True
|
||||
|
||||
cloth = context.cloth.collision_settings
|
||||
md = context.cloth
|
||||
ob = context.object
|
||||
|
||||
layout.active = (cloth.use_collision or cloth.use_self_collision) and cloth_panel_enabled(md)
|
||||
|
||||
flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=True)
|
||||
|
||||
col = flow.column()
|
||||
col.prop(cloth, "collision_quality", text="Quality")
|
||||
|
||||
|
||||
class PHYSICS_PT_cloth_object_collision(PhysicButtonsPanel, Panel):
|
||||
bl_label = "Object Collision"
|
||||
bl_parent_id = 'PHYSICS_PT_cloth_collision'
|
||||
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'}
|
||||
|
||||
def draw_header(self, context):
|
||||
cloth = context.cloth.collision_settings
|
||||
|
||||
@ -248,20 +269,18 @@ class PHYSICS_PT_cloth_object_collision(PhysicButtonsPanel, Panel):
|
||||
flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=True)
|
||||
|
||||
col = flow.column()
|
||||
col.prop(cloth, "collision_quality", text="Quality")
|
||||
col.prop(cloth, "distance_min", slider=True, text="Distance")
|
||||
col.prop(cloth, "repel_force", slider=True, text="Repel")
|
||||
|
||||
col = flow.column()
|
||||
col.prop(cloth, "distance_repel", slider=True, text="Repel Distance")
|
||||
col.prop(cloth, "friction")
|
||||
col.prop(cloth, "impulse_clamp")
|
||||
|
||||
col = flow.column()
|
||||
col.prop(cloth, "group")
|
||||
|
||||
|
||||
class PHYSICS_PT_cloth_self_collision(PhysicButtonsPanel, Panel):
|
||||
bl_label = "Self Collision"
|
||||
bl_parent_id = 'PHYSICS_PT_cloth'
|
||||
bl_options = {'DEFAULT_CLOSED'}
|
||||
bl_parent_id = 'PHYSICS_PT_cloth_collision'
|
||||
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'}
|
||||
|
||||
def draw_header(self, context):
|
||||
@ -283,9 +302,14 @@ class PHYSICS_PT_cloth_self_collision(PhysicButtonsPanel, Panel):
|
||||
flow = layout.grid_flow(row_major=False, columns=0, even_columns=True, even_rows=False, align=True)
|
||||
|
||||
col = flow.column()
|
||||
col.prop(cloth, "self_collision_quality", text="Quality")
|
||||
col.prop(cloth, "self_friction", text="Friction")
|
||||
|
||||
col = flow.column()
|
||||
col.prop(cloth, "self_distance_min", slider=True, text="Distance")
|
||||
|
||||
col = flow.column()
|
||||
col.prop(cloth, "self_impulse_clamp")
|
||||
|
||||
col = flow.column()
|
||||
col.prop_search(cloth, "vertex_group_self_collisions", ob, "vertex_groups", text="Vertex Group")
|
||||
|
||||
@ -363,6 +387,7 @@ classes = (
|
||||
PHYSICS_PT_cloth_damping,
|
||||
PHYSICS_PT_cloth_cache,
|
||||
PHYSICS_PT_cloth_shape,
|
||||
PHYSICS_PT_cloth_collision,
|
||||
PHYSICS_PT_cloth_object_collision,
|
||||
PHYSICS_PT_cloth_self_collision,
|
||||
PHYSICS_PT_cloth_property_weights,
|
||||
|
@ -377,7 +377,7 @@ class PHYSICS_PT_collision_particle(PhysicButtonsPanel, Panel):
|
||||
|
||||
|
||||
class PHYSICS_PT_collision_softbody(PhysicButtonsPanel, Panel):
|
||||
bl_label = "Softbody"
|
||||
bl_label = "Softbody And Cloth"
|
||||
bl_parent_id = "PHYSICS_PT_collision"
|
||||
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_OPENGL'}
|
||||
|
||||
@ -414,6 +414,15 @@ class PHYSICS_PT_collision_softbody(PhysicButtonsPanel, Panel):
|
||||
col = flow.column()
|
||||
col.prop(settings, "thickness_inner", text="Inner", slider=True)
|
||||
|
||||
col = flow.column()
|
||||
col.prop(settings, "cloth_friction")
|
||||
|
||||
col = flow.column()
|
||||
col.prop(settings, "use_culling")
|
||||
|
||||
col = flow.column()
|
||||
col.prop(settings, "use_normal")
|
||||
|
||||
|
||||
classes = (
|
||||
PHYSICS_PT_field,
|
||||
|
@ -117,6 +117,7 @@ typedef struct ClothVertex {
|
||||
float goal; /* goal, from SB */
|
||||
float impulse[3]; /* used in collision.c */
|
||||
float xrest[3]; /* rest position of the vertex */
|
||||
float dcvel[3]; /* delta velocities to be applied by collision response */
|
||||
unsigned int impulse_count; /* same as above */
|
||||
float avg_spring_len; /* average length of connected springs */
|
||||
float struct_stiff;
|
||||
@ -222,8 +223,7 @@ typedef struct ColliderContacts {
|
||||
} ColliderContacts;
|
||||
|
||||
// needed for implicit.c
|
||||
int cloth_bvh_objcollision (struct Depsgraph *depsgraph, struct Object *ob, struct ClothModifierData *clmd, float step, float dt );
|
||||
int cloth_points_objcollision(struct Depsgraph *depsgraph, struct Object *ob, struct ClothModifierData *clmd, float step, float dt);
|
||||
int cloth_bvh_collision(struct Depsgraph *depsgraph, struct Object *ob, struct ClothModifierData *clmd, float step, float dt);
|
||||
|
||||
void cloth_find_point_contacts(struct Depsgraph *depsgraph, struct Object *ob, struct ClothModifierData *clmd, float step, float dt,
|
||||
ColliderContacts **r_collider_contacts, int *r_totcolliders);
|
||||
@ -244,8 +244,7 @@ void clothModifier_do(struct ClothModifierData *clmd, struct Depsgraph *depsgrap
|
||||
int cloth_uses_vgroup(struct ClothModifierData *clmd);
|
||||
|
||||
// needed for collision.c
|
||||
void bvhtree_update_from_cloth(struct ClothModifierData *clmd, bool moving);
|
||||
void bvhselftree_update_from_cloth(struct ClothModifierData *clmd, bool moving);
|
||||
void bvhtree_update_from_cloth(struct ClothModifierData *clmd, bool moving, bool self);
|
||||
|
||||
// needed for button_object.c
|
||||
void cloth_clear_cache(
|
||||
|
@ -63,6 +63,7 @@ typedef enum {
|
||||
COLLISION_USE_COLLFACE = (1 << 2),
|
||||
COLLISION_IS_EDGES = (1 << 3),
|
||||
#endif
|
||||
COLLISION_INACTIVE = (1 << 4),
|
||||
} COLLISION_FLAGS;
|
||||
|
||||
|
||||
@ -73,7 +74,7 @@ typedef enum {
|
||||
typedef struct CollPair {
|
||||
unsigned int face1; // cloth face
|
||||
unsigned int face2; // object face
|
||||
double distance; // magnitude of vector
|
||||
float distance;
|
||||
float normal[3];
|
||||
float vector[3]; // unnormalized collision vector: p2-p1
|
||||
float pa[3], pb[3]; // collision point p1 on face1, p2 on face2
|
||||
|
@ -124,8 +124,7 @@ void cloth_init(ClothModifierData *clmd )
|
||||
clmd->coll_parms->epsilon = 0.015f;
|
||||
clmd->coll_parms->flags = CLOTH_COLLSETTINGS_FLAG_ENABLED;
|
||||
clmd->coll_parms->collision_list = NULL;
|
||||
clmd->coll_parms->self_loop_count = 1.0;
|
||||
clmd->coll_parms->selfepsilon = 0.75;
|
||||
clmd->coll_parms->selfepsilon = 0.015;
|
||||
clmd->coll_parms->vgroup_selfcol = 0;
|
||||
|
||||
/* These defaults are copied from softbody.c's
|
||||
@ -153,44 +152,6 @@ void cloth_init(ClothModifierData *clmd )
|
||||
clmd->point_cache->step = 1;
|
||||
}
|
||||
|
||||
static BVHTree *bvhselftree_build_from_cloth (ClothModifierData *clmd, float epsilon)
|
||||
{
|
||||
unsigned int i;
|
||||
BVHTree *bvhtree;
|
||||
Cloth *cloth;
|
||||
ClothVertex *verts;
|
||||
|
||||
if (!clmd)
|
||||
return NULL;
|
||||
|
||||
cloth = clmd->clothObject;
|
||||
|
||||
if (!cloth)
|
||||
return NULL;
|
||||
|
||||
verts = cloth->verts;
|
||||
|
||||
/* in the moment, return zero if no faces there */
|
||||
if (!cloth->mvert_num)
|
||||
return NULL;
|
||||
|
||||
/* create quadtree with k=26 */
|
||||
bvhtree = BLI_bvhtree_new(cloth->mvert_num, epsilon, 4, 6);
|
||||
|
||||
/* fill tree */
|
||||
for (i = 0; i < cloth->mvert_num; i++, verts++) {
|
||||
const float *co;
|
||||
co = verts->xold;
|
||||
|
||||
BLI_bvhtree_insert(bvhtree, i, co, 1);
|
||||
}
|
||||
|
||||
/* balance tree */
|
||||
BLI_bvhtree_balance(bvhtree);
|
||||
|
||||
return bvhtree;
|
||||
}
|
||||
|
||||
static BVHTree *bvhtree_build_from_cloth (ClothModifierData *clmd, float epsilon)
|
||||
{
|
||||
unsigned int i;
|
||||
@ -234,14 +195,21 @@ static BVHTree *bvhtree_build_from_cloth (ClothModifierData *clmd, float epsilon
|
||||
return bvhtree;
|
||||
}
|
||||
|
||||
void bvhtree_update_from_cloth(ClothModifierData *clmd, bool moving)
|
||||
void bvhtree_update_from_cloth(ClothModifierData *clmd, bool moving, bool self)
|
||||
{
|
||||
unsigned int i = 0;
|
||||
Cloth *cloth = clmd->clothObject;
|
||||
BVHTree *bvhtree = cloth->bvhtree;
|
||||
BVHTree *bvhtree;
|
||||
ClothVertex *verts = cloth->verts;
|
||||
const MVertTri *vt;
|
||||
|
||||
if (self) {
|
||||
bvhtree = cloth->bvhselftree;
|
||||
}
|
||||
else {
|
||||
bvhtree = cloth->bvhtree;
|
||||
}
|
||||
|
||||
if (!bvhtree)
|
||||
return;
|
||||
|
||||
@ -253,12 +221,12 @@ void bvhtree_update_from_cloth(ClothModifierData *clmd, bool moving)
|
||||
float co[3][3], co_moving[3][3];
|
||||
bool ret;
|
||||
|
||||
copy_v3_v3(co[0], verts[vt->tri[0]].txold);
|
||||
copy_v3_v3(co[1], verts[vt->tri[1]].txold);
|
||||
copy_v3_v3(co[2], verts[vt->tri[2]].txold);
|
||||
|
||||
/* copy new locations into array */
|
||||
if (moving) {
|
||||
copy_v3_v3(co[0], verts[vt->tri[0]].txold);
|
||||
copy_v3_v3(co[1], verts[vt->tri[1]].txold);
|
||||
copy_v3_v3(co[2], verts[vt->tri[2]].txold);
|
||||
|
||||
/* update moving positions */
|
||||
copy_v3_v3(co_moving[0], verts[vt->tri[0]].tx);
|
||||
copy_v3_v3(co_moving[1], verts[vt->tri[1]].tx);
|
||||
@ -267,6 +235,10 @@ void bvhtree_update_from_cloth(ClothModifierData *clmd, bool moving)
|
||||
ret = BLI_bvhtree_update_node(bvhtree, i, co[0], co_moving[0], 3);
|
||||
}
|
||||
else {
|
||||
copy_v3_v3(co[0], verts[vt->tri[0]].tx);
|
||||
copy_v3_v3(co[1], verts[vt->tri[1]].tx);
|
||||
copy_v3_v3(co[2], verts[vt->tri[2]].tx);
|
||||
|
||||
ret = BLI_bvhtree_update_node(bvhtree, i, co[0], NULL, 3);
|
||||
}
|
||||
|
||||
@ -280,47 +252,6 @@ void bvhtree_update_from_cloth(ClothModifierData *clmd, bool moving)
|
||||
}
|
||||
}
|
||||
|
||||
void bvhselftree_update_from_cloth(ClothModifierData *clmd, bool moving)
|
||||
{
|
||||
unsigned int i = 0;
|
||||
Cloth *cloth = clmd->clothObject;
|
||||
BVHTree *bvhtree = cloth->bvhselftree;
|
||||
ClothVertex *verts = cloth->verts;
|
||||
const MVertTri *vt;
|
||||
|
||||
if (!bvhtree)
|
||||
return;
|
||||
|
||||
vt = cloth->tri;
|
||||
|
||||
/* update vertex position in bvh tree */
|
||||
if (verts && vt) {
|
||||
for (i = 0; i < cloth->mvert_num; i++, verts++) {
|
||||
const float *co, *co_moving;
|
||||
bool ret;
|
||||
|
||||
co = verts->txold;
|
||||
|
||||
/* copy new locations into array */
|
||||
if (moving) {
|
||||
/* update moving positions */
|
||||
co_moving = verts->tx;
|
||||
ret = BLI_bvhtree_update_node(bvhtree, i, co, co_moving, 1);
|
||||
}
|
||||
else {
|
||||
ret = BLI_bvhtree_update_node(bvhtree, i, co, NULL, 1);
|
||||
}
|
||||
|
||||
/* check if tree is already full */
|
||||
if (ret == false) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
BLI_bvhtree_update_tree(bvhtree);
|
||||
}
|
||||
}
|
||||
|
||||
void cloth_clear_cache(Object *ob, ClothModifierData *clmd, float framenr)
|
||||
{
|
||||
PTCacheID pid;
|
||||
@ -357,6 +288,7 @@ static int do_init_cloth(Object *ob, ClothModifierData *clmd, Mesh *result, int
|
||||
BKE_cloth_solver_set_positions(clmd);
|
||||
|
||||
clmd->clothObject->last_frame= MINFRAME-1;
|
||||
clmd->sim_parms->dt = 1.0f / clmd->sim_parms->stepsPerFrame;
|
||||
}
|
||||
|
||||
return 1;
|
||||
@ -444,9 +376,6 @@ void clothModifier_do(ClothModifierData *clmd, Depsgraph *depsgraph, Scene *scen
|
||||
cache->flag &= ~PTCACHE_REDO_NEEDED;
|
||||
}
|
||||
|
||||
// unused in the moment, calculated separately in implicit.c
|
||||
clmd->sim_parms->dt = clmd->sim_parms->timescale / clmd->sim_parms->stepsPerFrame;
|
||||
|
||||
/* simulation is only active during a specific period */
|
||||
if (framenr < startframe) {
|
||||
BKE_ptcache_invalidate(cache);
|
||||
@ -795,8 +724,6 @@ static int cloth_from_object(Object *ob, ClothModifierData *clmd, Mesh *mesh, fl
|
||||
ClothVertex *verts = NULL;
|
||||
float (*shapekey_rest)[3] = NULL;
|
||||
float tnull[3] = {0, 0, 0};
|
||||
Cloth *cloth = NULL;
|
||||
float maxdist = 0;
|
||||
|
||||
// If we have a clothObject, free it.
|
||||
if ( clmd->clothObject != NULL ) {
|
||||
@ -809,8 +736,6 @@ static int cloth_from_object(Object *ob, ClothModifierData *clmd, Mesh *mesh, fl
|
||||
clmd->clothObject = MEM_callocN ( sizeof ( Cloth ), "cloth" );
|
||||
if ( clmd->clothObject ) {
|
||||
clmd->clothObject->old_solver_type = 255;
|
||||
// clmd->clothObject->old_collision_type = 255;
|
||||
cloth = clmd->clothObject;
|
||||
clmd->clothObject->edgeset = NULL;
|
||||
}
|
||||
else if (!clmd->clothObject) {
|
||||
@ -889,13 +814,8 @@ static int cloth_from_object(Object *ob, ClothModifierData *clmd, Mesh *mesh, fl
|
||||
if (!first)
|
||||
BKE_cloth_solver_set_positions(clmd);
|
||||
|
||||
clmd->clothObject->bvhtree = bvhtree_build_from_cloth ( clmd, MAX2(clmd->coll_parms->epsilon, clmd->coll_parms->distance_repel) );
|
||||
|
||||
for (i = 0; i < mesh->totvert; i++) {
|
||||
maxdist = MAX2(maxdist, clmd->coll_parms->selfepsilon* ( cloth->verts[i].avg_spring_len*2.0f));
|
||||
}
|
||||
|
||||
clmd->clothObject->bvhselftree = bvhselftree_build_from_cloth ( clmd, maxdist );
|
||||
clmd->clothObject->bvhtree = bvhtree_build_from_cloth (clmd, clmd->coll_parms->epsilon);
|
||||
clmd->clothObject->bvhselftree = bvhtree_build_from_cloth(clmd, clmd->coll_parms->selfepsilon);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -112,6 +112,7 @@ PartDeflect *object_add_collision_fields(int type)
|
||||
pd->pdef_sbdamp = 0.1f;
|
||||
pd->pdef_sbift = 0.2f;
|
||||
pd->pdef_sboft = 0.02f;
|
||||
pd->pdef_cfrict = 5.0f;
|
||||
pd->seed = ((uint)(ceil(PIL_check_seconds_timer())) + 1) % 128;
|
||||
pd->f_strength = 1.0f;
|
||||
pd->f_damp = 1.0f;
|
||||
@ -132,7 +133,7 @@ PartDeflect *object_add_collision_fields(int type)
|
||||
pd->f_flow = 1.0f;
|
||||
break;
|
||||
}
|
||||
pd->flag = PFIELD_DO_LOCATION | PFIELD_DO_ROTATION;
|
||||
pd->flag = PFIELD_DO_LOCATION | PFIELD_DO_ROTATION | PFIELD_CLOTH_USE_CULLING;
|
||||
|
||||
return pd;
|
||||
}
|
||||
|
@ -373,6 +373,8 @@ bool clip_segment_v3_plane_n(
|
||||
const float p1[3], const float p2[3], const float plane_array[][4], const int plane_tot,
|
||||
float r_p1[3], float r_p2[3]);
|
||||
|
||||
bool point_in_slice_seg(float p[3], float l1[3], float l2[3]);
|
||||
|
||||
/****************************** Interpolation ********************************/
|
||||
void interp_weights_tri_v3(float w[3], const float a[3], const float b[3], const float c[3], const float p[3]);
|
||||
void interp_weights_quad_v3(float w[4], const float a[3], const float b[3], const float c[3], const float d[3], const float p[3]);
|
||||
|
@ -2979,19 +2979,27 @@ static bool point_in_slice(const float p[3], const float v1[3], const float l1[3
|
||||
return (h >= 0.0f && h <= 1.0f);
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
||||
/* adult sister defining the slice planes by the origin and the normal
|
||||
* NOTE |normal| may not be 1 but defining the thickness of the slice */
|
||||
static int point_in_slice_as(float p[3], float origin[3], float normal[3])
|
||||
static bool point_in_slice_as(float p[3], float origin[3], float normal[3])
|
||||
{
|
||||
float h, rp[3];
|
||||
sub_v3_v3v3(rp, p, origin);
|
||||
h = dot_v3v3(normal, rp) / dot_v3v3(normal, normal);
|
||||
if (h < 0.0f || h > 1.0f) return 0;
|
||||
return 1;
|
||||
if (h < 0.0f || h > 1.0f) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool point_in_slice_seg(float p[3], float l1[3], float l2[3])
|
||||
{
|
||||
float normal[3];
|
||||
|
||||
sub_v3_v3v3(normal, l2, l1);
|
||||
|
||||
return point_in_slice_as(p, l1, normal);
|
||||
}
|
||||
|
||||
#if 0
|
||||
/*mama (knowing the squared length of the normal) */
|
||||
static int point_in_slice_m(float p[3], float origin[3], float normal[3], float lns)
|
||||
{
|
||||
|
@ -2090,4 +2090,22 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!MAIN_VERSION_ATLEAST(bmain, 280, 24)) {
|
||||
if (!DNA_struct_elem_find(fd->filesdna, "PartDeflect", "float", "pdef_cfrict")) {
|
||||
for (Object *ob = bmain->object.first; ob; ob = ob->id.next) {
|
||||
if (ob->pd) {
|
||||
ob->pd->pdef_cfrict = 5.0f;
|
||||
}
|
||||
|
||||
for (ModifierData *md = ob->modifiers.first; md; md = md->next) {
|
||||
if (md->type == eModifierType_Cloth) {
|
||||
ClothModifierData *clmd = (ClothModifierData *)md;
|
||||
|
||||
clmd->coll_parms->selfepsilon = 0.015f;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -121,14 +121,17 @@ typedef struct ClothCollSettings {
|
||||
float friction; /* Friction/damping applied on contact with other object.*/
|
||||
float damping; /* Collision restitution on contact with other object.*/
|
||||
float selfepsilon; /* for selfcollision */
|
||||
float repel_force, distance_repel;
|
||||
float repel_force DNA_DEPRECATED;
|
||||
float distance_repel DNA_DEPRECATED;
|
||||
int flags; /* collision flags defined in BKE_cloth.h */
|
||||
short self_loop_count; /* How many iterations for the selfcollision loop */
|
||||
short self_loop_count DNA_DEPRECATED; /* How many iterations for the selfcollision loop */
|
||||
short loop_count; /* How many iterations for the collision loop. */
|
||||
int pad;
|
||||
struct Collection *group; /* Only use colliders from this group of objects */
|
||||
short vgroup_selfcol; /* vgroup to paint which vertices are used for self collisions */
|
||||
short pad2[3];
|
||||
float clamp; /* Impulse clamp for object collisions. */
|
||||
float self_clamp; /* Impulse clamp for self collisions. */
|
||||
} ClothCollSettings;
|
||||
|
||||
|
||||
|
@ -120,6 +120,9 @@ typedef struct PartDeflect {
|
||||
float drawvec_falloff_max[3], pad2; /* Runtime only */
|
||||
|
||||
struct Object *f_source; /* force source object */
|
||||
|
||||
float pdef_cfrict; /* Friction of cloth collisions. */
|
||||
float pad;
|
||||
} PartDeflect;
|
||||
|
||||
typedef struct EffectorWeights {
|
||||
@ -337,6 +340,8 @@ typedef struct SoftBody {
|
||||
#define PFIELD_GUIDE_PATH_WEIGHT (1<<16) /* apply curve weights */
|
||||
#define PFIELD_SMOKE_DENSITY (1<<17) /* multiply smoke force by density */
|
||||
#define PFIELD_GRAVITATION (1<<18) /* used for (simple) force */
|
||||
#define PFIELD_CLOTH_USE_CULLING (1<<19) /* Enable cloth collision side detection based on normal. */
|
||||
#define PFIELD_CLOTH_USE_NORMAL (1<<20) /* Replace collision direction with collider normal. */
|
||||
|
||||
/* pd->falloff */
|
||||
#define PFIELD_FALL_SPHERE 0
|
||||
|
@ -774,26 +774,11 @@ static void rna_def_cloth_collision_settings(BlenderRNA *brna)
|
||||
RNA_def_property_ui_text(prop, "Enable Collision", "Enable collisions with other objects");
|
||||
RNA_def_property_update(prop, 0, "rna_cloth_update");
|
||||
|
||||
prop = RNA_def_property(srna, "repel_force", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_float_sdna(prop, NULL, "repel_force");
|
||||
RNA_def_property_range(prop, 0.0f, 20.0f);
|
||||
RNA_def_property_float_default(prop, 1.0f);
|
||||
RNA_def_property_ui_text(prop, "Repulsion Force", "Repulsion force to apply on cloth when close to colliding");
|
||||
RNA_def_property_update(prop, 0, "rna_cloth_update");
|
||||
|
||||
prop = RNA_def_property(srna, "distance_repel", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_float_sdna(prop, NULL, "distance_repel");
|
||||
RNA_def_property_range(prop, 0.001f, 10.0f);
|
||||
RNA_def_property_float_default(prop, 0.005f);
|
||||
RNA_def_property_ui_text(prop, "Repulsion Distance",
|
||||
"Maximum distance to apply repulsion force, must be greater than minimum distance");
|
||||
RNA_def_property_update(prop, 0, "rna_cloth_update");
|
||||
|
||||
prop = RNA_def_property(srna, "distance_min", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_float_sdna(prop, NULL, "epsilon");
|
||||
RNA_def_property_range(prop, 0.001f, 1.0f);
|
||||
RNA_def_property_ui_text(prop, "Minimum Distance",
|
||||
"Minimum distance between collision objects before collision response takes in");
|
||||
"Minimum distance between collision objects before collision response takes effect");
|
||||
RNA_def_property_update(prop, 0, "rna_cloth_update");
|
||||
|
||||
prop = RNA_def_property(srna, "friction", PROP_FLOAT, PROP_NONE);
|
||||
@ -816,6 +801,12 @@ static void rna_def_cloth_collision_settings(BlenderRNA *brna)
|
||||
"How many collision iterations should be done. (higher is better quality but slower)");
|
||||
RNA_def_property_update(prop, 0, "rna_cloth_update");
|
||||
|
||||
prop = RNA_def_property(srna, "impulse_clamp", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_float_sdna(prop, NULL, "clamp");
|
||||
RNA_def_property_range(prop, 0.0f, 100.0f);
|
||||
RNA_def_property_ui_text(prop, "Impulse Clamping", "Clamp collision impulses to avoid instability (0.0 to disable clamping)");
|
||||
RNA_def_property_update(prop, 0, "rna_cloth_update");
|
||||
|
||||
/* self collision */
|
||||
|
||||
prop = RNA_def_property(srna, "use_self_collision", PROP_BOOLEAN, PROP_NONE);
|
||||
@ -825,22 +816,13 @@ static void rna_def_cloth_collision_settings(BlenderRNA *brna)
|
||||
|
||||
prop = RNA_def_property(srna, "self_distance_min", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_float_sdna(prop, NULL, "selfepsilon");
|
||||
RNA_def_property_range(prop, 0.5f, 1.0f);
|
||||
RNA_def_property_ui_text(prop, "Self Minimum Distance", "0.5 means no distance at all, 1.0 is maximum distance");
|
||||
RNA_def_property_range(prop, 0.001f, 0.1f);
|
||||
RNA_def_property_ui_text(prop, "Self Minimum Distance", "Minimum distance between cloth faces before collision response takes effect");
|
||||
RNA_def_property_update(prop, 0, "rna_cloth_update");
|
||||
|
||||
prop = RNA_def_property(srna, "self_friction", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_range(prop, 0.0f, 80.0f);
|
||||
RNA_def_property_ui_text(prop, "Self Friction", "Friction/damping with self contact");
|
||||
RNA_def_property_update(prop, 0, "rna_cloth_update");
|
||||
|
||||
prop = RNA_def_property(srna, "self_collision_quality", PROP_INT, PROP_NONE);
|
||||
RNA_def_property_int_sdna(prop, NULL, "self_loop_count");
|
||||
RNA_def_property_range(prop, 1, SHRT_MAX);
|
||||
RNA_def_property_ui_range(prop, 1, 10, 1, -1);
|
||||
RNA_def_property_ui_text(prop, "Self Collision Quality",
|
||||
"How many self collision iterations should be done "
|
||||
"(higher is better quality but slower)");
|
||||
RNA_def_property_ui_text(prop, "Self Friction", "Friction with self contact");
|
||||
RNA_def_property_update(prop, 0, "rna_cloth_update");
|
||||
|
||||
prop = RNA_def_property(srna, "group", PROP_POINTER, PROP_NONE);
|
||||
@ -854,6 +836,12 @@ static void rna_def_cloth_collision_settings(BlenderRNA *brna)
|
||||
RNA_def_property_ui_text(prop, "Selfcollision Vertex Group",
|
||||
"Vertex group to define vertices which are not used during self collisions");
|
||||
RNA_def_property_update(prop, 0, "rna_cloth_update");
|
||||
|
||||
prop = RNA_def_property(srna, "self_impulse_clamp", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_float_sdna(prop, NULL, "self_clamp");
|
||||
RNA_def_property_range(prop, 0.0f, 100.0f);
|
||||
RNA_def_property_ui_text(prop, "Impulse Clamping", "Clamp collision impulses to avoid instability (0.0 to disable clamping)");
|
||||
RNA_def_property_update(prop, 0, "rna_cloth_update");
|
||||
}
|
||||
|
||||
void RNA_def_cloth(BlenderRNA *brna)
|
||||
|
@ -958,6 +958,22 @@ static void rna_def_collision(BlenderRNA *brna)
|
||||
RNA_def_property_ui_text(prop, "Absorption",
|
||||
"How much of effector force gets lost during collision with this object (in percent)");
|
||||
RNA_def_property_update(prop, 0, "rna_CollisionSettings_update");
|
||||
|
||||
prop = RNA_def_property(srna, "cloth_friction", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_float_sdna(prop, NULL, "pdef_cfrict");
|
||||
RNA_def_property_range(prop, 0.0f, 80.0f);
|
||||
RNA_def_property_ui_text(prop, "Friction", "Friction for cloth collisions");
|
||||
RNA_def_property_update(prop, 0, "rna_CollisionSettings_update");
|
||||
|
||||
prop = RNA_def_property(srna, "use_culling", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "flag", PFIELD_CLOTH_USE_CULLING);
|
||||
RNA_def_property_ui_text(prop, "Single Sided", "Cloth collision acts with respect to the collider normals (improves penetration recovery)");
|
||||
RNA_def_property_update(prop, 0, "rna_CollisionSettings_update");
|
||||
|
||||
prop = RNA_def_property(srna, "use_normal", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "flag", PFIELD_CLOTH_USE_NORMAL);
|
||||
RNA_def_property_ui_text(prop, "Override Normals", "Cloth collision impulses act in the direction of the collider normals (more reliable in some cases)");
|
||||
RNA_def_property_update(prop, 0, "rna_CollisionSettings_update");
|
||||
}
|
||||
|
||||
static void rna_def_effector_weight(BlenderRNA *brna)
|
||||
|
@ -146,113 +146,108 @@ static void deformVerts(
|
||||
|
||||
mvert_num = mesh_src->totvert;
|
||||
|
||||
if (current_time > collmd->time_xnew) {
|
||||
unsigned int i;
|
||||
|
||||
/* check if mesh has changed */
|
||||
if (collmd->x && (mvert_num != collmd->mvert_num))
|
||||
freeData((ModifierData *)collmd);
|
||||
|
||||
if (collmd->time_xnew == -1000) { /* first time */
|
||||
|
||||
collmd->x = MEM_dupallocN(mesh_src->mvert); /* frame start position */
|
||||
|
||||
for (i = 0; i < mvert_num; i++) {
|
||||
/* we save global positions */
|
||||
mul_m4_v3(ob->obmat, collmd->x[i].co);
|
||||
}
|
||||
|
||||
collmd->xnew = MEM_dupallocN(collmd->x); // frame end position
|
||||
collmd->current_x = MEM_dupallocN(collmd->x); // inter-frame
|
||||
collmd->current_xnew = MEM_dupallocN(collmd->x); // inter-frame
|
||||
collmd->current_v = MEM_dupallocN(collmd->x); // inter-frame
|
||||
|
||||
collmd->mvert_num = mvert_num;
|
||||
|
||||
{
|
||||
const MLoop *mloop = mesh_src->mloop;
|
||||
const MLoopTri *looptri = BKE_mesh_runtime_looptri_ensure(mesh_src);
|
||||
collmd->tri_num = BKE_mesh_runtime_looptri_len(mesh_src);
|
||||
MVertTri *tri = MEM_malloc_arrayN(collmd->tri_num, sizeof(*tri), __func__);
|
||||
BKE_mesh_runtime_verttri_from_looptri(tri, mloop, looptri, collmd->tri_num);
|
||||
collmd->tri = tri;
|
||||
}
|
||||
|
||||
/* create bounding box hierarchy */
|
||||
collmd->bvhtree = bvhtree_build_from_mvert(
|
||||
collmd->x,
|
||||
collmd->tri, collmd->tri_num,
|
||||
ob->pd->pdef_sboft);
|
||||
|
||||
collmd->time_x = collmd->time_xnew = current_time;
|
||||
collmd->is_static = true;
|
||||
}
|
||||
else if (mvert_num == collmd->mvert_num) {
|
||||
/* put positions to old positions */
|
||||
tempVert = collmd->x;
|
||||
collmd->x = collmd->xnew;
|
||||
collmd->xnew = tempVert;
|
||||
collmd->time_x = collmd->time_xnew;
|
||||
|
||||
memcpy(collmd->xnew, mesh_src->mvert, mvert_num * sizeof(MVert));
|
||||
|
||||
bool is_static = true;
|
||||
|
||||
for (i = 0; i < mvert_num; i++) {
|
||||
/* we save global positions */
|
||||
mul_m4_v3(ob->obmat, collmd->xnew[i].co);
|
||||
|
||||
/* detect motion */
|
||||
is_static = is_static && equals_v3v3(collmd->x[i].co, collmd->xnew[i].co);
|
||||
}
|
||||
|
||||
memcpy(collmd->current_xnew, collmd->x, mvert_num * sizeof(MVert));
|
||||
memcpy(collmd->current_x, collmd->x, mvert_num * sizeof(MVert));
|
||||
|
||||
/* check if GUI setting has changed for bvh */
|
||||
if (collmd->bvhtree) {
|
||||
if (ob->pd->pdef_sboft != BLI_bvhtree_get_epsilon(collmd->bvhtree)) {
|
||||
BLI_bvhtree_free(collmd->bvhtree);
|
||||
collmd->bvhtree = bvhtree_build_from_mvert(
|
||||
collmd->current_x,
|
||||
collmd->tri, collmd->tri_num,
|
||||
ob->pd->pdef_sboft);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* happens on file load (ONLY when i decomment changes in readfile.c) */
|
||||
if (!collmd->bvhtree) {
|
||||
collmd->bvhtree = bvhtree_build_from_mvert(
|
||||
collmd->current_x,
|
||||
collmd->tri, collmd->tri_num,
|
||||
ob->pd->pdef_sboft);
|
||||
}
|
||||
else if (!collmd->is_static || !is_static) {
|
||||
/* recalc static bounding boxes */
|
||||
bvhtree_update_from_mvert(
|
||||
collmd->bvhtree,
|
||||
collmd->current_x, collmd->current_xnew,
|
||||
collmd->tri, collmd->tri_num,
|
||||
true);
|
||||
}
|
||||
|
||||
collmd->is_static = is_static;
|
||||
collmd->time_xnew = current_time;
|
||||
}
|
||||
else if (mvert_num != collmd->mvert_num) {
|
||||
freeData((ModifierData *)collmd);
|
||||
}
|
||||
|
||||
}
|
||||
else if (current_time < collmd->time_xnew) {
|
||||
if (current_time < collmd->time_xnew) {
|
||||
freeData((ModifierData *)collmd);
|
||||
}
|
||||
else {
|
||||
else if (current_time == collmd->time_xnew) {
|
||||
if (mvert_num != collmd->mvert_num) {
|
||||
freeData((ModifierData *)collmd);
|
||||
}
|
||||
}
|
||||
|
||||
/* check if mesh has changed */
|
||||
if (collmd->x && (mvert_num != collmd->mvert_num))
|
||||
freeData((ModifierData *)collmd);
|
||||
|
||||
if (collmd->time_xnew == -1000) { /* first time */
|
||||
|
||||
collmd->x = MEM_dupallocN(mesh_src->mvert); /* frame start position */
|
||||
|
||||
for (uint i = 0; i < mvert_num; i++) {
|
||||
/* we save global positions */
|
||||
mul_m4_v3(ob->obmat, collmd->x[i].co);
|
||||
}
|
||||
|
||||
collmd->xnew = MEM_dupallocN(collmd->x); // frame end position
|
||||
collmd->current_x = MEM_dupallocN(collmd->x); // inter-frame
|
||||
collmd->current_xnew = MEM_dupallocN(collmd->x); // inter-frame
|
||||
collmd->current_v = MEM_dupallocN(collmd->x); // inter-frame
|
||||
|
||||
collmd->mvert_num = mvert_num;
|
||||
|
||||
{
|
||||
const MLoop *mloop = mesh_src->mloop;
|
||||
const MLoopTri *looptri = BKE_mesh_runtime_looptri_ensure(mesh_src);
|
||||
collmd->tri_num = BKE_mesh_runtime_looptri_len(mesh_src);
|
||||
MVertTri *tri = MEM_mallocN(sizeof(*tri) * collmd->tri_num, __func__);
|
||||
BKE_mesh_runtime_verttri_from_looptri(tri, mloop, looptri, collmd->tri_num);
|
||||
collmd->tri = tri;
|
||||
}
|
||||
|
||||
/* create bounding box hierarchy */
|
||||
collmd->bvhtree = bvhtree_build_from_mvert(
|
||||
collmd->x,
|
||||
collmd->tri, collmd->tri_num,
|
||||
ob->pd->pdef_sboft);
|
||||
|
||||
collmd->time_x = collmd->time_xnew = current_time;
|
||||
collmd->is_static = true;
|
||||
}
|
||||
else if (mvert_num == collmd->mvert_num) {
|
||||
/* put positions to old positions */
|
||||
tempVert = collmd->x;
|
||||
collmd->x = collmd->xnew;
|
||||
collmd->xnew = tempVert;
|
||||
collmd->time_x = collmd->time_xnew;
|
||||
|
||||
memcpy(collmd->xnew, mesh_src->mvert, mvert_num * sizeof(MVert));
|
||||
|
||||
bool is_static = true;
|
||||
|
||||
for (uint i = 0; i < mvert_num; i++) {
|
||||
/* we save global positions */
|
||||
mul_m4_v3(ob->obmat, collmd->xnew[i].co);
|
||||
|
||||
/* detect motion */
|
||||
is_static = is_static && equals_v3v3(collmd->x[i].co, collmd->xnew[i].co);
|
||||
}
|
||||
|
||||
memcpy(collmd->current_xnew, collmd->x, mvert_num * sizeof(MVert));
|
||||
memcpy(collmd->current_x, collmd->x, mvert_num * sizeof(MVert));
|
||||
|
||||
/* check if GUI setting has changed for bvh */
|
||||
if (collmd->bvhtree) {
|
||||
if (ob->pd->pdef_sboft != BLI_bvhtree_get_epsilon(collmd->bvhtree)) {
|
||||
BLI_bvhtree_free(collmd->bvhtree);
|
||||
collmd->bvhtree = bvhtree_build_from_mvert(
|
||||
collmd->current_x,
|
||||
collmd->tri, collmd->tri_num,
|
||||
ob->pd->pdef_sboft);
|
||||
}
|
||||
}
|
||||
|
||||
/* happens on file load (ONLY when i decomment changes in readfile.c) */
|
||||
if (!collmd->bvhtree) {
|
||||
collmd->bvhtree = bvhtree_build_from_mvert(
|
||||
collmd->current_x,
|
||||
collmd->tri, collmd->tri_num,
|
||||
ob->pd->pdef_sboft);
|
||||
}
|
||||
else if (!collmd->is_static || !is_static) {
|
||||
/* recalc static bounding boxes */
|
||||
bvhtree_update_from_mvert(
|
||||
collmd->bvhtree,
|
||||
collmd->current_x, collmd->current_xnew,
|
||||
collmd->tri, collmd->tri_num,
|
||||
true);
|
||||
}
|
||||
|
||||
collmd->is_static = is_static;
|
||||
collmd->time_xnew = current_time;
|
||||
}
|
||||
else if (mvert_num != collmd->mvert_num) {
|
||||
freeData((ModifierData *)collmd);
|
||||
}
|
||||
}
|
||||
|
||||
if (mesh_src != mesh) {
|
||||
|
@ -884,20 +884,13 @@ static void cloth_calc_volume_force(ClothModifierData *clmd)
|
||||
}
|
||||
#endif
|
||||
|
||||
/* old collision stuff for cloth, use for continuity
|
||||
* until a good replacement is ready
|
||||
*/
|
||||
static void cloth_collision_solve_extra(
|
||||
Depsgraph *depsgraph, Scene *scene, Object *ob, ClothModifierData *clmd, ListBase *effectors,
|
||||
float frame, float step, float dt)
|
||||
static void cloth_solve_collisions(Depsgraph *depsgraph, Object *ob, ClothModifierData *clmd, float step, float dt)
|
||||
{
|
||||
Cloth *cloth = clmd->clothObject;
|
||||
Implicit_Data *id = cloth->implicit;
|
||||
ClothVertex *verts = cloth->verts;
|
||||
int mvert_num = cloth->mvert_num;
|
||||
const float spf = (float)clmd->sim_parms->stepsPerFrame / clmd->sim_parms->timescale;
|
||||
|
||||
bool do_extra_solve;
|
||||
const float time_multiplier = 1.0f / (clmd->sim_parms->dt * clmd->sim_parms->timescale);
|
||||
int i;
|
||||
|
||||
if (!(clmd->coll_parms->flags & (CLOTH_COLLSETTINGS_FLAG_ENABLED | CLOTH_COLLSETTINGS_FLAG_SELF)))
|
||||
@ -906,69 +899,26 @@ static void cloth_collision_solve_extra(
|
||||
if (!clmd->clothObject->bvhtree)
|
||||
return;
|
||||
|
||||
// update verts to current positions
|
||||
BPH_mass_spring_solve_positions(id, dt);
|
||||
|
||||
/* Update verts to current positions. */
|
||||
for (i = 0; i < mvert_num; i++) {
|
||||
BPH_mass_spring_get_new_position(id, i, verts[i].tx);
|
||||
|
||||
sub_v3_v3v3(verts[i].tv, verts[i].tx, verts[i].txold);
|
||||
copy_v3_v3(verts[i].v, verts[i].tv);
|
||||
zero_v3(verts[i].dcvel);
|
||||
}
|
||||
|
||||
#if 0 /* unused */
|
||||
for (i=0, cv=cloth->verts; i<cloth->mvert_num; i++, cv++) {
|
||||
copy_v3_v3(initial_cos[i], cv->tx);
|
||||
}
|
||||
#endif
|
||||
|
||||
// call collision function
|
||||
// TODO: check if "step" or "step+dt" is correct - dg
|
||||
do_extra_solve = cloth_bvh_objcollision(
|
||||
depsgraph, ob, clmd, step / clmd->sim_parms->timescale, dt / clmd->sim_parms->timescale);
|
||||
|
||||
// copy corrected positions back to simulation
|
||||
for (i = 0; i < mvert_num; i++) {
|
||||
float curx[3];
|
||||
BPH_mass_spring_get_position(id, i, curx);
|
||||
// correct velocity again, just to be sure we had to change it due to adaptive collisions
|
||||
sub_v3_v3v3(verts[i].tv, verts[i].tx, curx);
|
||||
}
|
||||
|
||||
if (do_extra_solve) {
|
||||
// cloth_calc_helper_forces(ob, clmd, initial_cos, step/clmd->sim_parms->timescale, dt/clmd->sim_parms->timescale);
|
||||
|
||||
if (cloth_bvh_collision(depsgraph, ob, clmd, step / clmd->sim_parms->timescale, dt / clmd->sim_parms->timescale)) {
|
||||
for (i = 0; i < mvert_num; i++) {
|
||||
|
||||
float newv[3];
|
||||
|
||||
if ((clmd->sim_parms->vgroup_mass > 0) && (verts [i].flags & CLOTH_VERT_FLAG_PINNED))
|
||||
if ((clmd->sim_parms->vgroup_mass > 0) && (verts[i].flags & CLOTH_VERT_FLAG_PINNED))
|
||||
continue;
|
||||
|
||||
BPH_mass_spring_set_new_position(id, i, verts[i].tx);
|
||||
mul_v3_v3fl(newv, verts[i].tv, spf);
|
||||
BPH_mass_spring_set_new_velocity(id, i, newv);
|
||||
BPH_mass_spring_get_new_velocity(id, i, verts[i].tv);
|
||||
madd_v3_v3fl(verts[i].tv, verts[i].dcvel, time_multiplier);
|
||||
BPH_mass_spring_set_new_velocity(id, i, verts[i].tv);
|
||||
}
|
||||
}
|
||||
|
||||
// X = Xnew;
|
||||
BPH_mass_spring_apply_result(id);
|
||||
|
||||
if (do_extra_solve) {
|
||||
ImplicitSolverResult result;
|
||||
|
||||
/* initialize forces to zero */
|
||||
BPH_mass_spring_clear_forces(id);
|
||||
|
||||
// calculate forces
|
||||
cloth_calc_force(scene, clmd, frame, effectors, step);
|
||||
|
||||
// calculate new velocity and position
|
||||
BPH_mass_spring_solve_velocities(id, dt, &result);
|
||||
// cloth_record_result(clmd, &result, clmd->sim_parms->stepsPerFrame);
|
||||
|
||||
/* note: positions are advanced only once in the main solver step! */
|
||||
|
||||
BPH_mass_spring_apply_result(id);
|
||||
}
|
||||
}
|
||||
|
||||
static void cloth_clear_result(ClothModifierData *clmd)
|
||||
@ -981,7 +931,7 @@ static void cloth_clear_result(ClothModifierData *clmd)
|
||||
sres->avg_iterations = 0.0f;
|
||||
}
|
||||
|
||||
static void cloth_record_result(ClothModifierData *clmd, ImplicitSolverResult *result, int steps)
|
||||
static void cloth_record_result(ClothModifierData *clmd, ImplicitSolverResult *result, float dt)
|
||||
{
|
||||
ClothSolverResult *sres = clmd->solver_result;
|
||||
|
||||
@ -990,22 +940,22 @@ static void cloth_record_result(ClothModifierData *clmd, ImplicitSolverResult *r
|
||||
if (result->status == BPH_SOLVER_SUCCESS) {
|
||||
sres->min_error = min_ff(sres->min_error, result->error);
|
||||
sres->max_error = max_ff(sres->max_error, result->error);
|
||||
sres->avg_error += result->error / (float)steps;
|
||||
sres->avg_error += result->error * dt;
|
||||
}
|
||||
|
||||
sres->min_iterations = min_ii(sres->min_iterations, result->iterations);
|
||||
sres->max_iterations = max_ii(sres->max_iterations, result->iterations);
|
||||
sres->avg_iterations += (float)result->iterations / (float)steps;
|
||||
sres->avg_iterations += (float)result->iterations * dt;
|
||||
}
|
||||
else {
|
||||
/* error only makes sense for successful iterations */
|
||||
if (result->status == BPH_SOLVER_SUCCESS) {
|
||||
sres->min_error = sres->max_error = result->error;
|
||||
sres->avg_error += result->error / (float)steps;
|
||||
sres->avg_error += result->error * dt;
|
||||
}
|
||||
|
||||
sres->min_iterations = sres->max_iterations = result->iterations;
|
||||
sres->avg_iterations += (float)result->iterations / (float)steps;
|
||||
sres->avg_iterations += (float)result->iterations * dt;
|
||||
}
|
||||
|
||||
sres->status |= result->status;
|
||||
@ -1025,7 +975,7 @@ int BPH_cloth_solve(Depsgraph *depsgraph, Object *ob, float frame, ClothModifier
|
||||
Cloth *cloth = clmd->clothObject;
|
||||
ClothVertex *verts = cloth->verts/*, *cv*/;
|
||||
unsigned int mvert_num = cloth->mvert_num;
|
||||
float dt = clmd->sim_parms->timescale / clmd->sim_parms->stepsPerFrame;
|
||||
float dt = clmd->sim_parms->dt * clmd->sim_parms->timescale;
|
||||
Implicit_Data *id = cloth->implicit;
|
||||
ColliderContacts *contacts = NULL;
|
||||
int totcolliders = 0;
|
||||
@ -1053,12 +1003,6 @@ int BPH_cloth_solve(Depsgraph *depsgraph, Object *ob, float frame, ClothModifier
|
||||
while (step < tf) {
|
||||
ImplicitSolverResult result;
|
||||
|
||||
/* copy velocities for collision */
|
||||
for (i = 0; i < mvert_num; i++) {
|
||||
BPH_mass_spring_get_motion_state(id, i, NULL, verts[i].tv);
|
||||
copy_v3_v3(verts[i].v, verts[i].tv);
|
||||
}
|
||||
|
||||
if (is_hair) {
|
||||
/* determine contact points */
|
||||
if (clmd->coll_parms->flags & CLOTH_COLLSETTINGS_FLAG_ENABLED) {
|
||||
@ -1081,18 +1025,18 @@ int BPH_cloth_solve(Depsgraph *depsgraph, Object *ob, float frame, ClothModifier
|
||||
|
||||
// calculate new velocity and position
|
||||
BPH_mass_spring_solve_velocities(id, dt, &result);
|
||||
cloth_record_result(clmd, &result, clmd->sim_parms->stepsPerFrame);
|
||||
cloth_record_result(clmd, &result, dt);
|
||||
|
||||
/* Calculate collision impulses. */
|
||||
if (!is_hair) {
|
||||
cloth_solve_collisions(depsgraph, ob, clmd, step, dt);
|
||||
}
|
||||
|
||||
if (is_hair) {
|
||||
cloth_continuum_step(clmd, dt);
|
||||
}
|
||||
|
||||
BPH_mass_spring_solve_positions(id, dt);
|
||||
|
||||
if (!is_hair) {
|
||||
cloth_collision_solve_extra(depsgraph, scene, ob, clmd, effectors, frame, step, dt);
|
||||
}
|
||||
|
||||
BPH_mass_spring_apply_result(id);
|
||||
|
||||
/* move pinned verts to correct position */
|
||||
|
Loading…
Reference in New Issue
Block a user