Skip to content

Commit

Permalink
improved rigid particle cover function
Browse files Browse the repository at this point in the history
added support for 2D
  • Loading branch information
kurtkuehnert committed Mar 15, 2023
1 parent f59d0bf commit 87ac5aa
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 58 deletions.
128 changes: 78 additions & 50 deletions src/cuda/generate_rigid_particles.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,43 +16,71 @@ pub fn generate_rigid_particles(
) {
match collider.shape().as_typed_shape() {
TypedShape::Cuboid(cuboid) => {
let (points, triangles) = cuboid.to_trimesh();
#[cfg(feature = "dim2")]
{
let a = Point::new(-cuboid.half_extents.x, -cuboid.half_extents.y);
let b = Point::new(cuboid.half_extents.x, -cuboid.half_extents.y);
let c = Point::new(cuboid.half_extents.x, cuboid.half_extents.y);
let d = Point::new(-cuboid.half_extents.x, cuboid.half_extents.y);

for triangle in triangles {
cover_triangle(
rigid_particles,
cell_width,
collider_index,
Triangle::new(
points[triangle[0] as usize],
points[triangle[1] as usize],
points[triangle[2] as usize],
),
Triangle::new(a, b, c),
);
}
}
TypedShape::Capsule(capsule) => {
let (points, triangles) = capsule.to_trimesh(20, 10);

for triangle in triangles {
cover_triangle(
rigid_particles,
cell_width,
collider_index,
Triangle::new(
points[triangle[0] as usize],
points[triangle[1] as usize],
points[triangle[2] as usize],
),
Triangle::new(a, c, d),
);
}
#[cfg(feature = "dim3")]
{
let (points, triangles) = cuboid.to_trimesh();

for triangle in triangles {
cover_triangle(
rigid_particles,
cell_width,
collider_index,
Triangle::new(
points[triangle[0] as usize],
points[triangle[1] as usize],
points[triangle[2] as usize],
),
);
}
}
}
TypedShape::Capsule(capsule) => {
#[cfg(feature = "dim3")]
{
let (points, triangles) = capsule.to_trimesh(20, 10);

for triangle in triangles {
cover_triangle(
rigid_particles,
cell_width,
collider_index,
Triangle::new(
points[triangle[0] as usize],
points[triangle[1] as usize],
points[triangle[2] as usize],
),
);
}
}
}
TypedShape::TriMesh(trimesh) => {
for triangle in trimesh.triangles() {
cover_triangle(rigid_particles, cell_width, collider_index, triangle);
}
}
TypedShape::HeightField(heightfield) => {
TypedShape::HeightField(heightfield) =>
{
#[cfg(feature = "dim3")]
for triangle in heightfield.triangles() {
cover_triangle(rigid_particles, cell_width, collider_index, triangle);
}
Expand All @@ -70,14 +98,10 @@ fn cover_triangle(
collider_index: u32,
triangle: Triangle,
) {
// step along the AB edge in cell_width increments (primary_dir)
// additionally, step perpendicular to this edge in cell_width increments (secondary_dir)
// push all points inside the triangle onto the rigid particles vec

// select the longest edge as the base
let distance_ab = distance(&triangle.b, &triangle.a);
let distance_bc = distance(&triangle.c, &triangle.b);
let distance_ca = distance(&triangle.a, &triangle.c);

let max = distance_ab.max(distance_bc).max(distance_ca);

let triangle = if max == distance_bc {
Expand All @@ -96,34 +120,38 @@ fn cover_triangle(
triangle
};

let ab = triangle.b - triangle.a;
let ac = triangle.c - triangle.a;
let bc = triangle.c - triangle.b;
let normal = ab.cross(&ac).normalize();
let alpha = Real::acos(ab.dot(&ac) / ab.norm() / ac.norm());
let beta = Real::acos(-ab.dot(&bc) / ab.norm() / bc.norm());
let tan_alpha = alpha.tan();
let tan_beta = beta.tan();

let primary_length = ab.norm();
let primary_dir = ab.normalize();
let primary_step = primary_dir * cell_width;

let secondary_dir = normal.cross(&primary_dir).normalize();
let secondary_step = secondary_dir * cell_width;

let mut edge_position = triangle.a;

while distance(&triangle.a, &edge_position) <= primary_length {
let secondary_length_a = tan_alpha * distance(&triangle.a, &edge_position);
let secondary_length_b = tan_beta * distance(&triangle.b, &edge_position);
let secondary_length = secondary_length_a.min(secondary_length_b);

let mut particle_position = edge_position;
let base = triangle.b - triangle.a;
let base_length = base.norm();
let base_dir = base / base_length;
// Project C on the base AB.
let ac_offset_length = ac.dot(&base_dir);
let bc_offset_length = base_length - ac_offset_length;
// Compute the triangle’s height vector.
let height = ac - base_dir * ac_offset_length;
let height_length = height.norm();
let height_dir = height / height_length;
// Calculate the tangents.
let tan_alpha = height_length / ac_offset_length;
let tan_beta = height_length / bc_offset_length;
// Calculate the step increments on the base and the height.
let base_step = cell_width * base_dir;
let height_step = cell_width * height_dir;

let mut triangle_d = triangle.a;

// step along the base in cell_width increments
while distance(&triangle.a, &triangle_d) <= base_length {
let height_ac = tan_alpha * distance(&triangle.a, &triangle_d);
let height_bc = tan_beta * distance(&triangle.b, &triangle_d);
let min_height = height_ac.min(height_bc);

let mut particle_position = triangle_d;

let mut color_index = 0;

while distance(&edge_position, &particle_position) <= secondary_length {
// step along the height in cell_width increments
while distance(&triangle_d, &particle_position) <= min_height {
rigid_particles.push(RigidParticle {
position: particle_position,
collider_index,
Expand All @@ -132,9 +160,9 @@ fn cover_triangle(

color_index += 1;

particle_position += secondary_step;
particle_position += height_step;
}

edge_position += primary_step;
triangle_d += base_step;
}
}
10 changes: 2 additions & 8 deletions src/third_party/rapier/testbed_plugin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -709,11 +709,6 @@ impl TestbedPlugin for MpmTestbedPlugin {

if let Some(cuda_data) = self.cuda_data.get(0) {
if let Some(colliders) = &cuda_data.colliders {
let colors = vec![
[1.0, 0.0, 0.0, 1.0],
[0.0, 1.0, 0.0, 1.0],
[0.0, 0.0, 1.0, 1.0],
];
for particle in &colliders.rigid_particles {
let collider = colliders.gpu_colliders[particle.collider_index as usize];

Expand All @@ -726,10 +721,9 @@ impl TestbedPlugin for MpmTestbedPlugin {
let pos = [pos.x as f32, pos.y as f32, pos_z];

let color_index = particle.color_index as usize;
let count = 10;

let color = colors[color_index % colors.len()];

let color = [(color_index % 20) as f32 / 20.0, 0.0, 0.0, 1.0];
let color = [(color_index % count) as f32 / count as f32, 0.0, 0.0, 1.0];

instance_data.push(ParticleInstanceData {
position: pos.into(),
Expand Down

0 comments on commit 87ac5aa

Please sign in to comment.