feat: migrate to glam whenever relevant + migrate testbed to kiss3d instead of bevy + release v0.32.0 (#909)

* feat: migrate to glam whenever relevant + migrate testbed to kiss3d instead of bevy

* chore: update changelog

* Fix warnings and tests

* Release v0.32.0
This commit is contained in:
Sébastien Crozet
2026-01-09 17:26:36 +01:00
committed by GitHub
parent 48de83817e
commit 0b7c3b34ec
265 changed files with 8501 additions and 8575 deletions

View File

@@ -0,0 +1,53 @@
use glam::Vec3;
use rapier_testbed3d::Testbed;
use rapier3d::prelude::*;
pub fn init_world(testbed: &mut Testbed) {
/*
* World
*/
let mut bodies = RigidBodySet::new();
let mut colliders = ColliderSet::new();
let impulse_joints = ImpulseJointSet::new();
let multibody_joints = MultibodyJointSet::new();
/*
* Create the balls
*/
let num = 20;
let rad = 1.0;
let shift = rad * 2.0 + 1.0;
let centerx = shift * (num as f32) / 2.0;
let centery = shift / 2.0;
let centerz = shift * (num as f32) / 2.0;
for i in 0..num {
for j in 0usize..num {
for k in 0..num {
let x = i as f32 * shift - centerx;
let y = j as f32 * shift + centery;
let z = k as f32 * shift - centerz;
let status = if j == 0 {
RigidBodyType::Fixed
} else {
RigidBodyType::Dynamic
};
let density = 0.477;
// Build the rigid body.
let rigid_body = RigidBodyBuilder::new(status).translation(Vec3::new(x, y, z));
let handle = bodies.insert(rigid_body);
let collider = ColliderBuilder::ball(rad).density(density);
colliders.insert_with_parent(collider, handle, &mut bodies);
}
}
}
/*
* Set up the testbed.
*/
testbed.set_world(bodies, colliders, impulse_joints, multibody_joints);
testbed.look_at(Vec3::new(100.0, 100.0, 100.0), Vec3::ZERO);
}

View File

@@ -0,0 +1,60 @@
use rapier_testbed3d::Testbed;
use rapier3d::prelude::*;
pub fn init_world(testbed: &mut Testbed) {
/*
* World
*/
let mut bodies = RigidBodySet::new();
let mut colliders = ColliderSet::new();
let impulse_joints = ImpulseJointSet::new();
let multibody_joints = MultibodyJointSet::new();
/*
* Ground
*/
let ground_size = 200.1;
let ground_height = 0.1;
let rigid_body = RigidBodyBuilder::fixed().translation(Vec3::new(0.0, -ground_height, 0.0));
let handle = bodies.insert(rigid_body);
let collider = ColliderBuilder::cuboid(ground_size, ground_height, ground_size);
colliders.insert_with_parent(collider, handle, &mut bodies);
/*
* Create the cubes
*/
let num = 10;
let rad = 1.0;
let shift = rad * 2.0;
let centerx = shift * (num / 2) as f32;
let centery = shift / 2.0;
let centerz = shift * (num / 2) as f32;
let mut offset = -(num as f32) * (rad * 2.0) * 0.5;
for j in 0usize..num {
for i in 0..num {
for k in 0usize..num {
let x = i as f32 * shift - centerx + offset;
let y = j as f32 * shift + centery;
let z = k as f32 * shift - centerz + offset;
// Build the rigid body.
let rigid_body = RigidBodyBuilder::dynamic().translation(Vec3::new(x, y, z));
let handle = bodies.insert(rigid_body);
let collider = ColliderBuilder::cuboid(rad, rad, rad);
colliders.insert_with_parent(collider, handle, &mut bodies);
}
}
offset -= 0.05 * rad * (num as f32 - 1.0);
}
/*
* Set up the testbed.
*/
testbed.set_world(bodies, colliders, impulse_joints, multibody_joints);
testbed.look_at(Vec3::new(100.0, 100.0, 100.0), Vec3::ZERO);
}

View File

@@ -0,0 +1,61 @@
use rapier_testbed3d::Testbed;
use rapier3d::prelude::*;
pub fn init_world(testbed: &mut Testbed) {
/*
* World
*/
let mut bodies = RigidBodySet::new();
let mut colliders = ColliderSet::new();
let impulse_joints = ImpulseJointSet::new();
let multibody_joints = MultibodyJointSet::new();
/*
* Ground
*/
let ground_size = 200.1;
let ground_height = 0.1;
let rigid_body = RigidBodyBuilder::fixed().translation(Vec3::new(0.0, -ground_height, 0.0));
let handle = bodies.insert(rigid_body);
let collider = ColliderBuilder::cuboid(ground_size, ground_height, ground_size);
colliders.insert_with_parent(collider, handle, &mut bodies);
/*
* Create the cubes
*/
let num = 8;
let rad = 1.0;
let shift = rad * 2.0 + rad;
let shifty = rad * 4.0;
let centerx = shift * (num / 2) as f32;
let centery = shift / 2.0;
let centerz = shift * (num / 2) as f32;
let mut offset = -(num as f32) * (rad * 2.0 + rad) * 0.5;
for j in 0usize..47 {
for i in 0..num {
for k in 0usize..num {
let x = i as f32 * shift - centerx + offset;
let y = j as f32 * shifty + centery + 3.0;
let z = k as f32 * shift - centerz + offset;
// Build the rigid body.
let rigid_body = RigidBodyBuilder::dynamic().translation(Vec3::new(x, y, z));
let handle = bodies.insert(rigid_body);
let collider = ColliderBuilder::capsule_y(rad, rad);
colliders.insert_with_parent(collider, handle, &mut bodies);
}
}
offset -= 0.05 * rad * (num as f32 - 1.0);
}
/*
* Set up the testbed.
*/
testbed.set_world(bodies, colliders, impulse_joints, multibody_joints);
testbed.look_at(Vec3::new(100.0, 100.0, 100.0), Vec3::ZERO);
}

View File

@@ -0,0 +1,76 @@
use rapier_testbed3d::Testbed;
use rapier3d::prelude::*;
pub fn init_world(testbed: &mut Testbed) {
/*
* World
*/
let mut bodies = RigidBodySet::new();
let mut colliders = ColliderSet::new();
let impulse_joints = ImpulseJointSet::new();
let multibody_joints = MultibodyJointSet::new();
/*
* Ground
*/
let ground_size = 100.1;
let ground_height = 0.1;
let rigid_body = RigidBodyBuilder::fixed().translation(Vec3::new(0.0, -ground_height, 0.0));
let handle = bodies.insert(rigid_body);
let collider = ColliderBuilder::cuboid(ground_size, ground_height, ground_size);
colliders.insert_with_parent(collider, handle, &mut bodies);
/*
* Create the cubes
*/
let num = 4;
let numj = 20;
let rad = 1.0;
let shiftx = rad * 2.0 + rad;
let shifty = rad * 2.0 + rad;
let shiftz = rad * 2.0 + rad;
let centerx = shiftx * (num / 2) as f32;
let centery = shifty / 2.0;
let centerz = shiftz * (num / 2) as f32;
let mut offset = -(num as f32) * (rad * 2.0 + rad) * 0.5;
for j in 0usize..numj {
for i in 0..num {
for k in 0usize..num {
let x = i as f32 * shiftx - centerx + offset;
let y = j as f32 * shifty + centery + 3.0;
let z = k as f32 * shiftz - centerz + offset;
// Build the rigid body.
let rigid_body = RigidBodyBuilder::dynamic()
.translation(Vec3::new(x, y, z))
.linvel(Vec3::new(0.0, -1000.0, 0.0))
.ccd_enabled(true);
let handle = bodies.insert(rigid_body);
let collider = match j % 5 {
0 => ColliderBuilder::cuboid(rad, rad, rad),
1 => ColliderBuilder::ball(rad),
// Rounded cylinders are much more efficient that cylinder, even if the
// rounding margin is small.
2 => ColliderBuilder::round_cylinder(rad, rad, rad / 10.0),
3 => ColliderBuilder::cone(rad, rad),
_ => ColliderBuilder::capsule_y(rad, rad),
};
colliders.insert_with_parent(collider, handle, &mut bodies);
}
}
offset -= 0.05 * rad * (num as f32 - 1.0);
}
/*
* Set up the testbed.
*/
testbed.set_world(bodies, colliders, impulse_joints, multibody_joints);
testbed.look_at(Vec3::new(100.0, 100.0, 100.0), Vec3::ZERO);
}

View File

@@ -0,0 +1,66 @@
use rapier_testbed3d::Testbed;
use rapier3d::prelude::*;
pub fn init_world(testbed: &mut Testbed) {
/*
* World
*/
let mut bodies = RigidBodySet::new();
let mut colliders = ColliderSet::new();
let impulse_joints = ImpulseJointSet::new();
let multibody_joints = MultibodyJointSet::new();
/*
* Ground
*/
let ground_size = 200.1;
let ground_height = 0.1;
let rigid_body = RigidBodyBuilder::fixed().translation(Vec3::new(0.0, -ground_height, 0.0));
let handle = bodies.insert(rigid_body);
let collider = ColliderBuilder::cuboid(ground_size, ground_height, ground_size);
colliders.insert_with_parent(collider, handle, &mut bodies);
/*
* Create the cubes
*/
let num = 8;
let rad = 0.2;
let shift = rad * 4.0 + rad;
let centerx = shift * (num / 2) as f32;
let centery = shift / 2.0;
let centerz = shift * (num / 2) as f32;
let mut offset = -(num as f32) * (rad * 2.0 + rad) * 0.5;
for j in 0usize..25 {
for i in 0..num {
for k in 0usize..num {
let x = i as f32 * shift * 5.0 - centerx + offset;
let y = j as f32 * (shift * 5.0) + centery + 3.0;
let z = k as f32 * shift * 2.0 - centerz + offset;
// Build the rigid body.
let rigid_body = RigidBodyBuilder::dynamic().translation(Vec3::new(x, y, z));
let handle = bodies.insert(rigid_body);
let collider1 = ColliderBuilder::cuboid(rad * 10.0, rad, rad);
let collider2 = ColliderBuilder::cuboid(rad, rad * 10.0, rad)
.translation(Vec3::new(rad * 10.0, rad * 10.0, 0.0));
let collider3 = ColliderBuilder::cuboid(rad, rad * 10.0, rad)
.translation(Vec3::new(-rad * 10.0, rad * 10.0, 0.0));
colliders.insert_with_parent(collider1, handle, &mut bodies);
colliders.insert_with_parent(collider2, handle, &mut bodies);
colliders.insert_with_parent(collider3, handle, &mut bodies);
}
}
offset -= 0.05 * rad * (num as f32 - 1.0);
}
/*
* Set up the testbed.
*/
testbed.set_world(bodies, colliders, impulse_joints, multibody_joints);
testbed.look_at(Vec3::new(100.0, 100.0, 100.0), Vec3::ZERO);
}

View File

@@ -0,0 +1,73 @@
use rand::distr::{Distribution, StandardUniform};
use rand::{SeedableRng, rngs::StdRng};
use rapier_testbed3d::Testbed;
use rapier3d::prelude::*;
pub fn init_world(testbed: &mut Testbed) {
/*
* World
*/
let mut bodies = RigidBodySet::new();
let mut colliders = ColliderSet::new();
let impulse_joints = ImpulseJointSet::new();
let multibody_joints = MultibodyJointSet::new();
/*
* Ground
*/
let ground_size = 200.1;
let ground_height = 0.1;
let rigid_body = RigidBodyBuilder::fixed().translation(Vec3::new(0.0, -ground_height, 0.0));
let handle = bodies.insert(rigid_body);
let collider = ColliderBuilder::cuboid(ground_size, ground_height, ground_size);
colliders.insert_with_parent(collider, handle, &mut bodies);
/*
* Create the cubes
*/
let num = 8;
let scale = 2.0;
let rad = 1.0;
let border_rad = 0.1;
let shift = border_rad * 2.0 + scale;
let centerx = shift * (num / 2) as f32;
let centery = shift / 2.0;
let centerz = shift * (num / 2) as f32;
let mut offset = -(num as f32) * shift * 0.5;
let mut rng = StdRng::seed_from_u64(0);
let distribution = StandardUniform;
for j in 0usize..47 {
for i in 0..num {
for k in 0usize..num {
let x = i as f32 * shift - centerx + offset;
let y = j as f32 * shift + centery + 3.0;
let z = k as f32 * shift - centerz + offset;
let mut points = Vec::new();
for _ in 0..10 {
let pt: [f32; 3] = distribution.sample(&mut rng);
points.push(Vec3::from(pt) * scale);
}
// Build the rigid body.
let rigid_body = RigidBodyBuilder::dynamic().translation(Vec3::new(x, y, z));
let handle = bodies.insert(rigid_body);
let collider = ColliderBuilder::round_convex_hull(&points, border_rad).unwrap();
colliders.insert_with_parent(collider, handle, &mut bodies);
}
}
offset -= 0.05 * rad * (num as f32 - 1.0);
}
/*
* Set up the testbed.
*/
testbed.set_world(bodies, colliders, impulse_joints, multibody_joints);
testbed.look_at(Vec3::new(100.0, 100.0, 100.0), Vec3::ZERO);
}

View File

@@ -0,0 +1,77 @@
use rapier_testbed3d::Testbed;
use rapier3d::na::ComplexField;
use rapier3d::prelude::*;
pub fn init_world(testbed: &mut Testbed) {
/*
* World
*/
let mut bodies = RigidBodySet::new();
let mut colliders = ColliderSet::new();
let impulse_joints = ImpulseJointSet::new();
let multibody_joints = MultibodyJointSet::new();
/*
* Ground
*/
let ground_size = Vec3::new(200.0, 1.0, 200.0);
let nsubdivs = 20;
let heights = Array2::from_fn(nsubdivs + 1, nsubdivs + 1, |i, j| {
if i == 0 || i == nsubdivs || j == 0 || j == nsubdivs {
10.0
} else {
let x = i as f32 * ground_size.x / (nsubdivs as f32);
let z = j as f32 * ground_size.z / (nsubdivs as f32);
// NOTE: make sure we use the sin/cos from simba to ensure
// cross-platform determinism of the example when the
// enhanced_determinism feature is enabled.
<f32 as ComplexField>::sin(x) + <f32 as ComplexField>::cos(z)
}
});
let rigid_body = RigidBodyBuilder::fixed();
let handle = bodies.insert(rigid_body);
let collider = ColliderBuilder::heightfield(heights, ground_size);
colliders.insert_with_parent(collider, handle, &mut bodies);
/*
* Create the cubes
*/
let num = 8;
let rad = 1.0;
let shift = rad * 2.0 + rad;
let centerx = shift * (num / 2) as f32;
let centery = shift / 2.0;
let centerz = shift * (num / 2) as f32;
for j in 0usize..47 {
for i in 0..num {
for k in 0usize..num {
let x = i as f32 * shift - centerx;
let y = j as f32 * shift + centery + 3.0;
let z = k as f32 * shift - centerz;
// Build the rigid body.
let rigid_body = RigidBodyBuilder::dynamic().translation(Vec3::new(x, y, z));
let handle = bodies.insert(rigid_body);
if j % 2 == 0 {
let collider = ColliderBuilder::cuboid(rad, rad, rad);
colliders.insert_with_parent(collider, handle, &mut bodies);
} else {
let collider = ColliderBuilder::ball(rad);
colliders.insert_with_parent(collider, handle, &mut bodies);
}
}
}
}
/*
* Set up the testbed.
*/
testbed.set_world(bodies, colliders, impulse_joints, multibody_joints);
testbed.look_at(Vec3::new(100.0, 100.0, 100.0), Vec3::ZERO);
}

View File

@@ -0,0 +1,63 @@
use rapier_testbed3d::Testbed;
use rapier3d::prelude::*;
pub fn init_world(testbed: &mut Testbed) {
/*
* World
*/
let mut bodies = RigidBodySet::new();
let mut colliders = ColliderSet::new();
let mut impulse_joints = ImpulseJointSet::new();
let multibody_joints = MultibodyJointSet::new();
let rad = 0.4;
let num = 100;
let shift = 1.0;
let mut body_handles = Vec::new();
for k in 0..num {
for i in 0..num {
let fk = k as f32;
let fi = i as f32;
let status = if i == 0 && (k % 4 == 0 || k == num - 1) {
RigidBodyType::Fixed
} else {
RigidBodyType::Dynamic
};
let rigid_body =
RigidBodyBuilder::new(status).translation(Vec3::new(fk * shift, 0.0, fi * shift));
let child_handle = bodies.insert(rigid_body);
let collider = ColliderBuilder::ball(rad);
colliders.insert_with_parent(collider, child_handle, &mut bodies);
// Vertical joint.
if i > 0 {
let parent_handle = *body_handles.last().unwrap();
let joint = SphericalJointBuilder::new().local_anchor2(Vec3::new(0.0, 0.0, -shift));
impulse_joints.insert(parent_handle, child_handle, joint, true);
}
// Horizontal joint.
if k > 0 {
let parent_index = body_handles.len() - num;
let parent_handle = body_handles[parent_index];
let joint = SphericalJointBuilder::new().local_anchor2(Vec3::new(-shift, 0.0, 0.0));
impulse_joints.insert(parent_handle, child_handle, joint, true);
}
body_handles.push(child_handle);
}
}
/*
* Set up the testbed.
*/
testbed.set_world(bodies, colliders, impulse_joints, multibody_joints);
testbed.look_at(
Vec3::new(-110.0, -46.0, 170.0),
Vec3::new(54.0, -38.0, 29.0),
);
}

View File

@@ -0,0 +1,81 @@
use rapier_testbed3d::Testbed;
use rapier3d::prelude::*;
pub fn init_world(testbed: &mut Testbed) {
/*
* World
*/
let mut bodies = RigidBodySet::new();
let mut colliders = ColliderSet::new();
let mut impulse_joints = ImpulseJointSet::new();
let multibody_joints = MultibodyJointSet::new();
let rad = 0.4;
let num = 5;
let shift = 1.0;
let mut body_handles = Vec::new();
for m in 0..10 {
let z = m as f32 * shift * (num as f32 + 2.0);
for l in 0..10 {
let y = l as f32 * shift * 3.0;
for j in 0..5 {
let x = j as f32 * shift * (num as f32) * 2.0;
for k in 0..num {
for i in 0..num {
let fk = k as f32;
let fi = i as f32;
// NOTE: the num - 2 test is to avoid two consecutive
// fixed bodies. Because physx will crash if we add
// a joint between these.
let status = if i == 0 && (k % 4 == 0 && k != num - 2 || k == num - 1) {
RigidBodyType::Fixed
} else {
RigidBodyType::Dynamic
};
let rigid_body = RigidBodyBuilder::new(status).translation(Vec3::new(
x + fk * shift,
y,
z + fi * shift,
));
let child_handle = bodies.insert(rigid_body);
let collider = ColliderBuilder::ball(rad);
colliders.insert_with_parent(collider, child_handle, &mut bodies);
// Vertical joint.
if i > 0 {
let parent_handle = *body_handles.last().unwrap();
let joint =
FixedJointBuilder::new().local_anchor2(Vec3::new(0.0, 0.0, -shift));
impulse_joints.insert(parent_handle, child_handle, joint, true);
}
// Horizontal joint.
if k > 0 {
let parent_index = body_handles.len() - num;
let parent_handle = body_handles[parent_index];
let joint =
FixedJointBuilder::new().local_anchor2(Vec3::new(-shift, 0.0, 0.0));
impulse_joints.insert(parent_handle, child_handle, joint, true);
}
body_handles.push(child_handle);
}
}
}
}
}
/*
* Set up the testbed.
*/
testbed.set_world(bodies, colliders, impulse_joints, multibody_joints);
testbed.look_at(Vec3::new(-38.0, 14.0, 108.0), Vec3::new(46.0, 12.0, 23.0));
}

View File

@@ -0,0 +1,61 @@
use rapier_testbed3d::Testbed;
use rapier3d::prelude::*;
pub fn init_world(testbed: &mut Testbed) {
/*
* World
*/
let mut bodies = RigidBodySet::new();
let mut colliders = ColliderSet::new();
let mut impulse_joints = ImpulseJointSet::new();
let multibody_joints = MultibodyJointSet::new();
let rad = 0.4;
let num = 5;
let shift = 1.0;
for m in 0..8 {
let z = m as f32 * shift * (num as f32 + 2.0);
for l in 0..8 {
let y = l as f32 * shift * (num as f32) * 2.0;
for j in 0..50 {
let x = j as f32 * shift * 4.0;
let ground = RigidBodyBuilder::fixed().translation(Vec3::new(x, y, z));
let mut curr_parent = bodies.insert(ground);
let collider = ColliderBuilder::cuboid(rad, rad, rad);
colliders.insert_with_parent(collider, curr_parent, &mut bodies);
for i in 0..num {
let z = z + (i + 1) as f32 * shift;
let density = 1.0;
let rigid_body = RigidBodyBuilder::dynamic().translation(Vec3::new(x, y, z));
let curr_child = bodies.insert(rigid_body);
let collider = ColliderBuilder::cuboid(rad, rad, rad).density(density);
colliders.insert_with_parent(collider, curr_child, &mut bodies);
let axis = if i % 2 == 0 {
Vec3::new(1.0, 1.0, 0.0).normalize()
} else {
Vec3::new(-1.0, 1.0, 0.0).normalize()
};
let prism = PrismaticJointBuilder::new(axis)
.local_anchor2(Vec3::new(0.0, 0.0, -shift))
.limits([-2.0, 0.0]);
impulse_joints.insert(curr_parent, curr_child, prism, true);
curr_parent = curr_child;
}
}
}
}
/*
* Set up the testbed.
*/
testbed.set_world(bodies, colliders, impulse_joints, multibody_joints);
testbed.look_at(Vec3::new(262.0, 63.0, 124.0), Vec3::new(101.0, 4.0, -3.0));
}

View File

@@ -0,0 +1,76 @@
use rapier_testbed3d::Testbed;
use rapier3d::prelude::*;
pub fn init_world(testbed: &mut Testbed) {
/*
* World
*/
let mut bodies = RigidBodySet::new();
let mut colliders = ColliderSet::new();
let mut impulse_joints = ImpulseJointSet::new();
let multibody_joints = MultibodyJointSet::new();
let rad = 0.4;
let num = 10;
let shift = 2.0;
for l in 0..4 {
let y = l as f32 * shift * (num as f32) * 3.0;
for j in 0..50 {
let x = j as f32 * shift * 4.0;
let ground = RigidBodyBuilder::fixed().translation(Vec3::new(x, y, 0.0));
let mut curr_parent = bodies.insert(ground);
let collider = ColliderBuilder::cuboid(rad, rad, rad);
colliders.insert_with_parent(collider, curr_parent, &mut bodies);
for i in 0..num {
// Create four bodies.
let z = i as f32 * shift * 2.0 + shift;
let positions = [
Pose3::translation(x, y, z),
Pose3::translation(x + shift, y, z),
Pose3::translation(x + shift, y, z + shift),
Pose3::translation(x, y, z + shift),
];
let mut handles = [curr_parent; 4];
for k in 0..4 {
let density = 1.0;
let rigid_body = RigidBodyBuilder::dynamic().pose(positions[k]);
handles[k] = bodies.insert(rigid_body);
let collider = ColliderBuilder::cuboid(rad, rad, rad).density(density);
colliders.insert_with_parent(collider, handles[k], &mut bodies);
}
// Setup four impulse_joints.
let x = Vec3::X;
let z = Vec3::Z;
let revs = [
RevoluteJointBuilder::new(z).local_anchor2(Vec3::new(0.0, 0.0, -shift)),
RevoluteJointBuilder::new(x).local_anchor2(Vec3::new(-shift, 0.0, 0.0)),
RevoluteJointBuilder::new(z).local_anchor2(Vec3::new(0.0, 0.0, -shift)),
RevoluteJointBuilder::new(x).local_anchor2(Vec3::new(shift, 0.0, 0.0)),
];
impulse_joints.insert(curr_parent, handles[0], revs[0], true);
impulse_joints.insert(handles[0], handles[1], revs[1], true);
impulse_joints.insert(handles[1], handles[2], revs[2], true);
impulse_joints.insert(handles[2], handles[3], revs[3], true);
curr_parent = handles[3];
}
}
}
/*
* Set up the testbed.
*/
testbed.set_world(bodies, colliders, impulse_joints, multibody_joints);
testbed.look_at(
Vec3::new(478.0, 83.0, 228.0),
Vec3::new(134.0, 83.0, -116.0),
);
}

View File

@@ -0,0 +1,126 @@
use kiss3d::color::Color;
use rapier_testbed3d::Testbed;
use rapier3d::glamx::Vec3Swizzles;
use rapier3d::prelude::*;
pub fn build_block(
testbed: &mut Testbed,
bodies: &mut RigidBodySet,
colliders: &mut ColliderSet,
half_extents: Vec3,
shift: Vec3,
(mut numx, numy, mut numz): (usize, usize, usize),
) {
let dimensions = [half_extents.xyz(), half_extents.zyx()];
let block_width = 2.0 * half_extents.z * numx as f32;
let block_height = 2.0 * half_extents.y * numy as f32;
let spacing = (half_extents.z * numx as f32 - half_extents.x) / (numz as f32 - 1.0);
let mut color0 = Color::new(0.7, 0.5, 0.9, 1.0);
let mut color1 = Color::new(0.6, 1.0, 0.6, 1.0);
for i in 0..numy {
std::mem::swap(&mut numx, &mut numz);
let dim = dimensions[i % 2];
let y = dim.y * i as f32 * 2.0;
for j in 0..numx {
let x = if i % 2 == 0 {
spacing * j as f32 * 2.0
} else {
dim.x * j as f32 * 2.0
};
for k in 0..numz {
let z = if i % 2 == 0 {
dim.z * k as f32 * 2.0
} else {
spacing * k as f32 * 2.0
};
// Build the rigid body.
let rigid_body = RigidBodyBuilder::dynamic().translation(Vec3::new(
x + dim.x + shift.x,
y + dim.y + shift.y,
z + dim.z + shift.z,
));
let handle = bodies.insert(rigid_body);
let collider = ColliderBuilder::cuboid(dim.x, dim.y, dim.z);
colliders.insert_with_parent(collider, handle, bodies);
testbed.set_initial_body_color(handle, color0);
std::mem::swap(&mut color0, &mut color1);
}
}
}
// Close the top.
let dim = half_extents.zxy();
for i in 0..(block_width / (dim.x * 2.0)) as usize {
for j in 0..(block_width / (dim.z * 2.0)) as usize {
// Build the rigid body.
let rigid_body = RigidBodyBuilder::dynamic().translation(Vec3::new(
i as f32 * dim.x * 2.0 + dim.x + shift.x,
dim.y + shift.y + block_height,
j as f32 * dim.z * 2.0 + dim.z + shift.z,
));
let handle = bodies.insert(rigid_body);
let collider = ColliderBuilder::cuboid(dim.x, dim.y, dim.z);
colliders.insert_with_parent(collider, handle, bodies);
testbed.set_initial_body_color(handle, color0);
std::mem::swap(&mut color0, &mut color1);
}
}
}
pub fn init_world(testbed: &mut Testbed) {
/*
* World
*/
let mut bodies = RigidBodySet::new();
let mut colliders = ColliderSet::new();
let impulse_joints = ImpulseJointSet::new();
let multibody_joints = MultibodyJointSet::new();
/*
* Ground
*/
let ground_size = 50.0;
let ground_height = 0.1;
let rigid_body = RigidBodyBuilder::fixed().translation(Vec3::new(0.0, -ground_height, 0.0));
let handle = bodies.insert(rigid_body);
let collider = ColliderBuilder::cuboid(ground_size, ground_height, ground_size);
colliders.insert_with_parent(collider, handle, &mut bodies);
/*
* Create the cubes
*/
let half_extents = Vec3::new(0.02, 0.1, 0.4) / 2.0 * 10.0;
let mut block_height = 0.0;
// These should only be set to odd values otherwise
// the blocks won't align in the nicest way.
let numy = [0, 9, 13, 17, 21, 41];
for i in (1..=5).rev() {
let numx = i;
let numy = numy[i];
let numz = numx * 3 + 1;
let block_width = numx as f32 * half_extents.z * 2.0;
build_block(
testbed,
&mut bodies,
&mut colliders,
half_extents,
Vec3::new(-block_width / 2.0, block_height, -block_width / 2.0),
(numx, numy, numz),
);
block_height += numy as f32 * half_extents.y * 2.0 + half_extents.x * 2.0;
}
/*
* Set up the testbed.
*/
testbed.set_world(bodies, colliders, impulse_joints, multibody_joints);
testbed.look_at(Vec3::new(100.0, 100.0, 100.0), Vec3::ZERO);
}

View File

@@ -0,0 +1,68 @@
use rapier_testbed3d::Testbed;
use rapier3d::prelude::*;
pub fn init_world(testbed: &mut Testbed) {
/*
* World
*/
let mut bodies = RigidBodySet::new();
let mut colliders = ColliderSet::new();
let impulse_joints = ImpulseJointSet::new();
let multibody_joints = MultibodyJointSet::new();
/*
* Create the balls
*/
let num = 30;
let rad = 1.0;
let shift = rad * 6.0 + 1.0;
let centerx = shift * (num as f32) / 2.0;
let centery = shift * (num as f32) / 2.0;
let centerz = shift * (num as f32) / 2.0;
for i in 0..num {
for j in 0usize..num {
for k in 0..num {
let x = i as f32 * shift - centerx;
let y = j as f32 * shift - centery;
let z = k as f32 * shift - centerz;
// Build the rigid body.
let velocity = Vec3::new(
rand::random::<f32>() - 0.5,
rand::random::<f32>() - 0.5,
rand::random::<f32>() - 0.5,
) * 30.0;
let rigid_body = RigidBodyBuilder::new(RigidBodyType::KinematicVelocityBased)
.translation(Vec3::new(x, y, z))
.linvel(velocity);
let handle = bodies.insert(rigid_body);
let collider = ColliderBuilder::ball(rad);
colliders.insert_with_parent(collider, handle, &mut bodies);
}
}
}
testbed.add_callback(move |_, physics, _, _| {
for (_, rb) in physics.bodies.iter_mut() {
let mut linvel = rb.linvel();
for dim in 0..3 {
if (linvel[dim] > 0.0 && rb.translation()[dim] > (shift * num as f32) / 2.0)
|| (linvel[dim] < 0.0 && rb.translation()[dim] < -(shift * num as f32) / 2.0)
{
linvel[dim] = -linvel[dim];
}
}
rb.set_linvel(linvel, false);
}
});
/*
* Set up the testbed.
*/
testbed.set_world(bodies, colliders, impulse_joints, multibody_joints);
testbed.look_at(Vec3::new(100.0, 100.0, 100.0), Vec3::ZERO);
}

View File

@@ -0,0 +1,80 @@
use rapier_testbed3d::Testbed;
use rapier3d::prelude::*;
fn create_pyramid(
bodies: &mut RigidBodySet,
colliders: &mut ColliderSet,
offset: Vec3,
stack_height: usize,
rad: f32,
) {
let shift = rad * 2.0;
for i in 0usize..stack_height {
for j in i..stack_height {
let fj = j as f32;
let fi = i as f32;
let x = (fi * shift / 2.0) + (fj - fi) * shift;
let y = fi * shift;
// Build the rigid body.
let rigid_body = RigidBodyBuilder::dynamic().translation(Vec3::new(x, y, 0.0) + offset);
let handle = bodies.insert(rigid_body);
let collider = ColliderBuilder::cuboid(rad, rad, rad);
colliders.insert_with_parent(collider, handle, bodies);
}
}
}
pub fn init_world(testbed: &mut Testbed) {
/*
* World
*/
let mut bodies = RigidBodySet::new();
let mut colliders = ColliderSet::new();
let impulse_joints = ImpulseJointSet::new();
let multibody_joints = MultibodyJointSet::new();
let rad = 0.5;
let pyramid_count = 40;
let spacing = 4.0;
/*
* Ground
*/
let ground_size = 50.0;
let ground_height = 0.1;
let rigid_body = RigidBodyBuilder::fixed().translation(Vec3::new(0.0, -ground_height, 0.0));
let ground_handle = bodies.insert(rigid_body);
let collider = ColliderBuilder::cuboid(
ground_size,
ground_height,
pyramid_count as f32 * spacing / 2.0 + ground_size,
);
colliders.insert_with_parent(collider, ground_handle, &mut bodies);
/*
* Create the cubes
*/
for pyramid_index in 0..pyramid_count {
let bottomy = rad;
create_pyramid(
&mut bodies,
&mut colliders,
Vec3::new(
0.0,
bottomy,
(pyramid_index as f32 - pyramid_count as f32 / 2.0) * spacing,
),
20,
rad,
);
}
/*
* Set up the testbed.
*/
testbed.set_world(bodies, colliders, impulse_joints, multibody_joints);
testbed.look_at(Vec3::new(100.0, 100.0, 100.0), Vec3::ZERO);
}

View File

@@ -0,0 +1,54 @@
use rapier_testbed3d::Testbed;
use rapier3d::prelude::*;
pub fn init_world(testbed: &mut Testbed) {
/*
* World
*/
let mut bodies = RigidBodySet::new();
let mut colliders = ColliderSet::new();
let impulse_joints = ImpulseJointSet::new();
let multibody_joints = MultibodyJointSet::new();
/*
* Create the balls
*/
let num = 50;
let rad = 1.0;
let shift = rad * 2.0 + 1.0;
let centerx = shift * (num as f32) / 2.0;
let centery = shift / 2.0;
let centerz = shift * (num as f32) / 2.0;
for i in 0..num {
for j in 0usize..num {
for k in 0..num {
let x = i as f32 * shift - centerx;
let y = j as f32 * shift + centery;
let z = k as f32 * shift - centerz;
let status = if j == 0 {
RigidBodyType::Fixed
} else {
RigidBodyType::Dynamic
};
let density = 0.477;
// Build the rigid body.
let rigid_body = RigidBodyBuilder::new(status)
.translation(Vec3::new(x, y, z))
.sleeping(true); // j < num - 1);
let handle = bodies.insert(rigid_body);
let collider = ColliderBuilder::ball(rad).density(density);
colliders.insert_with_parent(collider, handle, &mut bodies);
}
}
}
/*
* Set up the testbed.
*/
testbed.set_world(bodies, colliders, impulse_joints, multibody_joints);
testbed.look_at(Vec3::new(100.0, 100.0, 100.0), Vec3::ZERO);
}

View File

@@ -0,0 +1,52 @@
use rapier_testbed3d::Testbed;
use rapier3d::prelude::*;
pub fn init_world(testbed: &mut Testbed) {
/*
* World
*/
let mut bodies = RigidBodySet::new();
let mut colliders = ColliderSet::new();
let impulse_joints = ImpulseJointSet::new();
let multibody_joints = MultibodyJointSet::new();
/*
* Create the balls
*/
let num = 50;
let rad = 1.0;
let shift = rad * 2.0 + 1.0;
let centerx = shift * (num as f32) / 2.0;
let centery = shift / 2.0;
let centerz = shift * (num as f32) / 2.0;
for i in 0..num {
for j in 0usize..num {
for k in 0..num {
let x = i as f32 * shift - centerx;
let y = j as f32 * shift + centery;
let z = k as f32 * shift - centerz;
let status = if j < num - 1 {
RigidBodyType::Fixed
} else {
RigidBodyType::Dynamic
};
let density = 0.477;
// Build the rigid body.
let rigid_body = RigidBodyBuilder::new(status).translation(Vec3::new(x, y, z));
let handle = bodies.insert(rigid_body);
let collider = ColliderBuilder::ball(rad).density(density);
colliders.insert_with_parent(collider, handle, &mut bodies);
}
}
}
/*
* Set up the testbed.
*/
testbed.set_world(bodies, colliders, impulse_joints, multibody_joints);
testbed.look_at(Vec3::new(100.0, 100.0, 100.0), Vec3::ZERO);
}

View File

@@ -0,0 +1,53 @@
use rapier_testbed3d::Example;
mod balls3;
mod boxes3;
mod capsules3;
mod ccd3;
mod compound3;
mod convex_polyhedron3;
mod heightfield3;
mod joint_ball3;
mod joint_fixed3;
mod joint_prismatic3;
mod joint_revolute3;
mod keva3;
mod many_kinematics3;
mod many_pyramids3;
mod many_sleep3;
mod many_static3;
mod pyramid3;
mod ray_cast3;
mod stacks3;
mod trimesh3;
pub fn builders() -> Vec<Example> {
const STRESS: &str = "Stress Tests";
vec![
Example::new(STRESS, "Balls", balls3::init_world),
Example::new(STRESS, "Boxes", boxes3::init_world),
Example::new(STRESS, "Capsules", capsules3::init_world),
Example::new(STRESS, "CCD", ccd3::init_world),
Example::new(STRESS, "Compound", compound3::init_world),
Example::new(STRESS, "Convex polyhedron", convex_polyhedron3::init_world),
Example::new(STRESS, "Many kinematics", many_kinematics3::init_world),
Example::new(STRESS, "Many static", many_static3::init_world),
Example::new(STRESS, "Many sleep", many_sleep3::init_world),
Example::new(STRESS, "Heightfield", heightfield3::init_world),
Example::new(STRESS, "Stacks", stacks3::init_world),
Example::new(STRESS, "Pyramid", pyramid3::init_world),
Example::new(STRESS, "Trimesh", trimesh3::init_world),
Example::new(STRESS, "ImpulseJoint ball", joint_ball3::init_world),
Example::new(STRESS, "ImpulseJoint fixed", joint_fixed3::init_world),
Example::new(STRESS, "ImpulseJoint revolute", joint_revolute3::init_world),
Example::new(
STRESS,
"ImpulseJoint prismatic",
joint_prismatic3::init_world,
),
Example::new(STRESS, "Many pyramids", many_pyramids3::init_world),
Example::new(STRESS, "Keva tower", keva3::init_world),
Example::new(STRESS, "Ray cast", ray_cast3::init_world),
]
}

View File

@@ -0,0 +1,75 @@
use rapier_testbed3d::Testbed;
use rapier3d::prelude::*;
fn create_pyramid(
bodies: &mut RigidBodySet,
colliders: &mut ColliderSet,
offset: Vec3,
stack_height: usize,
half_extents: Vec3,
) {
let shift = half_extents * 2.5;
for i in 0usize..stack_height {
for j in i..stack_height {
for k in i..stack_height {
let fi = i as f32;
let fj = j as f32;
let fk = k as f32;
let x = (fi * shift.x / 2.0) + (fk - fi) * shift.x + offset.x
- stack_height as f32 * half_extents.x;
let y = fi * shift.y + offset.y;
let z = (fi * shift.z / 2.0) + (fj - fi) * shift.z + offset.z
- stack_height as f32 * half_extents.z;
// Build the rigid body.
let rigid_body = RigidBodyBuilder::dynamic().translation(Vec3::new(x, y, z));
let rigid_body_handle = bodies.insert(rigid_body);
let collider =
ColliderBuilder::cuboid(half_extents.x, half_extents.y, half_extents.z);
colliders.insert_with_parent(collider, rigid_body_handle, bodies);
}
}
}
}
pub fn init_world(testbed: &mut Testbed) {
/*
* World
*/
let mut bodies = RigidBodySet::new();
let mut colliders = ColliderSet::new();
let impulse_joints = ImpulseJointSet::new();
let multibody_joints = MultibodyJointSet::new();
/*
* Ground
*/
let ground_size = 50.0;
let ground_height = 0.1;
let rigid_body = RigidBodyBuilder::fixed().translation(Vec3::new(0.0, -ground_height, 0.0));
let ground_handle = bodies.insert(rigid_body);
let collider = ColliderBuilder::cuboid(ground_size, ground_height, ground_size);
colliders.insert_with_parent(collider, ground_handle, &mut bodies);
/*
* Create the cubes
*/
let cube_size = 1.0;
let hext = Vec3::splat(cube_size);
let bottomy = cube_size;
create_pyramid(
&mut bodies,
&mut colliders,
Vec3::new(0.0, bottomy, 0.0),
24,
hext,
);
/*
* Set up the testbed.
*/
testbed.set_world(bodies, colliders, impulse_joints, multibody_joints);
testbed.look_at(Vec3::new(100.0, 100.0, 100.0), Vec3::ZERO);
}

View File

@@ -0,0 +1,82 @@
use crate::{Example, stress_tests};
use kiss3d::prelude::*;
use rapier_testbed3d::Testbed;
use rapier3d::prelude::*;
pub fn init_world(testbed: &mut Testbed) {
let settings = testbed.example_settings_mut();
// NOTE: this demo is a bit special. It takes as a setting the builder of another demo,
// builds it, and add a ton of rays into it. This gives us an easy way to check
// ray-casting in a wide variety of situations.
let demos: Vec<Example> = stress_tests::builders()
.into_iter()
.filter(|demo| !std::ptr::fn_addr_eq(demo.builder, self::init_world as fn(&mut Testbed)))
.collect();
let demo_names: Vec<_> = demos.iter().map(|demo| demo.name.to_string()).collect();
let selected = settings.get_or_set_string("Scene", 0, demo_names);
(demos[selected].builder)(testbed);
/*
* Cast rays at each frame.
*/
let ray_ball_radius = 100.0;
let ray_ball = Ball::new(ray_ball_radius);
let (ray_origins, _) = ray_ball.to_trimesh(100, 100);
let rays: Vec<_> = ray_origins
.into_iter()
.map(|pt| Ray::new(pt, -pt.normalize()))
.collect();
let mut centered_rays = rays.clone();
testbed.add_callback(move |graphics, physics, _, _| {
let Some(graphics) = graphics else {
return;
};
// Re-center the ray relative to the current position of all objects.
// This ensures demos with falling objects dont end up with a boring situation
// where all the rays point into the void.
let mut center = Vec3::ZERO;
for (_, b) in physics.bodies.iter() {
center += b.translation();
}
center /= physics.bodies.len() as Real;
for (centered, ray) in centered_rays.iter_mut().zip(rays.iter()) {
centered.origin = center + ray.origin;
}
// Cast the rays.
let t1 = std::time::Instant::now();
let max_toi = ray_ball_radius - 1.0;
let query_pipeline = physics.broad_phase.as_query_pipeline(
physics.narrow_phase.query_dispatcher(),
&physics.bodies,
&physics.colliders,
Default::default(),
);
for ray in &centered_rays {
if let Some((_, toi)) = query_pipeline.cast_ray(ray, max_toi, true) {
let a = ray.origin;
let b = ray.point_at(toi);
graphics.window.draw_line(a, b, GREEN, 100.0, true);
} else {
let a = ray.origin;
let b = ray.point_at(max_toi);
graphics.window.draw_line(a, b, RED, 100.0, true);
}
}
let main_check_time = t1.elapsed().as_secs_f32();
if let Some(settings) = &mut graphics.settings {
settings.set_label("Ray count:", format!("{}", rays.len()));
settings.set_label(
"Ray-cast time",
format!("{:.2}ms", main_check_time * 1000.0,),
);
}
});
}

View File

@@ -0,0 +1,180 @@
use rapier_testbed3d::Testbed;
use rapier3d::prelude::*;
fn create_tower_circle(
bodies: &mut RigidBodySet,
colliders: &mut ColliderSet,
offset: Vec3,
stack_height: usize,
nsubdivs: usize,
half_extents: Vec3,
) {
let ang_step = std::f32::consts::PI * 2.0 / nsubdivs as f32;
let radius = 1.3 * nsubdivs as f32 * half_extents.x / std::f32::consts::PI;
let shift = half_extents * 2.0;
for i in 0usize..stack_height {
for j in 0..nsubdivs {
let fj = j as f32;
let fi = i as f32;
let y = fi * shift.y;
let pos = Pose3::new(offset, Vec3::Y * (fi / 2.0 + fj) * ang_step)
.prepend_translation(Vec3::new(0.0, y, radius));
// Build the rigid body.
let rigid_body = RigidBodyBuilder::dynamic().pose(pos);
let handle = bodies.insert(rigid_body);
let collider = ColliderBuilder::cuboid(half_extents.x, half_extents.y, half_extents.z);
colliders.insert_with_parent(collider, handle, bodies);
}
}
}
fn create_wall(
bodies: &mut RigidBodySet,
colliders: &mut ColliderSet,
offset: Vec3,
stack_height: usize,
half_extents: Vec3,
) {
let shift = half_extents * 2.0;
for i in 0usize..stack_height {
for j in i..stack_height {
let fj = j as f32;
let fi = i as f32;
let x = offset.x;
let y = fi * shift.y + offset.y;
let z = (fi * shift.z / 2.0) + (fj - fi) * shift.z + offset.z
- stack_height as f32 * half_extents.z;
// Build the rigid body.
let rigid_body = RigidBodyBuilder::dynamic().translation(Vec3::new(x, y, z));
let handle = bodies.insert(rigid_body);
let collider = ColliderBuilder::cuboid(half_extents.x, half_extents.y, half_extents.z);
colliders.insert_with_parent(collider, handle, bodies);
}
}
}
fn create_pyramid(
bodies: &mut RigidBodySet,
colliders: &mut ColliderSet,
offset: Vec3,
stack_height: usize,
half_extents: Vec3,
) {
let shift = half_extents * 2.0;
for i in 0usize..stack_height {
for j in i..stack_height {
for k in i..stack_height {
let fi = i as f32;
let fj = j as f32;
let fk = k as f32;
let x = (fi * shift.x / 2.0) + (fk - fi) * shift.x + offset.x
- stack_height as f32 * half_extents.x;
let y = fi * shift.y + offset.y;
let z = (fi * shift.z / 2.0) + (fj - fi) * shift.z + offset.z
- stack_height as f32 * half_extents.z;
// Build the rigid body.
let rigid_body = RigidBodyBuilder::dynamic().translation(Vec3::new(x, y, z));
let handle = bodies.insert(rigid_body);
let collider =
ColliderBuilder::cuboid(half_extents.x, half_extents.y, half_extents.z);
colliders.insert_with_parent(collider, handle, bodies);
}
}
}
}
pub fn init_world(testbed: &mut Testbed) {
/*
* World
*/
let mut bodies = RigidBodySet::new();
let mut colliders = ColliderSet::new();
let impulse_joints = ImpulseJointSet::new();
let multibody_joints = MultibodyJointSet::new();
/*
* Ground
*/
let ground_size = 200.0;
let ground_height = 0.1;
let rigid_body = RigidBodyBuilder::fixed().translation(Vec3::new(0.0, -ground_height, 0.0));
let handle = bodies.insert(rigid_body);
let collider = ColliderBuilder::cuboid(ground_size, ground_height, ground_size);
colliders.insert_with_parent(collider, handle, &mut bodies);
/*
* Create the cubes
*/
let cube_size = 1.0;
let hext = Vec3::splat(cube_size);
let bottomy = cube_size * 50.0;
create_pyramid(
&mut bodies,
&mut colliders,
Vec3::new(-110.0, bottomy, 0.0),
12,
hext,
);
create_pyramid(
&mut bodies,
&mut colliders,
Vec3::new(-80.0, bottomy, 0.0),
12,
hext,
);
create_pyramid(
&mut bodies,
&mut colliders,
Vec3::new(-50.0, bottomy, 0.0),
12,
hext,
);
create_pyramid(
&mut bodies,
&mut colliders,
Vec3::new(-20.0, bottomy, 0.0),
12,
hext,
);
create_wall(
&mut bodies,
&mut colliders,
Vec3::new(-2.0, bottomy, 0.0),
12,
hext,
);
create_wall(
&mut bodies,
&mut colliders,
Vec3::new(4.0, bottomy, 0.0),
12,
hext,
);
create_wall(
&mut bodies,
&mut colliders,
Vec3::new(10.0, bottomy, 0.0),
12,
hext,
);
create_tower_circle(
&mut bodies,
&mut colliders,
Vec3::new(25.0, bottomy, 0.0),
8,
24,
hext,
);
/*
* Set up the testbed.
*/
testbed.set_world(bodies, colliders, impulse_joints, multibody_joints);
testbed.look_at(Vec3::new(100.0, 100.0, 100.0), Vec3::ZERO);
}

View File

@@ -0,0 +1,82 @@
use rapier_testbed3d::Testbed;
use rapier3d::na::ComplexField;
use rapier3d::prelude::*;
pub fn init_world(testbed: &mut Testbed) {
/*
* World
*/
let mut bodies = RigidBodySet::new();
let mut colliders = ColliderSet::new();
let impulse_joints = ImpulseJointSet::new();
let multibody_joints = MultibodyJointSet::new();
/*
* Ground
*/
let ground_size = Vec3::new(200.0, 1.0, 200.0);
let nsubdivs = 20;
let heights = Array2::from_fn(nsubdivs + 1, nsubdivs + 1, |i, j| {
if i == 0 || i == nsubdivs || j == 0 || j == nsubdivs {
10.0
} else {
let x = i as f32 * ground_size.x / (nsubdivs as f32);
let z = j as f32 * ground_size.z / (nsubdivs as f32);
// NOTE: make sure we use the sin/cos from simba to ensure
// cross-platform determinism of the example when the
// enhanced_determinism feature is enabled.
<f32 as ComplexField>::sin(x) + <f32 as ComplexField>::cos(z)
}
});
// Here we will build our trimesh from the mesh representation of an
// heightfield.
let heightfield = HeightField::new(heights, ground_size);
let (vertices, indices) = heightfield.to_trimesh();
let rigid_body = RigidBodyBuilder::fixed();
let handle = bodies.insert(rigid_body);
let collider = ColliderBuilder::trimesh(vertices, indices).unwrap();
colliders.insert_with_parent(collider, handle, &mut bodies);
/*
* Create the cubes
*/
let num = 8;
let rad = 1.0;
let shift = rad * 2.0 + rad;
let centerx = shift * (num / 2) as f32;
let centery = shift / 2.0;
let centerz = shift * (num / 2) as f32;
for j in 0usize..47 {
for i in 0..num {
for k in 0usize..num {
let x = i as f32 * shift - centerx;
let y = j as f32 * shift + centery + 3.0;
let z = k as f32 * shift - centerz;
// Build the rigid body.
let rigid_body = RigidBodyBuilder::dynamic().translation(Vec3::new(x, y, z));
let handle = bodies.insert(rigid_body);
if j % 2 == 0 {
let collider = ColliderBuilder::cuboid(rad, rad, rad);
colliders.insert_with_parent(collider, handle, &mut bodies);
} else {
let collider = ColliderBuilder::ball(rad);
colliders.insert_with_parent(collider, handle, &mut bodies);
}
}
}
}
/*
* Set up the testbed.
*/
testbed.set_world(bodies, colliders, impulse_joints, multibody_joints);
testbed.look_at(Vec3::new(100.0, 100.0, 100.0), Vec3::ZERO);
}