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:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -43,7 +43,8 @@
|
||||
#include "BLI_utildefines.h"
|
||||
#include "BLI_blenlib.h"
|
||||
#include "BLI_math.h"
|
||||
#include "BLI_edgehash.h"
|
||||
#include "BLI_task.h"
|
||||
#include "BLI_threads.h"
|
||||
|
||||
#include "BKE_cloth.h"
|
||||
#include "BKE_collection.h"
|
||||
@@ -52,9 +53,6 @@
|
||||
#include "BKE_modifier.h"
|
||||
#include "BKE_scene.h"
|
||||
|
||||
#ifdef WITH_BULLET
|
||||
#include "Bullet-C-Api.h"
|
||||
#endif
|
||||
#include "BLI_kdopbvh.h"
|
||||
#include "BKE_collision.h"
|
||||
|
||||
@@ -67,6 +65,23 @@
|
||||
#endif
|
||||
|
||||
|
||||
typedef struct ColDetectData {
|
||||
ClothModifierData *clmd;
|
||||
CollisionModifierData *collmd;
|
||||
BVHTreeOverlap *overlap;
|
||||
CollPair *collisions;
|
||||
bool culling;
|
||||
bool use_normal;
|
||||
bool collided;
|
||||
} ColDetectData;
|
||||
|
||||
typedef struct SelfColDetectData {
|
||||
ClothModifierData *clmd;
|
||||
BVHTreeOverlap *overlap;
|
||||
CollPair *collisions;
|
||||
bool collided;
|
||||
} SelfColDetectData;
|
||||
|
||||
/***********************************
|
||||
Collision modifier code start
|
||||
***********************************/
|
||||
@@ -74,7 +89,7 @@ Collision modifier code start
|
||||
/* step is limited from 0 (frame start position) to 1 (frame end position) */
|
||||
void collision_move_object(CollisionModifierData *collmd, float step, float prevstep)
|
||||
{
|
||||
float tv[3] = {0, 0, 0};
|
||||
float oldx[3];
|
||||
unsigned int i = 0;
|
||||
|
||||
/* the collider doesn't move this frame */
|
||||
@@ -87,15 +102,14 @@ void collision_move_object(CollisionModifierData *collmd, float step, float prev
|
||||
}
|
||||
|
||||
for (i = 0; i < collmd->mvert_num; i++) {
|
||||
sub_v3_v3v3(tv, collmd->xnew[i].co, collmd->x[i].co);
|
||||
VECADDS(collmd->current_x[i].co, collmd->x[i].co, tv, prevstep);
|
||||
VECADDS(collmd->current_xnew[i].co, collmd->x[i].co, tv, step);
|
||||
sub_v3_v3v3(collmd->current_v[i].co, collmd->current_xnew[i].co, collmd->current_x[i].co);
|
||||
interp_v3_v3v3(oldx, collmd->x[i].co, collmd->xnew[i].co, prevstep);
|
||||
interp_v3_v3v3(collmd->current_x[i].co, collmd->x[i].co, collmd->xnew[i].co, step);
|
||||
sub_v3_v3v3(collmd->current_v[i].co, collmd->current_x[i].co, oldx);
|
||||
}
|
||||
|
||||
bvhtree_update_from_mvert(
|
||||
collmd->bvhtree, collmd->current_x, collmd->current_xnew,
|
||||
collmd->tri, collmd->tri_num, true);
|
||||
collmd->bvhtree, collmd->current_x, NULL,
|
||||
collmd->tri, collmd->tri_num, false);
|
||||
}
|
||||
|
||||
BVHTree *bvhtree_build_from_mvert(
|
||||
@@ -178,6 +192,264 @@ void bvhtree_update_from_mvert(
|
||||
Collision modifier code end
|
||||
***********************************/
|
||||
|
||||
static void clamp_point_seg(float a[3], float b[3], float p[3])
|
||||
{
|
||||
float ap[3], bp[3], ab[3];
|
||||
|
||||
sub_v3_v3v3(ap, p, a);
|
||||
sub_v3_v3v3(bp, p, b);
|
||||
sub_v3_v3v3(ab, b, a);
|
||||
|
||||
if (dot_v3v3(ap, bp) > 0.0f) {
|
||||
if (dot_v3v3(ap, ab) > 0.0f) {
|
||||
copy_v3_v3(p, b);
|
||||
}
|
||||
else {
|
||||
copy_v3_v3(p, a);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool isect_seg_seg(float a1[3], float a2[3], float b1[3], float b2[3], float r_a[3], float r_b[3])
|
||||
{
|
||||
if (isect_line_line_epsilon_v3(a1, a2, b1, b2, r_a, r_b, 0.0f)) {
|
||||
clamp_point_seg(a1, a2, r_a);
|
||||
clamp_point_seg(b1, b2, r_b);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
BLI_INLINE int next_ind(int i)
|
||||
{
|
||||
return (++i < 3) ? i : 0;
|
||||
}
|
||||
|
||||
static float compute_collision_point(float a1[3], float a2[3], float a3[3], float b1[3], float b2[3], float b3[3],
|
||||
bool culling, bool use_normal, float r_a[3], float r_b[3], float r_vec[3])
|
||||
{
|
||||
float a[3][3];
|
||||
float b[3][3];
|
||||
float dist = FLT_MAX;
|
||||
float tmp_co1[3], tmp_co2[3];
|
||||
float isect_a[3], isect_b[3];
|
||||
int isect_count = 0;
|
||||
float tmp, tmp_vec[3];
|
||||
float normal[3], cent[3];
|
||||
bool backside = false;
|
||||
|
||||
copy_v3_v3(a[0], a1);
|
||||
copy_v3_v3(a[1], a2);
|
||||
copy_v3_v3(a[2], a3);
|
||||
|
||||
copy_v3_v3(b[0], b1);
|
||||
copy_v3_v3(b[1], b2);
|
||||
copy_v3_v3(b[2], b3);
|
||||
|
||||
/* Find intersections. */
|
||||
for (int i = 0; i < 3; i++) {
|
||||
if (isect_line_segment_tri_v3(a[i], a[next_ind(i)], b[0], b[1], b[2], &tmp, NULL)) {
|
||||
interp_v3_v3v3(isect_a, a[i], a[next_ind(i)], tmp);
|
||||
isect_count++;
|
||||
}
|
||||
}
|
||||
|
||||
if (isect_count == 0) {
|
||||
for (int i = 0; i < 3; i++) {
|
||||
if (isect_line_segment_tri_v3(b[i], b[next_ind(i)], a[0], a[1], a[2], &tmp, NULL)) {
|
||||
isect_count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (isect_count == 1) {
|
||||
for (int i = 0; i < 3; i++) {
|
||||
if (isect_line_segment_tri_v3(b[i], b[next_ind(i)], a[0], a[1], a[2], &tmp, NULL)) {
|
||||
interp_v3_v3v3(isect_b, b[i], b[next_ind(i)], tmp);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Determine collision side. */
|
||||
if (culling) {
|
||||
normal_tri_v3(normal, b[0], b[1], b[2]);
|
||||
mid_v3_v3v3v3(cent, b[0], b[1], b[2]);
|
||||
|
||||
if (isect_count == 2) {
|
||||
backside = true;
|
||||
}
|
||||
else if (isect_count == 0) {
|
||||
for (int i = 0; i < 3; i++) {
|
||||
sub_v3_v3v3(tmp_vec, a[i], cent);
|
||||
if (dot_v3v3(tmp_vec, normal) < 0.0f) {
|
||||
backside = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (use_normal) {
|
||||
normal_tri_v3(normal, b[0], b[1], b[2]);
|
||||
}
|
||||
|
||||
if (isect_count == 1) {
|
||||
/* Edge intersection. */
|
||||
copy_v3_v3(r_a, isect_a);
|
||||
copy_v3_v3(r_b, isect_b);
|
||||
|
||||
if (use_normal) {
|
||||
copy_v3_v3(r_vec, normal);
|
||||
}
|
||||
else {
|
||||
sub_v3_v3v3(r_vec, r_b, r_a);
|
||||
}
|
||||
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
if (backside) {
|
||||
float maxdist = 0.0f;
|
||||
bool found = false;
|
||||
|
||||
/* Point projections. */
|
||||
for (int i = 0; i < 3; i++) {
|
||||
if (isect_ray_tri_v3(a[i], normal, b[0], b[1], b[2], &tmp, NULL)) {
|
||||
if (tmp > maxdist) {
|
||||
maxdist = tmp;
|
||||
copy_v3_v3(r_a, a[i]);
|
||||
madd_v3_v3v3fl(r_b, a[i], normal, tmp);
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
negate_v3(normal);
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
if (isect_ray_tri_v3(b[i], normal, a[0], a[1], a[2], &tmp, NULL)) {
|
||||
if (tmp > maxdist) {
|
||||
maxdist = tmp;
|
||||
madd_v3_v3v3fl(r_a, b[i], normal, tmp);
|
||||
copy_v3_v3(r_b, b[i]);
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
negate_v3(normal);
|
||||
|
||||
/* Edge projections. */
|
||||
for (int i = 0; i < 3; i++) {
|
||||
float dir[3];
|
||||
|
||||
sub_v3_v3v3(tmp_vec, b[next_ind(i)], b[i]);
|
||||
cross_v3_v3v3(dir, tmp_vec, normal);
|
||||
|
||||
for (int j = 0; j < 3; j++) {
|
||||
if (isect_line_plane_v3(tmp_co1, a[j], a[next_ind(j)], b[i], dir) &&
|
||||
point_in_slice_seg(tmp_co1, a[j], a[next_ind(j)]) &&
|
||||
point_in_slice_seg(tmp_co1, b[i], b[next_ind(i)]))
|
||||
{
|
||||
closest_to_line_v3(tmp_co2, tmp_co1, b[i], b[next_ind(i)]);
|
||||
sub_v3_v3v3(tmp_vec, tmp_co1, tmp_co2);
|
||||
tmp = len_v3(tmp_vec);
|
||||
|
||||
if ((tmp > maxdist) && (dot_v3v3(tmp_vec, normal) < 0.0f)) {
|
||||
maxdist = tmp;
|
||||
copy_v3_v3(r_a, tmp_co1);
|
||||
copy_v3_v3(r_b, tmp_co2);
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* If no point is found, will fallback onto regular proximity test below. */
|
||||
if (found) {
|
||||
sub_v3_v3v3(r_vec, r_b, r_a);
|
||||
|
||||
if (use_normal) {
|
||||
if (dot_v3v3(normal, r_vec) >= 0.0f) {
|
||||
copy_v3_v3(r_vec, normal);
|
||||
}
|
||||
else {
|
||||
negate_v3_v3(r_vec, normal);
|
||||
}
|
||||
}
|
||||
|
||||
return 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
/* Closest point. */
|
||||
for (int i = 0; i < 3; i++) {
|
||||
closest_on_tri_to_point_v3(tmp_co1, a[i], b[0], b[1], b[2]);
|
||||
tmp = len_squared_v3v3(tmp_co1, a[i]);
|
||||
|
||||
if (tmp < dist) {
|
||||
dist = tmp;
|
||||
copy_v3_v3(r_a, a[i]);
|
||||
copy_v3_v3(r_b, tmp_co1);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
closest_on_tri_to_point_v3(tmp_co1, b[i], a[0], a[1], a[2]);
|
||||
tmp = len_squared_v3v3(tmp_co1, b[i]);
|
||||
|
||||
if (tmp < dist) {
|
||||
dist = tmp;
|
||||
copy_v3_v3(r_a, tmp_co1);
|
||||
copy_v3_v3(r_b, b[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/* Closest edge. */
|
||||
if (isect_count == 0) {
|
||||
for (int i = 0; i < 3; i++) {
|
||||
for (int j = 0; j < 3; j++) {
|
||||
if (isect_seg_seg(a[i], a[next_ind(i)], b[j], b[next_ind(j)], tmp_co1, tmp_co2)) {
|
||||
tmp = len_squared_v3v3(tmp_co1, tmp_co2);
|
||||
|
||||
if (tmp < dist) {
|
||||
dist = tmp;
|
||||
copy_v3_v3(r_a, tmp_co1);
|
||||
copy_v3_v3(r_b, tmp_co2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isect_count == 0) {
|
||||
sub_v3_v3v3(r_vec, r_a, r_b);
|
||||
dist = sqrtf(dist);
|
||||
}
|
||||
else {
|
||||
sub_v3_v3v3(r_vec, r_b, r_a);
|
||||
dist = 0.0f;
|
||||
}
|
||||
|
||||
if (culling && use_normal) {
|
||||
copy_v3_v3(r_vec, normal);
|
||||
}
|
||||
else if (use_normal) {
|
||||
if (dot_v3v3(normal, r_vec) >= 0.0f) {
|
||||
copy_v3_v3(r_vec, normal);
|
||||
}
|
||||
else {
|
||||
negate_v3_v3(r_vec, normal);
|
||||
}
|
||||
}
|
||||
else if (culling && (dot_v3v3(r_vec, normal) < 0.0f)) {
|
||||
return FLT_MAX;
|
||||
}
|
||||
|
||||
return dist;
|
||||
}
|
||||
|
||||
// w3 is not perfect
|
||||
static void collision_compute_barycentric ( float pv[3], float p1[3], float p2[3], float p3[3], float *w1, float *w2, float *w3 )
|
||||
{
|
||||
@@ -232,141 +504,131 @@ DO_INLINE void collision_interpolateOnTriangle ( float to[3], float v1[3], float
|
||||
VECADDMUL(to, v3, w3);
|
||||
}
|
||||
|
||||
static int cloth_collision_response_static ( ClothModifierData *clmd, CollisionModifierData *collmd, CollPair *collpair, CollPair *collision_end )
|
||||
static int cloth_collision_response_static(ClothModifierData *clmd, CollisionModifierData *collmd, Object *collob,
|
||||
CollPair *collpair, uint collision_count, const float dt)
|
||||
{
|
||||
int result = 0;
|
||||
Cloth *cloth1;
|
||||
float w1, w2, w3, u1, u2, u3;
|
||||
float v1[3], v2[3], relativeVelocity[3];
|
||||
float magrelVel;
|
||||
float epsilon2 = BLI_bvhtree_get_epsilon ( collmd->bvhtree );
|
||||
float epsilon2 = BLI_bvhtree_get_epsilon(collmd->bvhtree);
|
||||
|
||||
cloth1 = clmd->clothObject;
|
||||
|
||||
for ( ; collpair != collision_end; collpair++ ) {
|
||||
for (int i = 0; i < collision_count; i++, collpair++) {
|
||||
float i1[3], i2[3], i3[3];
|
||||
|
||||
zero_v3(i1);
|
||||
zero_v3(i2);
|
||||
zero_v3(i3);
|
||||
|
||||
/* only handle static collisions here */
|
||||
if ( collpair->flag & COLLISION_IN_FUTURE )
|
||||
/* Only handle static collisions here. */
|
||||
if (collpair->flag & (COLLISION_IN_FUTURE | COLLISION_INACTIVE)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* compute barycentric coordinates for both collision points */
|
||||
collision_compute_barycentric ( collpair->pa,
|
||||
cloth1->verts[collpair->ap1].txold,
|
||||
cloth1->verts[collpair->ap2].txold,
|
||||
cloth1->verts[collpair->ap3].txold,
|
||||
&w1, &w2, &w3 );
|
||||
/* Compute barycentric coordinates for both collision points. */
|
||||
collision_compute_barycentric(collpair->pa,
|
||||
cloth1->verts[collpair->ap1].tx,
|
||||
cloth1->verts[collpair->ap2].tx,
|
||||
cloth1->verts[collpair->ap3].tx,
|
||||
&w1, &w2, &w3);
|
||||
|
||||
/* was: txold */
|
||||
collision_compute_barycentric ( collpair->pb,
|
||||
collmd->current_x[collpair->bp1].co,
|
||||
collmd->current_x[collpair->bp2].co,
|
||||
collmd->current_x[collpair->bp3].co,
|
||||
&u1, &u2, &u3 );
|
||||
collision_compute_barycentric(collpair->pb,
|
||||
collmd->current_x[collpair->bp1].co,
|
||||
collmd->current_x[collpair->bp2].co,
|
||||
collmd->current_x[collpair->bp3].co,
|
||||
&u1, &u2, &u3);
|
||||
|
||||
/* Calculate relative "velocity". */
|
||||
collision_interpolateOnTriangle ( v1, cloth1->verts[collpair->ap1].tv, cloth1->verts[collpair->ap2].tv, cloth1->verts[collpair->ap3].tv, w1, w2, w3 );
|
||||
collision_interpolateOnTriangle(v1, cloth1->verts[collpair->ap1].tv, cloth1->verts[collpair->ap2].tv, cloth1->verts[collpair->ap3].tv, w1, w2, w3);
|
||||
|
||||
collision_interpolateOnTriangle ( v2, collmd->current_v[collpair->bp1].co, collmd->current_v[collpair->bp2].co, collmd->current_v[collpair->bp3].co, u1, u2, u3 );
|
||||
collision_interpolateOnTriangle(v2, collmd->current_v[collpair->bp1].co, collmd->current_v[collpair->bp2].co, collmd->current_v[collpair->bp3].co, u1, u2, u3);
|
||||
|
||||
sub_v3_v3v3(relativeVelocity, v2, v1);
|
||||
|
||||
/* Calculate the normal component of the relative velocity (actually only the magnitude - the direction is stored in 'normal'). */
|
||||
magrelVel = dot_v3v3(relativeVelocity, collpair->normal);
|
||||
|
||||
/* printf("magrelVel: %f\n", magrelVel); */
|
||||
|
||||
/* Calculate masses of points.
|
||||
* TODO */
|
||||
|
||||
/* If v_n_mag < 0 the edges are approaching each other. */
|
||||
if ( magrelVel > ALMOST_ZERO ) {
|
||||
/* If magrelVel < 0 the edges are approaching each other. */
|
||||
if (magrelVel > 0.0f) {
|
||||
/* Calculate Impulse magnitude to stop all motion in normal direction. */
|
||||
float magtangent = 0, repulse = 0, d = 0;
|
||||
double impulse = 0.0;
|
||||
float vrel_t_pre[3];
|
||||
float temp[3], spf;
|
||||
float temp[3];
|
||||
float time_multiplier;
|
||||
|
||||
/* calculate tangential velocity */
|
||||
copy_v3_v3 ( temp, collpair->normal );
|
||||
/* Calculate tangential velocity. */
|
||||
copy_v3_v3(temp, collpair->normal);
|
||||
mul_v3_fl(temp, magrelVel);
|
||||
sub_v3_v3v3(vrel_t_pre, relativeVelocity, temp);
|
||||
|
||||
/* Decrease in magnitude of relative tangential velocity due to coulomb friction
|
||||
* in original formula "magrelVel" should be the "change of relative velocity in normal direction" */
|
||||
magtangent = min_ff(clmd->coll_parms->friction * 0.01f * magrelVel, len_v3(vrel_t_pre));
|
||||
* in original formula "magrelVel" should be the "change of relative velocity in normal direction". */
|
||||
magtangent = min_ff(collob->pd->pdef_cfrict * 0.01f * magrelVel, len_v3(vrel_t_pre));
|
||||
|
||||
/* Apply friction impulse. */
|
||||
if ( magtangent > ALMOST_ZERO ) {
|
||||
normalize_v3(vrel_t_pre);
|
||||
|
||||
impulse = magtangent / ( 1.0f + w1*w1 + w2*w2 + w3*w3 ); /* 2.0 * */
|
||||
VECADDMUL ( i1, vrel_t_pre, w1 * impulse );
|
||||
VECADDMUL ( i2, vrel_t_pre, w2 * impulse );
|
||||
VECADDMUL ( i3, vrel_t_pre, w3 * impulse );
|
||||
impulse = magtangent / 1.5;
|
||||
|
||||
VECADDMUL(i1, vrel_t_pre, w1 * impulse);
|
||||
VECADDMUL(i2, vrel_t_pre, w2 * impulse);
|
||||
VECADDMUL(i3, vrel_t_pre, w3 * impulse);
|
||||
}
|
||||
|
||||
/* Apply velocity stopping impulse
|
||||
* I_c = m * v_N / 2.0
|
||||
* no 2.0 * magrelVel normally, but looks nicer DG */
|
||||
impulse = magrelVel / ( 1.0 + w1*w1 + w2*w2 + w3*w3 );
|
||||
/* Apply velocity stopping impulse. */
|
||||
impulse = magrelVel / 1.5f;
|
||||
|
||||
VECADDMUL ( i1, collpair->normal, w1 * impulse );
|
||||
VECADDMUL(i1, collpair->normal, w1 * impulse);
|
||||
cloth1->verts[collpair->ap1].impulse_count++;
|
||||
|
||||
VECADDMUL ( i2, collpair->normal, w2 * impulse );
|
||||
VECADDMUL(i2, collpair->normal, w2 * impulse);
|
||||
cloth1->verts[collpair->ap2].impulse_count++;
|
||||
|
||||
VECADDMUL ( i3, collpair->normal, w3 * impulse );
|
||||
VECADDMUL(i3, collpair->normal, w3 * impulse);
|
||||
cloth1->verts[collpair->ap3].impulse_count++;
|
||||
|
||||
/* Apply repulse impulse if distance too short
|
||||
* I_r = -min(dt*kd, m(0, 1d/dt - v_n))
|
||||
* DG: this formula ineeds to be changed for this code since we apply impulses/repulses like this:
|
||||
* v += impulse; x_new = x + v;
|
||||
* We don't use dt!!
|
||||
* DG TODO: Fix usage of dt here! */
|
||||
spf = (float)clmd->sim_parms->stepsPerFrame / clmd->sim_parms->timescale;
|
||||
time_multiplier = 1.0f / (clmd->sim_parms->dt * clmd->sim_parms->timescale);
|
||||
|
||||
d = clmd->coll_parms->epsilon*8.0f/9.0f + epsilon2*8.0f/9.0f - collpair->distance;
|
||||
if ( ( magrelVel < 0.1f*d*spf ) && ( d > ALMOST_ZERO ) ) {
|
||||
repulse = MIN2 ( d*1.0f/spf, 0.1f*d*spf - magrelVel );
|
||||
|
||||
/* stay on the safe side and clamp repulse */
|
||||
if ( impulse > ALMOST_ZERO )
|
||||
repulse = min_ff( repulse, 5.0*impulse );
|
||||
if ((magrelVel < 0.1f * d * time_multiplier) && (d > ALMOST_ZERO)) {
|
||||
repulse = MIN2(d / time_multiplier, 0.1f * d * time_multiplier - magrelVel);
|
||||
|
||||
/* Stay on the safe side and clamp repulse. */
|
||||
if (impulse > ALMOST_ZERO) {
|
||||
repulse = min_ff(repulse, 5.0f * impulse);
|
||||
}
|
||||
|
||||
repulse = max_ff(impulse, repulse);
|
||||
|
||||
impulse = repulse / ( 1.0f + w1*w1 + w2*w2 + w3*w3 ); /* original 2.0 / 0.25 */
|
||||
VECADDMUL ( i1, collpair->normal, impulse );
|
||||
VECADDMUL ( i2, collpair->normal, impulse );
|
||||
VECADDMUL ( i3, collpair->normal, impulse );
|
||||
impulse = repulse / 1.5f;
|
||||
|
||||
VECADDMUL(i1, collpair->normal, impulse);
|
||||
VECADDMUL(i2, collpair->normal, impulse);
|
||||
VECADDMUL(i3, collpair->normal, impulse);
|
||||
}
|
||||
|
||||
result = 1;
|
||||
}
|
||||
else {
|
||||
/* Apply repulse impulse if distance too short
|
||||
* I_r = -min(dt*kd, max(0, 1d/dt - v_n))
|
||||
* DG: this formula ineeds to be changed for this code since we apply impulses/repulses like this:
|
||||
* v += impulse; x_new = x + v;
|
||||
* We don't use dt!! */
|
||||
float spf = (float)clmd->sim_parms->stepsPerFrame / clmd->sim_parms->timescale;
|
||||
float time_multiplier = 1.0f / (clmd->sim_parms->dt * clmd->sim_parms->timescale);
|
||||
float d;
|
||||
|
||||
float d = clmd->coll_parms->epsilon*8.0f/9.0f + epsilon2*8.0f/9.0f - (float)collpair->distance;
|
||||
if ( d > ALMOST_ZERO) {
|
||||
/* stay on the safe side and clamp repulse */
|
||||
float repulse = d*1.0f/spf;
|
||||
d = clmd->coll_parms->epsilon*8.0f/9.0f + epsilon2*8.0f/9.0f - collpair->distance;
|
||||
|
||||
float impulse = repulse / ( 3.0f * ( 1.0f + w1*w1 + w2*w2 + w3*w3 )); /* original 2.0 / 0.25 */
|
||||
if (d > ALMOST_ZERO) {
|
||||
/* Stay on the safe side and clamp repulse. */
|
||||
float repulse = d / time_multiplier;
|
||||
float impulse = repulse / 4.5f;
|
||||
|
||||
VECADDMUL ( i1, collpair->normal, impulse );
|
||||
VECADDMUL ( i2, collpair->normal, impulse );
|
||||
VECADDMUL ( i3, collpair->normal, impulse );
|
||||
VECADDMUL(i1, collpair->normal, w1 * impulse);
|
||||
VECADDMUL(i2, collpair->normal, w2 * impulse);
|
||||
VECADDMUL(i3, collpair->normal, w3 * impulse);
|
||||
|
||||
cloth1->verts[collpair->ap1].impulse_count++;
|
||||
cloth1->verts[collpair->ap2].impulse_count++;
|
||||
@@ -377,20 +639,190 @@ static int cloth_collision_response_static ( ClothModifierData *clmd, CollisionM
|
||||
}
|
||||
|
||||
if (result) {
|
||||
int i = 0;
|
||||
float clamp = clmd->coll_parms->clamp * dt;
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
if (cloth1->verts[collpair->ap1].impulse_count > 0 && ABS(cloth1->verts[collpair->ap1].impulse[i]) < ABS(i1[i]))
|
||||
cloth1->verts[collpair->ap1].impulse[i] = i1[i];
|
||||
if ((clamp > 0.0f) &&
|
||||
((len_v3(i1) > clamp) ||
|
||||
(len_v3(i2) > clamp) ||
|
||||
(len_v3(i3) > clamp)))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (cloth1->verts[collpair->ap2].impulse_count > 0 && ABS(cloth1->verts[collpair->ap2].impulse[i]) < ABS(i2[i]))
|
||||
cloth1->verts[collpair->ap2].impulse[i] = i2[i];
|
||||
for (int j = 0; j < 3; j++) {
|
||||
if (cloth1->verts[collpair->ap1].impulse_count > 0 && ABS(cloth1->verts[collpair->ap1].impulse[j]) < ABS(i1[j]))
|
||||
cloth1->verts[collpair->ap1].impulse[j] = i1[j];
|
||||
|
||||
if (cloth1->verts[collpair->ap3].impulse_count > 0 && ABS(cloth1->verts[collpair->ap3].impulse[i]) < ABS(i3[i]))
|
||||
cloth1->verts[collpair->ap3].impulse[i] = i3[i];
|
||||
if (cloth1->verts[collpair->ap2].impulse_count > 0 && ABS(cloth1->verts[collpair->ap2].impulse[j]) < ABS(i2[j]))
|
||||
cloth1->verts[collpair->ap2].impulse[j] = i2[j];
|
||||
|
||||
if (cloth1->verts[collpair->ap3].impulse_count > 0 && ABS(cloth1->verts[collpair->ap3].impulse[j]) < ABS(i3[j]))
|
||||
cloth1->verts[collpair->ap3].impulse[j] = i3[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static int cloth_selfcollision_response_static(ClothModifierData *clmd, CollPair *collpair,
|
||||
uint collision_count, const float dt)
|
||||
{
|
||||
int result = 0;
|
||||
Cloth *cloth1;
|
||||
float w1, w2, w3, u1, u2, u3;
|
||||
float v1[3], v2[3], relativeVelocity[3];
|
||||
float magrelVel;
|
||||
|
||||
cloth1 = clmd->clothObject;
|
||||
|
||||
for (int i = 0; i < collision_count; i++, collpair++) {
|
||||
float i1[3], i2[3], i3[3];
|
||||
|
||||
zero_v3(i1);
|
||||
zero_v3(i2);
|
||||
zero_v3(i3);
|
||||
|
||||
/* Only handle static collisions here. */
|
||||
if (collpair->flag & (COLLISION_IN_FUTURE | COLLISION_INACTIVE)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Compute barycentric coordinates for both collision points. */
|
||||
collision_compute_barycentric(collpair->pa,
|
||||
cloth1->verts[collpair->ap1].tx,
|
||||
cloth1->verts[collpair->ap2].tx,
|
||||
cloth1->verts[collpair->ap3].tx,
|
||||
&w1, &w2, &w3);
|
||||
|
||||
collision_compute_barycentric(collpair->pb,
|
||||
cloth1->verts[collpair->bp1].tx,
|
||||
cloth1->verts[collpair->bp2].tx,
|
||||
cloth1->verts[collpair->bp3].tx,
|
||||
&u1, &u2, &u3);
|
||||
|
||||
/* Calculate relative "velocity". */
|
||||
collision_interpolateOnTriangle(v1, cloth1->verts[collpair->ap1].tv, cloth1->verts[collpair->ap2].tv, cloth1->verts[collpair->ap3].tv, w1, w2, w3);
|
||||
|
||||
collision_interpolateOnTriangle(v2, cloth1->verts[collpair->bp1].tv, cloth1->verts[collpair->bp2].tv, cloth1->verts[collpair->bp3].tv, u1, u2, u3);
|
||||
|
||||
sub_v3_v3v3(relativeVelocity, v2, v1);
|
||||
|
||||
/* Calculate the normal component of the relative velocity (actually only the magnitude - the direction is stored in 'normal'). */
|
||||
magrelVel = dot_v3v3(relativeVelocity, collpair->normal);
|
||||
|
||||
/* TODO: Impulses should be weighed by mass as this is self col,
|
||||
* this has to be done after mass distribution is implemented. */
|
||||
|
||||
/* If magrelVel < 0 the edges are approaching each other. */
|
||||
if (magrelVel > 0.0f) {
|
||||
/* Calculate Impulse magnitude to stop all motion in normal direction. */
|
||||
float magtangent = 0, repulse = 0, d = 0;
|
||||
double impulse = 0.0;
|
||||
float vrel_t_pre[3];
|
||||
float temp[3], time_multiplier;
|
||||
|
||||
/* Calculate tangential velocity. */
|
||||
copy_v3_v3(temp, collpair->normal);
|
||||
mul_v3_fl(temp, magrelVel);
|
||||
sub_v3_v3v3(vrel_t_pre, relativeVelocity, temp);
|
||||
|
||||
/* Decrease in magnitude of relative tangential velocity due to coulomb friction
|
||||
* in original formula "magrelVel" should be the "change of relative velocity in normal direction". */
|
||||
magtangent = min_ff(clmd->coll_parms->self_friction * 0.01f * magrelVel, len_v3(vrel_t_pre));
|
||||
|
||||
/* Apply friction impulse. */
|
||||
if (magtangent > ALMOST_ZERO) {
|
||||
normalize_v3(vrel_t_pre);
|
||||
|
||||
impulse = magtangent / 1.5;
|
||||
|
||||
VECADDMUL(i1, vrel_t_pre, w1 * impulse);
|
||||
VECADDMUL(i2, vrel_t_pre, w2 * impulse);
|
||||
VECADDMUL(i3, vrel_t_pre, w3 * impulse);
|
||||
}
|
||||
|
||||
/* Apply velocity stopping impulse. */
|
||||
impulse = magrelVel / 3.0f;
|
||||
|
||||
VECADDMUL(i1, collpair->normal, w1 * impulse);
|
||||
cloth1->verts[collpair->ap1].impulse_count++;
|
||||
|
||||
VECADDMUL(i2, collpair->normal, w2 * impulse);
|
||||
cloth1->verts[collpair->ap2].impulse_count++;
|
||||
|
||||
VECADDMUL(i3, collpair->normal, w3 * impulse);
|
||||
cloth1->verts[collpair->ap3].impulse_count++;
|
||||
|
||||
time_multiplier = 1.0f / (clmd->sim_parms->dt * clmd->sim_parms->timescale);
|
||||
|
||||
d = clmd->coll_parms->selfepsilon * 8.0f / 9.0f * 2.0f - collpair->distance;
|
||||
|
||||
if ((magrelVel < 0.1f * d * time_multiplier) && (d > ALMOST_ZERO)) {
|
||||
repulse = MIN2 (d / time_multiplier, 0.1f * d * time_multiplier - magrelVel);
|
||||
|
||||
if (impulse > ALMOST_ZERO) {
|
||||
repulse = min_ff(repulse, 5.0*impulse);
|
||||
}
|
||||
|
||||
repulse = max_ff(impulse, repulse);
|
||||
|
||||
impulse = repulse / 1.5f;
|
||||
|
||||
VECADDMUL(i1, collpair->normal, w1 * impulse);
|
||||
VECADDMUL(i2, collpair->normal, w2 * impulse);
|
||||
VECADDMUL(i3, collpair->normal, w3 * impulse);
|
||||
}
|
||||
|
||||
result = 1;
|
||||
}
|
||||
else {
|
||||
float time_multiplier = 1.0f / (clmd->sim_parms->dt * clmd->sim_parms->timescale);
|
||||
float d;
|
||||
|
||||
d = clmd->coll_parms->selfepsilon * 8.0f / 9.0f * 2.0f - collpair->distance;
|
||||
|
||||
if ( d > ALMOST_ZERO) {
|
||||
/* Stay on the safe side and clamp repulse. */
|
||||
float repulse = d*1.0f/time_multiplier;
|
||||
float impulse = repulse / 9.0f;
|
||||
|
||||
VECADDMUL(i1, collpair->normal, w1 * impulse);
|
||||
VECADDMUL(i2, collpair->normal, w2 * impulse);
|
||||
VECADDMUL(i3, collpair->normal, w3 * impulse);
|
||||
|
||||
cloth1->verts[collpair->ap1].impulse_count++;
|
||||
cloth1->verts[collpair->ap2].impulse_count++;
|
||||
cloth1->verts[collpair->ap3].impulse_count++;
|
||||
|
||||
result = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (result) {
|
||||
float clamp = clmd->coll_parms->self_clamp * dt;
|
||||
|
||||
if ((clamp > 0.0f) &&
|
||||
((len_v3(i1) > clamp) ||
|
||||
(len_v3(i2) > clamp) ||
|
||||
(len_v3(i3) > clamp)))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (int j = 0; j < 3; j++) {
|
||||
if (cloth1->verts[collpair->ap1].impulse_count > 0 && ABS(cloth1->verts[collpair->ap1].impulse[j]) < ABS(i1[j]))
|
||||
cloth1->verts[collpair->ap1].impulse[j] = i1[j];
|
||||
|
||||
if (cloth1->verts[collpair->ap2].impulse_count > 0 && ABS(cloth1->verts[collpair->ap2].impulse[j]) < ABS(i2[j]))
|
||||
cloth1->verts[collpair->ap2].impulse[j] = i2[j];
|
||||
|
||||
if (cloth1->verts[collpair->ap3].impulse_count > 0 && ABS(cloth1->verts[collpair->ap3].impulse[j]) < ABS(i3[j]))
|
||||
cloth1->verts[collpair->ap3].impulse[j] = i3[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -398,89 +830,118 @@ static int cloth_collision_response_static ( ClothModifierData *clmd, CollisionM
|
||||
# pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
//Determines collisions on overlap, collisions are written to collpair[i] and collision+number_collision_found is returned
|
||||
static CollPair* cloth_collision(ModifierData *md1, ModifierData *md2,
|
||||
BVHTreeOverlap *overlap, CollPair *collpair, float UNUSED(dt))
|
||||
static void cloth_collision(
|
||||
void *__restrict userdata,
|
||||
const int index,
|
||||
const ParallelRangeTLS *__restrict UNUSED(tls))
|
||||
{
|
||||
ClothModifierData *clmd = (ClothModifierData *)md1;
|
||||
CollisionModifierData *collmd = (CollisionModifierData *) md2;
|
||||
/* Cloth *cloth = clmd->clothObject; */ /* UNUSED */
|
||||
ColDetectData *data = (ColDetectData *)userdata;
|
||||
|
||||
ClothModifierData *clmd = data->clmd;
|
||||
CollisionModifierData *collmd = data->collmd;
|
||||
CollPair *collpair = data->collisions;
|
||||
const MVertTri *tri_a, *tri_b;
|
||||
#ifdef WITH_BULLET
|
||||
ClothVertex *verts1 = clmd->clothObject->verts;
|
||||
#endif
|
||||
double distance = 0;
|
||||
float distance = 0.0f;
|
||||
float epsilon1 = clmd->coll_parms->epsilon;
|
||||
float epsilon2 = BLI_bvhtree_get_epsilon ( collmd->bvhtree );
|
||||
float epsilon2 = BLI_bvhtree_get_epsilon(collmd->bvhtree);
|
||||
float pa[3], pb[3], vect[3];
|
||||
|
||||
tri_a = &clmd->clothObject->tri[overlap->indexA];
|
||||
tri_b = &collmd->tri[overlap->indexB];
|
||||
tri_a = &clmd->clothObject->tri[data->overlap[index].indexA];
|
||||
tri_b = &collmd->tri[data->overlap[index].indexB];
|
||||
|
||||
/* fill face_a */
|
||||
collpair->ap1 = tri_a->tri[0];
|
||||
collpair->ap2 = tri_a->tri[1];
|
||||
collpair->ap3 = tri_a->tri[2];
|
||||
/* Compute distance and normal. */
|
||||
distance = compute_collision_point(verts1[tri_a->tri[0]].tx, verts1[tri_a->tri[1]].tx, verts1[tri_a->tri[2]].tx,
|
||||
collmd->current_x[tri_b->tri[0]].co, collmd->current_x[tri_b->tri[1]].co, collmd->current_x[tri_b->tri[2]].co,
|
||||
data->culling, data->use_normal, pa, pb, vect);
|
||||
|
||||
/* fill face_b */
|
||||
collpair->bp1 = tri_b->tri[0];
|
||||
collpair->bp2 = tri_b->tri[1];
|
||||
collpair->bp3 = tri_b->tri[2];
|
||||
if ((distance <= (epsilon1 + epsilon2 + ALMOST_ZERO)) && (len_squared_v3(vect) > ALMOST_ZERO)) {
|
||||
collpair[index].ap1 = tri_a->tri[0];
|
||||
collpair[index].ap2 = tri_a->tri[1];
|
||||
collpair[index].ap3 = tri_a->tri[2];
|
||||
|
||||
{
|
||||
collpair[index].bp1 = tri_b->tri[0];
|
||||
collpair[index].bp2 = tri_b->tri[1];
|
||||
collpair[index].bp3 = tri_b->tri[2];
|
||||
|
||||
#ifdef WITH_BULLET
|
||||
// calc distance + normal
|
||||
distance = plNearestPoints (
|
||||
verts1[collpair->ap1].txold, verts1[collpair->ap2].txold, verts1[collpair->ap3].txold, collmd->current_x[collpair->bp1].co, collmd->current_x[collpair->bp2].co, collmd->current_x[collpair->bp3].co, collpair->pa, collpair->pb, collpair->vector );
|
||||
#else
|
||||
// just be sure that we don't add anything
|
||||
distance = 2.0 * (double)( epsilon1 + epsilon2 + ALMOST_ZERO );
|
||||
#endif
|
||||
copy_v3_v3(collpair[index].pa, pa);
|
||||
copy_v3_v3(collpair[index].pb, pb);
|
||||
copy_v3_v3(collpair[index].vector, vect);
|
||||
|
||||
// distance -1 means no collision result
|
||||
if (distance != -1.0 && (distance <= (double)(epsilon1 + epsilon2 + ALMOST_ZERO))) {
|
||||
normalize_v3_v3(collpair->normal, collpair->vector);
|
||||
normalize_v3_v3(collpair[index].normal, collpair[index].vector);
|
||||
|
||||
collpair->distance = distance;
|
||||
collpair->flag = 0;
|
||||
collpair++;
|
||||
}/*
|
||||
else {
|
||||
float w1, w2, w3, u1, u2, u3;
|
||||
float v1[3], v2[3], relativeVelocity[3];
|
||||
collpair[index].distance = distance;
|
||||
collpair[index].flag = 0;
|
||||
|
||||
// calc relative velocity
|
||||
|
||||
// compute barycentric coordinates for both collision points
|
||||
collision_compute_barycentric ( collpair->pa,
|
||||
verts1[collpair->ap1].txold,
|
||||
verts1[collpair->ap2].txold,
|
||||
verts1[collpair->ap3].txold,
|
||||
&w1, &w2, &w3 );
|
||||
|
||||
// was: txold
|
||||
collision_compute_barycentric ( collpair->pb,
|
||||
collmd->current_x[collpair->bp1].co,
|
||||
collmd->current_x[collpair->bp2].co,
|
||||
collmd->current_x[collpair->bp3].co,
|
||||
&u1, &u2, &u3 );
|
||||
|
||||
// Calculate relative "velocity".
|
||||
collision_interpolateOnTriangle ( v1, verts1[collpair->ap1].tv, verts1[collpair->ap2].tv, verts1[collpair->ap3].tv, w1, w2, w3 );
|
||||
|
||||
collision_interpolateOnTriangle ( v2, collmd->current_v[collpair->bp1].co, collmd->current_v[collpair->bp2].co, collmd->current_v[collpair->bp3].co, u1, u2, u3 );
|
||||
|
||||
sub_v3_v3v3(relativeVelocity, v2, v1);
|
||||
|
||||
if (sqrt(dot_v3v3(relativeVelocity, relativeVelocity)) >= distance)
|
||||
{
|
||||
// check for collision in the future
|
||||
collpair->flag |= COLLISION_IN_FUTURE;
|
||||
collpair++;
|
||||
}
|
||||
}*/
|
||||
data->collided = true;
|
||||
}
|
||||
else {
|
||||
collpair[index].flag = COLLISION_INACTIVE;
|
||||
}
|
||||
}
|
||||
|
||||
static void cloth_selfcollision(
|
||||
void *__restrict userdata,
|
||||
const int index,
|
||||
const ParallelRangeTLS *__restrict UNUSED(tls))
|
||||
{
|
||||
SelfColDetectData *data = (SelfColDetectData *)userdata;
|
||||
|
||||
ClothModifierData *clmd = data->clmd;
|
||||
CollPair *collpair = data->collisions;
|
||||
const MVertTri *tri_a, *tri_b;
|
||||
ClothVertex *verts1 = clmd->clothObject->verts;
|
||||
float distance = 0.0f;
|
||||
float epsilon = clmd->coll_parms->selfepsilon;
|
||||
float pa[3], pb[3], vect[3];
|
||||
|
||||
tri_a = &clmd->clothObject->tri[data->overlap[index].indexA];
|
||||
tri_b = &clmd->clothObject->tri[data->overlap[index].indexB];
|
||||
|
||||
for (uint i = 0; i < 3; i++) {
|
||||
for (uint j = 0; j < 3; j++) {
|
||||
if (tri_a->tri[i] == tri_b->tri[j]) {
|
||||
collpair[index].flag = COLLISION_INACTIVE;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (((verts1[tri_a->tri[0]].flags & verts1[tri_a->tri[1]].flags & verts1[tri_a->tri[2]].flags) |
|
||||
(verts1[tri_b->tri[0]].flags & verts1[tri_b->tri[1]].flags & verts1[tri_b->tri[2]].flags)) & CLOTH_VERT_FLAG_NOSELFCOLL)
|
||||
{
|
||||
collpair[index].flag = COLLISION_INACTIVE;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Compute distance and normal. */
|
||||
distance = compute_collision_point(verts1[tri_a->tri[0]].tx, verts1[tri_a->tri[1]].tx, verts1[tri_a->tri[2]].tx,
|
||||
verts1[tri_b->tri[0]].tx, verts1[tri_b->tri[1]].tx, verts1[tri_b->tri[2]].tx,
|
||||
false, false, pa, pb, vect);
|
||||
|
||||
if ((distance <= (epsilon * 2.0f + ALMOST_ZERO)) && (len_squared_v3(vect) > ALMOST_ZERO)) {
|
||||
collpair[index].ap1 = tri_a->tri[0];
|
||||
collpair[index].ap2 = tri_a->tri[1];
|
||||
collpair[index].ap3 = tri_a->tri[2];
|
||||
|
||||
collpair[index].bp1 = tri_b->tri[0];
|
||||
collpair[index].bp2 = tri_b->tri[1];
|
||||
collpair[index].bp3 = tri_b->tri[2];
|
||||
|
||||
copy_v3_v3(collpair[index].pa, pa);
|
||||
copy_v3_v3(collpair[index].pb, pb);
|
||||
copy_v3_v3(collpair[index].vector, vect);
|
||||
|
||||
normalize_v3_v3(collpair[index].normal, collpair[index].vector);
|
||||
|
||||
collpair[index].distance = distance;
|
||||
collpair[index].flag = 0;
|
||||
|
||||
data->collided = true;
|
||||
}
|
||||
else {
|
||||
collpair[index].flag = COLLISION_INACTIVE;
|
||||
}
|
||||
return collpair;
|
||||
}
|
||||
|
||||
static void add_collision_object(ListBase *relations, Object *ob, int level, unsigned int modifier_type)
|
||||
@@ -628,25 +1089,49 @@ void BKE_collider_cache_free(ListBase **colliders)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void cloth_bvh_objcollisions_nearcheck ( ClothModifierData * clmd, CollisionModifierData *collmd,
|
||||
CollPair **collisions, CollPair **collisions_index, int numresult, BVHTreeOverlap *overlap, double dt)
|
||||
static bool cloth_bvh_objcollisions_nearcheck(ClothModifierData * clmd, CollisionModifierData *collmd,
|
||||
CollPair **collisions, int numresult,
|
||||
BVHTreeOverlap *overlap, bool culling, bool use_normal)
|
||||
{
|
||||
int i;
|
||||
*collisions = (CollPair *)MEM_mallocN(sizeof(CollPair) * numresult, "collision array");
|
||||
|
||||
*collisions = (CollPair *) MEM_mallocN(sizeof(CollPair) * numresult * 4, "collision array" ); // * 4 since cloth_collision_static can return more than 1 collision
|
||||
*collisions_index = *collisions;
|
||||
ColDetectData data = {.clmd = clmd,
|
||||
.collmd = collmd,
|
||||
.overlap = overlap,
|
||||
.collisions = *collisions,
|
||||
.culling = culling,
|
||||
.use_normal = use_normal,
|
||||
.collided = false};
|
||||
|
||||
for ( i = 0; i < numresult; i++ ) {
|
||||
*collisions_index = cloth_collision((ModifierData *)clmd, (ModifierData *)collmd,
|
||||
overlap+i, *collisions_index, dt);
|
||||
}
|
||||
ParallelRangeSettings settings;
|
||||
BLI_parallel_range_settings_defaults(&settings);
|
||||
settings.use_threading = true;
|
||||
BLI_task_parallel_range(0, numresult, &data, cloth_collision, &settings);
|
||||
|
||||
return data.collided;
|
||||
}
|
||||
|
||||
static int cloth_bvh_objcollisions_resolve ( ClothModifierData * clmd, CollisionModifierData *collmd, CollPair *collisions, CollPair *collisions_index)
|
||||
static bool cloth_bvh_selfcollisions_nearcheck(ClothModifierData * clmd, CollPair *collisions,
|
||||
int numresult, BVHTreeOverlap *overlap)
|
||||
{
|
||||
SelfColDetectData data = {.clmd = clmd,
|
||||
.overlap = overlap,
|
||||
.collisions = collisions,
|
||||
.collided = false};
|
||||
|
||||
ParallelRangeSettings settings;
|
||||
BLI_parallel_range_settings_defaults(&settings);
|
||||
settings.use_threading = true;
|
||||
BLI_task_parallel_range(0, numresult, &data, cloth_selfcollision, &settings);
|
||||
|
||||
return data.collided;
|
||||
}
|
||||
|
||||
static int cloth_bvh_objcollisions_resolve(ClothModifierData * clmd, Object **collobjs, CollPair **collisions,
|
||||
uint *collision_counts, const uint numcollobj, const float dt)
|
||||
{
|
||||
Cloth *cloth = clmd->clothObject;
|
||||
int i=0, j = 0, /*numfaces = 0, */ mvert_num = 0;
|
||||
int i = 0, j = 0, mvert_num = 0;
|
||||
ClothVertex *verts = NULL;
|
||||
int ret = 0;
|
||||
int result = 0;
|
||||
@@ -654,26 +1139,68 @@ static int cloth_bvh_objcollisions_resolve ( ClothModifierData * clmd, Collision
|
||||
mvert_num = clmd->clothObject->mvert_num;
|
||||
verts = cloth->verts;
|
||||
|
||||
// process all collisions (calculate impulses, TODO: also repulses if distance too short)
|
||||
result = 1;
|
||||
for ( j = 0; j < 2; j++ ) { /* 5 is just a value that ensures convergence */
|
||||
|
||||
for (j = 0; j < 2; j++) {
|
||||
result = 0;
|
||||
|
||||
if ( collmd->bvhtree ) {
|
||||
result += cloth_collision_response_static ( clmd, collmd, collisions, collisions_index );
|
||||
for (i = 0; i < numcollobj; i++) {
|
||||
Object *collob= collobjs[i];
|
||||
CollisionModifierData *collmd = (CollisionModifierData *)modifiers_findByType(collob, eModifierType_Collision);
|
||||
|
||||
// apply impulses in parallel
|
||||
if (result) {
|
||||
for (i = 0; i < mvert_num; i++) {
|
||||
// calculate "velocities" (just xnew = xold + v; no dt in v)
|
||||
if (verts[i].impulse_count) {
|
||||
// VECADDMUL ( verts[i].tv, verts[i].impulse, 1.0f / verts[i].impulse_count );
|
||||
VECADD ( verts[i].tv, verts[i].tv, verts[i].impulse);
|
||||
zero_v3(verts[i].impulse);
|
||||
verts[i].impulse_count = 0;
|
||||
if ( collmd->bvhtree ) {
|
||||
result += cloth_collision_response_static(clmd, collmd, collob, collisions[i], collision_counts[i], dt);
|
||||
}
|
||||
}
|
||||
|
||||
ret++;
|
||||
}
|
||||
/* Apply impulses in parallel. */
|
||||
if (result) {
|
||||
for (i = 0; i < mvert_num; i++) {
|
||||
// calculate "velocities" (just xnew = xold + v; no dt in v)
|
||||
if (verts[i].impulse_count) {
|
||||
VECADD ( verts[i].tv, verts[i].tv, verts[i].impulse);
|
||||
VECADD ( verts[i].dcvel, verts[i].dcvel, verts[i].impulse);
|
||||
zero_v3(verts[i].impulse);
|
||||
verts[i].impulse_count = 0;
|
||||
|
||||
ret++;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int cloth_bvh_selfcollisions_resolve(ClothModifierData * clmd, CollPair *collisions, int collision_count, const float dt)
|
||||
{
|
||||
Cloth *cloth = clmd->clothObject;
|
||||
int i = 0, j = 0, mvert_num = 0;
|
||||
ClothVertex *verts = NULL;
|
||||
int ret = 0;
|
||||
int result = 0;
|
||||
|
||||
mvert_num = clmd->clothObject->mvert_num;
|
||||
verts = cloth->verts;
|
||||
|
||||
for (j = 0; j < 2; j++) {
|
||||
result = 0;
|
||||
|
||||
result += cloth_selfcollision_response_static(clmd, collisions, collision_count, dt);
|
||||
|
||||
/* Apply impulses in parallel. */
|
||||
if (result) {
|
||||
for (i = 0; i < mvert_num; i++) {
|
||||
if (verts[i].impulse_count) {
|
||||
// VECADDMUL ( verts[i].tv, verts[i].impulse, 1.0f / verts[i].impulse_count );
|
||||
VECADD ( verts[i].tv, verts[i].tv, verts[i].impulse);
|
||||
VECADD ( verts[i].dcvel, verts[i].dcvel, verts[i].impulse);
|
||||
zero_v3(verts[i].impulse);
|
||||
verts[i].impulse_count = 0;
|
||||
|
||||
ret++;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -685,91 +1212,86 @@ static int cloth_bvh_objcollisions_resolve ( ClothModifierData * clmd, Collision
|
||||
return ret;
|
||||
}
|
||||
|
||||
// cloth - object collisions
|
||||
int cloth_bvh_objcollision(Depsgraph *depsgraph, Object *ob, ClothModifierData *clmd, float step, float dt )
|
||||
int cloth_bvh_collision(Depsgraph *depsgraph, Object *ob, ClothModifierData *clmd, float step, float dt)
|
||||
{
|
||||
Cloth *cloth= clmd->clothObject;
|
||||
BVHTree *cloth_bvh= cloth->bvhtree;
|
||||
unsigned int i=0, /* numfaces = 0, */ /* UNUSED */ mvert_num = 0, k, l, j;
|
||||
int rounds = 0; // result counts applied collisions; ic is for debug output;
|
||||
Cloth *cloth = clmd->clothObject;
|
||||
BVHTree *cloth_bvh = cloth->bvhtree;
|
||||
uint i = 0, mvert_num = 0;
|
||||
int rounds = 0;
|
||||
ClothVertex *verts = NULL;
|
||||
int ret = 0, ret2 = 0;
|
||||
Object **collobjs = NULL;
|
||||
unsigned int numcollobj = 0;
|
||||
uint *coll_counts_obj = NULL;
|
||||
BVHTreeOverlap **overlap_obj = NULL;
|
||||
uint coll_count_self = 0;
|
||||
BVHTreeOverlap *overlap_self = NULL;
|
||||
|
||||
if ((clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_COLLOBJ) || cloth_bvh==NULL)
|
||||
return 0;
|
||||
|
||||
verts = cloth->verts;
|
||||
/* numfaces = cloth->numfaces; */ /* UNUSED */
|
||||
mvert_num = cloth->mvert_num;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// static collisions
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
if (clmd->coll_parms->flags & CLOTH_COLLSETTINGS_FLAG_ENABLED) {
|
||||
bvhtree_update_from_cloth(clmd, true);
|
||||
bvhtree_update_from_cloth(clmd, false, false);
|
||||
|
||||
collobjs = BKE_collision_objects_create(depsgraph, ob, clmd->coll_parms->group, &numcollobj, eModifierType_Collision);
|
||||
|
||||
if (!collobjs) {
|
||||
return 0;
|
||||
}
|
||||
if (collobjs) {
|
||||
coll_counts_obj = MEM_callocN(sizeof(uint) * numcollobj, "CollCounts");
|
||||
overlap_obj = MEM_callocN(sizeof(*overlap_obj) * numcollobj, "BVHOverlap");
|
||||
|
||||
/* Move object to position (step) in time. */
|
||||
for (i = 0; i < numcollobj; i++) {
|
||||
Object *collob = collobjs[i];
|
||||
CollisionModifierData *collmd = (CollisionModifierData *)modifiers_findByType(collob, eModifierType_Collision);
|
||||
|
||||
if (!collmd->bvhtree) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Move object to position (step) in time. */
|
||||
collision_move_object(collmd, step + dt, step);
|
||||
}
|
||||
}
|
||||
|
||||
if (clmd->coll_parms->flags & CLOTH_COLLSETTINGS_FLAG_SELF) {
|
||||
bvhselftree_update_from_cloth(clmd, false);
|
||||
}
|
||||
|
||||
do {
|
||||
ret2 = 0;
|
||||
|
||||
if (clmd->coll_parms->flags & CLOTH_COLLSETTINGS_FLAG_ENABLED) {
|
||||
CollPair **collisions, **collisions_index;
|
||||
|
||||
collisions = MEM_callocN(sizeof(CollPair *) *numcollobj, "CollPair");
|
||||
collisions_index = MEM_callocN(sizeof(CollPair *) *numcollobj, "CollPair");
|
||||
|
||||
/* Check all collision objects. */
|
||||
for (i = 0; i < numcollobj; i++) {
|
||||
Object *collob= collobjs[i];
|
||||
Object *collob = collobjs[i];
|
||||
CollisionModifierData *collmd = (CollisionModifierData *)modifiers_findByType(collob, eModifierType_Collision);
|
||||
BVHTreeOverlap *overlap = NULL;
|
||||
unsigned int result = 0;
|
||||
|
||||
if (!collmd->bvhtree) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Search for overlapping collision pairs. */
|
||||
overlap = BLI_bvhtree_overlap(cloth_bvh, collmd->bvhtree, &result, NULL, NULL);
|
||||
/* Move object to position (step) in time. */
|
||||
collision_move_object(collmd, step + dt, step);
|
||||
|
||||
/* Go to next object if no overlap is there. */
|
||||
if (result && overlap) {
|
||||
/* Check if collisions really happen (costly near check). */
|
||||
cloth_bvh_objcollisions_nearcheck(clmd, collmd, &collisions[i], &collisions_index[i],
|
||||
result, overlap, dt/(float)clmd->coll_parms->loop_count);
|
||||
overlap_obj[i] = BLI_bvhtree_overlap(cloth_bvh, collmd->bvhtree, &coll_counts_obj[i], NULL, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Resolve nearby collisions. */
|
||||
ret += cloth_bvh_objcollisions_resolve(clmd, collmd, collisions[i], collisions_index[i]);
|
||||
ret2 += ret;
|
||||
if (clmd->coll_parms->flags & CLOTH_COLLSETTINGS_FLAG_SELF) {
|
||||
bvhtree_update_from_cloth(clmd, false, true);
|
||||
|
||||
overlap_self = BLI_bvhtree_overlap(cloth->bvhselftree, cloth->bvhselftree, &coll_count_self, NULL, NULL);
|
||||
}
|
||||
|
||||
do {
|
||||
ret2 = 0;
|
||||
|
||||
/* Object collisions. */
|
||||
if ((clmd->coll_parms->flags & CLOTH_COLLSETTINGS_FLAG_ENABLED) && collobjs) {
|
||||
CollPair **collisions;
|
||||
bool collided = false;
|
||||
|
||||
collisions = MEM_callocN(sizeof(CollPair *) * numcollobj, "CollPair");
|
||||
|
||||
for (i = 0; i < numcollobj; i++) {
|
||||
Object *collob = collobjs[i];
|
||||
CollisionModifierData *collmd = (CollisionModifierData *)modifiers_findByType(collob, eModifierType_Collision);
|
||||
|
||||
if (!collmd->bvhtree) {
|
||||
continue;
|
||||
}
|
||||
|
||||
MEM_SAFE_FREE(overlap);
|
||||
if (coll_counts_obj[i] && overlap_obj[i]) {
|
||||
collided = cloth_bvh_objcollisions_nearcheck(clmd, collmd, &collisions[i], coll_counts_obj[i], overlap_obj[i],
|
||||
(collob->pd->flag & PFIELD_CLOTH_USE_CULLING),
|
||||
(collob->pd->flag & PFIELD_CLOTH_USE_NORMAL)) || collided;
|
||||
}
|
||||
}
|
||||
|
||||
if (collided) {
|
||||
ret += cloth_bvh_objcollisions_resolve(clmd, collobjs, collisions, coll_counts_obj, numcollobj, dt);
|
||||
ret2 += ret;
|
||||
}
|
||||
|
||||
for (i = 0; i < numcollobj; i++) {
|
||||
@@ -777,14 +1299,32 @@ int cloth_bvh_objcollision(Depsgraph *depsgraph, Object *ob, ClothModifierData *
|
||||
}
|
||||
|
||||
MEM_freeN(collisions);
|
||||
MEM_freeN(collisions_index);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// update positions
|
||||
// this is needed for bvh_calc_DOP_hull_moving() [kdop.c]
|
||||
////////////////////////////////////////////////////////////
|
||||
/* Self collisions. */
|
||||
if (clmd->coll_parms->flags & CLOTH_COLLSETTINGS_FLAG_SELF) {
|
||||
CollPair *collisions = NULL;
|
||||
|
||||
/* Verts come from clmd. */
|
||||
verts = cloth->verts;
|
||||
mvert_num = cloth->mvert_num;
|
||||
|
||||
if (cloth->bvhselftree) {
|
||||
if (coll_count_self && overlap_self) {
|
||||
collisions = (CollPair *)MEM_mallocN(sizeof(CollPair) * coll_count_self, "collision array");
|
||||
|
||||
if (cloth_bvh_selfcollisions_nearcheck(clmd, collisions, coll_count_self, overlap_self)) {
|
||||
ret += cloth_bvh_selfcollisions_resolve(clmd, collisions, coll_count_self, dt);
|
||||
ret2 += ret;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
MEM_SAFE_FREE(collisions);
|
||||
}
|
||||
|
||||
/* Apply all collision resolution. */
|
||||
if (ret2) {
|
||||
for (i = 0; i < mvert_num; i++) {
|
||||
if (clmd->sim_parms->vgroup_mass > 0) {
|
||||
if (verts [i].flags & CLOTH_VERT_FLAG_PINNED) {
|
||||
@@ -794,117 +1334,27 @@ int cloth_bvh_objcollision(Depsgraph *depsgraph, Object *ob, ClothModifierData *
|
||||
|
||||
VECADD(verts[i].tx, verts[i].txold, verts[i].tv);
|
||||
}
|
||||
////////////////////////////////////////////////////////////
|
||||
}
|
||||
|
||||
rounds++;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Test on *simple* selfcollisions
|
||||
////////////////////////////////////////////////////////////
|
||||
if ( clmd->coll_parms->flags & CLOTH_COLLSETTINGS_FLAG_SELF ) {
|
||||
for (l = 0; l < (unsigned int)clmd->coll_parms->self_loop_count; l++) {
|
||||
/* TODO: add coll quality rounds again */
|
||||
BVHTreeOverlap *overlap = NULL;
|
||||
unsigned int result = 0;
|
||||
|
||||
// collisions = 1;
|
||||
verts = cloth->verts; // needed for openMP
|
||||
|
||||
/* numfaces = cloth->numfaces; */ /* UNUSED */
|
||||
mvert_num = cloth->mvert_num;
|
||||
|
||||
verts = cloth->verts;
|
||||
|
||||
if ( cloth->bvhselftree ) {
|
||||
// search for overlapping collision pairs
|
||||
overlap = BLI_bvhtree_overlap(cloth->bvhselftree, cloth->bvhselftree, &result, NULL, NULL);
|
||||
|
||||
/* Could be parallelized (using BLI_task)... */
|
||||
for ( k = 0; k < result; k++ ) {
|
||||
float temp[3];
|
||||
float length = 0;
|
||||
float mindistance;
|
||||
|
||||
i = overlap[k].indexA;
|
||||
j = overlap[k].indexB;
|
||||
|
||||
mindistance = clmd->coll_parms->selfepsilon* ( cloth->verts[i].avg_spring_len + cloth->verts[j].avg_spring_len );
|
||||
|
||||
if (clmd->sim_parms->vgroup_mass > 0) {
|
||||
if ( ( cloth->verts [i].flags & CLOTH_VERT_FLAG_PINNED ) &&
|
||||
( cloth->verts [j].flags & CLOTH_VERT_FLAG_PINNED ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if ((cloth->verts[i].flags & CLOTH_VERT_FLAG_NOSELFCOLL) ||
|
||||
(cloth->verts[j].flags & CLOTH_VERT_FLAG_NOSELFCOLL))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
sub_v3_v3v3(temp, verts[i].tx, verts[j].tx);
|
||||
|
||||
if ( ( ABS ( temp[0] ) > mindistance ) || ( ABS ( temp[1] ) > mindistance ) || ( ABS ( temp[2] ) > mindistance ) ) continue;
|
||||
|
||||
if (BLI_edgeset_haskey(cloth->edgeset, i, j)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
length = normalize_v3(temp );
|
||||
|
||||
if ( length < mindistance ) {
|
||||
float correction = mindistance - length;
|
||||
|
||||
if ( cloth->verts [i].flags & CLOTH_VERT_FLAG_PINNED ) {
|
||||
mul_v3_fl(temp, -correction);
|
||||
VECADD ( verts[j].tx, verts[j].tx, temp );
|
||||
}
|
||||
else if ( cloth->verts [j].flags & CLOTH_VERT_FLAG_PINNED ) {
|
||||
mul_v3_fl(temp, correction);
|
||||
VECADD ( verts[i].tx, verts[i].tx, temp );
|
||||
}
|
||||
else {
|
||||
mul_v3_fl(temp, correction * -0.5f);
|
||||
VECADD ( verts[j].tx, verts[j].tx, temp );
|
||||
|
||||
sub_v3_v3v3(verts[i].tx, verts[i].tx, temp);
|
||||
}
|
||||
ret = 1;
|
||||
ret2 += ret;
|
||||
}
|
||||
else {
|
||||
// check for approximated time collisions
|
||||
}
|
||||
}
|
||||
|
||||
if ( overlap )
|
||||
MEM_freeN ( overlap );
|
||||
|
||||
}
|
||||
}
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// SELFCOLLISIONS: update velocities
|
||||
////////////////////////////////////////////////////////////
|
||||
if (ret2) {
|
||||
for (i = 0; i < cloth->mvert_num; i++) {
|
||||
if ( ! ( verts [i].flags & CLOTH_VERT_FLAG_PINNED ) ) {
|
||||
sub_v3_v3v3(verts[i].tv, verts[i].tx, verts[i].txold);
|
||||
}
|
||||
}
|
||||
}
|
||||
////////////////////////////////////////////////////////////
|
||||
}
|
||||
}
|
||||
while ( ret2 && ( clmd->coll_parms->loop_count>rounds ) );
|
||||
while (ret2 && (clmd->coll_parms->loop_count > rounds));
|
||||
|
||||
if (overlap_obj) {
|
||||
for (i = 0; i < numcollobj; i++) {
|
||||
MEM_SAFE_FREE(overlap_obj[i]);
|
||||
}
|
||||
|
||||
MEM_freeN(overlap_obj);
|
||||
}
|
||||
|
||||
MEM_SAFE_FREE(coll_counts_obj);
|
||||
|
||||
MEM_SAFE_FREE(overlap_self);
|
||||
|
||||
BKE_collision_objects_free(collobjs);
|
||||
|
||||
return 1|MIN2 ( ret, 1 );
|
||||
return MIN2(ret, 1);
|
||||
}
|
||||
|
||||
BLI_INLINE void max_v3_v3v3(float r[3], const float a[3], const float b[3])
|
||||
@@ -930,106 +1380,6 @@ void collision_get_collider_velocity(float vel_old[3], float vel_new[3], Collisi
|
||||
copy_v3_v3(vel_old, vel_new);
|
||||
}
|
||||
|
||||
static bool cloth_points_collision_response_static(ClothModifierData *clmd, CollisionModifierData *collmd, PartDeflect *pd,
|
||||
CollPair *collpair, CollPair *collision_end, float dt)
|
||||
{
|
||||
bool result = false;
|
||||
float restitution = (1.0f - clmd->coll_parms->damping) * (1.0f - pd->pdef_sbdamp);
|
||||
float inv_dt = 1.0f / dt;
|
||||
Cloth *cloth1 = clmd->clothObject;
|
||||
|
||||
// float w1, w2;
|
||||
float u1, u2, u3;
|
||||
float v1[3], v2_old[3], v2_new[3], v_rel_old[3], v_rel_new[3];
|
||||
float epsilon2 = BLI_bvhtree_get_epsilon ( collmd->bvhtree );
|
||||
|
||||
for ( ; collpair != collision_end; collpair++ ) {
|
||||
float margin_distance = (float)(collpair->distance - (double)epsilon2);
|
||||
float impulse[3];
|
||||
float mag_v_rel;
|
||||
|
||||
if (margin_distance > 0.0f)
|
||||
continue;
|
||||
|
||||
zero_v3(impulse);
|
||||
|
||||
/* only handle static collisions here */
|
||||
if ( collpair->flag & COLLISION_IN_FUTURE )
|
||||
continue;
|
||||
|
||||
/* compute barycentric coordinates for both collision points */
|
||||
// w1 = 1.0f - collpair->time;
|
||||
// w2 = collpair->time;
|
||||
|
||||
/* was: txold */
|
||||
collision_compute_barycentric ( collpair->pb,
|
||||
collmd->current_x[collpair->bp1].co,
|
||||
collmd->current_x[collpair->bp2].co,
|
||||
collmd->current_x[collpair->bp3].co,
|
||||
&u1, &u2, &u3 );
|
||||
|
||||
/* Calculate relative velocity */
|
||||
copy_v3_v3(v1, cloth1->verts[collpair->ap1].tv);
|
||||
|
||||
collision_interpolateOnTriangle ( v2_new, collmd->current_v[collpair->bp1].co, collmd->current_v[collpair->bp2].co, collmd->current_v[collpair->bp3].co, u1, u2, u3 );
|
||||
/* XXX assume constant velocity of the collider for now */
|
||||
copy_v3_v3(v2_old, v2_new);
|
||||
|
||||
sub_v3_v3v3(v_rel_old, v1, v2_old);
|
||||
sub_v3_v3v3(v_rel_new, v1, v2_new);
|
||||
|
||||
/* normal component of the relative velocity */
|
||||
mag_v_rel = dot_v3v3(v_rel_old, collpair->normal);
|
||||
|
||||
/**** DEBUG ****/
|
||||
BKE_sim_debug_data_add_dot(collpair->pa, 0.9, 0.2, 0.2, "collision", 833, collpair->face1, collpair->face2);
|
||||
BKE_sim_debug_data_add_dot(collpair->pb, 0.2, 0.9, 0.2, "collision", 834, collpair->face1, collpair->face2);
|
||||
BKE_sim_debug_data_add_line(collpair->pa, collpair->pb, 0.8, 0.8, 0.8, "collision", 835, collpair->face1, collpair->face2);
|
||||
/********/
|
||||
|
||||
if (mag_v_rel < -ALMOST_ZERO) {
|
||||
float v_nor_old, v_nor_new;
|
||||
float v_tan_old[3], v_tan_new[3];
|
||||
float bounce, repulse;
|
||||
|
||||
/* Collision response based on
|
||||
* "Simulating Complex Hair with Robust Collision Handling" (Choe, Choi, Ko, ACM SIGGRAPH 2005)
|
||||
* http://graphics.snu.ac.kr/publications/2005-choe-HairSim/Choe_2005_SCA.pdf
|
||||
*/
|
||||
|
||||
v_nor_old = mag_v_rel;
|
||||
v_nor_new = dot_v3v3(v_rel_new, collpair->normal);
|
||||
|
||||
madd_v3_v3v3fl(v_tan_old, v_rel_old, collpair->normal, -v_nor_old);
|
||||
madd_v3_v3v3fl(v_tan_new, v_rel_new, collpair->normal, -v_nor_new);
|
||||
|
||||
repulse = -margin_distance * inv_dt + dot_v3v3(v1, collpair->normal);
|
||||
|
||||
if (margin_distance < -epsilon2) {
|
||||
bounce = -v_nor_new + v_nor_old * restitution;
|
||||
mul_v3_v3fl(impulse, collpair->normal, max_ff(repulse, bounce));
|
||||
}
|
||||
else {
|
||||
bounce = 0.0f;
|
||||
mul_v3_v3fl(impulse, collpair->normal, repulse);
|
||||
}
|
||||
cloth1->verts[collpair->ap1].impulse_count++;
|
||||
|
||||
result = true;
|
||||
}
|
||||
|
||||
if (result) {
|
||||
int i = 0;
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
if (cloth1->verts[collpair->ap1].impulse_count > 0 && fabsf(cloth1->verts[collpair->ap1].impulse[i]) < fabsf(impulse[i]))
|
||||
cloth1->verts[collpair->ap1].impulse[i] = impulse[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
BLI_INLINE bool cloth_point_face_collision_params(const float p1[3], const float p2[3], const float v0[3], const float v1[3], const float v2[3],
|
||||
float r_nor[3], float *r_lambda, float r_w[3])
|
||||
{
|
||||
@@ -1181,160 +1531,6 @@ static void cloth_points_objcollisions_nearcheck(
|
||||
}
|
||||
}
|
||||
|
||||
static int cloth_points_objcollisions_resolve(
|
||||
ClothModifierData *clmd, CollisionModifierData *collmd, PartDeflect *pd,
|
||||
CollPair *collisions, CollPair *collisions_index, float dt)
|
||||
{
|
||||
Cloth *cloth = clmd->clothObject;
|
||||
int i = 0, mvert_num = clmd->clothObject->mvert_num;
|
||||
ClothVertex *verts = cloth->verts;
|
||||
int ret = 0;
|
||||
|
||||
// process all collisions
|
||||
if ( collmd->bvhtree ) {
|
||||
bool result = cloth_points_collision_response_static(clmd, collmd, pd, collisions, collisions_index, dt);
|
||||
|
||||
// apply impulses in parallel
|
||||
if (result) {
|
||||
for (i = 0; i < mvert_num; i++) {
|
||||
// calculate "velocities" (just xnew = xold + v; no dt in v)
|
||||
if (verts[i].impulse_count) {
|
||||
// VECADDMUL ( verts[i].tv, verts[i].impulse, 1.0f / verts[i].impulse_count );
|
||||
VECADD ( verts[i].tv, verts[i].tv, verts[i].impulse);
|
||||
zero_v3(verts[i].impulse);
|
||||
verts[i].impulse_count = 0;
|
||||
|
||||
ret++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// cloth - object collisions
|
||||
int cloth_points_objcollision(Depsgraph *depsgraph, Object *ob, ClothModifierData *clmd, float step, float dt)
|
||||
{
|
||||
Cloth *cloth= clmd->clothObject;
|
||||
BVHTree *cloth_bvh;
|
||||
int rounds = 0; // result counts applied collisions; ic is for debug output;
|
||||
float round_dt = dt / (float)clmd->coll_parms->loop_count;
|
||||
unsigned int i = 0, mvert_num = 0;
|
||||
ClothVertex *verts = NULL;
|
||||
int ret = 0, ret2 = 0;
|
||||
Object **collobjs = NULL;
|
||||
unsigned int numcollobj = 0;
|
||||
|
||||
verts = cloth->verts;
|
||||
mvert_num = cloth->mvert_num;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// static collisions
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
// create temporary cloth points bvh
|
||||
cloth_bvh = BLI_bvhtree_new(mvert_num, max_ff(clmd->coll_parms->epsilon, clmd->coll_parms->distance_repel), 4, 6);
|
||||
/* fill tree */
|
||||
for (i = 0; i < mvert_num; i++) {
|
||||
float co[2][3];
|
||||
|
||||
copy_v3_v3(co[0], verts[i].x);
|
||||
copy_v3_v3(co[1], verts[i].tx);
|
||||
|
||||
BLI_bvhtree_insert(cloth_bvh, i, co[0], 2);
|
||||
}
|
||||
/* balance tree */
|
||||
BLI_bvhtree_balance(cloth_bvh);
|
||||
|
||||
collobjs = BKE_collision_objects_create(depsgraph, ob, clmd->coll_parms->group, &numcollobj, eModifierType_Collision);
|
||||
if (!collobjs)
|
||||
return 0;
|
||||
|
||||
/* move object to position (step) in time */
|
||||
for (i = 0; i < numcollobj; i++) {
|
||||
Object *collob= collobjs[i];
|
||||
CollisionModifierData *collmd = (CollisionModifierData *)modifiers_findByType(collob, eModifierType_Collision);
|
||||
if (!collmd->bvhtree)
|
||||
continue;
|
||||
|
||||
/* move object to position (step) in time */
|
||||
collision_move_object ( collmd, step + dt, step );
|
||||
}
|
||||
|
||||
do {
|
||||
CollPair **collisions, **collisions_index;
|
||||
|
||||
ret2 = 0;
|
||||
|
||||
collisions = MEM_callocN(sizeof(CollPair *) *numcollobj, "CollPair");
|
||||
collisions_index = MEM_callocN(sizeof(CollPair *) *numcollobj, "CollPair");
|
||||
|
||||
// check all collision objects
|
||||
for (i = 0; i < numcollobj; i++) {
|
||||
Object *collob= collobjs[i];
|
||||
CollisionModifierData *collmd = (CollisionModifierData *)modifiers_findByType(collob, eModifierType_Collision);
|
||||
BVHTreeOverlap *overlap = NULL;
|
||||
unsigned int result = 0;
|
||||
float epsilon;
|
||||
|
||||
if (!collmd->bvhtree)
|
||||
continue;
|
||||
|
||||
/* search for overlapping collision pairs */
|
||||
overlap = BLI_bvhtree_overlap(cloth_bvh, collmd->bvhtree, &result, NULL, NULL);
|
||||
epsilon = BLI_bvhtree_get_epsilon(collmd->bvhtree);
|
||||
|
||||
// go to next object if no overlap is there
|
||||
if (result && overlap) {
|
||||
/* check if collisions really happen (costly near check) */
|
||||
cloth_points_objcollisions_nearcheck(clmd, collmd, &collisions[i], &collisions_index[i],
|
||||
result, overlap, epsilon, round_dt);
|
||||
|
||||
// resolve nearby collisions
|
||||
ret += cloth_points_objcollisions_resolve(clmd, collmd, collob->pd, collisions[i], collisions_index[i], round_dt);
|
||||
ret2 += ret;
|
||||
}
|
||||
|
||||
if (overlap)
|
||||
MEM_freeN ( overlap );
|
||||
}
|
||||
rounds++;
|
||||
|
||||
for (i = 0; i < numcollobj; i++) {
|
||||
if (collisions[i])
|
||||
MEM_freeN(collisions[i]);
|
||||
}
|
||||
|
||||
MEM_freeN(collisions);
|
||||
MEM_freeN(collisions_index);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// update positions
|
||||
// this is needed for bvh_calc_DOP_hull_moving() [kdop.c]
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
// verts come from clmd
|
||||
for (i = 0; i < mvert_num; i++) {
|
||||
if (clmd->sim_parms->vgroup_mass > 0) {
|
||||
if ( verts [i].flags & CLOTH_VERT_FLAG_PINNED ) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
VECADD ( verts[i].tx, verts[i].txold, verts[i].tv );
|
||||
}
|
||||
////////////////////////////////////////////////////////////
|
||||
}
|
||||
while ( ret2 && ( clmd->coll_parms->loop_count>rounds ) );
|
||||
|
||||
BKE_collision_objects_free(collobjs);
|
||||
|
||||
BLI_bvhtree_free(cloth_bvh);
|
||||
|
||||
return 1|MIN2 ( ret, 1 );
|
||||
}
|
||||
|
||||
void cloth_find_point_contacts(Depsgraph *depsgraph, Object *ob, ClothModifierData *clmd, float step, float dt,
|
||||
ColliderContacts **r_collider_contacts, int *r_totcolliders)
|
||||
{
|
||||
@@ -1364,7 +1560,7 @@ void cloth_find_point_contacts(Depsgraph *depsgraph, Object *ob, ClothModifierDa
|
||||
}
|
||||
|
||||
// create temporary cloth points bvh
|
||||
cloth_bvh = BLI_bvhtree_new(mvert_num, max_ff(clmd->coll_parms->epsilon, clmd->coll_parms->distance_repel), 4, 6);
|
||||
cloth_bvh = BLI_bvhtree_new(mvert_num, clmd->coll_parms->epsilon, 4, 6);
|
||||
/* fill tree */
|
||||
for (i = 0; i < mvert_num; i++) {
|
||||
float co[6];
|
||||
|
||||
@@ -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 */
|
||||
|
||||
Reference in New Issue
Block a user