normal_mass, tangent_mass[2];
u32 element_id;
+ int cluster;
}
rb_contact_buffer[256];
VG_STATIC int rb_contact_count = 0;
return 0;
}
+#define RIGIDBODY_DYNAMIC_MESH_EDGES
+
VG_STATIC int rb_sphere_triangle( rigidbody *rba, rigidbody *rbb,
v3f tri[3], rb_ct *buf )
{
v3f delta, co;
+#ifdef RIGIDBODY_DYNAMIC_MESH_EDGES
+ closest_on_triangle( rba->co, tri, co );
+#else
closest_on_triangle_1( rba->co, tri, co );
+#endif
+
v3_sub( rba->co, co, delta );
vg_line( rba->co, co, 0xffff0000 );
scene *sc = rbb->inf.scene.bh_scene->user;
u32 geo[128];
- v3f tri[3];
- int len = bh_select( rbb->inf.scene.bh_scene, rba->bbx_world, geo, 128 );
+ int len = bh_select( rbb->inf.scene.bh_scene, rba->bbx_world, geo, 128 );
int count = 0;
+#ifdef RIGIDBODY_DYNAMIC_MESH_EDGES
+ /* !experimental! build edge array on the fly. time could be improved! */
+
+ v3f co_picture[128*3];
+ int unique_cos = 0;
+
+ struct face_info
+ {
+ int unique_cos[3]; /* indexes co_picture array */
+ int collided;
+ v3f normal;
+ u32 element_id;
+ }
+ faces[128];
+
+ /* create geometry picture */
+ for( int i=0; i<len; i++ )
+ {
+ u32 *tri_indices = &sc->arrindices[ geo[i]*3 ];
+ struct face_info *inf = &faces[i];
+ inf->element_id = tri_indices[0];
+ inf->collided = 0;
+
+ for( int j=0; j<3; j++ )
+ {
+ struct mdl_vert *pvert = &sc->arrvertices[tri_indices[j]];
+
+ for( int k=0; k<unique_cos; k++ )
+ {
+ if( v3_dist( pvert->co, co_picture[k] ) < 0.01f*0.01f )
+ {
+ inf->unique_cos[j] = k;
+ goto next_vert;
+ }
+ }
+
+ inf->unique_cos[j] = unique_cos;
+ v3_copy( pvert->co, co_picture[ unique_cos ++ ] );
+next_vert:;
+ }
+
+ v3f ab, ac;
+ v3_sub( co_picture[inf->unique_cos[2]],
+ co_picture[inf->unique_cos[0]], ab );
+
+ v3_sub( co_picture[inf->unique_cos[1]],
+ co_picture[inf->unique_cos[0]], ac );
+ v3_cross( ac, ab, inf->normal );
+ v3_normalize( inf->normal );
+ }
+
+
+ /* build edges brute force */
+ int edge_picture[ 128*3 ][4];
+ int unique_edges = 0;
+
+ for( int i=0; i<len; i++ )
+ {
+ struct face_info *inf = &faces[i];
+
+ for( int j=0; j<3; j++ )
+ {
+ int i0 = j,
+ i1 = (j+1)%3,
+ e0 = VG_MIN( inf->unique_cos[i0], inf->unique_cos[i1] ),
+ e1 = VG_MAX( inf->unique_cos[i0], inf->unique_cos[i1] ),
+ matched = 0;
+
+ for( int k=0; k<unique_edges; k ++ )
+ {
+ int k0 = VG_MIN( edge_picture[k][0], edge_picture[k][1] ),
+ k1 = VG_MAX( edge_picture[k][0], edge_picture[k][1] );
+
+ /* matched ! */
+ if( (k0 == e0) && (k1 == e1) )
+ {
+ edge_picture[ k ][3] = i;
+ matched = 1;
+ break;
+ }
+ }
+
+ if( !matched )
+ {
+ /* create new edge */
+ edge_picture[ unique_edges ][0] = inf->unique_cos[i0];
+ edge_picture[ unique_edges ][1] = inf->unique_cos[i1];
+
+ edge_picture[ unique_edges ][2] = i;
+ edge_picture[ unique_edges ][3] = -1;
+
+ unique_edges ++;
+ }
+ }
+ }
+#endif
+
+ v3f tri[3];
+
for( int i=0; i<len; i++ )
{
+#ifdef RIGIDBODY_DYNAMIC_MESH_EDGES
+ struct face_info *inf = &faces[i];
+
+ float *v0 = co_picture[inf->unique_cos[0]],
+ *v1 = co_picture[inf->unique_cos[1]],
+ *v2 = co_picture[inf->unique_cos[2]];
+
+ v3_copy( v0, tri[0] );
+ v3_copy( v1, tri[1] );
+ v3_copy( v2, tri[2] );
+
+ buf[count].element_id = inf->element_id;
+#else
u32 *ptri = &sc->arrindices[ geo[i]*3 ];
for( int j=0; j<3; j++ )
v3_copy( sc->arrvertices[ptri[j]].co, tri[j] );
-
- vg_line(tri[0],tri[1],0xff00ff00 );
- vg_line(tri[1],tri[2],0xff00ff00 );
- vg_line(tri[2],tri[0],0xff00ff00 );
buf[count].element_id = ptri[0];
- count += rb_sphere_triangle( rba, rbb, tri, buf+count );
+#endif
+
+ vg_line( tri[0],tri[1],0x10ffffff );
+ vg_line( tri[1],tri[2],0x10ffffff );
+ vg_line( tri[2],tri[0],0x10ffffff );
+
+ int hits = rb_sphere_triangle( rba, rbb, tri, buf+count );
+#ifdef RIGIDBODY_DYNAMIC_MESH_EDGES
+ if( hits )
+ inf->collided = 1;
+#endif
+ count += hits;
if( count == 12 )
{
}
}
+#ifdef RIGIDBODY_DYNAMIC_MESH_EDGES
+ for( int i=0; i<unique_edges; i++ )
+ {
+ int *edge = edge_picture[i];
+
+ if( edge[3] == -1 )
+ continue;
+
+ struct face_info *inf_i = &faces[edge[2]],
+ *inf_j = &faces[edge[3]];
+
+ if( inf_i->collided || inf_j->collided )
+ continue;
+
+ v3f co, delta;
+ closest_point_segment( co_picture[edge[0]], co_picture[edge[1]],
+ rba->co, co );
+
+ v3_sub( rba->co, co, delta );
+ float d2 = v3_length2( delta ),
+ r = rba->inf.sphere.radius;
+
+ if( d2 < r*r )
+ {
+ float d = sqrtf(d2);
+
+ v3_muls( delta, 1.0f/d, delta );
+ float c0 = v3_dot( inf_i->normal, delta ),
+ c1 = v3_dot( inf_j->normal, delta );
+
+ if( c0 < 0.0f || c1 < 0.0f )
+ continue;
+
+ rb_ct *ct = buf+count;
+
+ v3_muls( inf_i->normal, c0, ct->n );
+ v3_muladds( ct->n, inf_j->normal, c1, ct->n );
+ v3_normalize( ct->n );
+
+ v3_copy( co, ct->co );
+ ct->p = r-d;
+ ct->rba = rba;
+ ct->rbb = rbb;
+ ct->element_id = inf_i->element_id;
+
+ count ++;
+
+ if( count == 12 )
+ {
+ vg_warn( "Geometry too dense!\n" );
+ return count;
+ }
+ }
+ }
+#endif
+
return count;
}