├── .github ├── FUNDING.yml └── workflows │ ├── rapier-ci-bench.yml │ └── rapier-ci-build.yml ├── .gitignore ├── .typos.toml ├── ARCHITECTURE.md ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── Cargo.toml ├── LICENSE ├── README.md ├── assets ├── 3d │ ├── T12 │ │ ├── README.md │ │ ├── meshes │ │ │ ├── Ankle1.STL │ │ │ ├── Ankle2.STL │ │ │ ├── Ankle3.STL │ │ │ ├── Ankle4.STL │ │ │ ├── Ankle5.STL │ │ │ ├── Ankle6.STL │ │ │ ├── Body.STL │ │ │ ├── Foot1.STL │ │ │ ├── Foot2.STL │ │ │ ├── Foot3.STL │ │ │ ├── Foot4.STL │ │ │ ├── Foot5.STL │ │ │ ├── Foot6.STL │ │ │ ├── Hip1.STL │ │ │ ├── Hip2.STL │ │ │ ├── Hip3.STL │ │ │ ├── Hip4.STL │ │ │ ├── Hip5.STL │ │ │ ├── Hip6.STL │ │ │ ├── Knee1.STL │ │ │ ├── Knee2.STL │ │ │ ├── Knee3.STL │ │ │ ├── Knee4.STL │ │ │ ├── Knee5.STL │ │ │ ├── Knee6.STL │ │ │ ├── Shin1.STL │ │ │ ├── Shin2.STL │ │ │ ├── Shin3.STL │ │ │ ├── Shin4.STL │ │ │ ├── Shin5.STL │ │ │ ├── Shin6.STL │ │ │ ├── Thigh1.STL │ │ │ ├── Thigh2.STL │ │ │ ├── Thigh3.STL │ │ │ ├── Thigh4.STL │ │ │ ├── Thigh5.STL │ │ │ └── Thigh6.STL │ │ └── urdf │ │ │ ├── T12.URDF │ │ │ ├── T12_flipped.URDF │ │ │ └── T12_wrong_axes.orig.URDF │ ├── camel_decimated.obj │ ├── chair.obj │ ├── cup_decimated.obj │ ├── dilo_decimated.obj │ ├── feline_decimated.obj │ ├── genus3_decimated.obj │ ├── hand2_decimated.obj │ ├── hand_decimated.obj │ ├── hornbug.obj │ ├── octopus_decimated.obj │ ├── rabbit_decimated.obj │ ├── rust_logo_simplified.obj │ ├── screwdriver_decimated.obj │ ├── table.obj │ ├── tstTorusModel.obj │ ├── tstTorusModel2.obj │ └── tstTorusModel3.obj └── FiraSans-Bold.ttf ├── benchmarks2d ├── Cargo.toml ├── all_benchmarks2.rs ├── balls2.rs ├── boxes2.rs ├── capsules2.rs ├── convex_polygons2.rs ├── heightfield2.rs ├── joint_ball2.rs ├── joint_fixed2.rs ├── joint_prismatic2.rs ├── pyramid2.rs └── vertical_stacks2.rs ├── benchmarks3d ├── Cargo.toml ├── all_benchmarks3.rs ├── balls3.rs ├── boxes3.rs ├── capsules3.rs ├── ccd3.rs ├── compound3.rs ├── convex_polyhedron3.rs ├── heightfield3.rs ├── joint_ball3.rs ├── joint_fixed3.rs ├── joint_prismatic3.rs ├── joint_revolute3.rs ├── keva3.rs ├── many_pyramids3.rs ├── many_sleep3.rs ├── many_static3.rs ├── pyramid3.rs ├── stacks3.rs └── trimesh3.rs ├── crates ├── rapier2d-f64 │ └── Cargo.toml ├── rapier2d │ └── Cargo.toml ├── rapier3d-f64 │ └── Cargo.toml ├── rapier3d-meshloader │ ├── CHANGELOG.md │ ├── Cargo.toml │ ├── LICENSE │ ├── README.md │ └── src │ │ └── lib.rs ├── rapier3d-urdf │ ├── CHANGELOG.md │ ├── Cargo.toml │ ├── LICENSE │ ├── README.md │ └── src │ │ └── lib.rs ├── rapier3d │ └── Cargo.toml ├── rapier_testbed2d-f64 │ └── Cargo.toml ├── rapier_testbed2d │ └── Cargo.toml ├── rapier_testbed3d-f64 │ └── Cargo.toml └── rapier_testbed3d │ └── Cargo.toml ├── examples2d ├── Cargo.toml ├── add_remove2.rs ├── all_examples2.rs ├── ccd2.rs ├── character_controller2.rs ├── collision_groups2.rs ├── convex_polygons2.rs ├── damping2.rs ├── debug_box_ball2.rs ├── debug_compression2.rs ├── debug_intersection2.rs ├── debug_total_overlap2.rs ├── debug_vertical_column2.rs ├── drum2.rs ├── heightfield2.rs ├── inverse_kinematics2.rs ├── joint_motor_position2.rs ├── joints2.rs ├── locked_rotations2.rs ├── one_way_platforms2.rs ├── platform2.rs ├── polyline2.rs ├── pyramid2.rs ├── restitution2.rs ├── rope_joints2.rs ├── s2d_arch.rs ├── s2d_ball_and_chain.rs ├── s2d_bridge.rs ├── s2d_card_house.rs ├── s2d_confined.rs ├── s2d_far_pyramid.rs ├── s2d_high_mass_ratio_1.rs ├── s2d_high_mass_ratio_2.rs ├── s2d_high_mass_ratio_3.rs ├── s2d_joint_grid.rs ├── s2d_pyramid.rs ├── sensor2.rs ├── trimesh2.rs ├── utils │ ├── character.rs │ ├── mod.rs │ └── svg.rs └── voxels2.rs ├── examples3d-f64 ├── Cargo.toml ├── all_examples3-f64.rs ├── debug_serialized3.rs └── rapier.data ├── examples3d ├── Cargo.toml ├── all_examples3.rs ├── all_examples3_wasm.rs ├── ccd3.rs ├── character_controller3.rs ├── collision_groups3.rs ├── compound3.rs ├── convex_decomposition3.rs ├── convex_polyhedron3.rs ├── damping3.rs ├── debug_add_remove_collider3.rs ├── debug_articulations3.rs ├── debug_big_colliders3.rs ├── debug_boxes3.rs ├── debug_chain_high_mass_ratio3.rs ├── debug_cube_high_mass_ratio3.rs ├── debug_cylinder3.rs ├── debug_deserialize3.rs ├── debug_dynamic_collider_add3.rs ├── debug_eccentric_boxes3.rs ├── debug_friction3.rs ├── debug_infinite_fall3.rs ├── debug_internal_edges3.rs ├── debug_long_chain3.rs ├── debug_multibody_ang_motor_pos3.rs ├── debug_pop3.rs ├── debug_prismatic3.rs ├── debug_rollback3.rs ├── debug_shape_modification3.rs ├── debug_thin_cube_on_mesh3.rs ├── debug_triangle3.rs ├── debug_trimesh3.rs ├── domino3.rs ├── dynamic_trimesh3.rs ├── fountain3.rs ├── harness_capsules3.rs ├── heightfield3.rs ├── inverse_kinematics3.rs ├── joint_motor_position3.rs ├── joints3.rs ├── keva3.rs ├── locked_rotations3.rs ├── newton_cradle3.rs ├── one_way_platforms3.rs ├── platform3.rs ├── primitives3.rs ├── rapier.data ├── restitution3.rs ├── rope_joints3.rs ├── sensor3.rs ├── spring_joints3.rs ├── trimesh3.rs ├── urdf3.rs ├── utils │ ├── character.rs │ └── mod.rs ├── vehicle_controller3.rs ├── vehicle_joints3.rs └── voxels3.rs ├── publish-all.sh ├── rustfmt.toml ├── scripts ├── publish-extra-formats.sh ├── publish-rapier.sh └── publish-testbeds.sh ├── src ├── control │ ├── character_controller.rs │ ├── mod.rs │ ├── pid_controller.rs │ └── ray_cast_vehicle_controller.rs ├── counters │ ├── ccd_counters.rs │ ├── collision_detection_counters.rs │ ├── mod.rs │ ├── solver_counters.rs │ ├── stages_counters.rs │ └── timer.rs ├── data │ ├── arena.rs │ ├── coarena.rs │ ├── graph.rs │ ├── mod.rs │ ├── modified_objects.rs │ └── pubsub.rs ├── dynamics │ ├── ccd │ │ ├── ccd_solver.rs │ │ ├── mod.rs │ │ └── toi_entry.rs │ ├── coefficient_combine_rule.rs │ ├── integration_parameters.rs │ ├── island_manager.rs │ ├── joint │ │ ├── fixed_joint.rs │ │ ├── generic_joint.rs │ │ ├── impulse_joint │ │ │ ├── impulse_joint.rs │ │ │ ├── impulse_joint_set.rs │ │ │ └── mod.rs │ │ ├── mod.rs │ │ ├── motor_model.rs │ │ ├── multibody_joint │ │ │ ├── mod.rs │ │ │ ├── multibody.rs │ │ │ ├── multibody_ik.rs │ │ │ ├── multibody_joint.rs │ │ │ ├── multibody_joint_set.rs │ │ │ ├── multibody_link.rs │ │ │ ├── multibody_workspace.rs │ │ │ └── unit_multibody_joint.rs │ │ ├── prismatic_joint.rs │ │ ├── revolute_joint.rs │ │ ├── rope_joint.rs │ │ ├── spherical_joint.rs │ │ └── spring_joint.rs │ ├── mod.rs │ ├── rigid_body.rs │ ├── rigid_body_components.rs │ ├── rigid_body_set.rs │ └── solver │ │ ├── categorization.rs │ │ ├── contact_constraint │ │ ├── contact_constraints_set.rs │ │ ├── generic_one_body_constraint.rs │ │ ├── generic_one_body_constraint_element.rs │ │ ├── generic_two_body_constraint.rs │ │ ├── generic_two_body_constraint_element.rs │ │ ├── mod.rs │ │ ├── one_body_constraint.rs │ │ ├── one_body_constraint_element.rs │ │ ├── one_body_constraint_simd.rs │ │ ├── two_body_constraint.rs │ │ ├── two_body_constraint_element.rs │ │ └── two_body_constraint_simd.rs │ │ ├── interaction_groups.rs │ │ ├── island_solver.rs │ │ ├── joint_constraint │ │ ├── any_joint_constraint.rs │ │ ├── joint_constraint_builder.rs │ │ ├── joint_constraints_set.rs │ │ ├── joint_generic_constraint.rs │ │ ├── joint_generic_constraint_builder.rs │ │ ├── joint_velocity_constraint.rs │ │ └── mod.rs │ │ ├── mod.rs │ │ ├── parallel_island_solver.rs │ │ ├── parallel_solver_constraints.rs │ │ ├── parallel_velocity_solver.rs │ │ ├── solver_body.rs │ │ ├── solver_constraints_set.rs │ │ ├── solver_vel.rs │ │ └── velocity_solver.rs ├── geometry │ ├── broad_phase.rs │ ├── broad_phase_multi_sap │ │ ├── broad_phase_multi_sap.rs │ │ ├── broad_phase_pair_event.rs │ │ ├── mod.rs │ │ ├── sap_axis.rs │ │ ├── sap_endpoint.rs │ │ ├── sap_layer.rs │ │ ├── sap_proxy.rs │ │ ├── sap_region.rs │ │ └── sap_utils.rs │ ├── broad_phase_qbvh.rs │ ├── collider.rs │ ├── collider_components.rs │ ├── collider_set.rs │ ├── contact_pair.rs │ ├── interaction_graph.rs │ ├── interaction_groups.rs │ ├── mesh_converter.rs │ ├── mod.rs │ └── narrow_phase.rs ├── lib.rs ├── pipeline │ ├── collision_pipeline.rs │ ├── debug_render_pipeline │ │ ├── debug_render_backend.rs │ │ ├── debug_render_pipeline.rs │ │ ├── debug_render_style.rs │ │ ├── mod.rs │ │ └── outlines.rs │ ├── event_handler.rs │ ├── mod.rs │ ├── physics_hooks.rs │ ├── physics_pipeline.rs │ ├── query_pipeline │ │ ├── generators.rs │ │ └── mod.rs │ └── user_changes.rs └── utils.rs └── src_testbed ├── Inconsolata.otf ├── box2d_backend.rs ├── camera2d.rs ├── camera3d.rs ├── debug_render.rs ├── graphics.rs ├── harness ├── mod.rs └── plugin.rs ├── lib.rs ├── mouse.rs ├── objects ├── mod.rs └── node.rs ├── physics └── mod.rs ├── physx_backend.rs ├── plugin.rs ├── save.rs ├── settings.rs ├── testbed.rs └── ui.rs /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [ "dimforge" ] # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 13 | -------------------------------------------------------------------------------- /.github/workflows/rapier-ci-bench.yml: -------------------------------------------------------------------------------- 1 | name: Rapier CI bench 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request_target: 7 | branches: [ master ] 8 | workflow_dispatch: 9 | 10 | jobs: 11 | send-bench-message: 12 | env: 13 | BENCHBOT_AMQP_USER: ${{ secrets.BENCHBOT_AMQP_USER }} 14 | BENCHBOT_AMQP_PASS: ${{ secrets.BENCHBOT_AMQP_PASS }} 15 | BENCHBOT_AMQP_VHOST: ${{ secrets.BENCHBOT_AMQP_VHOST }} 16 | BENCHBOT_AMQP_HOST: ${{ secrets.BENCHBOT_AMQP_HOST }} 17 | BENCHBOT_TARGET_REPO: ${{ github.event.pull_request.head.repo.clone_url }} 18 | BENCHBOT_TARGET_COMMIT: ${{ github.event.pull_request.head.sha }} 19 | BENCHBOT_SHA: ${{ github.sha }} 20 | BENCHBOT_HEAD_REF: ${{ github.head_ref }} 21 | BENCHBOT_OTHER_BACKENDS: false 22 | runs-on: ubuntu-latest 23 | steps: 24 | - name: Set env on master 25 | if: github.head_ref == '' 26 | run: | 27 | echo "BENCHBOT_TARGET_COMMIT=$BENCHBOT_SHA" >> $GITHUB_ENV 28 | echo "BENCHBOT_TARGET_REPO=https://github.com/dimforge/rapier" >> $GITHUB_ENV 29 | echo "BENCHBOT_HEAD_REF=master" >> $GITHUB_ENV 30 | echo "BENCHBOT_OTHER_BACKENDS=true" >> $GITHUB_ENV 31 | - name: Send 3D bench message 32 | shell: bash 33 | run: curl -u $BENCHBOT_AMQP_USER:$BENCHBOT_AMQP_PASS 34 | -i -H "content-type:application/json" -X POST 35 | https://$BENCHBOT_AMQP_HOST/api/exchanges/$BENCHBOT_AMQP_VHOST//publish 36 | -d'{"properties":{},"routing_key":"benchmark","payload":"{ \"repository\":\"'$BENCHBOT_TARGET_REPO'\", \"branch\":\"'$BENCHBOT_HEAD_REF'\", \"commit\":\"'$BENCHBOT_TARGET_COMMIT'\", \"other_backends\":'$BENCHBOT_OTHER_BACKENDS' }","payload_encoding":"string"}' -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | **/*.rs.bk 2 | Cargo.lock 3 | node_modules 4 | target 5 | .idea 6 | .DS_Store 7 | package-lock.json 8 | **/*.csv 9 | .history 10 | .vscode/ 11 | *.autosave.json -------------------------------------------------------------------------------- /.typos.toml: -------------------------------------------------------------------------------- 1 | # Corrections take the form of a key/value pair. The key is the incorrect word 2 | # and the value is the correct word. If the key and value are the same, the 3 | # word is treated as always correct. If the value is an empty string, the word 4 | # is treated as always incorrect. 5 | 6 | [files] 7 | extend-exclude = [ 8 | ".git/", 9 | ] 10 | ignore-hidden = false 11 | 12 | [default] 13 | extend-ignore-re = [ 14 | "\\bPolygon::PN\\b", 15 | ] 16 | 17 | # Case sensitive, matches entire word. 18 | [default.extend-identifiers] 19 | anc_color = "anc_color" 20 | rady = "rady" 21 | 22 | # Case insensitive, matches inside word. 23 | [default.extend-words] 24 | bellow = "below" 25 | toi = "toi" 26 | -------------------------------------------------------------------------------- /ARCHITECTURE.md: -------------------------------------------------------------------------------- 1 | ## Repository architecture 2 | 3 | The architecture of this repository is a bit unusual because we are using some tricks to have both 4 | the 2D and 3D version of Rapier share the same code-base. Here are the main folders: 5 | - **`build/`**: contains one folder per Rapier crate (for the 2D, 3D, `f32`, and `f64` versions). Each 6 | crate has its own `Cargo.toml` file that adjusts some cargo features, and reference the `src` folder. 7 | - **`src/`**: contains the actual `.rs` source code of the Rapier physics engine. 8 | - **`src_testbed/`**: contains the `.rs` source code of the Rapier testbed (which our examples are based on). 9 | - **`examples2d/`**: simple 2D scenes showcasing some of Rapier's capabilities. 10 | Run them with `cargo run --release --bin all_examples2`. 11 | - **`examples3d/`**: simple 3D scenes showcasing some of Rapier's capabilities. 12 | Run them with `cargo run --release --bin all_examples3`. 13 | - **`benchmarks2d/`**: a set of 2D stress-tests, to see how Rapier performs when it has lots of elements 14 | to simulate. 15 | - **`benchmarks3d/`**: a set of 3D stress-tests, to see how Rapier performs when it has lots of elements 16 | to simulate. We use the these benchmarks to track the performances of Rapier after some changes, 17 | and spot unexpected regressions: https://www.rapier.rs/benchmarks/ -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "crates/rapier2d", 4 | "crates/rapier2d-f64", 5 | "crates/rapier_testbed2d", 6 | "crates/rapier_testbed2d-f64", 7 | "examples2d", 8 | "benchmarks2d", 9 | "crates/rapier3d", 10 | "crates/rapier3d-f64", 11 | "crates/rapier_testbed3d", 12 | "crates/rapier_testbed3d-f64", 13 | "examples3d", 14 | "examples3d-f64", 15 | "benchmarks3d", 16 | "crates/rapier3d-urdf", 17 | "crates/rapier3d-meshloader", 18 | ] 19 | resolver = "2" 20 | 21 | [workspace.lints.clippy] 22 | needless_lifetimes = "allow" 23 | 24 | [patch.crates-io] 25 | #wrapped2d = { git = "https://github.com/Bastacyclop/rust_box2d.git" } 26 | #xurdf = { path = "../xurdf/xurdf" } 27 | 28 | #simba = { path = "../simba" } 29 | #kiss3d = { path = "../kiss3d" } 30 | #parry2d = { path = "../parry/crates/parry2d" } 31 | #parry3d = { path = "../parry/crates/parry3d" } 32 | #parry2d-f64 = { path = "../parry/crates/parry2d-f64" } 33 | #parry3d-f64 = { path = "../parry/crates/parry3d-f64" } 34 | #nalgebra = { path = "../nalgebra" } 35 | 36 | 37 | #kiss3d = { git = "https://github.com/sebcrozet/kiss3d" } 38 | #nalgebra = { git = "https://github.com/dimforge/nalgebra", branch = "dev" } 39 | #parry2d = { git = "https://github.com/dimforge/parry", branch = "master" } 40 | #parry3d = { git = "https://github.com/dimforge/parry", branch = "master" } 41 | #parry2d-f64 = { git = "https://github.com/dimforge/parry", branch = "master" } 42 | #parry3d-f64 = { git = "https://github.com/dimforge/parry", branch = "master" } 43 | 44 | # See https://github.com/EmbarkStudios/puffin/pull/234 45 | puffin_egui = { git = "https://github.com/tedsteen/puffin.git", rev = "11771ebe00fd257aedbb545df3339ad597b1cc34" } 46 | 47 | 48 | # # For feature unstable-puffin-pr-235 49 | # # See https://github.com/dimforge/rapier/issues/760. 50 | # puffin_egui = { version = "0.29", optional = true, git = "https://github.com/Vrixyz/puffin.git", branch = "expose_ui_options" } 51 | # puffin = { version = "0.19", optional = true, git = "https://github.com/Vrixyz/puffin.git", branch = "expose_ui_options" } 52 | # # 53 | 54 | [profile.release] 55 | #debug = true 56 | #codegen-units = 1 57 | #lto = true 58 | 59 | [profile.dev] 60 | opt-level = 1 61 | 62 | 63 | #[profile.dev.package.rapier3d] 64 | #opt-level = 3 65 | # 66 | #[profile.dev.package.kiss3d] 67 | #opt-level = 3 68 | -------------------------------------------------------------------------------- /assets/3d/T12/README.md: -------------------------------------------------------------------------------- 1 | These samples files originate from the repository 2 | [gkjohnson/urdf-loaders](https://github.com/gkjohnson/urdf-loaders/tree/b67f5de98f6222e2d921ce24f46a6725dad9704e/urdf/T12) 3 | (Apache 2.0 license). -------------------------------------------------------------------------------- /assets/3d/T12/meshes/Ankle1.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dimforge/rapier/cd7fc6e11f26db67c51db0713a53d4e3951dfe3f/assets/3d/T12/meshes/Ankle1.STL -------------------------------------------------------------------------------- /assets/3d/T12/meshes/Ankle2.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dimforge/rapier/cd7fc6e11f26db67c51db0713a53d4e3951dfe3f/assets/3d/T12/meshes/Ankle2.STL -------------------------------------------------------------------------------- /assets/3d/T12/meshes/Ankle3.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dimforge/rapier/cd7fc6e11f26db67c51db0713a53d4e3951dfe3f/assets/3d/T12/meshes/Ankle3.STL -------------------------------------------------------------------------------- /assets/3d/T12/meshes/Ankle4.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dimforge/rapier/cd7fc6e11f26db67c51db0713a53d4e3951dfe3f/assets/3d/T12/meshes/Ankle4.STL -------------------------------------------------------------------------------- /assets/3d/T12/meshes/Ankle5.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dimforge/rapier/cd7fc6e11f26db67c51db0713a53d4e3951dfe3f/assets/3d/T12/meshes/Ankle5.STL -------------------------------------------------------------------------------- /assets/3d/T12/meshes/Ankle6.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dimforge/rapier/cd7fc6e11f26db67c51db0713a53d4e3951dfe3f/assets/3d/T12/meshes/Ankle6.STL -------------------------------------------------------------------------------- /assets/3d/T12/meshes/Body.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dimforge/rapier/cd7fc6e11f26db67c51db0713a53d4e3951dfe3f/assets/3d/T12/meshes/Body.STL -------------------------------------------------------------------------------- /assets/3d/T12/meshes/Foot1.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dimforge/rapier/cd7fc6e11f26db67c51db0713a53d4e3951dfe3f/assets/3d/T12/meshes/Foot1.STL -------------------------------------------------------------------------------- /assets/3d/T12/meshes/Foot2.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dimforge/rapier/cd7fc6e11f26db67c51db0713a53d4e3951dfe3f/assets/3d/T12/meshes/Foot2.STL -------------------------------------------------------------------------------- /assets/3d/T12/meshes/Foot3.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dimforge/rapier/cd7fc6e11f26db67c51db0713a53d4e3951dfe3f/assets/3d/T12/meshes/Foot3.STL -------------------------------------------------------------------------------- /assets/3d/T12/meshes/Foot4.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dimforge/rapier/cd7fc6e11f26db67c51db0713a53d4e3951dfe3f/assets/3d/T12/meshes/Foot4.STL -------------------------------------------------------------------------------- /assets/3d/T12/meshes/Foot5.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dimforge/rapier/cd7fc6e11f26db67c51db0713a53d4e3951dfe3f/assets/3d/T12/meshes/Foot5.STL -------------------------------------------------------------------------------- /assets/3d/T12/meshes/Foot6.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dimforge/rapier/cd7fc6e11f26db67c51db0713a53d4e3951dfe3f/assets/3d/T12/meshes/Foot6.STL -------------------------------------------------------------------------------- /assets/3d/T12/meshes/Hip1.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dimforge/rapier/cd7fc6e11f26db67c51db0713a53d4e3951dfe3f/assets/3d/T12/meshes/Hip1.STL -------------------------------------------------------------------------------- /assets/3d/T12/meshes/Hip2.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dimforge/rapier/cd7fc6e11f26db67c51db0713a53d4e3951dfe3f/assets/3d/T12/meshes/Hip2.STL -------------------------------------------------------------------------------- /assets/3d/T12/meshes/Hip3.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dimforge/rapier/cd7fc6e11f26db67c51db0713a53d4e3951dfe3f/assets/3d/T12/meshes/Hip3.STL -------------------------------------------------------------------------------- /assets/3d/T12/meshes/Hip4.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dimforge/rapier/cd7fc6e11f26db67c51db0713a53d4e3951dfe3f/assets/3d/T12/meshes/Hip4.STL -------------------------------------------------------------------------------- /assets/3d/T12/meshes/Hip5.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dimforge/rapier/cd7fc6e11f26db67c51db0713a53d4e3951dfe3f/assets/3d/T12/meshes/Hip5.STL -------------------------------------------------------------------------------- /assets/3d/T12/meshes/Hip6.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dimforge/rapier/cd7fc6e11f26db67c51db0713a53d4e3951dfe3f/assets/3d/T12/meshes/Hip6.STL -------------------------------------------------------------------------------- /assets/3d/T12/meshes/Knee1.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dimforge/rapier/cd7fc6e11f26db67c51db0713a53d4e3951dfe3f/assets/3d/T12/meshes/Knee1.STL -------------------------------------------------------------------------------- /assets/3d/T12/meshes/Knee2.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dimforge/rapier/cd7fc6e11f26db67c51db0713a53d4e3951dfe3f/assets/3d/T12/meshes/Knee2.STL -------------------------------------------------------------------------------- /assets/3d/T12/meshes/Knee3.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dimforge/rapier/cd7fc6e11f26db67c51db0713a53d4e3951dfe3f/assets/3d/T12/meshes/Knee3.STL -------------------------------------------------------------------------------- /assets/3d/T12/meshes/Knee4.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dimforge/rapier/cd7fc6e11f26db67c51db0713a53d4e3951dfe3f/assets/3d/T12/meshes/Knee4.STL -------------------------------------------------------------------------------- /assets/3d/T12/meshes/Knee5.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dimforge/rapier/cd7fc6e11f26db67c51db0713a53d4e3951dfe3f/assets/3d/T12/meshes/Knee5.STL -------------------------------------------------------------------------------- /assets/3d/T12/meshes/Knee6.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dimforge/rapier/cd7fc6e11f26db67c51db0713a53d4e3951dfe3f/assets/3d/T12/meshes/Knee6.STL -------------------------------------------------------------------------------- /assets/3d/T12/meshes/Shin1.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dimforge/rapier/cd7fc6e11f26db67c51db0713a53d4e3951dfe3f/assets/3d/T12/meshes/Shin1.STL -------------------------------------------------------------------------------- /assets/3d/T12/meshes/Shin2.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dimforge/rapier/cd7fc6e11f26db67c51db0713a53d4e3951dfe3f/assets/3d/T12/meshes/Shin2.STL -------------------------------------------------------------------------------- /assets/3d/T12/meshes/Shin3.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dimforge/rapier/cd7fc6e11f26db67c51db0713a53d4e3951dfe3f/assets/3d/T12/meshes/Shin3.STL -------------------------------------------------------------------------------- /assets/3d/T12/meshes/Shin4.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dimforge/rapier/cd7fc6e11f26db67c51db0713a53d4e3951dfe3f/assets/3d/T12/meshes/Shin4.STL -------------------------------------------------------------------------------- /assets/3d/T12/meshes/Shin5.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dimforge/rapier/cd7fc6e11f26db67c51db0713a53d4e3951dfe3f/assets/3d/T12/meshes/Shin5.STL -------------------------------------------------------------------------------- /assets/3d/T12/meshes/Shin6.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dimforge/rapier/cd7fc6e11f26db67c51db0713a53d4e3951dfe3f/assets/3d/T12/meshes/Shin6.STL -------------------------------------------------------------------------------- /assets/3d/T12/meshes/Thigh1.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dimforge/rapier/cd7fc6e11f26db67c51db0713a53d4e3951dfe3f/assets/3d/T12/meshes/Thigh1.STL -------------------------------------------------------------------------------- /assets/3d/T12/meshes/Thigh2.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dimforge/rapier/cd7fc6e11f26db67c51db0713a53d4e3951dfe3f/assets/3d/T12/meshes/Thigh2.STL -------------------------------------------------------------------------------- /assets/3d/T12/meshes/Thigh3.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dimforge/rapier/cd7fc6e11f26db67c51db0713a53d4e3951dfe3f/assets/3d/T12/meshes/Thigh3.STL -------------------------------------------------------------------------------- /assets/3d/T12/meshes/Thigh4.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dimforge/rapier/cd7fc6e11f26db67c51db0713a53d4e3951dfe3f/assets/3d/T12/meshes/Thigh4.STL -------------------------------------------------------------------------------- /assets/3d/T12/meshes/Thigh5.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dimforge/rapier/cd7fc6e11f26db67c51db0713a53d4e3951dfe3f/assets/3d/T12/meshes/Thigh5.STL -------------------------------------------------------------------------------- /assets/3d/T12/meshes/Thigh6.STL: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dimforge/rapier/cd7fc6e11f26db67c51db0713a53d4e3951dfe3f/assets/3d/T12/meshes/Thigh6.STL -------------------------------------------------------------------------------- /assets/FiraSans-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dimforge/rapier/cd7fc6e11f26db67c51db0713a53d4e3951dfe3f/assets/FiraSans-Bold.ttf -------------------------------------------------------------------------------- /benchmarks2d/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rapier-benchmarks-2d" 3 | version = "0.1.0" 4 | authors = ["Sébastien Crozet "] 5 | edition = "2021" 6 | 7 | [features] 8 | parallel = ["rapier2d/parallel", "rapier_testbed2d/parallel"] 9 | simd-stable = ["rapier2d/simd-stable"] 10 | simd-nightly = ["rapier2d/simd-nightly"] 11 | other-backends = ["rapier_testbed2d/other-backends"] 12 | enhanced-determinism = ["rapier2d/enhanced-determinism"] 13 | 14 | [dependencies] 15 | rand = "0.8" 16 | Inflector = "0.11" 17 | 18 | [dependencies.rapier_testbed2d] 19 | path = "../crates/rapier_testbed2d" 20 | 21 | [dependencies.rapier2d] 22 | path = "../crates/rapier2d" 23 | 24 | [[bin]] 25 | name = "all_benchmarks2" 26 | path = "./all_benchmarks2.rs" -------------------------------------------------------------------------------- /benchmarks2d/all_benchmarks2.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | 3 | #[cfg(target_arch = "wasm32")] 4 | use wasm_bindgen::prelude::*; 5 | 6 | use rapier_testbed2d::{Testbed, TestbedApp}; 7 | use std::cmp::Ordering; 8 | 9 | mod balls2; 10 | mod boxes2; 11 | mod capsules2; 12 | mod convex_polygons2; 13 | mod heightfield2; 14 | mod joint_ball2; 15 | mod joint_fixed2; 16 | mod joint_prismatic2; 17 | mod pyramid2; 18 | mod vertical_stacks2; 19 | 20 | fn demo_name_from_command_line() -> Option { 21 | let mut args = std::env::args(); 22 | 23 | while let Some(arg) = args.next() { 24 | if &arg[..] == "--example" { 25 | return args.next(); 26 | } 27 | } 28 | 29 | None 30 | } 31 | 32 | #[cfg(target_arch = "wasm32")] 33 | fn demo_name_from_url() -> Option { 34 | None 35 | // let window = stdweb::web::window(); 36 | // let hash = window.location()?.search().ok()?; 37 | // Some(hash[1..].to_string()) 38 | } 39 | 40 | #[cfg(not(target_arch = "wasm32"))] 41 | fn demo_name_from_url() -> Option { 42 | None 43 | } 44 | 45 | #[cfg_attr(target_arch = "wasm32", wasm_bindgen(start))] 46 | pub fn main() { 47 | let mut builders: Vec<(_, fn(&mut Testbed))> = vec![ 48 | ("Balls", balls2::init_world), 49 | ("Boxes", boxes2::init_world), 50 | ("Capsules", capsules2::init_world), 51 | ("Convex polygons", convex_polygons2::init_world), 52 | ("Heightfield", heightfield2::init_world), 53 | ("Pyramid", pyramid2::init_world), 54 | ("Verticals stacks", vertical_stacks2::init_world), 55 | ("(Stress test) joint ball", joint_ball2::init_world), 56 | ("(Stress test) joint fixed", joint_fixed2::init_world), 57 | ( 58 | "(Stress test) joint prismatic", 59 | joint_prismatic2::init_world, 60 | ), 61 | ]; 62 | 63 | // Lexicographic sort, with stress tests moved at the end of the list. 64 | builders.sort_by(|a, b| match (a.0.starts_with('('), b.0.starts_with('(')) { 65 | (true, true) | (false, false) => a.0.cmp(b.0), 66 | (true, false) => Ordering::Greater, 67 | (false, true) => Ordering::Less, 68 | }); 69 | 70 | let testbed = TestbedApp::from_builders(builders); 71 | 72 | testbed.run() 73 | } 74 | -------------------------------------------------------------------------------- /benchmarks2d/balls2.rs: -------------------------------------------------------------------------------- 1 | use rapier2d::prelude::*; 2 | use rapier_testbed2d::Testbed; 3 | 4 | pub fn init_world(testbed: &mut Testbed) { 5 | /* 6 | * World 7 | */ 8 | let mut bodies = RigidBodySet::new(); 9 | let mut colliders = ColliderSet::new(); 10 | let impulse_joints = ImpulseJointSet::new(); 11 | let multibody_joints = MultibodyJointSet::new(); 12 | 13 | /* 14 | * Ground 15 | */ 16 | let _ground_size = 25.0; 17 | 18 | /* 19 | let ground_shape = ShapeHandle::new(Cuboid::new(Vector2::new(ground_size, 1.0))); 20 | 21 | let ground_handle = bodies.insert(Ground::new()); 22 | let co = ColliderDesc::new(ground_shape) 23 | .translation(-Vector2::y()) 24 | .build(BodyPartHandle(ground_handle, 0)); 25 | colliders.insert_with_parent(co); 26 | */ 27 | 28 | /* 29 | * Create the balls 30 | */ 31 | let num = 50; 32 | let rad = 1.0; 33 | 34 | let shiftx = rad * 2.5; 35 | let shifty = rad * 2.0; 36 | let centerx = shiftx * (num as f32) / 2.0; 37 | let centery = shifty / 2.0; 38 | 39 | for i in 0..num { 40 | for j in 0usize..num * 5 { 41 | let x = i as f32 * shiftx - centerx; 42 | let y = j as f32 * shifty + centery; 43 | 44 | let status = if j == 0 { 45 | RigidBodyType::Fixed 46 | } else { 47 | RigidBodyType::Dynamic 48 | }; 49 | 50 | // Build the rigid body. 51 | let rigid_body = RigidBodyBuilder::new(status).translation(vector![x, y]); 52 | let handle = bodies.insert(rigid_body); 53 | let collider = ColliderBuilder::ball(rad); 54 | colliders.insert_with_parent(collider, handle, &mut bodies); 55 | } 56 | } 57 | 58 | /* 59 | * Set up the testbed. 60 | */ 61 | testbed.set_world(bodies, colliders, impulse_joints, multibody_joints); 62 | testbed.look_at(point![0.0, 2.5], 5.0); 63 | } 64 | -------------------------------------------------------------------------------- /benchmarks2d/boxes2.rs: -------------------------------------------------------------------------------- 1 | use rapier2d::prelude::*; 2 | use rapier_testbed2d::Testbed; 3 | 4 | pub fn init_world(testbed: &mut Testbed) { 5 | /* 6 | * World 7 | */ 8 | let mut bodies = RigidBodySet::new(); 9 | let mut colliders = ColliderSet::new(); 10 | let impulse_joints = ImpulseJointSet::new(); 11 | let multibody_joints = MultibodyJointSet::new(); 12 | 13 | /* 14 | * Ground 15 | */ 16 | let ground_size = 25.0; 17 | 18 | let rigid_body = RigidBodyBuilder::fixed(); 19 | let handle = bodies.insert(rigid_body); 20 | let collider = ColliderBuilder::cuboid(ground_size, 1.2); 21 | colliders.insert_with_parent(collider, handle, &mut bodies); 22 | 23 | let rigid_body = RigidBodyBuilder::fixed() 24 | .rotation(std::f32::consts::FRAC_PI_2) 25 | .translation(vector![ground_size, ground_size * 2.0]); 26 | let handle = bodies.insert(rigid_body); 27 | let collider = ColliderBuilder::cuboid(ground_size * 2.0, 1.2); 28 | colliders.insert_with_parent(collider, handle, &mut bodies); 29 | 30 | let rigid_body = RigidBodyBuilder::fixed() 31 | .rotation(std::f32::consts::FRAC_PI_2) 32 | .translation(vector![-ground_size, ground_size * 2.0]); 33 | let handle = bodies.insert(rigid_body); 34 | let collider = ColliderBuilder::cuboid(ground_size * 2.0, 1.2); 35 | colliders.insert_with_parent(collider, handle, &mut bodies); 36 | 37 | /* 38 | * Create the cubes 39 | */ 40 | let num = 26; 41 | let rad = 0.5; 42 | 43 | let shift = rad * 2.0; 44 | let centerx = shift * (num as f32) / 2.0; 45 | let centery = shift / 2.0; 46 | 47 | for i in 0..num { 48 | for j in 0usize..num * 5 { 49 | let x = i as f32 * shift - centerx; 50 | let y = j as f32 * shift + centery + 2.0; 51 | 52 | // Build the rigid body. 53 | let rigid_body = RigidBodyBuilder::dynamic().translation(vector![x, y]); 54 | let handle = bodies.insert(rigid_body); 55 | let collider = ColliderBuilder::cuboid(rad, rad); 56 | colliders.insert_with_parent(collider, handle, &mut bodies); 57 | } 58 | } 59 | 60 | /* 61 | * Set up the testbed. 62 | */ 63 | testbed.set_world(bodies, colliders, impulse_joints, multibody_joints); 64 | testbed.look_at(point![0.0, 50.0], 10.0); 65 | } 66 | -------------------------------------------------------------------------------- /benchmarks2d/capsules2.rs: -------------------------------------------------------------------------------- 1 | use rapier2d::prelude::*; 2 | use rapier_testbed2d::Testbed; 3 | 4 | pub fn init_world(testbed: &mut Testbed) { 5 | /* 6 | * World 7 | */ 8 | let mut bodies = RigidBodySet::new(); 9 | let mut colliders = ColliderSet::new(); 10 | let impulse_joints = ImpulseJointSet::new(); 11 | let multibody_joints = MultibodyJointSet::new(); 12 | 13 | /* 14 | * Ground 15 | */ 16 | let ground_size = 25.0; 17 | 18 | let rigid_body = RigidBodyBuilder::fixed(); 19 | let handle = bodies.insert(rigid_body); 20 | let collider = ColliderBuilder::cuboid(ground_size, 1.2); 21 | colliders.insert_with_parent(collider, handle, &mut bodies); 22 | 23 | let rigid_body = RigidBodyBuilder::fixed() 24 | .rotation(std::f32::consts::FRAC_PI_2) 25 | .translation(vector![ground_size, ground_size * 4.0]); 26 | let handle = bodies.insert(rigid_body); 27 | let collider = ColliderBuilder::cuboid(ground_size * 4.0, 1.2); 28 | colliders.insert_with_parent(collider, handle, &mut bodies); 29 | 30 | let rigid_body = RigidBodyBuilder::fixed() 31 | .rotation(std::f32::consts::FRAC_PI_2) 32 | .translation(vector![-ground_size, ground_size * 4.0]); 33 | let handle = bodies.insert(rigid_body); 34 | let collider = ColliderBuilder::cuboid(ground_size * 4.0, 1.2); 35 | colliders.insert_with_parent(collider, handle, &mut bodies); 36 | 37 | /* 38 | * Create the cubes 39 | */ 40 | let num = 26; 41 | let numy = num * 5; 42 | let rad = 0.5; 43 | 44 | let shift = rad * 2.0; 45 | let shifty = rad * 5.0; 46 | let centerx = shift * (num as f32) / 2.0; 47 | let centery = shift / 2.0; 48 | 49 | for i in 0..num { 50 | for j in 0usize..numy { 51 | let x = i as f32 * shift - centerx; 52 | let y = j as f32 * shifty + centery + 3.0; 53 | 54 | // Build the rigid body. 55 | let rigid_body = RigidBodyBuilder::dynamic().translation(vector![x, y]); 56 | let handle = bodies.insert(rigid_body); 57 | let collider = ColliderBuilder::capsule_y(rad * 1.5, rad); 58 | colliders.insert_with_parent(collider, handle, &mut bodies); 59 | } 60 | } 61 | 62 | /* 63 | * Set up the testbed. 64 | */ 65 | testbed.set_world(bodies, colliders, impulse_joints, multibody_joints); 66 | testbed.look_at(point![0.0, 50.0], 10.0); 67 | } 68 | -------------------------------------------------------------------------------- /benchmarks2d/heightfield2.rs: -------------------------------------------------------------------------------- 1 | use rapier2d::na::DVector; 2 | use rapier2d::prelude::*; 3 | use rapier_testbed2d::Testbed; 4 | 5 | pub fn init_world(testbed: &mut Testbed) { 6 | /* 7 | * World 8 | */ 9 | let mut bodies = RigidBodySet::new(); 10 | let mut colliders = ColliderSet::new(); 11 | let impulse_joints = ImpulseJointSet::new(); 12 | let multibody_joints = MultibodyJointSet::new(); 13 | 14 | /* 15 | * Ground 16 | */ 17 | let ground_size = Vector::new(50.0, 1.0); 18 | let nsubdivs = 2000; 19 | 20 | let heights = DVector::from_fn(nsubdivs + 1, |i, _| { 21 | if i == 0 || i == nsubdivs { 22 | 80.0 23 | } else { 24 | (i as f32 * ground_size.x / (nsubdivs as f32)).cos() * 2.0 25 | } 26 | }); 27 | 28 | let rigid_body = RigidBodyBuilder::fixed(); 29 | let handle = bodies.insert(rigid_body); 30 | let collider = ColliderBuilder::heightfield(heights, ground_size); 31 | colliders.insert_with_parent(collider, handle, &mut bodies); 32 | 33 | /* 34 | * Create the cubes 35 | */ 36 | let num = 26; 37 | let rad = 0.5; 38 | 39 | let shift = rad * 2.0; 40 | let centerx = shift * (num / 2) as f32; 41 | let centery = shift / 2.0; 42 | 43 | for i in 0..num { 44 | for j in 0usize..num * 5 { 45 | let x = i as f32 * shift - centerx; 46 | let y = j as f32 * shift + centery + 3.0; 47 | 48 | // Build the rigid body. 49 | let rigid_body = RigidBodyBuilder::dynamic().translation(vector![x, y]); 50 | let handle = bodies.insert(rigid_body); 51 | 52 | if j % 2 == 0 { 53 | let collider = ColliderBuilder::cuboid(rad, rad); 54 | colliders.insert_with_parent(collider, handle, &mut bodies); 55 | } else { 56 | let collider = ColliderBuilder::ball(rad); 57 | colliders.insert_with_parent(collider, handle, &mut bodies); 58 | } 59 | } 60 | } 61 | 62 | /* 63 | * Set up the testbed. 64 | */ 65 | testbed.set_world(bodies, colliders, impulse_joints, multibody_joints); 66 | testbed.look_at(point![0.0, 50.0], 10.0); 67 | } 68 | -------------------------------------------------------------------------------- /benchmarks2d/joint_ball2.rs: -------------------------------------------------------------------------------- 1 | use rapier2d::prelude::*; 2 | use rapier_testbed2d::Testbed; 3 | 4 | pub fn init_world(testbed: &mut Testbed) { 5 | /* 6 | * World 7 | */ 8 | let mut bodies = RigidBodySet::new(); 9 | let mut colliders = ColliderSet::new(); 10 | let mut impulse_joints = ImpulseJointSet::new(); 11 | let multibody_joints = MultibodyJointSet::new(); 12 | 13 | /* 14 | * Create the balls 15 | */ 16 | // Build the rigid body. 17 | let rad = 0.4; 18 | let numi = 100; // Num vertical nodes. 19 | let numk = 100; // Num horizontal nodes. 20 | let shift = 1.0; 21 | 22 | let mut body_handles = Vec::new(); 23 | 24 | for k in 0..numk { 25 | for i in 0..numi { 26 | let fk = k as f32; 27 | let fi = i as f32; 28 | 29 | let status = if k >= numk / 2 - 3 && k <= numk / 2 + 3 && i == 0 { 30 | RigidBodyType::Fixed 31 | } else { 32 | RigidBodyType::Dynamic 33 | }; 34 | 35 | let rigid_body = 36 | RigidBodyBuilder::new(status).translation(vector![fk * shift, -fi * shift]); 37 | let child_handle = bodies.insert(rigid_body); 38 | let collider = ColliderBuilder::ball(rad); 39 | colliders.insert_with_parent(collider, child_handle, &mut bodies); 40 | 41 | // Vertical joint. 42 | if i > 0 { 43 | let parent_handle = *body_handles.last().unwrap(); 44 | let joint = RevoluteJointBuilder::new().local_anchor2(point![0.0, shift]); 45 | impulse_joints.insert(parent_handle, child_handle, joint, true); 46 | } 47 | 48 | // Horizontal joint. 49 | if k > 0 { 50 | let parent_index = body_handles.len() - numi; 51 | let parent_handle = body_handles[parent_index]; 52 | let joint = RevoluteJointBuilder::new().local_anchor2(point![-shift, 0.0]); 53 | impulse_joints.insert(parent_handle, child_handle, joint, true); 54 | } 55 | 56 | body_handles.push(child_handle); 57 | } 58 | } 59 | 60 | /* 61 | * Set up the testbed. 62 | */ 63 | testbed.set_world(bodies, colliders, impulse_joints, multibody_joints); 64 | testbed.look_at(point![numk as f32 * rad, numi as f32 * -rad], 5.0); 65 | } 66 | -------------------------------------------------------------------------------- /benchmarks2d/joint_prismatic2.rs: -------------------------------------------------------------------------------- 1 | use rapier2d::prelude::*; 2 | use rapier_testbed2d::Testbed; 3 | 4 | pub fn init_world(testbed: &mut Testbed) { 5 | /* 6 | * World 7 | */ 8 | let mut bodies = RigidBodySet::new(); 9 | let mut colliders = ColliderSet::new(); 10 | let mut impulse_joints = ImpulseJointSet::new(); 11 | let multibody_joints = MultibodyJointSet::new(); 12 | 13 | /* 14 | * Create the balls 15 | */ 16 | // Build the rigid body. 17 | let rad = 0.4; 18 | let num = 10; 19 | let shift = 1.0; 20 | 21 | for l in 0..25 { 22 | let y = l as f32 * shift * (num as f32 + 2.0) * 2.0; 23 | 24 | for j in 0..50 { 25 | let x = j as f32 * shift * 4.0; 26 | 27 | let ground = RigidBodyBuilder::fixed().translation(vector![x, y]); 28 | let mut curr_parent = bodies.insert(ground); 29 | let collider = ColliderBuilder::cuboid(rad, rad); 30 | colliders.insert_with_parent(collider, curr_parent, &mut bodies); 31 | 32 | for i in 0..num { 33 | let y = y - (i + 1) as f32 * shift; 34 | let density = 1.0; 35 | let rigid_body = RigidBodyBuilder::dynamic().translation(vector![x, y]); 36 | let curr_child = bodies.insert(rigid_body); 37 | let collider = ColliderBuilder::cuboid(rad, rad).density(density); 38 | colliders.insert_with_parent(collider, curr_child, &mut bodies); 39 | 40 | let axis = if i % 2 == 0 { 41 | UnitVector::new_normalize(vector![1.0, 1.0]) 42 | } else { 43 | UnitVector::new_normalize(vector![-1.0, 1.0]) 44 | }; 45 | 46 | let prism = PrismaticJointBuilder::new(axis) 47 | .local_anchor2(point![0.0, shift]) 48 | .limits([-1.5, 1.5]); 49 | impulse_joints.insert(curr_parent, curr_child, prism, true); 50 | 51 | curr_parent = curr_child; 52 | } 53 | } 54 | } 55 | 56 | /* 57 | * Set up the testbed. 58 | */ 59 | testbed.set_world(bodies, colliders, impulse_joints, multibody_joints); 60 | testbed.look_at(point![80.0, 80.0], 15.0); 61 | } 62 | -------------------------------------------------------------------------------- /benchmarks2d/pyramid2.rs: -------------------------------------------------------------------------------- 1 | use rapier2d::prelude::*; 2 | use rapier_testbed2d::Testbed; 3 | 4 | pub fn init_world(testbed: &mut Testbed) { 5 | /* 6 | * World 7 | */ 8 | let mut bodies = RigidBodySet::new(); 9 | let mut colliders = ColliderSet::new(); 10 | let impulse_joints = ImpulseJointSet::new(); 11 | let multibody_joints = MultibodyJointSet::new(); 12 | 13 | /* 14 | * Ground 15 | */ 16 | let ground_size = 100.0; 17 | let ground_thickness = 1.0; 18 | 19 | let rigid_body = RigidBodyBuilder::fixed(); 20 | let ground_handle = bodies.insert(rigid_body); 21 | let collider = ColliderBuilder::cuboid(ground_size, ground_thickness); 22 | colliders.insert_with_parent(collider, ground_handle, &mut bodies); 23 | 24 | /* 25 | * Create the cubes 26 | */ 27 | let num = 100; 28 | let rad = 0.5; 29 | 30 | let shift = rad * 2.0; 31 | let centerx = shift * (num as f32) / 2.0; 32 | let centery = shift / 2.0 + ground_thickness + rad * 1.5; 33 | 34 | for i in 0usize..num { 35 | for j in i..num { 36 | let fj = j as f32; 37 | let fi = i as f32; 38 | let x = (fi * shift / 2.0) + (fj - fi) * shift - centerx; 39 | let y = fi * shift + centery; 40 | 41 | // Build the rigid body. 42 | let rigid_body = RigidBodyBuilder::dynamic().translation(vector![x, y]); 43 | let handle = bodies.insert(rigid_body); 44 | let collider = ColliderBuilder::cuboid(rad, rad); 45 | colliders.insert_with_parent(collider, handle, &mut bodies); 46 | } 47 | } 48 | 49 | /* 50 | * Set up the testbed. 51 | */ 52 | testbed.set_world(bodies, colliders, impulse_joints, multibody_joints); 53 | testbed.look_at(point![0.0, 2.5], 5.0); 54 | } 55 | -------------------------------------------------------------------------------- /benchmarks2d/vertical_stacks2.rs: -------------------------------------------------------------------------------- 1 | use rapier2d::prelude::*; 2 | use rapier_testbed2d::Testbed; 3 | 4 | pub fn init_world(testbed: &mut Testbed) { 5 | /* 6 | * World 7 | */ 8 | let mut bodies = RigidBodySet::new(); 9 | let mut colliders = ColliderSet::new(); 10 | let impulse_joints = ImpulseJointSet::new(); 11 | let multibody_joints = MultibodyJointSet::new(); 12 | 13 | let num = 80; 14 | let rad = 0.5; 15 | 16 | /* 17 | * Ground 18 | */ 19 | let ground_size = num as f32 * rad * 10.0; 20 | let ground_thickness = 1.0; 21 | 22 | let rigid_body = RigidBodyBuilder::fixed(); 23 | let ground_handle = bodies.insert(rigid_body); 24 | let collider = ColliderBuilder::cuboid(ground_size, ground_thickness); 25 | colliders.insert_with_parent(collider, ground_handle, &mut bodies); 26 | 27 | /* 28 | * Create the cubes 29 | */ 30 | 31 | let shiftx_centerx = [ 32 | (rad * 2.0 + 0.0002, -(num as f32) * rad * 2.0 * 1.5), 33 | (rad * 2.0 + rad, num as f32 * rad * 2.0 * 1.5), 34 | ]; 35 | 36 | for (shiftx, centerx) in shiftx_centerx { 37 | let shifty = rad * 2.0; 38 | let centery = shifty / 2.0 + ground_thickness; 39 | 40 | for i in 0..num { 41 | for j in 0usize..1 + i * 2 { 42 | let fj = j as f32; 43 | let fi = i as f32; 44 | let x = (fj - fi) * shiftx + centerx; 45 | let y = (num as f32 - fi - 1.0) * shifty + centery; 46 | 47 | // Build the rigid body. 48 | let rigid_body = RigidBodyBuilder::dynamic().translation(vector![x, y]); 49 | let handle = bodies.insert(rigid_body); 50 | let collider = ColliderBuilder::cuboid(rad, rad); 51 | colliders.insert_with_parent(collider, handle, &mut bodies); 52 | } 53 | } 54 | } 55 | 56 | /* 57 | * Set up the testbed. 58 | */ 59 | testbed.set_world(bodies, colliders, impulse_joints, multibody_joints); 60 | testbed.look_at(point![0.0, 2.5], 5.0); 61 | } 62 | -------------------------------------------------------------------------------- /benchmarks3d/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rapier-benchmarks-3d" 3 | version = "0.1.0" 4 | authors = ["Sébastien Crozet "] 5 | edition = "2021" 6 | 7 | [features] 8 | parallel = ["rapier3d/parallel", "rapier_testbed3d/parallel"] 9 | simd-stable = ["rapier3d/simd-stable"] 10 | simd-nightly = ["rapier3d/simd-nightly"] 11 | other-backends = ["rapier_testbed3d/other-backends"] 12 | enhanced-determinism = ["rapier3d/enhanced-determinism"] 13 | 14 | [dependencies] 15 | rand = "0.8" 16 | Inflector = "0.11" 17 | 18 | [dependencies.rapier_testbed3d] 19 | path = "../crates/rapier_testbed3d" 20 | 21 | [dependencies.rapier3d] 22 | path = "../crates/rapier3d" 23 | 24 | [[bin]] 25 | name = "all_benchmarks3" 26 | path = "all_benchmarks3.rs" 27 | -------------------------------------------------------------------------------- /benchmarks3d/balls3.rs: -------------------------------------------------------------------------------- 1 | use rapier3d::prelude::*; 2 | use rapier_testbed3d::Testbed; 3 | 4 | pub fn init_world(testbed: &mut Testbed) { 5 | /* 6 | * World 7 | */ 8 | let mut bodies = RigidBodySet::new(); 9 | let mut colliders = ColliderSet::new(); 10 | let impulse_joints = ImpulseJointSet::new(); 11 | let multibody_joints = MultibodyJointSet::new(); 12 | 13 | /* 14 | * Create the balls 15 | */ 16 | let num = 20; 17 | let rad = 1.0; 18 | 19 | let shift = rad * 2.0 + 1.0; 20 | let centerx = shift * (num as f32) / 2.0; 21 | let centery = shift / 2.0; 22 | let centerz = shift * (num as f32) / 2.0; 23 | 24 | for i in 0..num { 25 | for j in 0usize..num { 26 | for k in 0..num { 27 | let x = i as f32 * shift - centerx; 28 | let y = j as f32 * shift + centery; 29 | let z = k as f32 * shift - centerz; 30 | 31 | let status = if j == 0 { 32 | RigidBodyType::Fixed 33 | } else { 34 | RigidBodyType::Dynamic 35 | }; 36 | let density = 0.477; 37 | 38 | // Build the rigid body. 39 | let rigid_body = RigidBodyBuilder::new(status).translation(vector![x, y, z]); 40 | let handle = bodies.insert(rigid_body); 41 | let collider = ColliderBuilder::ball(rad).density(density); 42 | colliders.insert_with_parent(collider, handle, &mut bodies); 43 | } 44 | } 45 | } 46 | 47 | /* 48 | * Set up the testbed. 49 | */ 50 | testbed.set_world(bodies, colliders, impulse_joints, multibody_joints); 51 | testbed.look_at(point![100.0, 100.0, 100.0], Point::origin()); 52 | } 53 | -------------------------------------------------------------------------------- /benchmarks3d/boxes3.rs: -------------------------------------------------------------------------------- 1 | use rapier3d::prelude::*; 2 | use rapier_testbed3d::Testbed; 3 | 4 | pub fn init_world(testbed: &mut Testbed) { 5 | /* 6 | * World 7 | */ 8 | let mut bodies = RigidBodySet::new(); 9 | let mut colliders = ColliderSet::new(); 10 | let impulse_joints = ImpulseJointSet::new(); 11 | let multibody_joints = MultibodyJointSet::new(); 12 | 13 | /* 14 | * Ground 15 | */ 16 | let ground_size = 200.1; 17 | let ground_height = 0.1; 18 | 19 | let rigid_body = RigidBodyBuilder::fixed().translation(vector![0.0, -ground_height, 0.0]); 20 | let handle = bodies.insert(rigid_body); 21 | let collider = ColliderBuilder::cuboid(ground_size, ground_height, ground_size); 22 | colliders.insert_with_parent(collider, handle, &mut bodies); 23 | 24 | /* 25 | * Create the cubes 26 | */ 27 | let num = 8; 28 | let rad = 1.0; 29 | 30 | let shift = rad * 2.0 + rad; 31 | let centerx = shift * (num / 2) as f32; 32 | let centery = shift / 2.0; 33 | let centerz = shift * (num / 2) as f32; 34 | 35 | let mut offset = -(num as f32) * (rad * 2.0 + rad) * 0.5; 36 | 37 | for j in 0usize..47 { 38 | for i in 0..num { 39 | for k in 0usize..num { 40 | let x = i as f32 * shift - centerx + offset; 41 | let y = j as f32 * shift + centery + 3.0; 42 | let z = k as f32 * shift - centerz + offset; 43 | 44 | // Build the rigid body. 45 | let rigid_body = RigidBodyBuilder::dynamic().translation(vector![x, y, z]); 46 | let handle = bodies.insert(rigid_body); 47 | let collider = ColliderBuilder::cuboid(rad, rad, rad); 48 | colliders.insert_with_parent(collider, handle, &mut bodies); 49 | } 50 | } 51 | 52 | offset -= 0.05 * rad * (num as f32 - 1.0); 53 | } 54 | 55 | /* 56 | * Set up the testbed. 57 | */ 58 | testbed.set_world(bodies, colliders, impulse_joints, multibody_joints); 59 | testbed.look_at(point![100.0, 100.0, 100.0], Point::origin()); 60 | } 61 | -------------------------------------------------------------------------------- /benchmarks3d/capsules3.rs: -------------------------------------------------------------------------------- 1 | use rapier3d::prelude::*; 2 | use rapier_testbed3d::Testbed; 3 | 4 | pub fn init_world(testbed: &mut Testbed) { 5 | /* 6 | * World 7 | */ 8 | let mut bodies = RigidBodySet::new(); 9 | let mut colliders = ColliderSet::new(); 10 | let impulse_joints = ImpulseJointSet::new(); 11 | let multibody_joints = MultibodyJointSet::new(); 12 | 13 | /* 14 | * Ground 15 | */ 16 | let ground_size = 200.1; 17 | let ground_height = 0.1; 18 | 19 | let rigid_body = RigidBodyBuilder::fixed().translation(vector![0.0, -ground_height, 0.0]); 20 | let handle = bodies.insert(rigid_body); 21 | let collider = ColliderBuilder::cuboid(ground_size, ground_height, ground_size); 22 | colliders.insert_with_parent(collider, handle, &mut bodies); 23 | 24 | /* 25 | * Create the cubes 26 | */ 27 | let num = 8; 28 | let rad = 1.0; 29 | 30 | let shift = rad * 2.0 + rad; 31 | let shifty = rad * 4.0; 32 | let centerx = shift * (num / 2) as f32; 33 | let centery = shift / 2.0; 34 | let centerz = shift * (num / 2) as f32; 35 | 36 | let mut offset = -(num as f32) * (rad * 2.0 + rad) * 0.5; 37 | 38 | for j in 0usize..47 { 39 | for i in 0..num { 40 | for k in 0usize..num { 41 | let x = i as f32 * shift - centerx + offset; 42 | let y = j as f32 * shifty + centery + 3.0; 43 | let z = k as f32 * shift - centerz + offset; 44 | 45 | // Build the rigid body. 46 | let rigid_body = RigidBodyBuilder::dynamic().translation(vector![x, y, z]); 47 | let handle = bodies.insert(rigid_body); 48 | let collider = ColliderBuilder::capsule_y(rad, rad); 49 | colliders.insert_with_parent(collider, handle, &mut bodies); 50 | } 51 | } 52 | 53 | offset -= 0.05 * rad * (num as f32 - 1.0); 54 | } 55 | 56 | /* 57 | * Set up the testbed. 58 | */ 59 | testbed.set_world(bodies, colliders, impulse_joints, multibody_joints); 60 | testbed.look_at(point![100.0, 100.0, 100.0], Point::origin()); 61 | } 62 | -------------------------------------------------------------------------------- /benchmarks3d/convex_polyhedron3.rs: -------------------------------------------------------------------------------- 1 | use rand::distributions::{Distribution, Standard}; 2 | use rand::{rngs::StdRng, SeedableRng}; 3 | use rapier3d::prelude::*; 4 | use rapier_testbed3d::Testbed; 5 | 6 | pub fn init_world(testbed: &mut Testbed) { 7 | /* 8 | * World 9 | */ 10 | let mut bodies = RigidBodySet::new(); 11 | let mut colliders = ColliderSet::new(); 12 | let impulse_joints = ImpulseJointSet::new(); 13 | let multibody_joints = MultibodyJointSet::new(); 14 | 15 | /* 16 | * Ground 17 | */ 18 | let ground_size = 200.1; 19 | let ground_height = 0.1; 20 | 21 | let rigid_body = RigidBodyBuilder::fixed().translation(vector![0.0, -ground_height, 0.0]); 22 | let handle = bodies.insert(rigid_body); 23 | let collider = ColliderBuilder::cuboid(ground_size, ground_height, ground_size); 24 | colliders.insert_with_parent(collider, handle, &mut bodies); 25 | 26 | /* 27 | * Create the cubes 28 | */ 29 | let num = 8; 30 | let scale = 2.0; 31 | let rad = 1.0; 32 | let border_rad = 0.1; 33 | 34 | let shift = border_rad * 2.0 + scale; 35 | let centerx = shift * (num / 2) as f32; 36 | let centery = shift / 2.0; 37 | let centerz = shift * (num / 2) as f32; 38 | 39 | let mut offset = -(num as f32) * shift * 0.5; 40 | 41 | let mut rng = StdRng::seed_from_u64(0); 42 | let distribution = Standard; 43 | 44 | for j in 0usize..47 { 45 | for i in 0..num { 46 | for k in 0usize..num { 47 | let x = i as f32 * shift - centerx + offset; 48 | let y = j as f32 * shift + centery + 3.0; 49 | let z = k as f32 * shift - centerz + offset; 50 | 51 | let mut points = Vec::new(); 52 | for _ in 0..10 { 53 | let pt: Point = distribution.sample(&mut rng); 54 | points.push(pt * scale); 55 | } 56 | 57 | // Build the rigid body. 58 | let rigid_body = RigidBodyBuilder::dynamic().translation(vector![x, y, z]); 59 | let handle = bodies.insert(rigid_body); 60 | let collider = ColliderBuilder::round_convex_hull(&points, border_rad).unwrap(); 61 | colliders.insert_with_parent(collider, handle, &mut bodies); 62 | } 63 | } 64 | 65 | offset -= 0.05 * rad * (num as f32 - 1.0); 66 | } 67 | 68 | /* 69 | * Set up the testbed. 70 | */ 71 | testbed.set_world(bodies, colliders, impulse_joints, multibody_joints); 72 | testbed.look_at(point![100.0, 100.0, 100.0], Point::origin()); 73 | } 74 | -------------------------------------------------------------------------------- /benchmarks3d/joint_ball3.rs: -------------------------------------------------------------------------------- 1 | use rapier3d::prelude::*; 2 | use rapier_testbed3d::Testbed; 3 | 4 | pub fn init_world(testbed: &mut Testbed) { 5 | /* 6 | * World 7 | */ 8 | let mut bodies = RigidBodySet::new(); 9 | let mut colliders = ColliderSet::new(); 10 | let mut impulse_joints = ImpulseJointSet::new(); 11 | let multibody_joints = MultibodyJointSet::new(); 12 | 13 | let rad = 0.4; 14 | let num = 100; 15 | let shift = 1.0; 16 | 17 | let mut body_handles = Vec::new(); 18 | 19 | for k in 0..num { 20 | for i in 0..num { 21 | let fk = k as f32; 22 | let fi = i as f32; 23 | 24 | let status = if i == 0 && (k % 4 == 0 || k == num - 1) { 25 | RigidBodyType::Fixed 26 | } else { 27 | RigidBodyType::Dynamic 28 | }; 29 | 30 | let rigid_body = 31 | RigidBodyBuilder::new(status).translation(vector![fk * shift, 0.0, fi * shift]); 32 | let child_handle = bodies.insert(rigid_body); 33 | let collider = ColliderBuilder::ball(rad); 34 | colliders.insert_with_parent(collider, child_handle, &mut bodies); 35 | 36 | // Vertical joint. 37 | if i > 0 { 38 | let parent_handle = *body_handles.last().unwrap(); 39 | let joint = SphericalJointBuilder::new().local_anchor2(point![0.0, 0.0, -shift]); 40 | impulse_joints.insert(parent_handle, child_handle, joint, true); 41 | } 42 | 43 | // Horizontal joint. 44 | if k > 0 { 45 | let parent_index = body_handles.len() - num; 46 | let parent_handle = body_handles[parent_index]; 47 | let joint = SphericalJointBuilder::new().local_anchor2(point![-shift, 0.0, 0.0]); 48 | impulse_joints.insert(parent_handle, child_handle, joint, true); 49 | } 50 | 51 | body_handles.push(child_handle); 52 | } 53 | } 54 | 55 | /* 56 | * Set up the testbed. 57 | */ 58 | testbed.set_world(bodies, colliders, impulse_joints, multibody_joints); 59 | testbed.look_at(point![-110.0, -46.0, 170.0], point![54.0, -38.0, 29.0]); 60 | } 61 | -------------------------------------------------------------------------------- /benchmarks3d/joint_prismatic3.rs: -------------------------------------------------------------------------------- 1 | use rapier3d::prelude::*; 2 | use rapier_testbed3d::Testbed; 3 | 4 | pub fn init_world(testbed: &mut Testbed) { 5 | /* 6 | * World 7 | */ 8 | let mut bodies = RigidBodySet::new(); 9 | let mut colliders = ColliderSet::new(); 10 | let mut impulse_joints = ImpulseJointSet::new(); 11 | let multibody_joints = MultibodyJointSet::new(); 12 | 13 | let rad = 0.4; 14 | let num = 5; 15 | let shift = 1.0; 16 | 17 | for m in 0..8 { 18 | let z = m as f32 * shift * (num as f32 + 2.0); 19 | 20 | for l in 0..8 { 21 | let y = l as f32 * shift * (num as f32) * 2.0; 22 | 23 | for j in 0..50 { 24 | let x = j as f32 * shift * 4.0; 25 | 26 | let ground = RigidBodyBuilder::fixed().translation(vector![x, y, z]); 27 | let mut curr_parent = bodies.insert(ground); 28 | let collider = ColliderBuilder::cuboid(rad, rad, rad); 29 | colliders.insert_with_parent(collider, curr_parent, &mut bodies); 30 | 31 | for i in 0..num { 32 | let z = z + (i + 1) as f32 * shift; 33 | let density = 1.0; 34 | let rigid_body = RigidBodyBuilder::dynamic().translation(vector![x, y, z]); 35 | let curr_child = bodies.insert(rigid_body); 36 | let collider = ColliderBuilder::cuboid(rad, rad, rad).density(density); 37 | colliders.insert_with_parent(collider, curr_child, &mut bodies); 38 | 39 | let axis = if i % 2 == 0 { 40 | UnitVector::new_normalize(vector![1.0, 1.0, 0.0]) 41 | } else { 42 | UnitVector::new_normalize(vector![-1.0, 1.0, 0.0]) 43 | }; 44 | 45 | let prism = PrismaticJointBuilder::new(axis) 46 | .local_anchor2(point![0.0, 0.0, -shift]) 47 | .limits([-2.0, 0.0]); 48 | impulse_joints.insert(curr_parent, curr_child, prism, true); 49 | 50 | curr_parent = curr_child; 51 | } 52 | } 53 | } 54 | } 55 | 56 | /* 57 | * Set up the testbed. 58 | */ 59 | testbed.set_world(bodies, colliders, impulse_joints, multibody_joints); 60 | testbed.look_at(point![262.0, 63.0, 124.0], point![101.0, 4.0, -3.0]); 61 | } 62 | -------------------------------------------------------------------------------- /benchmarks3d/many_pyramids3.rs: -------------------------------------------------------------------------------- 1 | use rapier3d::prelude::*; 2 | use rapier_testbed3d::Testbed; 3 | 4 | fn create_pyramid( 5 | bodies: &mut RigidBodySet, 6 | colliders: &mut ColliderSet, 7 | offset: Vector, 8 | stack_height: usize, 9 | rad: f32, 10 | ) { 11 | let shift = rad * 2.0; 12 | 13 | for i in 0usize..stack_height { 14 | for j in i..stack_height { 15 | let fj = j as f32; 16 | let fi = i as f32; 17 | let x = (fi * shift / 2.0) + (fj - fi) * shift; 18 | let y = fi * shift; 19 | 20 | // Build the rigid body. 21 | let rigid_body = RigidBodyBuilder::dynamic().translation(vector![x, y, 0.0] + offset); 22 | let handle = bodies.insert(rigid_body); 23 | let collider = ColliderBuilder::cuboid(rad, rad, rad); 24 | colliders.insert_with_parent(collider, handle, bodies); 25 | } 26 | } 27 | } 28 | 29 | pub fn init_world(testbed: &mut Testbed) { 30 | /* 31 | * World 32 | */ 33 | let mut bodies = RigidBodySet::new(); 34 | let mut colliders = ColliderSet::new(); 35 | let impulse_joints = ImpulseJointSet::new(); 36 | let multibody_joints = MultibodyJointSet::new(); 37 | 38 | let rad = 0.5; 39 | let pyramid_count = 40; 40 | let spacing = 4.0; 41 | 42 | /* 43 | * Ground 44 | */ 45 | let ground_size = 50.0; 46 | let ground_height = 0.1; 47 | 48 | let rigid_body = RigidBodyBuilder::fixed().translation(vector![0.0, -ground_height, 0.0]); 49 | let ground_handle = bodies.insert(rigid_body); 50 | let collider = ColliderBuilder::cuboid( 51 | ground_size, 52 | ground_height, 53 | pyramid_count as f32 * spacing / 2.0 + ground_size, 54 | ); 55 | colliders.insert_with_parent(collider, ground_handle, &mut bodies); 56 | 57 | /* 58 | * Create the cubes 59 | */ 60 | for pyramid_index in 0..pyramid_count { 61 | let bottomy = rad; 62 | create_pyramid( 63 | &mut bodies, 64 | &mut colliders, 65 | vector![ 66 | 0.0, 67 | bottomy, 68 | (pyramid_index as f32 - pyramid_count as f32 / 2.0) * spacing 69 | ], 70 | 20, 71 | rad, 72 | ); 73 | } 74 | 75 | /* 76 | * Set up the testbed. 77 | */ 78 | testbed.set_world(bodies, colliders, impulse_joints, multibody_joints); 79 | testbed.look_at(point![100.0, 100.0, 100.0], Point::origin()); 80 | } 81 | -------------------------------------------------------------------------------- /benchmarks3d/many_sleep3.rs: -------------------------------------------------------------------------------- 1 | use rapier3d::prelude::*; 2 | use rapier_testbed3d::Testbed; 3 | 4 | pub fn init_world(testbed: &mut Testbed) { 5 | /* 6 | * World 7 | */ 8 | let mut bodies = RigidBodySet::new(); 9 | let mut colliders = ColliderSet::new(); 10 | let impulse_joints = ImpulseJointSet::new(); 11 | let multibody_joints = MultibodyJointSet::new(); 12 | 13 | /* 14 | * Create the balls 15 | */ 16 | let num = 50; 17 | let rad = 1.0; 18 | 19 | let shift = rad * 2.0 + 1.0; 20 | let centerx = shift * (num as f32) / 2.0; 21 | let centery = shift / 2.0; 22 | let centerz = shift * (num as f32) / 2.0; 23 | 24 | for i in 0..num { 25 | for j in 0usize..num { 26 | for k in 0..num { 27 | let x = i as f32 * shift - centerx; 28 | let y = j as f32 * shift + centery; 29 | let z = k as f32 * shift - centerz; 30 | 31 | let status = if j == 0 { 32 | RigidBodyType::Fixed 33 | } else { 34 | RigidBodyType::Dynamic 35 | }; 36 | let density = 0.477; 37 | 38 | // Build the rigid body. 39 | let rigid_body = RigidBodyBuilder::new(status) 40 | .translation(vector![x, y, z]) 41 | .sleeping(true); // j < num - 1); 42 | let handle = bodies.insert(rigid_body); 43 | let collider = ColliderBuilder::ball(rad).density(density); 44 | colliders.insert_with_parent(collider, handle, &mut bodies); 45 | } 46 | } 47 | } 48 | 49 | /* 50 | * Set up the testbed. 51 | */ 52 | testbed.set_world(bodies, colliders, impulse_joints, multibody_joints); 53 | testbed.look_at(point![100.0, 100.0, 100.0], Point::origin()); 54 | } 55 | -------------------------------------------------------------------------------- /benchmarks3d/many_static3.rs: -------------------------------------------------------------------------------- 1 | use rapier3d::prelude::*; 2 | use rapier_testbed3d::Testbed; 3 | 4 | pub fn init_world(testbed: &mut Testbed) { 5 | /* 6 | * World 7 | */ 8 | let mut bodies = RigidBodySet::new(); 9 | let mut colliders = ColliderSet::new(); 10 | let impulse_joints = ImpulseJointSet::new(); 11 | let multibody_joints = MultibodyJointSet::new(); 12 | 13 | /* 14 | * Create the balls 15 | */ 16 | let num = 50; 17 | let rad = 1.0; 18 | 19 | let shift = rad * 2.0 + 1.0; 20 | let centerx = shift * (num as f32) / 2.0; 21 | let centery = shift / 2.0; 22 | let centerz = shift * (num as f32) / 2.0; 23 | 24 | for i in 0..num { 25 | for j in 0usize..num { 26 | for k in 0..num { 27 | let x = i as f32 * shift - centerx; 28 | let y = j as f32 * shift + centery; 29 | let z = k as f32 * shift - centerz; 30 | 31 | let status = if j < num - 1 { 32 | RigidBodyType::Fixed 33 | } else { 34 | RigidBodyType::Dynamic 35 | }; 36 | let density = 0.477; 37 | 38 | // Build the rigid body. 39 | let rigid_body = RigidBodyBuilder::new(status).translation(vector![x, y, z]); 40 | let handle = bodies.insert(rigid_body); 41 | let collider = ColliderBuilder::ball(rad).density(density); 42 | colliders.insert_with_parent(collider, handle, &mut bodies); 43 | } 44 | } 45 | } 46 | 47 | /* 48 | * Set up the testbed. 49 | */ 50 | testbed.set_world(bodies, colliders, impulse_joints, multibody_joints); 51 | testbed.look_at(point![100.0, 100.0, 100.0], Point::origin()); 52 | } 53 | -------------------------------------------------------------------------------- /benchmarks3d/pyramid3.rs: -------------------------------------------------------------------------------- 1 | use rapier3d::prelude::*; 2 | use rapier_testbed3d::Testbed; 3 | 4 | fn create_pyramid( 5 | bodies: &mut RigidBodySet, 6 | colliders: &mut ColliderSet, 7 | offset: Vector, 8 | stack_height: usize, 9 | half_extents: Vector, 10 | ) { 11 | let shift = half_extents * 2.5; 12 | for i in 0usize..stack_height { 13 | for j in i..stack_height { 14 | for k in i..stack_height { 15 | let fi = i as f32; 16 | let fj = j as f32; 17 | let fk = k as f32; 18 | let x = (fi * shift.x / 2.0) + (fk - fi) * shift.x + offset.x 19 | - stack_height as f32 * half_extents.x; 20 | let y = fi * shift.y + offset.y; 21 | let z = (fi * shift.z / 2.0) + (fj - fi) * shift.z + offset.z 22 | - stack_height as f32 * half_extents.z; 23 | 24 | // Build the rigid body. 25 | let rigid_body = RigidBodyBuilder::dynamic().translation(vector![x, y, z]); 26 | let rigid_body_handle = bodies.insert(rigid_body); 27 | 28 | let collider = 29 | ColliderBuilder::cuboid(half_extents.x, half_extents.y, half_extents.z); 30 | colliders.insert_with_parent(collider, rigid_body_handle, bodies); 31 | } 32 | } 33 | } 34 | } 35 | 36 | pub fn init_world(testbed: &mut Testbed) { 37 | /* 38 | * World 39 | */ 40 | let mut bodies = RigidBodySet::new(); 41 | let mut colliders = ColliderSet::new(); 42 | let impulse_joints = ImpulseJointSet::new(); 43 | let multibody_joints = MultibodyJointSet::new(); 44 | 45 | /* 46 | * Ground 47 | */ 48 | let ground_size = 50.0; 49 | let ground_height = 0.1; 50 | 51 | let rigid_body = RigidBodyBuilder::fixed().translation(vector![0.0, -ground_height, 0.0]); 52 | let ground_handle = bodies.insert(rigid_body); 53 | let collider = ColliderBuilder::cuboid(ground_size, ground_height, ground_size); 54 | colliders.insert_with_parent(collider, ground_handle, &mut bodies); 55 | 56 | /* 57 | * Create the cubes 58 | */ 59 | let cube_size = 1.0; 60 | let hext = Vector::repeat(cube_size); 61 | let bottomy = cube_size; 62 | create_pyramid( 63 | &mut bodies, 64 | &mut colliders, 65 | vector![0.0, bottomy, 0.0], 66 | 24, 67 | hext, 68 | ); 69 | 70 | /* 71 | * Set up the testbed. 72 | */ 73 | testbed.set_world(bodies, colliders, impulse_joints, multibody_joints); 74 | testbed.look_at(point![100.0, 100.0, 100.0], Point::origin()); 75 | } 76 | -------------------------------------------------------------------------------- /crates/rapier3d-meshloader/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 0.4.0 2 | 3 | Renamed the crate from `rapier3d-stl` to `rapier3d-meshloader`, to better reflect its support for multiple formats. 4 | 5 | ### Added 6 | 7 | - Add optional support for Collada and Wavefront files through new feature flags `collada` and `wavefront`. 8 | 9 | ### Modified 10 | 11 | - Support for STL is now optional through feature `stl`. 12 | - Features `stl`, `wavefront` and `collada` are enabled by default. 13 | 14 | ## 0.3.0 15 | 16 | This is the initial release of the `rapier3d-stl` crate. 17 | 18 | ### Added 19 | 20 | - Add `load_from_path` for creating a shape from a stl file. 21 | - Add `load_from_reader` for creating a shape from an object implementing `Read`. 22 | - Add `load_from_raw_mesh` for creating a shape from an already loaded `IndexedMesh`. 23 | -------------------------------------------------------------------------------- /crates/rapier3d-meshloader/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rapier3d-meshloader" 3 | version = "0.7.0" 4 | authors = ["Sébastien Crozet "] 5 | description = "STL file loader for the 3D rapier physics engine." 6 | documentation = "https://docs.rs/rapier3d-meshloader" 7 | homepage = "https://rapier.rs" 8 | repository = "https://github.com/dimforge/rapier" 9 | readme = "README.md" 10 | categories = [ 11 | "science", 12 | "game-development", 13 | "mathematics", 14 | "simulation", 15 | "wasm", 16 | ] 17 | keywords = ["physics", "joints", "multibody", "robotics", "urdf"] 18 | license = "Apache-2.0" 19 | edition = "2021" 20 | 21 | [features] 22 | default = ["stl", "collada", "wavefront"] 23 | stl = ["mesh-loader/stl"] 24 | collada = ["mesh-loader/collada"] 25 | wavefront = ["mesh-loader/obj"] 26 | 27 | [dependencies] 28 | thiserror = "2" 29 | profiling = "1.0" 30 | mesh-loader = "0.1.12" 31 | 32 | rapier3d = { version = "0.26", path = "../rapier3d" } 33 | -------------------------------------------------------------------------------- /crates/rapier3d-meshloader/README.md: -------------------------------------------------------------------------------- 1 | ## Mesh loader for the Rapier physics engine 2 | 3 | Rapier is a set of 2D and 3D physics engines for games, animation, and robotics. The `rapier3d-meshloader` 4 | crate lets you create a shape compatible with `rapier3d` and `parry3d` (the underlying collision-detection 5 | library) from different file formats, see the following features list: 6 | 7 | - `stl`: support .stl files 8 | - `collada`: support .dae files 9 | - `wavefront`: support .obj files 10 | 11 | ## Resources and discussions 12 | 13 | - [Dimforge](https://dimforge.com): See all the open-source projects we are working on! Follow our announcements 14 | on our [blog](https://www.dimforge.com/blog). 15 | - [User guide](https://www.rapier.rs/docs/): Learn to use Rapier in your project by reading the official User Guides. 16 | - [Discord](https://discord.gg/vt9DJSW): Come chat with us, get help, suggest features, on Discord! 17 | - [NPM packages](https://www.npmjs.com/search?q=%40dimforge): Check out our NPM packages for Rapier, if you need to 18 | use it with JavaScript/Typescript. 19 | 20 | Please make sure to familiarize yourself with our [Code of Conduct](CODE_OF_CONDUCT.md) 21 | and our [Contribution Guidelines](CONTRIBUTING.md) before contributing or participating in 22 | discussions with the community. 23 | -------------------------------------------------------------------------------- /crates/rapier3d-urdf/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 0.4.0 2 | 3 | ### Modified 4 | 5 | - Pre-parsing of urdf files is now done through the more recent `urdf_rs` crate. 6 | 7 | ### Added 8 | 9 | - Add optional support for Collada and Wavefront files through new feature flags `collada` and `wavefront`. 10 | - Add support for capsule urdf geometry 11 | 12 | ## 0.3.0 13 | 14 | This is the initial release of the `rapier3d-urdf` crate. 15 | 16 | ### Added 17 | 18 | - Add `UrdfRobot` which is a collection of colliders, rigid-bodies and joints representing a robot loaded from an URDF 19 | file. 20 | - Add `UrdfRobot::from_file` to load an `UrdfRobot` from an URDF file. 21 | - Add `UrdfRobot::from_str` to load an `UrdfRobot` from a string in URDF format. 22 | - Add `UrdfRobot::from_robot` to load an `UrdfRobot` from an already loaded URDF 23 | robot (pre-parsed with the `xurdf` crate). 24 | - Add `UrdfRobot::insert_using_impulse_joints` to insert the robot to the rapier sets. Joints are represented as 25 | **impulse** joints. 26 | - Add `UrdfRobot::insert_using_impulse_joints` to insert the robot to the rapier sets. Joints are represented as 27 | **multibody** joints. 28 | -------------------------------------------------------------------------------- /crates/rapier3d-urdf/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rapier3d-urdf" 3 | version = "0.7.0" 4 | authors = ["Sébastien Crozet "] 5 | description = "URDF file loader for the 3D rapier physics engine." 6 | documentation = "https://docs.rs/rapier3d-urdf" 7 | homepage = "https://rapier.rs" 8 | repository = "https://github.com/dimforge/rapier" 9 | readme = "README.md" 10 | categories = [ 11 | "science", 12 | "game-development", 13 | "mathematics", 14 | "simulation", 15 | "wasm", 16 | ] 17 | keywords = ["physics", "joints", "multibody", "robotics", "urdf"] 18 | license = "Apache-2.0" 19 | edition = "2021" 20 | 21 | [features] 22 | stl = ["dep:rapier3d-meshloader", "rapier3d-meshloader/stl", "__meshloader_is_enabled"] 23 | collada = ["dep:rapier3d-meshloader", "rapier3d-meshloader/collada", "__meshloader_is_enabled"] 24 | wavefront = ["dep:rapier3d-meshloader", "rapier3d-meshloader/wavefront", "__meshloader_is_enabled"] 25 | ## Private feature for detecting when meshloader is enabled by any of the file type features above. 26 | __meshloader_is_enabled = [] 27 | 28 | [dependencies] 29 | log = "0.4" 30 | anyhow = "1" 31 | bitflags = "2" 32 | urdf-rs = "0.9" 33 | 34 | rapier3d = { version = "0.26", path = "../rapier3d" } 35 | rapier3d-meshloader = { version = "0.7.0", path = "../rapier3d-meshloader", default-features = false, optional = true } 36 | -------------------------------------------------------------------------------- /crates/rapier3d-urdf/README.md: -------------------------------------------------------------------------------- 1 | ## Mesh loader for the Rapier physics engine 2 | 3 | Rapier is a set of 2D and 3D physics engines for games, animation, and robotics. The `rapier3d-urdf` 4 | crate lets you convert an URDF file into a set of rigid-bodies, colliders, and joints, for usage with the 5 | `rapier3d` physics engine. 6 | 7 | ## Optional cargo features 8 | 9 | - `stl`: enables loading `.STL` meshes referenced by the URDF file. 10 | - `collada`: enables loading `.dae` meshes referenced by the URDF file. 11 | - `wavefront`: enables loading `.obj` meshes referenced by the URDF file. 12 | 13 | ## Limitations 14 | 15 | Are listed below some known limitations you might want to be aware of before picking this library. Contributions to 16 | improve 17 | these elements are very welcome! 18 | 19 | - Supported mesh formats are `stl`, `collada` and `wavefront`. Contributions are welcome. You my check the `rapier3d-meshloader` 20 | repository for an example of mesh loader. 21 | - When inserting joints as multibody joints, they will be reset to their neutral position (all coordinates = 0). 22 | - The following fields are currently ignored: 23 | - `Joint::dynamics` 24 | - `Joint::limit.effort` / `limit.velocity` 25 | - `Joint::mimic` 26 | - `Joint::safety_controller` 27 | 28 | ## Resources and discussions 29 | 30 | - [Dimforge](https://dimforge.com): See all the open-source projects we are working on! Follow our announcements 31 | on our [blog](https://www.dimforge.com/blog). 32 | - [User guide](https://www.rapier.rs/docs/): Learn to use Rapier in your project by reading the official User Guides. 33 | - [Discord](https://discord.gg/vt9DJSW): Come chat with us, get help, suggest features, on Discord! 34 | - [NPM packages](https://www.npmjs.com/search?q=%40dimforge): Check out our NPM packages for Rapier, if you need to 35 | use it with JavaScript/Typescript. 36 | 37 | Please make sure to familiarize yourself with our [Code of Conduct](CODE_OF_CONDUCT.md) 38 | and our [Contribution Guidelines](CONTRIBUTING.md) before contributing or participating in 39 | discussions with the community. 40 | -------------------------------------------------------------------------------- /examples2d/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rapier-examples-2d" 3 | version = "0.1.0" 4 | authors = ["Sébastien Crozet "] 5 | edition = "2021" 6 | default-run = "all_examples2" 7 | 8 | [features] 9 | parallel = ["rapier2d/parallel", "rapier_testbed2d/parallel"] 10 | simd-stable = ["rapier2d/simd-stable"] 11 | simd-nightly = ["rapier2d/simd-nightly"] 12 | other-backends = ["rapier_testbed2d/other-backends"] 13 | enhanced-determinism = ["rapier2d/enhanced-determinism"] 14 | 15 | [dependencies] 16 | rand = "0.8" 17 | lyon = "0.17" 18 | usvg = "0.14" 19 | dot_vox = "5" 20 | 21 | [dependencies.rapier_testbed2d] 22 | path = "../crates/rapier_testbed2d" 23 | features = ["profiler_ui"] 24 | 25 | [dependencies.rapier2d] 26 | path = "../crates/rapier2d" 27 | 28 | [[bin]] 29 | name = "all_examples2" 30 | path = "./all_examples2.rs" 31 | -------------------------------------------------------------------------------- /examples2d/damping2.rs: -------------------------------------------------------------------------------- 1 | use rapier2d::prelude::*; 2 | use rapier_testbed2d::Testbed; 3 | 4 | pub fn init_world(testbed: &mut Testbed) { 5 | /* 6 | * World 7 | */ 8 | let mut bodies = RigidBodySet::new(); 9 | let mut colliders = ColliderSet::new(); 10 | let impulse_joints = ImpulseJointSet::new(); 11 | let multibody_joints = MultibodyJointSet::new(); 12 | 13 | /* 14 | * Create the balls 15 | */ 16 | let num = 10; 17 | let rad = 0.2; 18 | 19 | let subdiv = 1.0 / (num as f32); 20 | 21 | for i in 0usize..num { 22 | let (x, y) = (i as f32 * subdiv * std::f32::consts::PI * 2.0).sin_cos(); 23 | 24 | // Build the rigid body. 25 | let rb = RigidBodyBuilder::dynamic() 26 | .translation(vector![x, y]) 27 | .linvel(vector![x * 10.0, y * 10.0]) 28 | .angvel(100.0) 29 | .linear_damping((i + 1) as f32 * subdiv * 10.0) 30 | .angular_damping((num - i) as f32 * subdiv * 10.0); 31 | let rb_handle = bodies.insert(rb); 32 | 33 | // Build the collider. 34 | let co = ColliderBuilder::cuboid(rad, rad); 35 | colliders.insert_with_parent(co, rb_handle, &mut bodies); 36 | } 37 | 38 | /* 39 | * Set up the testbed. 40 | */ 41 | testbed.set_world_with_params( 42 | bodies, 43 | colliders, 44 | impulse_joints, 45 | multibody_joints, 46 | Vector::zeros(), 47 | (), 48 | ); 49 | testbed.look_at(point![3.0, 2.0], 50.0); 50 | } 51 | -------------------------------------------------------------------------------- /examples2d/debug_box_ball2.rs: -------------------------------------------------------------------------------- 1 | use rapier2d::prelude::*; 2 | use rapier_testbed2d::Testbed; 3 | 4 | pub fn init_world(testbed: &mut Testbed) { 5 | /* 6 | * World 7 | */ 8 | let mut bodies = RigidBodySet::new(); 9 | let mut colliders = ColliderSet::new(); 10 | let impulse_joints = ImpulseJointSet::new(); 11 | let multibody_joints = MultibodyJointSet::new(); 12 | 13 | /* 14 | * Ground 15 | */ 16 | let rad = 1.0; 17 | let rigid_body = RigidBodyBuilder::fixed() 18 | .translation(vector![0.0, -rad]) 19 | .rotation(std::f32::consts::PI / 4.0); 20 | let handle = bodies.insert(rigid_body); 21 | let collider = ColliderBuilder::cuboid(rad, rad); 22 | colliders.insert_with_parent(collider, handle, &mut bodies); 23 | 24 | // Build the dynamic box rigid body. 25 | let rigid_body = RigidBodyBuilder::dynamic() 26 | .translation(vector![0.0, 3.0 * rad]) 27 | .can_sleep(false); 28 | let handle = bodies.insert(rigid_body); 29 | let collider = ColliderBuilder::ball(rad); 30 | colliders.insert_with_parent(collider, handle, &mut bodies); 31 | 32 | /* 33 | * Set up the testbed. 34 | */ 35 | testbed.set_world(bodies, colliders, impulse_joints, multibody_joints); 36 | testbed.look_at(point![0.0, 0.0], 50.0); 37 | } 38 | -------------------------------------------------------------------------------- /examples2d/debug_intersection2.rs: -------------------------------------------------------------------------------- 1 | use rapier2d::prelude::*; 2 | use rapier_testbed2d::Testbed; 3 | 4 | pub fn init_world(testbed: &mut Testbed) { 5 | /* 6 | * World 7 | */ 8 | let mut bodies = RigidBodySet::new(); 9 | let mut colliders = ColliderSet::new(); 10 | let impulse_joints = ImpulseJointSet::new(); 11 | let multibody_joints = MultibodyJointSet::new(); 12 | 13 | let rad = 1.0; 14 | let collider = ColliderBuilder::ball(rad); 15 | 16 | let count = 100; 17 | for x in 0..count { 18 | for y in 0..count { 19 | let rigid_body = RigidBodyBuilder::fixed().translation(vector![ 20 | (x as f32 - count as f32 / 2.0) * rad * 3.0, 21 | (y as f32 - count as f32 / 2.0) * rad * 3.0 22 | ]); 23 | let handle = bodies.insert(rigid_body); 24 | colliders.insert_with_parent(collider.clone(), handle, &mut bodies); 25 | testbed.set_initial_body_color( 26 | handle, 27 | [ 28 | x as f32 / count as f32, 29 | (count - y) as f32 / count as f32, 30 | 0.5, 31 | ], 32 | ); 33 | } 34 | } 35 | 36 | /* 37 | * Set up the testbed. 38 | */ 39 | testbed.set_world(bodies, colliders, impulse_joints, multibody_joints); 40 | testbed.look_at(point![0.0, 0.0], 50.0); 41 | 42 | testbed.add_callback(move |graphics, physics, _, run| { 43 | let slow_time = run.timestep_id as f32 / 3.0; 44 | let intersection = physics.query_pipeline.intersection_with_shape( 45 | &physics.bodies, 46 | &physics.colliders, 47 | &Isometry::translation(slow_time.cos() * 10.0, slow_time.sin() * 10.0), 48 | &Ball::new(rad / 2.0), 49 | QueryFilter::default(), 50 | ); 51 | 52 | if let Some(graphics) = graphics { 53 | for (handle, _) in physics.bodies.iter() { 54 | graphics.set_body_color(handle, [0.5, 0.5, 0.5]); 55 | } 56 | if let Some(intersection) = intersection { 57 | let collider = physics.colliders.get(intersection).unwrap(); 58 | let body_handle = collider.parent().unwrap(); 59 | 60 | graphics.set_body_color(body_handle, [1.0, 0.0, 0.0]); 61 | } 62 | } 63 | }); 64 | } 65 | -------------------------------------------------------------------------------- /examples2d/debug_total_overlap2.rs: -------------------------------------------------------------------------------- 1 | use rapier2d::prelude::*; 2 | use rapier_testbed2d::Testbed; 3 | 4 | pub fn init_world(testbed: &mut Testbed) { 5 | /* 6 | * World 7 | */ 8 | let mut bodies = RigidBodySet::new(); 9 | let mut colliders = ColliderSet::new(); 10 | let impulse_joints = ImpulseJointSet::new(); 11 | let multibody_joints = MultibodyJointSet::new(); 12 | 13 | // Build many balls, all spawned at the same point. 14 | let rad = 0.5; 15 | 16 | for _ in 0..100 { 17 | let rigid_body = RigidBodyBuilder::dynamic(); 18 | let handle = bodies.insert(rigid_body); 19 | let collider = ColliderBuilder::cuboid(rad, rad); 20 | colliders.insert_with_parent(collider, handle, &mut bodies); 21 | } 22 | 23 | /* 24 | * Set up the testbed. 25 | */ 26 | testbed.set_world(bodies, colliders, impulse_joints, multibody_joints); 27 | testbed.look_at(point![0.0, 0.0], 50.0); 28 | } 29 | -------------------------------------------------------------------------------- /examples2d/debug_vertical_column2.rs: -------------------------------------------------------------------------------- 1 | use rapier2d::prelude::*; 2 | use rapier_testbed2d::Testbed; 3 | 4 | pub fn init_world(testbed: &mut Testbed) { 5 | /* 6 | * World 7 | */ 8 | let mut bodies = RigidBodySet::new(); 9 | let mut colliders = ColliderSet::new(); 10 | let impulse_joints = ImpulseJointSet::new(); 11 | let multibody_joints = MultibodyJointSet::new(); 12 | 13 | let num = 80; 14 | let rad = 0.5; 15 | 16 | /* 17 | * Ground 18 | */ 19 | let ground_size = 1.0; 20 | let ground_thickness = 1.0; 21 | 22 | let rigid_body = RigidBodyBuilder::fixed(); 23 | let ground_handle = bodies.insert(rigid_body); 24 | let collider = ColliderBuilder::cuboid(ground_size, ground_thickness).friction(0.3); 25 | colliders.insert_with_parent(collider, ground_handle, &mut bodies); 26 | 27 | /* 28 | * Create the cubes 29 | */ 30 | 31 | for i in 0..num { 32 | let y = i as f32 * rad * 2.0 + ground_thickness + rad; 33 | 34 | // Build the rigid body. 35 | let rigid_body = RigidBodyBuilder::dynamic().translation(vector![0.0, y]); 36 | let handle = bodies.insert(rigid_body); 37 | let collider = ColliderBuilder::cuboid(rad, rad).friction(0.3); 38 | colliders.insert_with_parent(collider, handle, &mut bodies); 39 | } 40 | 41 | /* 42 | * Set up the testbed. 43 | */ 44 | testbed.set_world(bodies, colliders, impulse_joints, multibody_joints); 45 | // testbed.harness_mut().physics.gravity.y = -981.0; 46 | testbed.look_at(point![0.0, 2.5], 5.0); 47 | } 48 | -------------------------------------------------------------------------------- /examples2d/heightfield2.rs: -------------------------------------------------------------------------------- 1 | use rapier2d::na::DVector; 2 | use rapier2d::prelude::*; 3 | use rapier_testbed2d::Testbed; 4 | 5 | pub fn init_world(testbed: &mut Testbed) { 6 | /* 7 | * World 8 | */ 9 | let mut bodies = RigidBodySet::new(); 10 | let mut colliders = ColliderSet::new(); 11 | let impulse_joints = ImpulseJointSet::new(); 12 | let multibody_joints = MultibodyJointSet::new(); 13 | 14 | /* 15 | * Ground 16 | */ 17 | let ground_size = Vector::new(50.0, 1.0); 18 | let nsubdivs = 2000; 19 | 20 | let heights = DVector::from_fn(nsubdivs + 1, |i, _| { 21 | if i == 0 || i == nsubdivs { 22 | 8.0 23 | } else { 24 | (i as f32 * ground_size.x / (nsubdivs as f32)).cos() * 2.0 25 | } 26 | }); 27 | 28 | let rigid_body = RigidBodyBuilder::fixed(); 29 | let handle = bodies.insert(rigid_body); 30 | let collider = ColliderBuilder::heightfield(heights, ground_size); 31 | colliders.insert_with_parent(collider, handle, &mut bodies); 32 | 33 | /* 34 | * Create the cubes 35 | */ 36 | let num = 20; 37 | let rad = 0.5; 38 | 39 | let shift = rad * 2.0; 40 | let centerx = shift * (num / 2) as f32; 41 | let centery = shift / 2.0; 42 | 43 | for i in 0..num { 44 | for j in 0usize..num { 45 | let x = i as f32 * shift - centerx; 46 | let y = j as f32 * shift + centery + 3.0; 47 | 48 | // Build the rigid body. 49 | let rigid_body = RigidBodyBuilder::dynamic().translation(vector![x, y]); 50 | let handle = bodies.insert(rigid_body); 51 | 52 | if j % 2 == 0 { 53 | let collider = ColliderBuilder::cuboid(rad, rad); 54 | colliders.insert_with_parent(collider, handle, &mut bodies); 55 | } else { 56 | let collider = ColliderBuilder::ball(rad); 57 | colliders.insert_with_parent(collider, handle, &mut bodies); 58 | } 59 | } 60 | } 61 | 62 | /* 63 | * Set up the testbed. 64 | */ 65 | testbed.set_world(bodies, colliders, impulse_joints, multibody_joints); 66 | testbed.look_at(point![0.0, 0.0], 10.0); 67 | } 68 | -------------------------------------------------------------------------------- /examples2d/joints2.rs: -------------------------------------------------------------------------------- 1 | use rapier2d::prelude::*; 2 | use rapier_testbed2d::Testbed; 3 | 4 | pub fn init_world(testbed: &mut Testbed) { 5 | /* 6 | * World 7 | */ 8 | let mut bodies = RigidBodySet::new(); 9 | let mut colliders = ColliderSet::new(); 10 | let mut impulse_joints = ImpulseJointSet::new(); 11 | let multibody_joints = MultibodyJointSet::new(); 12 | 13 | /* 14 | * Create the balls 15 | */ 16 | // Build the rigid body. 17 | // NOTE: a smaller radius (e.g. 0.1) breaks Box2D so 18 | // in order to be able to compare rapier with Box2D, 19 | // we set it to 0.4. 20 | let rad = 0.4; 21 | let numi = 10; // Num vertical nodes. 22 | let numk = 10; // Num horizontal nodes. 23 | let shift = 1.0; 24 | 25 | let mut body_handles = Vec::new(); 26 | 27 | for k in 0..numk { 28 | for i in 0..numi { 29 | let fk = k as f32; 30 | let fi = i as f32; 31 | 32 | let status = if i == 0 && k == 0 { 33 | RigidBodyType::Fixed 34 | } else { 35 | RigidBodyType::Dynamic 36 | }; 37 | 38 | let rigid_body = 39 | RigidBodyBuilder::new(status).translation(vector![fk * shift, -fi * shift]); 40 | let child_handle = bodies.insert(rigid_body); 41 | let collider = ColliderBuilder::ball(rad); 42 | colliders.insert_with_parent(collider, child_handle, &mut bodies); 43 | 44 | // Vertical joint. 45 | if i > 0 { 46 | let parent_handle = *body_handles.last().unwrap(); 47 | let joint = RevoluteJointBuilder::new().local_anchor2(point![0.0, shift]); 48 | impulse_joints.insert(parent_handle, child_handle, joint, true); 49 | } 50 | 51 | // Horizontal joint. 52 | if k > 0 { 53 | let parent_index = body_handles.len() - numi; 54 | let parent_handle = body_handles[parent_index]; 55 | let joint = RevoluteJointBuilder::new().local_anchor2(point![-shift, 0.0]); 56 | impulse_joints.insert(parent_handle, child_handle, joint, true); 57 | } 58 | 59 | body_handles.push(child_handle); 60 | } 61 | } 62 | 63 | /* 64 | * Set up the testbed. 65 | */ 66 | testbed.set_world(bodies, colliders, impulse_joints, multibody_joints); 67 | testbed.look_at(point![numk as f32 * rad, numi as f32 * -rad], 20.0); 68 | } 69 | -------------------------------------------------------------------------------- /examples2d/locked_rotations2.rs: -------------------------------------------------------------------------------- 1 | use rapier2d::prelude::*; 2 | use rapier_testbed2d::Testbed; 3 | 4 | // This shows a bug when a cylinder is in contact with a very large 5 | // but very thin cuboid. In this case the EPA returns an incorrect 6 | // contact normal, resulting in the cylinder falling through the floor. 7 | pub fn init_world(testbed: &mut Testbed) { 8 | /* 9 | * World 10 | */ 11 | let mut bodies = RigidBodySet::new(); 12 | let mut colliders = ColliderSet::new(); 13 | let impulse_joints = ImpulseJointSet::new(); 14 | let multibody_joints = MultibodyJointSet::new(); 15 | 16 | /* 17 | * The ground 18 | */ 19 | let ground_size = 5.0; 20 | let ground_height = 0.1; 21 | 22 | let rigid_body = RigidBodyBuilder::fixed().translation(vector![0.0, -ground_height]); 23 | let handle = bodies.insert(rigid_body); 24 | let collider = ColliderBuilder::cuboid(ground_size, ground_height); 25 | colliders.insert_with_parent(collider, handle, &mut bodies); 26 | 27 | /* 28 | * A rectangle that only rotate. 29 | */ 30 | let rigid_body = RigidBodyBuilder::dynamic() 31 | .translation(vector![0.0, 3.0]) 32 | .lock_translations(); 33 | let handle = bodies.insert(rigid_body); 34 | let collider = ColliderBuilder::cuboid(2.0, 0.6); 35 | colliders.insert_with_parent(collider, handle, &mut bodies); 36 | 37 | /* 38 | * A tilted capsule that cannot rotate. 39 | */ 40 | let rigid_body = RigidBodyBuilder::dynamic() 41 | .translation(vector![0.0, 5.0]) 42 | .rotation(1.0) 43 | .lock_rotations(); 44 | let handle = bodies.insert(rigid_body); 45 | let collider = ColliderBuilder::capsule_y(0.6, 0.4); 46 | colliders.insert_with_parent(collider, handle, &mut bodies); 47 | 48 | /* 49 | * Set up the testbed. 50 | */ 51 | testbed.set_world(bodies, colliders, impulse_joints, multibody_joints); 52 | testbed.look_at(point![0.0, 0.0], 40.0); 53 | } 54 | -------------------------------------------------------------------------------- /examples2d/polyline2.rs: -------------------------------------------------------------------------------- 1 | use rapier2d::na::ComplexField; 2 | use rapier2d::prelude::*; 3 | use rapier_testbed2d::Testbed; 4 | 5 | pub fn init_world(testbed: &mut Testbed) { 6 | /* 7 | * World 8 | */ 9 | let mut bodies = RigidBodySet::new(); 10 | let mut colliders = ColliderSet::new(); 11 | let impulse_joints = ImpulseJointSet::new(); 12 | let multibody_joints = MultibodyJointSet::new(); 13 | 14 | /* 15 | * Ground 16 | */ 17 | let ground_size = 50.0; 18 | let nsubdivs = 2000; 19 | let step_size = ground_size / (nsubdivs as f32); 20 | let mut points = Vec::new(); 21 | 22 | points.push(point![-ground_size / 2.0, 40.0]); 23 | for i in 1..nsubdivs - 1 { 24 | let x = -ground_size / 2.0 + i as f32 * step_size; 25 | let y = ComplexField::cos(i as f32 * step_size) * 2.0; 26 | points.push(point![x, y]); 27 | } 28 | points.push(point![ground_size / 2.0, 40.0]); 29 | 30 | let rigid_body = RigidBodyBuilder::fixed(); 31 | let handle = bodies.insert(rigid_body); 32 | let collider = ColliderBuilder::polyline(points, None); 33 | colliders.insert_with_parent(collider, handle, &mut bodies); 34 | 35 | /* 36 | * Create the cubes 37 | */ 38 | let num = 20; 39 | let rad = 0.5; 40 | 41 | let shift = rad * 2.0; 42 | let centerx = shift * (num / 2) as f32; 43 | let centery = shift / 2.0; 44 | 45 | for i in 0..num { 46 | for j in 0usize..num { 47 | let x = i as f32 * shift - centerx; 48 | let y = j as f32 * shift + centery + 3.0; 49 | 50 | // Build the rigid body. 51 | let rigid_body = RigidBodyBuilder::dynamic().translation(vector![x, y]); 52 | let handle = bodies.insert(rigid_body); 53 | 54 | if j % 2 == 0 { 55 | let collider = ColliderBuilder::cuboid(rad, rad); 56 | colliders.insert_with_parent(collider, handle, &mut bodies); 57 | } else { 58 | let collider = ColliderBuilder::ball(rad); 59 | colliders.insert_with_parent(collider, handle, &mut bodies); 60 | } 61 | } 62 | } 63 | 64 | /* 65 | * Set up the testbed. 66 | */ 67 | testbed.set_world(bodies, colliders, impulse_joints, multibody_joints); 68 | testbed.look_at(point![0.0, 0.0], 10.0); 69 | } 70 | -------------------------------------------------------------------------------- /examples2d/pyramid2.rs: -------------------------------------------------------------------------------- 1 | use rapier2d::prelude::*; 2 | use rapier_testbed2d::Testbed; 3 | 4 | pub fn init_world(testbed: &mut Testbed) { 5 | /* 6 | * World 7 | */ 8 | let mut bodies = RigidBodySet::new(); 9 | let mut colliders = ColliderSet::new(); 10 | let impulse_joints = ImpulseJointSet::new(); 11 | let multibody_joints = MultibodyJointSet::new(); 12 | 13 | /* 14 | * Ground 15 | */ 16 | let ground_size = 10.0; 17 | let ground_thickness = 1.0; 18 | 19 | let rigid_body = RigidBodyBuilder::fixed(); 20 | let ground_handle = bodies.insert(rigid_body); 21 | let collider = ColliderBuilder::cuboid(ground_size, ground_thickness); 22 | colliders.insert_with_parent(collider, ground_handle, &mut bodies); 23 | 24 | /* 25 | * Create the cubes 26 | */ 27 | let num = 10; 28 | let rad = 0.5; 29 | 30 | let shift = rad * 2.0; 31 | let centerx = shift * (num as f32) / 2.0; 32 | let centery = shift / 2.0 + ground_thickness + rad * 1.5; 33 | 34 | for i in 0usize..num { 35 | for j in i..num { 36 | let fj = j as f32; 37 | let fi = i as f32; 38 | let x = (fi * shift / 2.0) + (fj - fi) * shift - centerx; 39 | let y = fi * shift + centery; 40 | 41 | // Build the rigid body. 42 | let rigid_body = RigidBodyBuilder::dynamic().translation(vector![x, y]); 43 | let handle = bodies.insert(rigid_body); 44 | let collider = ColliderBuilder::cuboid(rad, rad); 45 | colliders.insert_with_parent(collider, handle, &mut bodies); 46 | } 47 | } 48 | 49 | /* 50 | * Set up the testbed. 51 | */ 52 | testbed.set_world(bodies, colliders, impulse_joints, multibody_joints); 53 | testbed.look_at(point![0.0, 2.5], 20.0); 54 | } 55 | -------------------------------------------------------------------------------- /examples2d/restitution2.rs: -------------------------------------------------------------------------------- 1 | use rapier2d::prelude::*; 2 | use rapier_testbed2d::Testbed; 3 | 4 | pub fn init_world(testbed: &mut Testbed) { 5 | /* 6 | * World 7 | */ 8 | let mut bodies = RigidBodySet::new(); 9 | let mut colliders = ColliderSet::new(); 10 | let impulse_joints = ImpulseJointSet::new(); 11 | let multibody_joints = MultibodyJointSet::new(); 12 | 13 | /* 14 | * Ground 15 | */ 16 | let ground_size = 20.; 17 | let ground_height = 1.0; 18 | 19 | let rigid_body = RigidBodyBuilder::fixed().translation(vector![0.0, -ground_height]); 20 | let handle = bodies.insert(rigid_body); 21 | let collider = ColliderBuilder::cuboid(ground_size, ground_height).restitution(1.0); 22 | colliders.insert_with_parent(collider, handle, &mut bodies); 23 | 24 | let num = 10; 25 | let rad = 0.5; 26 | 27 | for j in 0..2 { 28 | for i in 0..=num { 29 | let x = (i as f32) - num as f32 / 2.0; 30 | let rigid_body = 31 | RigidBodyBuilder::dynamic().translation(vector![x * 2.0, 10.0 * (j as f32 + 1.0)]); 32 | let handle = bodies.insert(rigid_body); 33 | let collider = ColliderBuilder::ball(rad).restitution((i as f32) / (num as f32)); 34 | colliders.insert_with_parent(collider, handle, &mut bodies); 35 | } 36 | } 37 | 38 | /* 39 | * Set up the testbed. 40 | */ 41 | testbed.set_world(bodies, colliders, impulse_joints, multibody_joints); 42 | testbed.look_at(point![0.0, 1.0], 25.0); 43 | } 44 | -------------------------------------------------------------------------------- /examples2d/s2d_bridge.rs: -------------------------------------------------------------------------------- 1 | use rapier2d::prelude::*; 2 | use rapier_testbed2d::Testbed; 3 | 4 | pub fn init_world(testbed: &mut Testbed) { 5 | /* 6 | * World 7 | */ 8 | let mut bodies = RigidBodySet::new(); 9 | let mut colliders = ColliderSet::new(); 10 | let mut impulse_joints = ImpulseJointSet::new(); 11 | let multibody_joints = MultibodyJointSet::new(); 12 | 13 | /* 14 | * Ground 15 | */ 16 | let ground = bodies.insert(RigidBodyBuilder::fixed()); 17 | 18 | /* 19 | * Create the bridge. 20 | */ 21 | let density = 20.0; 22 | let x_base = -80.0; 23 | let count = 160; 24 | let mut prev = ground; 25 | 26 | for i in 0..count { 27 | let rigid_body = RigidBodyBuilder::dynamic() 28 | .linear_damping(0.1) 29 | .angular_damping(0.1) 30 | .translation(vector![x_base + 0.5 + 1.0 * i as f32, 20.0]); 31 | let handle = bodies.insert(rigid_body); 32 | let collider = ColliderBuilder::cuboid(0.5, 0.125).density(density); 33 | colliders.insert_with_parent(collider, handle, &mut bodies); 34 | 35 | let pivot = point![x_base + 1.0 * i as f32, 20.0]; 36 | let joint = RevoluteJointBuilder::new() 37 | .local_anchor1(bodies[prev].position().inverse_transform_point(&pivot)) 38 | .local_anchor2(bodies[handle].position().inverse_transform_point(&pivot)) 39 | .contacts_enabled(false); 40 | impulse_joints.insert(prev, handle, joint, true); 41 | prev = handle; 42 | } 43 | 44 | let pivot = point![x_base + 1.0 * count as f32, 20.0]; 45 | let joint = RevoluteJointBuilder::new() 46 | .local_anchor1(bodies[prev].position().inverse_transform_point(&pivot)) 47 | .local_anchor2(bodies[ground].position().inverse_transform_point(&pivot)) 48 | .contacts_enabled(false); 49 | impulse_joints.insert(prev, ground, joint, true); 50 | 51 | /* 52 | * Set up the testbed. 53 | */ 54 | testbed.set_world(bodies, colliders, impulse_joints, multibody_joints); 55 | testbed.look_at(point![0.0, 2.5], 20.0); 56 | } 57 | -------------------------------------------------------------------------------- /examples2d/s2d_confined.rs: -------------------------------------------------------------------------------- 1 | use rapier2d::prelude::*; 2 | use rapier_testbed2d::Testbed; 3 | 4 | pub fn init_world(testbed: &mut Testbed) { 5 | /* 6 | * World 7 | */ 8 | let mut bodies = RigidBodySet::new(); 9 | let mut colliders = ColliderSet::new(); 10 | let impulse_joints = ImpulseJointSet::new(); 11 | let multibody_joints = MultibodyJointSet::new(); 12 | 13 | let radius = 0.5; 14 | let grid_count = 25; 15 | let friction = 0.6; 16 | let max_count = grid_count * grid_count; 17 | 18 | /* 19 | * Ground 20 | */ 21 | let collider = 22 | ColliderBuilder::capsule_from_endpoints(point![-10.5, 0.0], point![10.5, 0.0], radius) 23 | .friction(friction); 24 | colliders.insert(collider); 25 | let collider = 26 | ColliderBuilder::capsule_from_endpoints(point![-10.5, 0.0], point![-10.5, 20.5], radius) 27 | .friction(friction); 28 | colliders.insert(collider); 29 | let collider = 30 | ColliderBuilder::capsule_from_endpoints(point![10.5, 0.0], point![10.5, 20.5], radius) 31 | .friction(friction); 32 | colliders.insert(collider); 33 | let collider = 34 | ColliderBuilder::capsule_from_endpoints(point![-10.5, 20.5], point![10.5, 20.5], radius) 35 | .friction(friction); 36 | colliders.insert(collider); 37 | 38 | /* 39 | * Create the spheres 40 | */ 41 | let mut row; 42 | let mut count = 0; 43 | let mut column = 0; 44 | 45 | while count < max_count { 46 | row = 0; 47 | for _ in 0..grid_count { 48 | let x = -8.75 + column as f32 * 18.0 / (grid_count as f32); 49 | let y = 1.5 + row as f32 * 18.0 / (grid_count as f32); 50 | let body = RigidBodyBuilder::dynamic() 51 | .translation(vector![x, y]) 52 | .gravity_scale(0.0); 53 | let body_handle = bodies.insert(body); 54 | let ball = ColliderBuilder::ball(radius).friction(friction); 55 | colliders.insert_with_parent(ball, body_handle, &mut bodies); 56 | 57 | count += 1; 58 | row += 1; 59 | } 60 | 61 | column += 1; 62 | } 63 | 64 | /* 65 | * Set up the testbed. 66 | */ 67 | testbed.set_world(bodies, colliders, impulse_joints, multibody_joints); 68 | testbed.look_at(point![0.0, 2.5], 20.0); 69 | } 70 | -------------------------------------------------------------------------------- /examples2d/s2d_far_pyramid.rs: -------------------------------------------------------------------------------- 1 | use rapier2d::prelude::*; 2 | use rapier_testbed2d::Testbed; 3 | 4 | pub fn init_world(testbed: &mut Testbed) { 5 | /* 6 | * World 7 | */ 8 | let mut bodies = RigidBodySet::new(); 9 | let mut colliders = ColliderSet::new(); 10 | let impulse_joints = ImpulseJointSet::new(); 11 | let multibody_joints = MultibodyJointSet::new(); 12 | 13 | let origin = vector![100_000.0, -80_000.0]; 14 | let friction = 0.6; 15 | 16 | /* 17 | * Ground 18 | */ 19 | let rigid_body = RigidBodyBuilder::fixed().translation(vector![0.0, -1.0] + origin); 20 | let ground_handle = bodies.insert(rigid_body); 21 | let collider = ColliderBuilder::cuboid(100.0, 1.0).friction(friction); 22 | colliders.insert_with_parent(collider, ground_handle, &mut bodies); 23 | 24 | /* 25 | * Create the cubes 26 | */ 27 | let base_count = 10; 28 | 29 | let h = 0.5; 30 | let shift = 1.25 * h; 31 | 32 | for i in 0..base_count { 33 | let y = (2.0 * i as f32 + 1.0) * shift + 0.5; 34 | 35 | for j in i..base_count { 36 | let x = (i as f32 + 1.0) * shift + 2.0 * (j as f32 - i as f32) * shift 37 | - h * base_count as f32; 38 | let rigid_body = RigidBodyBuilder::dynamic().translation(vector![x, y] + origin); 39 | let ground_handle = bodies.insert(rigid_body); 40 | let collider = ColliderBuilder::cuboid(h, h).friction(friction); 41 | colliders.insert_with_parent(collider, ground_handle, &mut bodies); 42 | } 43 | } 44 | 45 | /* 46 | * Set up the testbed. 47 | */ 48 | testbed.set_world(bodies, colliders, impulse_joints, multibody_joints); 49 | testbed.look_at(point![0.0, 2.5] + origin, 20.0); 50 | } 51 | -------------------------------------------------------------------------------- /examples2d/s2d_high_mass_ratio_1.rs: -------------------------------------------------------------------------------- 1 | use rapier2d::prelude::*; 2 | use rapier_testbed2d::Testbed; 3 | 4 | pub fn init_world(testbed: &mut Testbed) { 5 | /* 6 | * World 7 | */ 8 | let mut bodies = RigidBodySet::new(); 9 | let mut colliders = ColliderSet::new(); 10 | let impulse_joints = ImpulseJointSet::new(); 11 | let multibody_joints = MultibodyJointSet::new(); 12 | 13 | let extent = 1.0; 14 | let friction = 0.5; 15 | 16 | /* 17 | * Ground 18 | */ 19 | let ground_width = 66.0 * extent; 20 | 21 | let rigid_body = RigidBodyBuilder::fixed(); 22 | let ground_handle = bodies.insert(rigid_body); 23 | let collider = ColliderBuilder::segment( 24 | point![-0.5 * 2.0 * ground_width, 0.0], 25 | point![0.5 * 2.0 * ground_width, 0.0], 26 | ) 27 | .friction(friction); 28 | colliders.insert_with_parent(collider, ground_handle, &mut bodies); 29 | 30 | /* 31 | * Create the cubes 32 | */ 33 | 34 | for j in 0..3 { 35 | let mut count = 10; 36 | let offset = -20.0 * extent + 2.0 * (count as f32 + 1.0) * extent * j as f32; 37 | let mut y = extent; 38 | 39 | while count > 0 { 40 | for i in 0..count { 41 | let coeff = i as f32 - 0.5 * count as f32; 42 | let yy = if count == 1 { y + 2.0 } else { y }; 43 | let position = vector![2.0 * coeff * extent + offset, yy]; 44 | let rigid_body = RigidBodyBuilder::dynamic().translation(position); 45 | let parent = bodies.insert(rigid_body); 46 | 47 | let collider = ColliderBuilder::cuboid(extent, extent) 48 | .density(if count == 1 { 49 | (j as f32 + 1.0) * 100.0 50 | } else { 51 | 1.0 52 | }) 53 | .friction(friction); 54 | colliders.insert_with_parent(collider, parent, &mut bodies); 55 | } 56 | 57 | count -= 1; 58 | y += 2.0 * extent; 59 | } 60 | } 61 | /* 62 | * Set up the testbed. 63 | */ 64 | testbed.set_world(bodies, colliders, impulse_joints, multibody_joints); 65 | testbed.look_at(point![0.0, 2.5], 20.0); 66 | } 67 | -------------------------------------------------------------------------------- /examples2d/s2d_high_mass_ratio_2.rs: -------------------------------------------------------------------------------- 1 | use rapier2d::prelude::*; 2 | use rapier_testbed2d::Testbed; 3 | 4 | pub fn init_world(testbed: &mut Testbed) { 5 | /* 6 | * World 7 | */ 8 | let mut bodies = RigidBodySet::new(); 9 | let mut colliders = ColliderSet::new(); 10 | let impulse_joints = ImpulseJointSet::new(); 11 | let multibody_joints = MultibodyJointSet::new(); 12 | 13 | let extent = 1.0; 14 | let friction = 0.6; 15 | 16 | /* 17 | * Ground 18 | */ 19 | let ground_width = 66.0 * extent; 20 | 21 | let rigid_body = RigidBodyBuilder::fixed(); 22 | let ground_handle = bodies.insert(rigid_body); 23 | let collider = ColliderBuilder::segment( 24 | point![-0.5 * 2.0 * ground_width, 0.0], 25 | point![0.5 * 2.0 * ground_width, 0.0], 26 | ) 27 | .friction(friction); 28 | colliders.insert_with_parent(collider, ground_handle, &mut bodies); 29 | 30 | /* 31 | * Create the cubes 32 | */ 33 | let rigid_body = RigidBodyBuilder::dynamic().translation(vector![-9.0 * extent, 0.5 * extent]); 34 | let ground_handle = bodies.insert(rigid_body); 35 | let collider = ColliderBuilder::cuboid(0.5 * extent, 0.5 * extent).friction(friction); 36 | colliders.insert_with_parent(collider, ground_handle, &mut bodies); 37 | 38 | let rigid_body = RigidBodyBuilder::dynamic().translation(vector![9.0 * extent, 0.5 * extent]); 39 | let ground_handle = bodies.insert(rigid_body); 40 | let collider = ColliderBuilder::cuboid(0.5 * extent, 0.5 * extent).friction(friction); 41 | colliders.insert_with_parent(collider, ground_handle, &mut bodies); 42 | 43 | let rigid_body = RigidBodyBuilder::dynamic().translation(vector![0.0, (10.0 + 16.0) * extent]); 44 | let ground_handle = bodies.insert(rigid_body); 45 | let collider = ColliderBuilder::cuboid(10.0 * extent, 10.0 * extent).friction(friction); 46 | colliders.insert_with_parent(collider, ground_handle, &mut bodies); 47 | 48 | /* 49 | * Set up the testbed. 50 | */ 51 | testbed.set_world(bodies, colliders, impulse_joints, multibody_joints); 52 | testbed.look_at(point![0.0, 2.5], 20.0); 53 | } 54 | -------------------------------------------------------------------------------- /examples2d/s2d_high_mass_ratio_3.rs: -------------------------------------------------------------------------------- 1 | use rapier2d::prelude::*; 2 | use rapier_testbed2d::Testbed; 3 | 4 | pub fn init_world(testbed: &mut Testbed) { 5 | /* 6 | * World 7 | */ 8 | let mut bodies = RigidBodySet::new(); 9 | let mut colliders = ColliderSet::new(); 10 | let impulse_joints = ImpulseJointSet::new(); 11 | let multibody_joints = MultibodyJointSet::new(); 12 | 13 | let extent = 1.0; 14 | let friction = 0.6; 15 | 16 | /* 17 | * Ground 18 | */ 19 | let rigid_body = RigidBodyBuilder::fixed().translation(vector![0.0, -2.0]); 20 | let ground_handle = bodies.insert(rigid_body); 21 | let collider = ColliderBuilder::cuboid(40.0, 2.0).friction(friction); 22 | colliders.insert_with_parent(collider, ground_handle, &mut bodies); 23 | 24 | /* 25 | * Create the cubes 26 | */ 27 | let rigid_body = RigidBodyBuilder::dynamic().translation(vector![-9.0 * extent, 0.5 * extent]); 28 | let ground_handle = bodies.insert(rigid_body); 29 | let collider = ColliderBuilder::cuboid(0.5 * extent, 0.5 * extent).friction(friction); 30 | colliders.insert_with_parent(collider, ground_handle, &mut bodies); 31 | 32 | let rigid_body = RigidBodyBuilder::dynamic().translation(vector![9.0 * extent, 0.5 * extent]); 33 | let ground_handle = bodies.insert(rigid_body); 34 | let collider = ColliderBuilder::cuboid(0.5 * extent, 0.5 * extent).friction(friction); 35 | colliders.insert_with_parent(collider, ground_handle, &mut bodies); 36 | 37 | let rigid_body = RigidBodyBuilder::dynamic().translation(vector![0.0, (10.0 + 16.0) * extent]); 38 | let ground_handle = bodies.insert(rigid_body); 39 | let collider = ColliderBuilder::cuboid(10.0 * extent, 10.0 * extent).friction(friction); 40 | colliders.insert_with_parent(collider, ground_handle, &mut bodies); 41 | 42 | /* 43 | * Set up the testbed. 44 | */ 45 | testbed.set_world(bodies, colliders, impulse_joints, multibody_joints); 46 | testbed.look_at(point![0.0, 2.5], 20.0); 47 | } 48 | -------------------------------------------------------------------------------- /examples2d/s2d_joint_grid.rs: -------------------------------------------------------------------------------- 1 | use rapier2d::prelude::*; 2 | use rapier_testbed2d::Testbed; 3 | 4 | pub fn init_world(testbed: &mut Testbed) { 5 | /* 6 | * World 7 | */ 8 | let mut bodies = RigidBodySet::new(); 9 | let mut colliders = ColliderSet::new(); 10 | let mut impulse_joints = ImpulseJointSet::new(); 11 | let multibody_joints = MultibodyJointSet::new(); 12 | 13 | /* 14 | * Create the joint grid. 15 | */ 16 | let rad = 0.4; 17 | let numi = 100; 18 | let numk = 100; 19 | let shift = 1.0; 20 | let mut index = 0; 21 | let mut handles = vec![RigidBodyHandle::invalid(); numi * numk]; 22 | 23 | for k in 0..numk { 24 | for i in 0..numi { 25 | let body_type = if k >= numk / 2 - 3 && k <= numk / 2 + 3 && i == 0 { 26 | RigidBodyType::Fixed 27 | } else { 28 | RigidBodyType::Dynamic 29 | }; 30 | 31 | let rigid_body = RigidBodyBuilder::new(body_type) 32 | .translation(vector![k as f32 * shift, -(i as f32) * shift]); 33 | let handle = bodies.insert(rigid_body); 34 | let collider = ColliderBuilder::ball(rad); 35 | colliders.insert_with_parent(collider, handle, &mut bodies); 36 | 37 | if i > 0 { 38 | let joint = RevoluteJointBuilder::new() 39 | .local_anchor1(point![0.0, -0.5 * shift]) 40 | .local_anchor2(point![0.0, 0.5 * shift]) 41 | .contacts_enabled(false); 42 | impulse_joints.insert(handles[index - 1], handle, joint, true); 43 | } 44 | 45 | if k > 0 { 46 | let joint = RevoluteJointBuilder::new() 47 | .local_anchor1(point![0.5 * shift, 0.0]) 48 | .local_anchor2(point![-0.5 * shift, 0.0]) 49 | .contacts_enabled(false); 50 | impulse_joints.insert(handles[index - numi], handle, joint, true); 51 | } 52 | 53 | handles[index] = handle; 54 | index += 1; 55 | } 56 | } 57 | 58 | /* 59 | * Set up the testbed. 60 | */ 61 | testbed.set_world(bodies, colliders, impulse_joints, multibody_joints); 62 | testbed.look_at(point![0.0, 2.5], 20.0); 63 | } 64 | -------------------------------------------------------------------------------- /examples2d/s2d_pyramid.rs: -------------------------------------------------------------------------------- 1 | use rapier2d::prelude::*; 2 | use rapier_testbed2d::Testbed; 3 | 4 | pub fn init_world(testbed: &mut Testbed) { 5 | /* 6 | * World 7 | */ 8 | let mut bodies = RigidBodySet::new(); 9 | let mut colliders = ColliderSet::new(); 10 | let impulse_joints = ImpulseJointSet::new(); 11 | let multibody_joints = MultibodyJointSet::new(); 12 | 13 | /* 14 | * Ground 15 | */ 16 | let rigid_body = RigidBodyBuilder::fixed().translation(vector![0.0, -1.0]); 17 | let ground_handle = bodies.insert(rigid_body); 18 | let collider = ColliderBuilder::cuboid(100.0, 1.0).friction(0.6); 19 | colliders.insert_with_parent(collider, ground_handle, &mut bodies); 20 | 21 | /* 22 | * Create the cubes 23 | */ 24 | const BASE_COUNT_SETTING: &str = "# of basis cubes"; 25 | let settings = testbed.example_settings_mut(); 26 | let base_count = settings.get_or_set_u32(BASE_COUNT_SETTING, 100, 2..=200); 27 | 28 | let h = 0.5; 29 | let shift = 1.0 * h; 30 | 31 | for i in 0..base_count { 32 | let y = (2.0 * i as f32 + 1.0) * shift; 33 | 34 | for j in i..base_count { 35 | let x = (i as f32 + 1.0) * shift + 2.0 * (j as f32 - i as f32) * shift 36 | - h * base_count as f32; 37 | let rigid_body = RigidBodyBuilder::dynamic().translation(vector![x, y]); 38 | let ground_handle = bodies.insert(rigid_body); 39 | let collider = ColliderBuilder::cuboid(h, h).friction(0.6); 40 | colliders.insert_with_parent(collider, ground_handle, &mut bodies); 41 | } 42 | } 43 | 44 | /* 45 | * Set up the testbed. 46 | */ 47 | testbed.set_world(bodies, colliders, impulse_joints, multibody_joints); 48 | testbed.look_at(point![0.0, 2.5], 20.0); 49 | } 50 | -------------------------------------------------------------------------------- /examples2d/trimesh2.rs: -------------------------------------------------------------------------------- 1 | use rapier2d::prelude::*; 2 | use rapier_testbed2d::Testbed; 3 | 4 | pub fn init_world(testbed: &mut Testbed) { 5 | /* 6 | * World 7 | */ 8 | let mut bodies = RigidBodySet::new(); 9 | let mut colliders = ColliderSet::new(); 10 | let impulse_joints = ImpulseJointSet::new(); 11 | let multibody_joints = MultibodyJointSet::new(); 12 | 13 | /* 14 | * Ground 15 | */ 16 | let ground_size = 25.0; 17 | 18 | let rigid_body = RigidBodyBuilder::fixed(); 19 | let handle = bodies.insert(rigid_body); 20 | let collider = ColliderBuilder::cuboid(ground_size, 1.2); 21 | colliders.insert_with_parent(collider, handle, &mut bodies); 22 | 23 | let rigid_body = RigidBodyBuilder::fixed() 24 | .rotation(std::f32::consts::FRAC_PI_2) 25 | .translation(vector![ground_size, ground_size]); 26 | let handle = bodies.insert(rigid_body); 27 | let collider = ColliderBuilder::cuboid(ground_size, 1.2); 28 | colliders.insert_with_parent(collider, handle, &mut bodies); 29 | 30 | let rigid_body = RigidBodyBuilder::fixed() 31 | .rotation(std::f32::consts::FRAC_PI_2) 32 | .translation(vector![-ground_size, ground_size]); 33 | let handle = bodies.insert(rigid_body); 34 | let collider = ColliderBuilder::cuboid(ground_size, 1.2); 35 | colliders.insert_with_parent(collider, handle, &mut bodies); 36 | 37 | /* 38 | * Create the trimeshes from a tessellated SVG. 39 | */ 40 | let rapier_logo_buffers = crate::utils::svg::rapier_logo(); 41 | 42 | for (ith, (vtx, idx)) in rapier_logo_buffers.into_iter().enumerate() { 43 | for k in 0..5 { 44 | let collider = ColliderBuilder::trimesh(vtx.clone(), idx.clone()) 45 | .unwrap() 46 | .contact_skin(0.2); 47 | let rigid_body = RigidBodyBuilder::dynamic() 48 | .translation(vector![ith as f32 * 8.0 - 20.0, 20.0 + k as f32 * 11.0]); 49 | let handle = bodies.insert(rigid_body); 50 | colliders.insert_with_parent(collider, handle, &mut bodies); 51 | } 52 | } 53 | 54 | /* 55 | * Set up the testbed. 56 | */ 57 | testbed.set_world(bodies, colliders, impulse_joints, multibody_joints); 58 | testbed.look_at(point![0.0, 20.0], 17.0); 59 | } 60 | -------------------------------------------------------------------------------- /examples2d/utils/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod character; 2 | pub mod svg; 3 | -------------------------------------------------------------------------------- /examples3d-f64/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rapier-examples-3d-f64" 3 | version = "0.1.0" 4 | authors = ["Sébastien Crozet "] 5 | edition = "2021" 6 | default-run = "all_examples3-f64" 7 | 8 | [features] 9 | parallel = ["rapier3d-f64/parallel", "rapier_testbed3d-f64/parallel"] 10 | simd-stable = ["rapier3d-f64/simd-stable"] 11 | simd-nightly = ["rapier3d-f64/simd-nightly"] 12 | enhanced-determinism = ["rapier3d-f64/enhanced-determinism"] 13 | 14 | [dependencies] 15 | rand = "0.8" 16 | getrandom = { version = "0.2", features = ["js"] } 17 | wasm-bindgen = "0.2" 18 | obj-rs = { version = "0.7", default-features = false } 19 | bincode = "1" 20 | serde = "1" 21 | 22 | [dependencies.rapier_testbed3d-f64] 23 | path = "../crates/rapier_testbed3d-f64" 24 | 25 | [dependencies.rapier3d-f64] 26 | path = "../crates/rapier3d-f64" 27 | 28 | [[bin]] 29 | name = "all_examples3-f64" 30 | path = "./all_examples3-f64.rs" 31 | 32 | #[lib] 33 | #crate-type = ["cdylib", "rlib"] 34 | #path = "./all_examples3_wasm.rs" 35 | 36 | -------------------------------------------------------------------------------- /examples3d-f64/all_examples3-f64.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | 3 | #[cfg(target_arch = "wasm32")] 4 | use wasm_bindgen::prelude::*; 5 | extern crate rapier3d_f64 as rapier3d; 6 | extern crate rapier_testbed3d_f64 as rapier_testbed3d; 7 | 8 | use rapier_testbed3d::{Testbed, TestbedApp}; 9 | use std::cmp::Ordering; 10 | 11 | mod debug_serialized3; 12 | 13 | #[cfg_attr(target_arch = "wasm32", wasm_bindgen(start))] 14 | pub fn main() { 15 | let mut builders: Vec<(_, fn(&mut Testbed))> = 16 | vec![("(Debug) serialized", debug_serialized3::init_world)]; 17 | 18 | // Lexicographic sort, with stress tests moved at the end of the list. 19 | builders.sort_by(|a, b| match (a.0.starts_with('('), b.0.starts_with('(')) { 20 | (true, true) | (false, false) => a.0.cmp(b.0), 21 | (true, false) => Ordering::Greater, 22 | (false, true) => Ordering::Less, 23 | }); 24 | 25 | let testbed = TestbedApp::from_builders(builders); 26 | testbed.run() 27 | } 28 | -------------------------------------------------------------------------------- /examples3d-f64/debug_serialized3.rs: -------------------------------------------------------------------------------- 1 | use rapier3d::prelude::*; 2 | use rapier_testbed3d::Testbed; 3 | 4 | #[derive(serde::Deserialize)] 5 | struct State { 6 | pub islands: IslandManager, 7 | pub broad_phase: DefaultBroadPhase, 8 | pub narrow_phase: NarrowPhase, 9 | pub bodies: RigidBodySet, 10 | pub colliders: ColliderSet, 11 | pub impulse_joints: ImpulseJointSet, 12 | pub multibody_joints: MultibodyJointSet, 13 | pub ccd_solver: CCDSolver, 14 | } 15 | 16 | pub fn init_world(testbed: &mut Testbed) { 17 | /* 18 | * Set up the testbed. 19 | */ 20 | let bytes = std::fs::read("state.bin").unwrap(); 21 | let state: State = bincode::deserialize(&bytes).unwrap(); 22 | 23 | testbed.set_world( 24 | state.bodies, 25 | state.colliders, 26 | state.impulse_joints, 27 | state.multibody_joints, 28 | ); 29 | testbed.harness_mut().physics.islands = state.islands; 30 | testbed.harness_mut().physics.broad_phase = state.broad_phase; 31 | testbed.harness_mut().physics.narrow_phase = state.narrow_phase; 32 | testbed.harness_mut().physics.ccd_solver = state.ccd_solver; 33 | 34 | testbed.set_graphics_shift(vector![-541.0, -6377257.0, -61.0]); 35 | testbed.look_at(point![10.0, 10.0, 10.0], point![0.0, 0.0, 0.0]); 36 | } 37 | -------------------------------------------------------------------------------- /examples3d-f64/rapier.data: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dimforge/rapier/cd7fc6e11f26db67c51db0713a53d4e3951dfe3f/examples3d-f64/rapier.data -------------------------------------------------------------------------------- /examples3d/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rapier-examples-3d" 3 | version = "0.1.0" 4 | authors = ["Sébastien Crozet "] 5 | edition = "2021" 6 | default-run = "all_examples3" 7 | 8 | [features] 9 | parallel = ["rapier3d/parallel", "rapier_testbed3d/parallel"] 10 | simd-stable = ["rapier3d/simd-stable"] 11 | simd-nightly = ["rapier3d/simd-nightly"] 12 | other-backends = ["rapier_testbed3d/other-backends"] 13 | enhanced-determinism = ["rapier3d/enhanced-determinism"] 14 | 15 | [dependencies] 16 | rand = "0.8" 17 | getrandom = { version = "0.2", features = ["js"] } 18 | wasm-bindgen = "0.2" 19 | obj-rs = { version = "0.7", default-features = false } 20 | serde = "1" 21 | bincode = "1" 22 | serde_json = "1" 23 | dot_vox = "5" 24 | 25 | [dependencies.rapier_testbed3d] 26 | path = "../crates/rapier_testbed3d" 27 | features = ["profiler_ui"] 28 | 29 | [dependencies.rapier3d] 30 | path = "../crates/rapier3d" 31 | 32 | [dependencies.rapier3d-urdf] 33 | path = "../crates/rapier3d-urdf" 34 | features = ["stl"] 35 | 36 | [[bin]] 37 | name = "all_examples3" 38 | path = "./all_examples3.rs" 39 | 40 | [[bin]] 41 | name = "harness_capsules3" 42 | path = "./harness_capsules3.rs" 43 | 44 | #[lib] 45 | #crate-type = ["cdylib", "rlib"] 46 | #path = "./all_examples3_wasm.rs" 47 | -------------------------------------------------------------------------------- /examples3d/convex_decomposition3.rs: -------------------------------------------------------------------------------- 1 | use rapier_testbed3d::Testbed; 2 | 3 | pub fn init_world(testbed: &mut Testbed) { 4 | crate::dynamic_trimesh3::do_init_world(testbed, true); 5 | } 6 | -------------------------------------------------------------------------------- /examples3d/convex_polyhedron3.rs: -------------------------------------------------------------------------------- 1 | use rand::distributions::{Distribution, Standard}; 2 | use rand::{rngs::StdRng, SeedableRng}; 3 | use rapier3d::prelude::*; 4 | use rapier_testbed3d::Testbed; 5 | 6 | pub fn init_world(testbed: &mut Testbed) { 7 | /* 8 | * World 9 | */ 10 | let mut bodies = RigidBodySet::new(); 11 | let mut colliders = ColliderSet::new(); 12 | let impulse_joints = ImpulseJointSet::new(); 13 | let multibody_joints = MultibodyJointSet::new(); 14 | 15 | /* 16 | * Ground 17 | */ 18 | let ground_size = 40.0; 19 | let ground_height = 0.1; 20 | 21 | let rigid_body = RigidBodyBuilder::fixed().translation(vector![0.0, -ground_height, 0.0]); 22 | let handle = bodies.insert(rigid_body); 23 | let collider = ColliderBuilder::cuboid(ground_size, ground_height, ground_size); 24 | colliders.insert_with_parent(collider, handle, &mut bodies); 25 | 26 | /* 27 | * Create the polyhedra 28 | */ 29 | let num = 5; 30 | let scale = 2.0; 31 | let border_rad = 0.1; 32 | 33 | let shift = border_rad * 2.0 + scale; 34 | let centerx = shift * (num / 2) as f32; 35 | let centery = shift / 2.0; 36 | let centerz = shift * (num / 2) as f32; 37 | 38 | let mut rng = StdRng::seed_from_u64(0); 39 | let distribution = Standard; 40 | 41 | for j in 0usize..25 { 42 | for i in 0..num { 43 | for k in 0usize..num { 44 | let x = i as f32 * shift - centerx; 45 | let y = j as f32 * shift + centery + 3.0; 46 | let z = k as f32 * shift - centerz; 47 | 48 | let mut points = Vec::new(); 49 | for _ in 0..10 { 50 | let pt: Point = distribution.sample(&mut rng); 51 | points.push(pt * scale); 52 | } 53 | 54 | // Build the rigid body. 55 | let rigid_body = RigidBodyBuilder::dynamic().translation(vector![x, y, z]); 56 | let handle = bodies.insert(rigid_body); 57 | let collider = ColliderBuilder::round_convex_hull(&points, border_rad).unwrap(); 58 | colliders.insert_with_parent(collider, handle, &mut bodies); 59 | } 60 | } 61 | } 62 | 63 | /* 64 | * Set up the testbed. 65 | */ 66 | testbed.set_world(bodies, colliders, impulse_joints, multibody_joints); 67 | testbed.look_at(point![30.0, 30.0, 30.0], Point::origin()); 68 | } 69 | -------------------------------------------------------------------------------- /examples3d/damping3.rs: -------------------------------------------------------------------------------- 1 | use rapier3d::prelude::*; 2 | use rapier_testbed3d::Testbed; 3 | 4 | pub fn init_world(testbed: &mut Testbed) { 5 | /* 6 | * World 7 | */ 8 | let mut bodies = RigidBodySet::new(); 9 | let mut colliders = ColliderSet::new(); 10 | let impulse_joints = ImpulseJointSet::new(); 11 | let multibody_joints = MultibodyJointSet::new(); 12 | 13 | /* 14 | * Create the cubes 15 | */ 16 | let num = 10; 17 | let rad = 0.2; 18 | 19 | let subdiv = 1.0 / (num as f32); 20 | 21 | for i in 0usize..num { 22 | let (x, y) = (i as f32 * subdiv * std::f32::consts::PI * 2.0).sin_cos(); 23 | 24 | // Build the rigid body. 25 | let rb = RigidBodyBuilder::dynamic() 26 | .translation(vector![x, y, 0.0]) 27 | .linvel(vector![x * 10.0, y * 10.0, 0.0]) 28 | .angvel(Vector::z() * 100.0) 29 | .linear_damping((i + 1) as f32 * subdiv * 10.0) 30 | .angular_damping((num - i) as f32 * subdiv * 10.0); 31 | let rb_handle = bodies.insert(rb); 32 | 33 | // Build the collider. 34 | let co = ColliderBuilder::cuboid(rad, rad, rad); 35 | colliders.insert_with_parent(co, rb_handle, &mut bodies); 36 | } 37 | 38 | /* 39 | * Set up the testbed. 40 | */ 41 | testbed.set_world_with_params( 42 | bodies, 43 | colliders, 44 | impulse_joints, 45 | multibody_joints, 46 | Vector::zeros(), 47 | (), 48 | ); 49 | testbed.look_at(point![2.0, 2.5, 20.0], point![2.0, 2.5, 0.0]); 50 | } 51 | -------------------------------------------------------------------------------- /examples3d/debug_add_remove_collider3.rs: -------------------------------------------------------------------------------- 1 | use rapier3d::prelude::*; 2 | use rapier_testbed3d::Testbed; 3 | 4 | pub fn init_world(testbed: &mut Testbed) { 5 | /* 6 | * World 7 | */ 8 | let mut bodies = RigidBodySet::new(); 9 | let mut colliders = ColliderSet::new(); 10 | let impulse_joints = ImpulseJointSet::new(); 11 | let multibody_joints = MultibodyJointSet::new(); 12 | 13 | /* 14 | * Ground. 15 | */ 16 | let ground_size = 3.0; 17 | let ground_height = 0.1; 18 | 19 | let rigid_body = RigidBodyBuilder::fixed().translation(vector![0.0, -ground_height, 0.0]); 20 | let ground_handle = bodies.insert(rigid_body); 21 | let collider = ColliderBuilder::cuboid(ground_size, ground_height, 0.4); 22 | let mut ground_collider_handle = 23 | colliders.insert_with_parent(collider, ground_handle, &mut bodies); 24 | 25 | /* 26 | * Rolling ball 27 | */ 28 | let ball_rad = 0.1; 29 | let rb = RigidBodyBuilder::dynamic().translation(vector![0.0, 0.2, 0.0]); 30 | let ball_handle = bodies.insert(rb); 31 | let collider = ColliderBuilder::ball(ball_rad).density(100.0); 32 | colliders.insert_with_parent(collider, ball_handle, &mut bodies); 33 | 34 | testbed.add_callback(move |_, physics, _, _| { 35 | // Remove then re-add the ground collider. 36 | let removed_collider_handle = ground_collider_handle; 37 | let coll = physics 38 | .colliders 39 | .remove( 40 | removed_collider_handle, 41 | &mut physics.islands, 42 | &mut physics.bodies, 43 | true, 44 | ) 45 | .unwrap(); 46 | ground_collider_handle = 47 | physics 48 | .colliders 49 | .insert_with_parent(coll, ground_handle, &mut physics.bodies); 50 | }); 51 | 52 | /* 53 | * Set up the testbed. 54 | */ 55 | testbed.set_world(bodies, colliders, impulse_joints, multibody_joints); 56 | testbed.look_at(point![10.0, 10.0, 10.0], Point::origin()); 57 | } 58 | -------------------------------------------------------------------------------- /examples3d/debug_big_colliders3.rs: -------------------------------------------------------------------------------- 1 | use rapier3d::prelude::*; 2 | use rapier_testbed3d::Testbed; 3 | 4 | pub fn init_world(testbed: &mut Testbed) { 5 | /* 6 | * World 7 | */ 8 | let mut bodies = RigidBodySet::new(); 9 | let mut colliders = ColliderSet::new(); 10 | let impulse_joints = ImpulseJointSet::new(); 11 | let multibody_joints = MultibodyJointSet::new(); 12 | 13 | /* 14 | * Ground 15 | */ 16 | let rigid_body = RigidBodyBuilder::fixed(); 17 | let handle = bodies.insert(rigid_body); 18 | let halfspace = SharedShape::new(HalfSpace::new(Vector::y_axis())); 19 | let collider = ColliderBuilder::new(halfspace); 20 | colliders.insert_with_parent(collider, handle, &mut bodies); 21 | 22 | let mut curr_y = 0.0; 23 | let mut curr_width = 10_000.0; 24 | 25 | for _ in 0..12 { 26 | let curr_height = 0.1f32.min(curr_width); 27 | curr_y += curr_height * 4.0; 28 | 29 | let rigid_body = RigidBodyBuilder::dynamic().translation(vector![0.0, curr_y, 0.0]); 30 | let handle = bodies.insert(rigid_body); 31 | let collider = ColliderBuilder::cuboid(curr_width, curr_height, curr_width); 32 | colliders.insert_with_parent(collider, handle, &mut bodies); 33 | 34 | curr_width /= 5.0; 35 | } 36 | 37 | /* 38 | * Set up the testbed. 39 | */ 40 | testbed.set_world(bodies, colliders, impulse_joints, multibody_joints); 41 | testbed.look_at(point![10.0, 10.0, 10.0], Point::origin()); 42 | } 43 | -------------------------------------------------------------------------------- /examples3d/debug_boxes3.rs: -------------------------------------------------------------------------------- 1 | use rapier3d::prelude::*; 2 | use rapier_testbed3d::Testbed; 3 | 4 | pub fn init_world(testbed: &mut Testbed) { 5 | /* 6 | * World 7 | */ 8 | let mut bodies = RigidBodySet::new(); 9 | let mut colliders = ColliderSet::new(); 10 | let impulse_joints = ImpulseJointSet::new(); 11 | let multibody_joints = MultibodyJointSet::new(); 12 | 13 | /* 14 | * Ground 15 | */ 16 | let ground_size = 100.1; 17 | let ground_height = 0.1; 18 | 19 | for _ in 0..6 { 20 | let rigid_body = RigidBodyBuilder::fixed().translation(vector![0.0, -ground_height, 0.0]); 21 | let handle = bodies.insert(rigid_body); 22 | let collider = ColliderBuilder::cuboid(ground_size, ground_height, ground_size); 23 | colliders.insert_with_parent(collider, handle, &mut bodies); 24 | } 25 | 26 | // Build the dynamic box rigid body. 27 | for _ in 0..2 { 28 | let rigid_body = RigidBodyBuilder::dynamic() 29 | .translation(vector![1.1, 0.0, 0.0]) 30 | // .rotation(vector![0.8, 0.2, 0.1]) 31 | .can_sleep(false); 32 | let handle = bodies.insert(rigid_body); 33 | let collider = ColliderBuilder::cuboid(2.0, 0.1, 1.0); 34 | colliders.insert_with_parent(collider, handle, &mut bodies); 35 | } 36 | 37 | /* 38 | * Set up the testbed. 39 | */ 40 | testbed.set_world(bodies, colliders, impulse_joints, multibody_joints); 41 | testbed.look_at(point![10.0, 10.0, 10.0], Point::origin()); 42 | } 43 | -------------------------------------------------------------------------------- /examples3d/debug_chain_high_mass_ratio3.rs: -------------------------------------------------------------------------------- 1 | use rapier3d::prelude::*; 2 | use rapier_testbed3d::Testbed; 3 | 4 | pub fn init_world(testbed: &mut Testbed) { 5 | /* 6 | * World 7 | */ 8 | let mut bodies = RigidBodySet::new(); 9 | let mut colliders = ColliderSet::new(); 10 | let mut impulse_joints = ImpulseJointSet::new(); 11 | let mut multibody_joints = MultibodyJointSet::new(); 12 | let use_articulations = false; 13 | 14 | /* 15 | * Create a chain with a very heavy ball at the end. 16 | */ 17 | let num = 17; 18 | let rad = 0.2; 19 | 20 | let mut body_handles = Vec::new(); 21 | 22 | for i in 0..num { 23 | let fi = i as f32; 24 | 25 | let status = if i == 0 { 26 | RigidBodyType::Fixed 27 | } else { 28 | RigidBodyType::Dynamic 29 | }; 30 | 31 | let ball_rad = if i == num - 1 { rad * 10.0 } else { rad }; 32 | let shift1 = rad * 1.1; 33 | let shift2 = ball_rad + rad * 0.1; 34 | let z = if i == 0 { 35 | 0.0 36 | } else { 37 | (fi - 1.0) * 2.0 * shift1 + shift1 + shift2 38 | }; 39 | 40 | let rigid_body = RigidBodyBuilder::new(status) 41 | .translation(vector![0.0, 0.0, z]) 42 | .additional_solver_iterations(16); 43 | let child_handle = bodies.insert(rigid_body); 44 | let collider = ColliderBuilder::ball(ball_rad); 45 | colliders.insert_with_parent(collider, child_handle, &mut bodies); 46 | 47 | // Vertical joint. 48 | if i > 0 { 49 | let parent_handle = *body_handles.last().unwrap(); 50 | let joint = if i == 1 { 51 | SphericalJointBuilder::new().local_anchor2(point![0.0, 0.0, -shift1 * 2.0]) 52 | } else { 53 | SphericalJointBuilder::new() 54 | .local_anchor1(point![0.0, 0.0, shift1]) 55 | .local_anchor2(point![0.0, 0.0, -shift2]) 56 | }; 57 | 58 | if use_articulations { 59 | multibody_joints.insert(parent_handle, child_handle, joint, true); 60 | } else { 61 | impulse_joints.insert(parent_handle, child_handle, joint, true); 62 | } 63 | } 64 | 65 | body_handles.push(child_handle); 66 | } 67 | 68 | /* 69 | * Set up the testbed. 70 | */ 71 | testbed.set_world(bodies, colliders, impulse_joints, multibody_joints); 72 | testbed.look_at(point![10.0, 10.0, 10.0], Point::origin()); 73 | } 74 | -------------------------------------------------------------------------------- /examples3d/debug_cylinder3.rs: -------------------------------------------------------------------------------- 1 | use rapier3d::prelude::*; 2 | use rapier_testbed3d::Testbed; 3 | 4 | // This shows a bug when a cylinder is in contact with a very large 5 | // but very thin cuboid. In this case the EPA returns an incorrect 6 | // contact normal, resulting in the cylinder falling through the floor. 7 | pub fn init_world(testbed: &mut Testbed) { 8 | /* 9 | * World 10 | */ 11 | let mut bodies = RigidBodySet::new(); 12 | let mut colliders = ColliderSet::new(); 13 | let impulse_joints = ImpulseJointSet::new(); 14 | let multibody_joints = MultibodyJointSet::new(); 15 | 16 | /* 17 | * Ground 18 | */ 19 | let ground_size = 100.1; 20 | let ground_height = 0.1; 21 | 22 | let rigid_body = RigidBodyBuilder::fixed().translation(vector![0.0, -ground_height, 0.0]); 23 | let handle = bodies.insert(rigid_body); 24 | let collider = ColliderBuilder::cuboid(ground_size, ground_height, ground_size); 25 | colliders.insert_with_parent(collider, handle, &mut bodies); 26 | 27 | /* 28 | * Create the cubes 29 | */ 30 | let num = 1; 31 | let rad = 1.0; 32 | 33 | let shiftx = rad * 2.0 + rad; 34 | let shifty = rad * 2.0 + rad; 35 | let shiftz = rad * 2.0 + rad; 36 | let centerx = shiftx * (num / 2) as f32; 37 | let centery = shifty / 2.0; 38 | let centerz = shiftz * (num / 2) as f32; 39 | 40 | let offset = -(num as f32) * (rad * 2.0 + rad) * 0.5; 41 | 42 | let x = -centerx + offset; 43 | let y = centery + 3.0; 44 | let z = -centerz + offset; 45 | 46 | // Build the rigid body. 47 | let rigid_body = RigidBodyBuilder::dynamic().translation(vector![x, y, z]); 48 | let handle = bodies.insert(rigid_body); 49 | let collider = ColliderBuilder::cylinder(rad, rad); 50 | colliders.insert_with_parent(collider, handle, &mut bodies); 51 | 52 | /* 53 | * Set up the testbed. 54 | */ 55 | testbed.set_world(bodies, colliders, impulse_joints, multibody_joints); 56 | testbed.look_at(point![100.0, 100.0, 100.0], Point::origin()); 57 | } 58 | -------------------------------------------------------------------------------- /examples3d/debug_deserialize3.rs: -------------------------------------------------------------------------------- 1 | use rapier3d::prelude::*; 2 | use rapier_testbed3d::Testbed; 3 | 4 | #[derive(serde::Deserialize)] 5 | struct PhysicsState { 6 | pub gravity: Vector, 7 | pub integration_parameters: IntegrationParameters, 8 | pub islands: IslandManager, 9 | pub broad_phase: DefaultBroadPhase, 10 | pub narrow_phase: NarrowPhase, 11 | pub bodies: RigidBodySet, 12 | pub colliders: ColliderSet, 13 | pub impulse_joints: ImpulseJointSet, 14 | pub multibody_joints: MultibodyJointSet, 15 | } 16 | 17 | pub fn init_world(testbed: &mut Testbed) { 18 | /* 19 | * Set up the testbed. 20 | */ 21 | let path = "state.bin"; 22 | let bytes = match std::fs::read(path) { 23 | Ok(bytes) => bytes, 24 | Err(err) => { 25 | println!( 26 | "Failed to open the serialzed scene file {:?}: {}", 27 | path, err 28 | ); 29 | return; 30 | } 31 | }; 32 | match bincode::deserialize(&bytes) { 33 | Ok(state) => { 34 | let state: PhysicsState = state; 35 | testbed.set_world( 36 | state.bodies, 37 | state.colliders, 38 | state.impulse_joints, 39 | state.multibody_joints, 40 | ); 41 | testbed.harness_mut().physics.islands = state.islands; 42 | testbed.harness_mut().physics.broad_phase = state.broad_phase; 43 | testbed.harness_mut().physics.narrow_phase = state.narrow_phase; 44 | testbed.harness_mut().physics.integration_parameters = state.integration_parameters; 45 | testbed.harness_mut().physics.gravity = state.gravity; 46 | 47 | testbed.set_graphics_shift(vector![-541.0, -6377257.0, -61.0]); 48 | testbed.look_at(point![10.0, 10.0, 10.0], point![0.0, 0.0, 0.0]); 49 | } 50 | Err(err) => println!("Failed to deserialize the world state: {}", err), 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /examples3d/debug_eccentric_boxes3.rs: -------------------------------------------------------------------------------- 1 | use rapier3d::prelude::*; 2 | use rapier_testbed3d::Testbed; 3 | 4 | pub fn init_world(testbed: &mut Testbed) { 5 | /* 6 | * World 7 | */ 8 | let mut bodies = RigidBodySet::new(); 9 | let mut colliders = ColliderSet::new(); 10 | let impulse_joints = ImpulseJointSet::new(); 11 | let multibody_joints = MultibodyJointSet::new(); 12 | 13 | /* 14 | * Ground 15 | */ 16 | let ground_size = 100.1; 17 | let ground_height = 0.1; 18 | 19 | let rigid_body = RigidBodyBuilder::fixed().translation(vector![0.0, -ground_height, 0.0]); 20 | let handle = bodies.insert(rigid_body); 21 | let collider = ColliderBuilder::cuboid(ground_size, ground_height, ground_size); 22 | colliders.insert_with_parent(collider, handle, &mut bodies); 23 | 24 | // Build the dynamic box rigid body. 25 | let (mut vtx, idx) = Cuboid::new(vector![1.0, 1.0, 1.0]).to_trimesh(); 26 | vtx.iter_mut() 27 | .for_each(|pt| *pt += vector![100.0, 100.0, 100.0]); 28 | let shape = SharedShape::convex_mesh(vtx, &idx).unwrap(); 29 | 30 | for _ in 0..2 { 31 | let rigid_body = RigidBodyBuilder::dynamic() 32 | .translation(vector![-100.0, -100.0 + 10.0, -100.0]) 33 | .can_sleep(false); 34 | let handle = bodies.insert(rigid_body); 35 | let collider = ColliderBuilder::new(shape.clone()); 36 | colliders.insert_with_parent(collider, handle, &mut bodies); 37 | } 38 | 39 | /* 40 | * Set up the testbed. 41 | */ 42 | testbed.set_world(bodies, colliders, impulse_joints, multibody_joints); 43 | testbed.look_at(point![10.0, 10.0, 10.0], Point::origin()); 44 | } 45 | -------------------------------------------------------------------------------- /examples3d/debug_friction3.rs: -------------------------------------------------------------------------------- 1 | use rapier3d::prelude::*; 2 | use rapier_testbed3d::Testbed; 3 | 4 | pub fn init_world(testbed: &mut Testbed) { 5 | /* 6 | * World 7 | */ 8 | let mut bodies = RigidBodySet::new(); 9 | let mut colliders = ColliderSet::new(); 10 | let impulse_joints = ImpulseJointSet::new(); 11 | let multibody_joints = MultibodyJointSet::new(); 12 | 13 | /* 14 | * Ground 15 | */ 16 | let ground_size = 100.0; 17 | let ground_height = 0.1; 18 | 19 | let rigid_body = RigidBodyBuilder::fixed(); 20 | let handle = bodies.insert(rigid_body); 21 | let collider = ColliderBuilder::cuboid(ground_size, ground_height, ground_size).friction(1.5); 22 | colliders.insert_with_parent(collider, handle, &mut bodies); 23 | 24 | // Build a dynamic box rigid body. 25 | let rigid_body = RigidBodyBuilder::dynamic() 26 | .translation(vector![0.0, 1.1, 0.0]) 27 | .rotation(Vector::y() * 0.3); 28 | let handle = bodies.insert(rigid_body); 29 | let collider = ColliderBuilder::cuboid(2.0, 1.0, 3.0).friction(1.5); 30 | colliders.insert_with_parent(collider, handle, &mut bodies); 31 | 32 | let rigid_body = &mut bodies[handle]; 33 | let force = rigid_body.position() * Vector::z() * 50.0; 34 | rigid_body.set_linvel(force, true); 35 | 36 | /* 37 | * Set up the testbed. 38 | */ 39 | testbed.set_world(bodies, colliders, impulse_joints, multibody_joints); 40 | testbed.look_at(point![100.0, 100.0, 100.0], Point::origin()); 41 | } 42 | -------------------------------------------------------------------------------- /examples3d/debug_infinite_fall3.rs: -------------------------------------------------------------------------------- 1 | use rapier3d::prelude::*; 2 | use rapier_testbed3d::Testbed; 3 | 4 | pub fn init_world(testbed: &mut Testbed) { 5 | /* 6 | * World 7 | */ 8 | let mut bodies = RigidBodySet::new(); 9 | let mut colliders = ColliderSet::new(); 10 | let impulse_joints = ImpulseJointSet::new(); 11 | let multibody_joints = MultibodyJointSet::new(); 12 | 13 | /* 14 | * Ground 15 | */ 16 | let ground_size = 100.1; 17 | let ground_height = 2.1; 18 | 19 | let rigid_body = RigidBodyBuilder::fixed().translation(vector![0.0, 4.0, 0.0]); 20 | let handle = bodies.insert(rigid_body); 21 | let collider = ColliderBuilder::cuboid(ground_size, ground_height, ground_size); 22 | colliders.insert_with_parent(collider, handle, &mut bodies); 23 | 24 | let rad = 1.0; 25 | // Build the dynamic box rigid body. 26 | let rigid_body = RigidBodyBuilder::dynamic() 27 | .translation(vector![0.0, 7.0 * rad, 0.0]) 28 | .can_sleep(false); 29 | let handle = bodies.insert(rigid_body); 30 | let collider = ColliderBuilder::ball(rad); 31 | colliders.insert_with_parent(collider, handle, &mut bodies); 32 | 33 | let rigid_body = RigidBodyBuilder::dynamic() 34 | .translation(vector![0.0, 2.0 * rad, 0.0]) 35 | .can_sleep(false); 36 | let handle = bodies.insert(rigid_body); 37 | let collider = ColliderBuilder::ball(rad); 38 | colliders.insert_with_parent(collider, handle, &mut bodies); 39 | 40 | /* 41 | * Set up the testbed. 42 | */ 43 | testbed.look_at(point![100.0, -10.0, 100.0], Point::origin()); 44 | testbed.set_world(bodies, colliders, impulse_joints, multibody_joints); 45 | } 46 | -------------------------------------------------------------------------------- /examples3d/debug_internal_edges3.rs: -------------------------------------------------------------------------------- 1 | use rapier3d::prelude::*; 2 | use rapier_testbed3d::Testbed; 3 | 4 | pub fn init_world(testbed: &mut Testbed) { 5 | /* 6 | * World 7 | */ 8 | let mut bodies = RigidBodySet::new(); 9 | let mut colliders = ColliderSet::new(); 10 | let impulse_joints = ImpulseJointSet::new(); 11 | let multibody_joints = MultibodyJointSet::new(); 12 | 13 | let heights = DMatrix::zeros(100, 100); 14 | let heightfield = 15 | HeightField::with_flags(heights, vector![60.0, 1.0, 60.0], HeightFieldFlags::all()); 16 | let rotation = vector![0.0, 0.0, 0.0]; // vector![-0.1, 0.0, 0.0]; 17 | colliders 18 | .insert(ColliderBuilder::new(SharedShape::new(heightfield.clone())).rotation(rotation)); 19 | 20 | // let mut trimesh = TriMesh::from(heightfield); 21 | // trimesh.set_flags(TriMeshFlags::MERGE_DUPLICATE_VERTICES) 22 | // colliders.insert(ColliderBuilder::new(SharedShape::new(trimesh.clone())).rotation(rotation)); 23 | // // NOTE: we add a sensor just because we want the testbed to display the mesh’s wireframe. 24 | // colliders.insert( 25 | // ColliderBuilder::new(SharedShape::new(trimesh)) 26 | // .sensor(true) 27 | // .rotation(rotation), 28 | // ); 29 | 30 | // Dynamic rigid bodies. 31 | let rigid_body = RigidBodyBuilder::dynamic() 32 | .translation(vector![4.0, 0.5, 0.0]) 33 | .linvel(vector![0.0, -40.0, 20.0]) 34 | .can_sleep(false); 35 | let handle = bodies.insert(rigid_body); 36 | let collider = ColliderBuilder::ball(0.5); 37 | colliders.insert_with_parent(collider, handle, &mut bodies); 38 | 39 | let rigid_body = RigidBodyBuilder::dynamic() 40 | .translation(vector![-3.0, 5.0, 0.0]) 41 | .linvel(vector![0.0, -4.0, 20.0]) 42 | .can_sleep(false); 43 | let handle = bodies.insert(rigid_body); 44 | let collider = ColliderBuilder::cuboid(0.5, 0.5, 0.5); 45 | colliders.insert_with_parent(collider, handle, &mut bodies); 46 | 47 | let rigid_body = RigidBodyBuilder::dynamic() 48 | .translation(vector![8.0, 0.2, 0.0]) 49 | .linvel(vector![0.0, -4.0, 20.0]) 50 | .can_sleep(false); 51 | let handle = bodies.insert(rigid_body); 52 | let collider = 53 | ColliderBuilder::cylinder(0.5, 0.2).rotation(vector![0.0, 0.0, std::f32::consts::PI / 2.0]); 54 | colliders.insert_with_parent(collider, handle, &mut bodies); 55 | 56 | /* 57 | * Set up the testbed. 58 | */ 59 | testbed.set_world(bodies, colliders, impulse_joints, multibody_joints); 60 | testbed.look_at(point![10.0, 10.0, 10.0], Point::origin()); 61 | } 62 | -------------------------------------------------------------------------------- /examples3d/debug_long_chain3.rs: -------------------------------------------------------------------------------- 1 | use rapier3d::prelude::*; 2 | use rapier_testbed3d::Testbed; 3 | 4 | pub fn init_world(testbed: &mut Testbed) { 5 | /* 6 | * World 7 | */ 8 | let mut bodies = RigidBodySet::new(); 9 | let mut colliders = ColliderSet::new(); 10 | let mut impulse_joints = ImpulseJointSet::new(); 11 | let mut multibody_joints = MultibodyJointSet::new(); 12 | let use_articulations = false; 13 | 14 | /* 15 | * Create the long chain. 16 | */ 17 | let num = 100; 18 | let rad = 0.2; 19 | let shift = rad * 2.2; 20 | 21 | let mut body_handles = Vec::new(); 22 | 23 | for i in 0..num { 24 | let fi = i as f32; 25 | 26 | let status = if i == 0 { 27 | RigidBodyType::Fixed 28 | } else { 29 | RigidBodyType::Dynamic 30 | }; 31 | 32 | let rigid_body = RigidBodyBuilder::new(status).translation(vector![0.0, 0.0, fi * shift]); 33 | let child_handle = bodies.insert(rigid_body); 34 | let collider = ColliderBuilder::ball(rad); 35 | colliders.insert_with_parent(collider, child_handle, &mut bodies); 36 | 37 | // Vertical joint. 38 | if i > 0 { 39 | let parent_handle = *body_handles.last().unwrap(); 40 | let joint = if i == 1 { 41 | SphericalJointBuilder::new().local_anchor2(point![0.0, 0.0, -shift]) 42 | } else { 43 | SphericalJointBuilder::new() 44 | .local_anchor1(point![0.0, 0.0, shift / 2.0]) 45 | .local_anchor2(point![0.0, 0.0, -shift / 2.0]) 46 | }; 47 | 48 | if use_articulations { 49 | multibody_joints.insert(parent_handle, child_handle, joint, true); 50 | } else { 51 | impulse_joints.insert(parent_handle, child_handle, joint, true); 52 | } 53 | } 54 | 55 | body_handles.push(child_handle); 56 | } 57 | 58 | /* 59 | * Set up the testbed. 60 | */ 61 | testbed.set_world(bodies, colliders, impulse_joints, multibody_joints); 62 | testbed.look_at(point![10.0, 10.0, 10.0], Point::origin()); 63 | } 64 | -------------------------------------------------------------------------------- /examples3d/debug_multibody_ang_motor_pos3.rs: -------------------------------------------------------------------------------- 1 | use rapier3d::prelude::*; 2 | use rapier_testbed3d::Testbed; 3 | 4 | pub fn init_world(testbed: &mut Testbed) { 5 | let mut bodies = RigidBodySet::new(); 6 | let mut colliders = ColliderSet::new(); 7 | let impulse_joints = ImpulseJointSet::new(); 8 | let mut multibody_joints = MultibodyJointSet::new(); 9 | 10 | let ground = RigidBodyBuilder::fixed().translation(vector![0.0, 0.0, 0.0]); 11 | let body = bodies.insert(ground); 12 | let collider = ColliderBuilder::cuboid(1.0, 1.0, 1.0); 13 | colliders.insert_with_parent(collider, body, &mut bodies); 14 | 15 | let rigid_body = RigidBodyBuilder::dynamic().position(Isometry::translation(0.0, 1.0, 0.0)); 16 | let body_part = bodies.insert(rigid_body); 17 | let collider = ColliderBuilder::cuboid(1.0, 1.0, 1.0).density(1.0); 18 | colliders.insert_with_parent(collider, body_part, &mut bodies); 19 | 20 | let joint = SphericalJointBuilder::new() 21 | .local_anchor1(point![0.0, 4.0, 0.0]) 22 | .local_anchor2(point![0.0, 0.0, 0.0]) 23 | .motor_position(JointAxis::AngX, 1.0, 1000.0, 200.0) 24 | .motor_position(JointAxis::AngY, 0.0, 1000.0, 200.0) 25 | .motor_position(JointAxis::AngZ, 0.0, 1000.0, 200.0); 26 | 27 | multibody_joints.insert(body, body_part, joint, true); 28 | 29 | testbed.set_world(bodies, colliders, impulse_joints, multibody_joints); 30 | testbed.look_at(point![20.0, 0.0, 0.0], point![0.0, 0.0, 0.0]); 31 | } 32 | -------------------------------------------------------------------------------- /examples3d/debug_pop3.rs: -------------------------------------------------------------------------------- 1 | use rapier3d::prelude::*; 2 | use rapier_testbed3d::Testbed; 3 | 4 | pub fn init_world(testbed: &mut Testbed) { 5 | /* 6 | * World 7 | */ 8 | let mut bodies = RigidBodySet::new(); 9 | let mut colliders = ColliderSet::new(); 10 | let impulse_joints = ImpulseJointSet::new(); 11 | let multibody_joints = MultibodyJointSet::new(); 12 | 13 | /* 14 | * Ground 15 | */ 16 | let ground_size = 10.0; 17 | let ground_height = 10.0; 18 | 19 | for _ in 0..1 { 20 | let rigid_body = RigidBodyBuilder::fixed().translation(vector![0.0, -ground_height, 0.0]); 21 | let handle = bodies.insert(rigid_body); 22 | let collider = ColliderBuilder::cuboid(ground_size, ground_height, ground_size); 23 | colliders.insert_with_parent(collider, handle, &mut bodies); 24 | } 25 | 26 | // Build the dynamic box rigid body. 27 | for _ in 0..1 { 28 | let rigid_body = RigidBodyBuilder::dynamic() 29 | // .translation(vector![0.0, 0.1, 0.0]) 30 | // .rotation(vector![0.8, 0.2, 0.1]) 31 | .can_sleep(false); 32 | let handle = bodies.insert(rigid_body); 33 | let collider = ColliderBuilder::cuboid(1.0, 1.0, 1.0); 34 | colliders.insert_with_parent(collider.clone(), handle, &mut bodies); 35 | } 36 | 37 | /* 38 | * Set up the testbed. 39 | */ 40 | testbed.set_world(bodies, colliders, impulse_joints, multibody_joints); 41 | testbed.look_at(point![10.0, 10.0, 10.0], Point::origin()); 42 | } 43 | -------------------------------------------------------------------------------- /examples3d/debug_rollback3.rs: -------------------------------------------------------------------------------- 1 | use rapier3d::prelude::*; 2 | use rapier_testbed3d::Testbed; 3 | 4 | pub fn init_world(testbed: &mut Testbed) { 5 | /* 6 | * World 7 | */ 8 | let mut bodies = RigidBodySet::new(); 9 | let mut colliders = ColliderSet::new(); 10 | let impulse_joints = ImpulseJointSet::new(); 11 | let multibody_joints = MultibodyJointSet::new(); 12 | 13 | /* 14 | * Ground. 15 | */ 16 | let ground_size = 20.0; 17 | let ground_height = 0.1; 18 | 19 | let rigid_body = RigidBodyBuilder::fixed().translation(vector![0.0, -ground_height, 0.0]); 20 | let ground_handle = bodies.insert(rigid_body); 21 | let collider = ColliderBuilder::cuboid(ground_size, ground_height, 0.4) 22 | .friction(0.15) 23 | // .restitution(0.5) 24 | ; 25 | colliders.insert_with_parent(collider, ground_handle, &mut bodies); 26 | 27 | /* 28 | * Rolling ball 29 | */ 30 | let ball_rad = 0.1; 31 | let rb = RigidBodyBuilder::dynamic() 32 | .translation(vector![0.0, 0.2, 0.0]) 33 | .linvel(vector![10.0, 0.0, 0.0]); 34 | let ball_handle = bodies.insert(rb); 35 | let collider = ColliderBuilder::ball(ball_rad).density(100.0); 36 | colliders.insert_with_parent(collider, ball_handle, &mut bodies); 37 | 38 | let mut linvel = Vector::zeros(); 39 | let mut angvel = Vector::zeros(); 40 | let mut pos = Isometry::identity(); 41 | let mut step = 0; 42 | let snapped_frame = 51; 43 | 44 | testbed.add_callback(move |_, physics, _, _| { 45 | step += 1; 46 | 47 | // Snap the ball velocity or restore it. 48 | let ball = physics.bodies.get_mut(ball_handle).unwrap(); 49 | 50 | if step == snapped_frame { 51 | linvel = *ball.linvel(); 52 | angvel = *ball.angvel(); 53 | pos = *ball.position(); 54 | } 55 | 56 | if step == 100 { 57 | ball.set_linvel(linvel, true); 58 | ball.set_angvel(angvel, true); 59 | ball.set_position(pos, true); 60 | step = snapped_frame; 61 | } 62 | }); 63 | 64 | /* 65 | * Set up the testbed. 66 | */ 67 | testbed.set_world(bodies, colliders, impulse_joints, multibody_joints); 68 | testbed.look_at(point![10.0, 10.0, 10.0], Point::origin()); 69 | } 70 | -------------------------------------------------------------------------------- /examples3d/debug_thin_cube_on_mesh3.rs: -------------------------------------------------------------------------------- 1 | use rapier3d::prelude::*; 2 | use rapier_testbed3d::Testbed; 3 | 4 | // This shows a bug when a cylinder is in contact with a very large 5 | // but very thin cuboid. In this case the EPA returns an incorrect 6 | // contact normal, resulting in the cylinder falling through the floor. 7 | pub fn init_world(testbed: &mut Testbed) { 8 | /* 9 | * World 10 | */ 11 | let mut bodies = RigidBodySet::new(); 12 | let mut colliders = ColliderSet::new(); 13 | let impulse_joints = ImpulseJointSet::new(); 14 | let multibody_joints = MultibodyJointSet::new(); 15 | 16 | /* 17 | * Ground 18 | */ 19 | // let vertices = vec![ 20 | // point![-50.0, 0.0, -50.0], 21 | // point![-50.0, 0.0, 50.0], 22 | // point![50.0, 0.0, 50.0], 23 | // point![50.0, 0.0, -50.0], 24 | // ]; 25 | // let indices = vec![[0, 1, 2], [0, 2, 3]]; 26 | // 27 | // let collider = ColliderBuilder::trimesh_with_flags(vertices, indices, TriMeshFlags::all()); 28 | // colliders.insert(collider); 29 | 30 | let heights = DMatrix::repeat(2, 2, 0.0); 31 | let collider = ColliderBuilder::heightfield_with_flags( 32 | heights, 33 | Vector::new(50.0, 1.0, 50.0), 34 | HeightFieldFlags::FIX_INTERNAL_EDGES, 35 | ); 36 | colliders.insert(collider); 37 | 38 | /* 39 | * Create the cubes 40 | */ 41 | // Build the rigid body. 42 | let rigid_body = RigidBodyBuilder::dynamic() 43 | .translation(vector![0.0, 5.0, 0.0]) 44 | .rotation(vector![0.5, 0.0, 0.5]) 45 | .linvel(vector![0.0, -100.0, 0.0]) 46 | .soft_ccd_prediction(10.0); 47 | let handle = bodies.insert(rigid_body); 48 | let collider = ColliderBuilder::cuboid(5.0, 0.015, 5.0); 49 | colliders.insert_with_parent(collider, handle, &mut bodies); 50 | 51 | /* 52 | * Set up the testbed. 53 | */ 54 | testbed.set_world(bodies, colliders, impulse_joints, multibody_joints); 55 | testbed.look_at(point![100.0, 100.0, 100.0], Point::origin()); 56 | } 57 | -------------------------------------------------------------------------------- /examples3d/debug_triangle3.rs: -------------------------------------------------------------------------------- 1 | use rapier3d::prelude::*; 2 | use rapier_testbed3d::Testbed; 3 | 4 | pub fn init_world(testbed: &mut Testbed) { 5 | /* 6 | * World 7 | */ 8 | let mut bodies = RigidBodySet::new(); 9 | let mut colliders = ColliderSet::new(); 10 | let impulse_joints = ImpulseJointSet::new(); 11 | let multibody_joints = MultibodyJointSet::new(); 12 | 13 | // Triangle ground. 14 | let vtx = [ 15 | point![-10.0, 0.0, -10.0], 16 | point![10.0, 0.0, -10.0], 17 | point![0.0, 0.0, 10.0], 18 | ]; 19 | 20 | let rigid_body = RigidBodyBuilder::fixed().translation(vector![0.0, 0.0, 0.0]); 21 | let handle = bodies.insert(rigid_body); 22 | let collider = ColliderBuilder::triangle(vtx[0], vtx[1], vtx[2]); 23 | colliders.insert_with_parent(collider, handle, &mut bodies); 24 | 25 | // Dynamic box rigid body. 26 | let rigid_body = RigidBodyBuilder::dynamic() 27 | .translation(vector![1.1, 0.01, 0.0]) 28 | // .rotation(Vector3::new(0.8, 0.2, 0.1)) 29 | .can_sleep(false); 30 | let handle = bodies.insert(rigid_body); 31 | let collider = ColliderBuilder::cuboid(20.0, 0.1, 1.0); 32 | colliders.insert_with_parent(collider, handle, &mut bodies); 33 | 34 | /* 35 | * Set up the testbed. 36 | */ 37 | testbed.set_world(bodies, colliders, impulse_joints, multibody_joints); 38 | testbed.look_at(point![10.0, 10.0, 10.0], Point::origin()); 39 | } 40 | -------------------------------------------------------------------------------- /examples3d/debug_trimesh3.rs: -------------------------------------------------------------------------------- 1 | use rapier3d::prelude::*; 2 | use rapier_testbed3d::Testbed; 3 | 4 | pub fn init_world(testbed: &mut Testbed) { 5 | /* 6 | * World 7 | */ 8 | let mut bodies = RigidBodySet::new(); 9 | let mut colliders = ColliderSet::new(); 10 | let impulse_joints = ImpulseJointSet::new(); 11 | let multibody_joints = MultibodyJointSet::new(); 12 | 13 | // Triangle ground. 14 | let width = 0.5; 15 | let vtx = vec![ 16 | point![-width, 0.0, -width], 17 | point![width, 0.0, -width], 18 | point![width, 0.0, width], 19 | point![-width, 0.0, width], 20 | point![-width, -width, -width], 21 | point![width, -width, -width], 22 | point![width, -width, width], 23 | point![-width, -width, width], 24 | ]; 25 | let idx = vec![ 26 | [0, 2, 1], 27 | [0, 3, 2], 28 | [4, 5, 6], 29 | [4, 6, 7], 30 | [0, 4, 7], 31 | [0, 7, 3], 32 | [1, 6, 5], 33 | [1, 2, 6], 34 | [3, 7, 2], 35 | [2, 7, 6], 36 | [0, 1, 5], 37 | [0, 5, 4], 38 | ]; 39 | 40 | // Dynamic box rigid body. 41 | let rigid_body = RigidBodyBuilder::dynamic() 42 | .translation(vector![0.0, 35.0, 0.0]) 43 | // .rotation(Vector3::new(0.8, 0.2, 0.1)) 44 | .can_sleep(false); 45 | let handle = bodies.insert(rigid_body); 46 | let collider = ColliderBuilder::cuboid(1.0, 2.0, 1.0); 47 | colliders.insert_with_parent(collider, handle, &mut bodies); 48 | 49 | let rigid_body = RigidBodyBuilder::fixed().translation(vector![0.0, 0.0, 0.0]); 50 | let handle = bodies.insert(rigid_body); 51 | let collider = ColliderBuilder::trimesh(vtx, idx).expect("Could not create trimesh collider."); 52 | colliders.insert_with_parent(collider, handle, &mut bodies); 53 | testbed.set_initial_body_color(handle, [0.3, 0.3, 0.3]); 54 | 55 | /* 56 | * Set up the testbed. 57 | */ 58 | testbed.set_world(bodies, colliders, impulse_joints, multibody_joints); 59 | testbed.look_at(point![10.0, 10.0, 10.0], Point::origin()); 60 | } 61 | -------------------------------------------------------------------------------- /examples3d/harness_capsules3.rs: -------------------------------------------------------------------------------- 1 | use rapier3d::prelude::*; 2 | use rapier_testbed3d::harness::Harness; 3 | 4 | pub fn init_world(harness: &mut Harness) { 5 | /* 6 | * World 7 | */ 8 | let mut bodies = RigidBodySet::new(); 9 | let mut colliders = ColliderSet::new(); 10 | let impulse_joints = ImpulseJointSet::new(); 11 | let multibody_joints = MultibodyJointSet::new(); 12 | 13 | /* 14 | * Ground 15 | */ 16 | let ground_size = 200.1; 17 | let ground_height = 0.1; 18 | 19 | let rigid_body = RigidBodyBuilder::fixed().translation(vector![0.0, -ground_height, 0.0]); 20 | let handle = bodies.insert(rigid_body); 21 | let collider = ColliderBuilder::cuboid(ground_size, ground_height, ground_size); 22 | colliders.insert_with_parent(collider, handle, &mut bodies); 23 | 24 | /* 25 | * Create the cubes 26 | */ 27 | let num = 8; 28 | let rad = 1.0; 29 | 30 | let shift = rad * 2.0 + rad; 31 | let shifty = rad * 4.0; 32 | let centerx = shift * (num / 2) as f32; 33 | let centery = shift / 2.0; 34 | let centerz = shift * (num / 2) as f32; 35 | 36 | let mut offset = -(num as f32) * (rad * 2.0 + rad) * 0.5; 37 | 38 | for j in 0usize..47 { 39 | for i in 0..num { 40 | for k in 0usize..num { 41 | let x = i as f32 * shift - centerx + offset; 42 | let y = j as f32 * shifty + centery + 3.0; 43 | let z = k as f32 * shift - centerz + offset; 44 | 45 | // Build the rigid body. 46 | let rigid_body = RigidBodyBuilder::dynamic().translation(vector![x, y, z]); 47 | let handle = bodies.insert(rigid_body); 48 | let collider = ColliderBuilder::capsule_y(rad, rad); 49 | colliders.insert_with_parent(collider, handle, &mut bodies); 50 | } 51 | } 52 | 53 | offset -= 0.05 * rad * (num as f32 - 1.0); 54 | } 55 | 56 | /* 57 | * Set up the harness. 58 | */ 59 | harness.set_world(bodies, colliders, impulse_joints, multibody_joints); 60 | } 61 | 62 | fn main() { 63 | let harness = &mut Harness::new_empty(); 64 | init_world(harness); 65 | harness.set_max_steps(10000); 66 | harness.run(); 67 | println!("{}", harness.state.timestep_id); 68 | } 69 | -------------------------------------------------------------------------------- /examples3d/locked_rotations3.rs: -------------------------------------------------------------------------------- 1 | use rapier3d::prelude::*; 2 | use rapier_testbed3d::Testbed; 3 | 4 | // This shows a bug when a cylinder is in contact with a very large 5 | // but very thin cuboid. In this case the EPA returns an incorrect 6 | // contact normal, resulting in the cylinder falling through the floor. 7 | pub fn init_world(testbed: &mut Testbed) { 8 | /* 9 | * World 10 | */ 11 | let mut bodies = RigidBodySet::new(); 12 | let mut colliders = ColliderSet::new(); 13 | let impulse_joints = ImpulseJointSet::new(); 14 | let multibody_joints = MultibodyJointSet::new(); 15 | 16 | /* 17 | * The ground 18 | */ 19 | let ground_size = 5.0; 20 | let ground_height = 0.1; 21 | 22 | let rigid_body = RigidBodyBuilder::fixed().translation(vector![0.0, -ground_height, 0.0]); 23 | let handle = bodies.insert(rigid_body); 24 | let collider = ColliderBuilder::cuboid(ground_size, ground_height, ground_size); 25 | colliders.insert_with_parent(collider, handle, &mut bodies); 26 | 27 | /* 28 | * A rectangle that only rotates along the `x` axis. 29 | */ 30 | let rigid_body = RigidBodyBuilder::dynamic() 31 | .translation(vector![0.0, 3.0, 0.0]) 32 | .lock_translations() 33 | .enabled_rotations(true, false, false); 34 | let handle = bodies.insert(rigid_body); 35 | let collider = ColliderBuilder::cuboid(0.2, 0.6, 2.0); 36 | colliders.insert_with_parent(collider, handle, &mut bodies); 37 | 38 | /* 39 | * A tilted capsule that cannot rotate. 40 | */ 41 | let rigid_body = RigidBodyBuilder::dynamic() 42 | .translation(vector![0.0, 5.0, 0.0]) 43 | .rotation(Vector::x() * 1.0) 44 | .lock_rotations(); 45 | let handle = bodies.insert(rigid_body); 46 | let collider = ColliderBuilder::capsule_y(0.6, 0.4); 47 | colliders.insert_with_parent(collider, handle, &mut bodies); 48 | let collider = ColliderBuilder::capsule_x(0.6, 0.4); 49 | colliders.insert_with_parent(collider, handle, &mut bodies); 50 | 51 | /* 52 | * Set up the testbed. 53 | */ 54 | testbed.set_world(bodies, colliders, impulse_joints, multibody_joints); 55 | testbed.look_at(point![10.0, 3.0, 0.0], point![0.0, 3.0, 0.0]); 56 | } 57 | -------------------------------------------------------------------------------- /examples3d/newton_cradle3.rs: -------------------------------------------------------------------------------- 1 | use rapier3d::prelude::*; 2 | use rapier_testbed3d::Testbed; 3 | 4 | pub fn init_world(testbed: &mut Testbed) { 5 | /* 6 | * World 7 | */ 8 | let mut bodies = RigidBodySet::new(); 9 | let mut colliders = ColliderSet::new(); 10 | let mut impulse_joints = ImpulseJointSet::new(); 11 | let multibody_joints = MultibodyJointSet::new(); 12 | 13 | let radius = 0.5; 14 | let length = 10.0 * radius; 15 | let rb = RigidBodyBuilder::dynamic(); 16 | let co = ColliderBuilder::ball(radius).restitution(1.0); 17 | 18 | let n = 5; 19 | 20 | for i in 0..n { 21 | let (ball_pos, attach) = ( 22 | vector![i as Real * 2.2 * radius, 0.0, 0.0], 23 | Vector::y() * length, 24 | ); 25 | let vel = if i >= n - 1 { 26 | vector![7.0, 0.0, 0.0] 27 | } else { 28 | Vector::zeros() 29 | }; 30 | 31 | let ground = bodies.insert(RigidBodyBuilder::fixed().translation(ball_pos + attach)); 32 | let rb = rb.clone().translation(ball_pos).linvel(vel); 33 | let handle = bodies.insert(rb); 34 | colliders.insert_with_parent(co.clone(), handle, &mut bodies); 35 | 36 | let joint = SphericalJointBuilder::new().local_anchor2(attach.into()); 37 | impulse_joints.insert(ground, handle, joint, true); 38 | } 39 | 40 | /* 41 | * Set up the testbed. 42 | */ 43 | testbed.set_world(bodies, colliders, impulse_joints, multibody_joints); 44 | testbed.look_at(point![100.0, 100.0, 100.0], Point::origin()); 45 | } 46 | -------------------------------------------------------------------------------- /examples3d/primitives3.rs: -------------------------------------------------------------------------------- 1 | use rapier3d::prelude::*; 2 | use rapier_testbed3d::Testbed; 3 | 4 | pub fn init_world(testbed: &mut Testbed) { 5 | /* 6 | * World 7 | */ 8 | let mut bodies = RigidBodySet::new(); 9 | let mut colliders = ColliderSet::new(); 10 | let impulse_joints = ImpulseJointSet::new(); 11 | let multibody_joints = MultibodyJointSet::new(); 12 | 13 | /* 14 | * Ground 15 | */ 16 | let ground_size = 100.1; 17 | let ground_height = 2.1; 18 | 19 | let rigid_body = RigidBodyBuilder::fixed().translation(vector![0.0, -ground_height, 0.0]); 20 | let handle = bodies.insert(rigid_body); 21 | let collider = ColliderBuilder::cuboid(ground_size, ground_height, ground_size); 22 | colliders.insert_with_parent(collider, handle, &mut bodies); 23 | 24 | /* 25 | * Create the primitives 26 | */ 27 | let num = 8; 28 | let rad = 1.0; 29 | 30 | let shiftx = rad * 2.0 + rad; 31 | let shifty = rad * 2.0 + rad; 32 | let shiftz = rad * 2.0 + rad; 33 | let centerx = shiftx * (num / 2) as f32; 34 | let centery = shifty / 2.0; 35 | let centerz = shiftz * (num / 2) as f32; 36 | 37 | let mut offset = -(num as f32) * (rad * 2.0 + rad) * 0.5; 38 | 39 | for j in 0usize..20 { 40 | for i in 0..num { 41 | for k in 0usize..num { 42 | let x = i as f32 * shiftx - centerx + offset; 43 | let y = j as f32 * shifty + centery + 3.0; 44 | let z = k as f32 * shiftz - centerz + offset; 45 | 46 | // Build the rigid body. 47 | let rigid_body = RigidBodyBuilder::dynamic().translation(vector![x, y, z]); 48 | let handle = bodies.insert(rigid_body); 49 | 50 | let collider = match j % 5 { 51 | // _ => ColliderBuilder::cuboid(rad, rad, rad), 52 | 1 => ColliderBuilder::ball(rad), 53 | // Rounded cylinders are much more efficient that cylinder, even if the 54 | // rounding margin is small. 55 | 2 => ColliderBuilder::round_cylinder(rad, rad, rad / 10.0), 56 | 3 => ColliderBuilder::cone(rad, rad), 57 | _ => ColliderBuilder::capsule_y(rad, rad), 58 | }; 59 | 60 | colliders.insert_with_parent(collider, handle, &mut bodies); 61 | } 62 | } 63 | 64 | offset -= 0.05 * rad * (num as f32 - 1.0); 65 | } 66 | 67 | /* 68 | * Set up the testbed. 69 | */ 70 | testbed.set_world(bodies, colliders, impulse_joints, multibody_joints); 71 | testbed.look_at(point![100.0, 100.0, 100.0], Point::origin()); 72 | } 73 | -------------------------------------------------------------------------------- /examples3d/rapier.data: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dimforge/rapier/cd7fc6e11f26db67c51db0713a53d4e3951dfe3f/examples3d/rapier.data -------------------------------------------------------------------------------- /examples3d/restitution3.rs: -------------------------------------------------------------------------------- 1 | use rapier3d::prelude::*; 2 | use rapier_testbed3d::Testbed; 3 | 4 | pub fn init_world(testbed: &mut Testbed) { 5 | /* 6 | * World 7 | */ 8 | let mut bodies = RigidBodySet::new(); 9 | let mut colliders = ColliderSet::new(); 10 | let impulse_joints = ImpulseJointSet::new(); 11 | let multibody_joints = MultibodyJointSet::new(); 12 | 13 | /* 14 | * Ground 15 | */ 16 | let ground_size = 20.; 17 | let ground_height = 1.0; 18 | 19 | let rigid_body = RigidBodyBuilder::fixed().translation(vector![0.0, -ground_height, 0.0]); 20 | let handle = bodies.insert(rigid_body); 21 | let collider = ColliderBuilder::cuboid(ground_size, ground_height, 2.0).restitution(1.0); 22 | colliders.insert_with_parent(collider, handle, &mut bodies); 23 | 24 | let num = 10; 25 | let rad = 0.5; 26 | 27 | for j in 0..2 { 28 | for i in 0..=num { 29 | let x = (i as f32) - num as f32 / 2.0; 30 | let rigid_body = RigidBodyBuilder::dynamic().translation(vector![ 31 | x * 2.0, 32 | 10.0 * (j as f32 + 1.0), 33 | 0.0 34 | ]); 35 | let handle = bodies.insert(rigid_body); 36 | let collider = ColliderBuilder::ball(rad).restitution((i as f32) / (num as f32)); 37 | colliders.insert_with_parent(collider, handle, &mut bodies); 38 | } 39 | } 40 | 41 | /* 42 | * Set up the testbed. 43 | */ 44 | testbed.set_world(bodies, colliders, impulse_joints, multibody_joints); 45 | testbed.look_at(point![0.0, 3.0, 30.0], point![0.0, 3.0, 0.0]); 46 | } 47 | -------------------------------------------------------------------------------- /examples3d/spring_joints3.rs: -------------------------------------------------------------------------------- 1 | use rapier3d::prelude::*; 2 | use rapier_testbed3d::Testbed; 3 | 4 | pub fn init_world(testbed: &mut Testbed) { 5 | /* 6 | * World 7 | */ 8 | let mut bodies = RigidBodySet::new(); 9 | let mut colliders = ColliderSet::new(); 10 | let mut impulse_joints = ImpulseJointSet::new(); 11 | let multibody_joints = MultibodyJointSet::new(); 12 | 13 | /* 14 | * Fixed ground to attach one end of the joints. 15 | */ 16 | let rigid_body = RigidBodyBuilder::fixed(); 17 | let ground_handle = bodies.insert(rigid_body); 18 | 19 | /* 20 | * Spring joints with a variety of spring parameters. 21 | * The middle one has uses critical damping. 22 | */ 23 | let num = 30; 24 | let radius = 0.5; 25 | let mass = Ball::new(radius).mass_properties(1.0).mass(); 26 | let stiffness = 1.0e3; 27 | let critical_damping = 2.0 * (stiffness * mass).sqrt(); 28 | for i in 0..=num { 29 | let x_pos = -6.0 + 1.5 * i as f32; 30 | let ball_pos = point![x_pos, 4.5, 0.0]; 31 | let rigid_body = RigidBodyBuilder::dynamic() 32 | .translation(ball_pos.coords) 33 | .can_sleep(false); 34 | let handle = bodies.insert(rigid_body); 35 | let collider = ColliderBuilder::ball(radius); 36 | colliders.insert_with_parent(collider, handle, &mut bodies); 37 | 38 | let damping_ratio = i as f32 / (num as f32 / 2.0); 39 | let damping = damping_ratio * critical_damping; 40 | let joint = SpringJointBuilder::new(0.0, stiffness, damping) 41 | .local_anchor1(ball_pos - Vector::y() * 3.0); 42 | impulse_joints.insert(ground_handle, handle, joint, true); 43 | 44 | // Box that will fall on to of the springed balls, makes the simulation funier to watch. 45 | let rigid_body = 46 | RigidBodyBuilder::dynamic().translation(ball_pos.coords + Vector::y() * 5.0); 47 | let handle = bodies.insert(rigid_body); 48 | let collider = ColliderBuilder::cuboid(radius, radius, radius).density(100.0); 49 | colliders.insert_with_parent(collider, handle, &mut bodies); 50 | } 51 | 52 | /* 53 | * Set up the testbed. 54 | */ 55 | testbed.set_world_with_params( 56 | bodies, 57 | colliders, 58 | impulse_joints, 59 | multibody_joints, 60 | vector![0.0, -9.81, 0.0], 61 | (), 62 | ); 63 | testbed.look_at(point![15.0, 5.0, 42.0], point![13.0, 1.0, 1.0]); 64 | } 65 | -------------------------------------------------------------------------------- /examples3d/urdf3.rs: -------------------------------------------------------------------------------- 1 | use rapier3d::prelude::*; 2 | use rapier3d_urdf::{UrdfLoaderOptions, UrdfMultibodyOptions, UrdfRobot}; 3 | use rapier_testbed3d::Testbed; 4 | 5 | pub fn init_world(testbed: &mut Testbed) { 6 | /* 7 | * World 8 | */ 9 | let mut bodies = RigidBodySet::new(); 10 | let mut colliders = ColliderSet::new(); 11 | let mut impulse_joints = ImpulseJointSet::new(); 12 | let mut multibody_joints = MultibodyJointSet::new(); 13 | 14 | /* 15 | * Ground 16 | */ 17 | let options = UrdfLoaderOptions { 18 | create_colliders_from_visual_shapes: true, 19 | create_colliders_from_collision_shapes: false, 20 | make_roots_fixed: true, 21 | // Z-up to Y-up. 22 | shift: Isometry::rotation(Vector::x() * std::f32::consts::FRAC_PI_2), 23 | ..Default::default() 24 | }; 25 | 26 | let (mut robot, _) = 27 | UrdfRobot::from_file("assets/3d/T12/urdf/T12.URDF", options, None).unwrap(); 28 | 29 | // The robot can be inserted using impulse joints. 30 | // (We clone because we want to insert the same robot once more afterward.) 31 | robot 32 | .clone() 33 | .insert_using_impulse_joints(&mut bodies, &mut colliders, &mut impulse_joints); 34 | // Insert the robot a second time, but using multibody joints this time. 35 | robot.append_transform(&Isometry::translation(10.0, 0.0, 0.0)); 36 | robot.insert_using_multibody_joints( 37 | &mut bodies, 38 | &mut colliders, 39 | &mut multibody_joints, 40 | UrdfMultibodyOptions::DISABLE_SELF_CONTACTS, 41 | ); 42 | 43 | /* 44 | * Set up the testbed. 45 | */ 46 | testbed.set_world(bodies, colliders, impulse_joints, multibody_joints); 47 | testbed.look_at(point![20.0, 20.0, 20.0], point![5.0, 0.0, 0.0]); 48 | } 49 | -------------------------------------------------------------------------------- /examples3d/utils/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod character; 2 | -------------------------------------------------------------------------------- /publish-all.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | if [[ "$PUBLISH_MODE" == 1 ]] 4 | then 5 | ./scripts/publish-rapier.sh && 6 | ./scripts/publish-testbeds.sh && 7 | ./scripts/publish-extra-formats.sh 8 | else 9 | echo "Running in dry mode, re-run with \`PUBLISH_MODE=1 publish-all.sh\` to actually publish." 10 | 11 | DRY_RUN="--dry-run" ./scripts/publish-rapier.sh && 12 | DRY_RUN="--dry-run" ./scripts/publish-testbeds.sh && 13 | DRY_RUN="--dry-run" ./scripts/publish-extra-formats.sh 14 | fi -------------------------------------------------------------------------------- /rustfmt.toml: -------------------------------------------------------------------------------- 1 | #indent_style = "Block" 2 | #where_single_line = true 3 | #brace_style = "PreferSameLine" -------------------------------------------------------------------------------- /scripts/publish-extra-formats.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | currdir=$(pwd) 4 | 5 | ### Publish rapier3d-meshloader. 6 | cd "crates/rapier3d-meshloader" && cargo publish $DRY_RUN || exit 1 7 | cd "$currdir" || exit 2 8 | 9 | ### Publish rapier3d-urdf. 10 | cd "crates/rapier3d-urdf" && cargo publish $DRY_RUN || exit 1 11 | cd "$currdir" || exit 2 -------------------------------------------------------------------------------- /scripts/publish-rapier.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | tmp=$(mktemp -d) 4 | 5 | echo "$tmp" 6 | 7 | cp -r src "$tmp"/. 8 | cp -r LICENSE README.md "$tmp"/. 9 | 10 | ### Publish the 2D version. 11 | sed 's#\.\./\.\./src#src#g' crates/rapier2d/Cargo.toml > "$tmp"/Cargo.toml 12 | currdir=$(pwd) 13 | cd "$tmp" && cargo publish $DRY_RUN || exit 1 14 | cd "$currdir" || exit 2 15 | 16 | 17 | ### Publish the 3D version. 18 | sed 's#\.\./\.\./src#src#g' crates/rapier3d/Cargo.toml > "$tmp"/Cargo.toml 19 | cp -r LICENSE README.md "$tmp"/. 20 | cd "$tmp" && cargo publish $DRY_RUN || exit 1 21 | cd "$currdir" || exit 2 22 | 23 | ### Publish the 2D f64 version. 24 | sed 's#\.\./\.\./src#src#g' crates/rapier2d-f64/Cargo.toml > "$tmp"/Cargo.toml 25 | currdir=$(pwd) 26 | cd "$tmp" && cargo publish $DRY_RUN || exit 1 27 | cd "$currdir" || exit 2 28 | 29 | 30 | ### Publish the 3D f64 version. 31 | sed 's#\.\./\.\./src#src#g' crates/rapier3d-f64/Cargo.toml > "$tmp"/Cargo.toml 32 | cp -r LICENSE README.md "$tmp"/. 33 | cd "$tmp" && cargo publish $DRY_RUN || exit 1 34 | 35 | rm -rf "$tmp" -------------------------------------------------------------------------------- /scripts/publish-testbeds.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | gsed -v >> /dev/null 4 | if [ $? == 0 ]; then 5 | gsed=gsed 6 | else 7 | # Hopefully installed sed is the gnu one. 8 | gsed=sed 9 | fi 10 | 11 | tmp=$(mktemp -d) 12 | 13 | echo "$tmp" 14 | 15 | cp -r src "$tmp"/. 16 | cp -r src_testbed "$tmp"/. 17 | cp -r crates "$tmp"/. 18 | cp -r LICENSE README.md "$tmp"/. 19 | 20 | ### Publish the 2D version. 21 | $gsed 's#\.\./\.\./src#src#g' crates/rapier_testbed2d/Cargo.toml > "$tmp"/Cargo.toml 22 | $gsed -i 's#\.\./rapier#./crates/rapier#g' "$tmp"/Cargo.toml 23 | currdir=$(pwd) 24 | cd "$tmp" && cargo publish $DRY_RUN 25 | cd "$currdir" || exit 26 | 27 | ### Publish the 3D version. 28 | $gsed 's#\.\./\.\./src#src#g' crates/rapier_testbed3d/Cargo.toml > "$tmp"/Cargo.toml 29 | $gsed -i 's#\.\./rapier#./crates/rapier#g' "$tmp"/Cargo.toml 30 | cp -r LICENSE README.md "$tmp"/. 31 | cd "$tmp" && cargo publish $DRY_RUN 32 | 33 | ### Publish the 2D f64 version. 34 | $gsed 's#\.\./\.\./src#src#g' crates/rapier_testbed2d-f64/Cargo.toml > "$tmp"/Cargo.toml 35 | $gsed -i 's#\.\./rapier#./crates/rapier#g' "$tmp"/Cargo.toml 36 | currdir=$(pwd) 37 | cd "$tmp" && cargo publish $DRY_RUN 38 | cd "$currdir" || exit 39 | 40 | ### Publish the 3D f64 version. 41 | $gsed 's#\.\./\.\./src#src#g' crates/rapier_testbed3d-f64/Cargo.toml > "$tmp"/Cargo.toml 42 | $gsed -i 's#\.\./rapier#./crates/rapier#g' "$tmp"/Cargo.toml 43 | cp -r LICENSE README.md "$tmp"/. 44 | cd "$tmp" && cargo publish $DRY_RUN 45 | 46 | rm -rf "$tmp" 47 | -------------------------------------------------------------------------------- /src/control/mod.rs: -------------------------------------------------------------------------------- 1 | //! Utilities for controlling the trajectories of objects in a non-physical way. 2 | 3 | pub use self::character_controller::{ 4 | CharacterAutostep, CharacterCollision, CharacterLength, EffectiveCharacterMovement, 5 | KinematicCharacterController, 6 | }; 7 | pub use self::pid_controller::{PdController, PdErrors, PidController}; 8 | 9 | #[cfg(feature = "dim3")] 10 | pub use self::ray_cast_vehicle_controller::{DynamicRayCastVehicleController, Wheel, WheelTuning}; 11 | 12 | mod character_controller; 13 | 14 | mod pid_controller; 15 | #[cfg(feature = "dim3")] 16 | mod ray_cast_vehicle_controller; 17 | -------------------------------------------------------------------------------- /src/counters/ccd_counters.rs: -------------------------------------------------------------------------------- 1 | use crate::counters::Timer; 2 | use std::fmt::{Display, Formatter, Result}; 3 | 4 | /// Performance counters related to continuous collision detection (CCD). 5 | #[derive(Default, Clone, Copy)] 6 | pub struct CCDCounters { 7 | /// The number of substeps actually performed by the CCD resolution. 8 | pub num_substeps: usize, 9 | /// The total time spent for TOI computation in the CCD resolution. 10 | pub toi_computation_time: Timer, 11 | /// The total time spent for force computation and integration in the CCD resolution. 12 | pub solver_time: Timer, 13 | /// The total time spent by the broad-phase in the CCD resolution. 14 | pub broad_phase_time: Timer, 15 | /// The total time spent by the narrow-phase in the CCD resolution. 16 | pub narrow_phase_time: Timer, 17 | } 18 | 19 | impl CCDCounters { 20 | /// Creates a new counter initialized to zero. 21 | pub fn new() -> Self { 22 | CCDCounters { 23 | num_substeps: 0, 24 | toi_computation_time: Timer::new(), 25 | solver_time: Timer::new(), 26 | broad_phase_time: Timer::new(), 27 | narrow_phase_time: Timer::new(), 28 | } 29 | } 30 | 31 | /// Resets this counter to 0. 32 | pub fn reset(&mut self) { 33 | self.num_substeps = 0; 34 | self.toi_computation_time.reset(); 35 | self.solver_time.reset(); 36 | self.broad_phase_time.reset(); 37 | self.narrow_phase_time.reset(); 38 | } 39 | } 40 | 41 | impl Display for CCDCounters { 42 | fn fmt(&self, f: &mut Formatter) -> Result { 43 | writeln!(f, "Number of substeps: {}", self.num_substeps)?; 44 | writeln!(f, "TOI computation time: {}", self.toi_computation_time)?; 45 | writeln!(f, "Constraints solver time: {}", self.solver_time)?; 46 | writeln!(f, "Broad-phase time: {}", self.broad_phase_time)?; 47 | writeln!(f, "Narrow-phase time: {}", self.narrow_phase_time) 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/counters/collision_detection_counters.rs: -------------------------------------------------------------------------------- 1 | use crate::counters::Timer; 2 | use std::fmt::{Display, Formatter, Result}; 3 | 4 | /// Performance counters related to collision detection. 5 | #[derive(Default, Clone, Copy)] 6 | pub struct CollisionDetectionCounters { 7 | /// Number of contact pairs detected. 8 | pub ncontact_pairs: usize, 9 | /// Time spent for the broad-phase of the collision detection. 10 | pub broad_phase_time: Timer, 11 | /// Time spent for the narrow-phase of the collision detection. 12 | pub narrow_phase_time: Timer, 13 | } 14 | 15 | impl CollisionDetectionCounters { 16 | /// Creates a new counter initialized to zero. 17 | pub fn new() -> Self { 18 | CollisionDetectionCounters { 19 | ncontact_pairs: 0, 20 | broad_phase_time: Timer::new(), 21 | narrow_phase_time: Timer::new(), 22 | } 23 | } 24 | 25 | /// Resets all the counters and timers. 26 | pub fn reset(&mut self) { 27 | self.ncontact_pairs = 0; 28 | self.broad_phase_time.reset(); 29 | self.narrow_phase_time.reset(); 30 | } 31 | } 32 | 33 | impl Display for CollisionDetectionCounters { 34 | fn fmt(&self, f: &mut Formatter) -> Result { 35 | writeln!(f, "Number of contact pairs: {}", self.ncontact_pairs)?; 36 | writeln!(f, "Broad-phase time: {}", self.broad_phase_time)?; 37 | writeln!(f, "Narrow-phase time: {}", self.narrow_phase_time) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/counters/solver_counters.rs: -------------------------------------------------------------------------------- 1 | use crate::counters::Timer; 2 | use std::fmt::{Display, Formatter, Result}; 3 | 4 | /// Performance counters related to constraints resolution. 5 | #[derive(Default, Clone, Copy)] 6 | pub struct SolverCounters { 7 | /// Number of constraints generated. 8 | pub nconstraints: usize, 9 | /// Number of contacts found. 10 | pub ncontacts: usize, 11 | /// Time spent for the resolution of the constraints (force computation). 12 | pub velocity_resolution_time: Timer, 13 | /// Time spent for the assembly of all the velocity constraints. 14 | pub velocity_assembly_time: Timer, 15 | /// Time spent for the update of the velocity of the bodies. 16 | pub velocity_update_time: Timer, 17 | /// Time spent to write force back to user-accessible data. 18 | pub velocity_writeback_time: Timer, 19 | } 20 | 21 | impl SolverCounters { 22 | /// Creates a new counter initialized to zero. 23 | pub fn new() -> Self { 24 | SolverCounters { 25 | nconstraints: 0, 26 | ncontacts: 0, 27 | velocity_assembly_time: Timer::new(), 28 | velocity_resolution_time: Timer::new(), 29 | velocity_update_time: Timer::new(), 30 | velocity_writeback_time: Timer::new(), 31 | } 32 | } 33 | 34 | /// Reset all the counters to zero. 35 | pub fn reset(&mut self) { 36 | self.nconstraints = 0; 37 | self.ncontacts = 0; 38 | self.velocity_resolution_time.reset(); 39 | self.velocity_assembly_time.reset(); 40 | self.velocity_update_time.reset(); 41 | self.velocity_writeback_time.reset(); 42 | } 43 | } 44 | 45 | impl Display for SolverCounters { 46 | fn fmt(&self, f: &mut Formatter) -> Result { 47 | writeln!(f, "Number of contacts: {}", self.ncontacts)?; 48 | writeln!(f, "Number of constraints: {}", self.nconstraints)?; 49 | writeln!(f, "Velocity assembly time: {}", self.velocity_assembly_time)?; 50 | writeln!( 51 | f, 52 | "Velocity resolution time: {}", 53 | self.velocity_resolution_time 54 | )?; 55 | writeln!(f, "Velocity update time: {}", self.velocity_update_time)?; 56 | writeln!( 57 | f, 58 | "Velocity writeback time: {}", 59 | self.velocity_writeback_time 60 | ) 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/counters/stages_counters.rs: -------------------------------------------------------------------------------- 1 | use crate::counters::Timer; 2 | use std::fmt::{Display, Formatter, Result}; 3 | 4 | /// Performance counters related to each stage of the time step. 5 | #[derive(Default, Clone, Copy)] 6 | pub struct StagesCounters { 7 | /// Time spent for updating the kinematic and dynamics of every body. 8 | pub update_time: Timer, 9 | /// Total time spent for the collision detection (including both broad- and narrow- phases). 10 | pub collision_detection_time: Timer, 11 | /// Time spent for the computation of collision island and body activation/deactivation (sleeping). 12 | pub island_construction_time: Timer, 13 | /// Total time spent for the constraints resolution and position update.t 14 | pub solver_time: Timer, 15 | /// Total time spent for CCD and CCD resolution. 16 | pub ccd_time: Timer, 17 | /// Total time spent updating the query pipeline (if provided to `PhysicsPipeline::step`). 18 | pub query_pipeline_time: Timer, 19 | /// Total time spent propagating user changes. 20 | pub user_changes: Timer, 21 | } 22 | 23 | impl StagesCounters { 24 | /// Create a new counter initialized to zero. 25 | pub fn new() -> Self { 26 | StagesCounters { 27 | update_time: Timer::new(), 28 | collision_detection_time: Timer::new(), 29 | island_construction_time: Timer::new(), 30 | solver_time: Timer::new(), 31 | ccd_time: Timer::new(), 32 | query_pipeline_time: Timer::new(), 33 | user_changes: Timer::new(), 34 | } 35 | } 36 | 37 | /// Resets all the counters and timers. 38 | pub fn reset(&mut self) { 39 | self.update_time.reset(); 40 | self.collision_detection_time.reset(); 41 | self.island_construction_time.reset(); 42 | self.solver_time.reset(); 43 | self.ccd_time.reset(); 44 | self.query_pipeline_time.reset(); 45 | self.user_changes.reset(); 46 | } 47 | } 48 | 49 | impl Display for StagesCounters { 50 | fn fmt(&self, f: &mut Formatter) -> Result { 51 | writeln!(f, "Update time: {}", self.update_time)?; 52 | writeln!( 53 | f, 54 | "Collision detection time: {}", 55 | self.collision_detection_time 56 | )?; 57 | writeln!( 58 | f, 59 | "Island construction time: {}", 60 | self.island_construction_time 61 | )?; 62 | writeln!(f, "Solver time: {}", self.solver_time)?; 63 | writeln!(f, "CCD time: {}", self.ccd_time)?; 64 | writeln!(f, "Query pipeline time: {}", self.query_pipeline_time)?; 65 | writeln!(f, "User changes time: {}", self.user_changes) 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/counters/timer.rs: -------------------------------------------------------------------------------- 1 | use std::{ 2 | fmt::{Display, Error, Formatter}, 3 | time::Duration, 4 | }; 5 | 6 | /// A timer. 7 | #[derive(Copy, Clone, Debug, Default)] 8 | pub struct Timer { 9 | time: Duration, 10 | #[allow(dead_code)] // The field isn’t used if the `profiler` feature isn’t enabled. 11 | start: Option, 12 | } 13 | 14 | impl Timer { 15 | /// Creates a new timer initialized to zero and not started. 16 | pub fn new() -> Self { 17 | Timer { 18 | time: Duration::from_secs(0), 19 | start: None, 20 | } 21 | } 22 | 23 | /// Resets the timer to 0. 24 | pub fn reset(&mut self) { 25 | self.time = Duration::from_secs(0) 26 | } 27 | 28 | /// Start the timer. 29 | pub fn start(&mut self) { 30 | #[cfg(feature = "profiler")] 31 | { 32 | self.time = Duration::from_secs(0); 33 | self.start = Some(web_time::Instant::now()); 34 | } 35 | } 36 | 37 | /// Pause the timer. 38 | pub fn pause(&mut self) { 39 | #[cfg(feature = "profiler")] 40 | { 41 | if let Some(start) = self.start { 42 | self.time += web_time::Instant::now().duration_since(start); 43 | } 44 | self.start = None; 45 | } 46 | } 47 | 48 | /// Resume the timer. 49 | pub fn resume(&mut self) { 50 | #[cfg(feature = "profiler")] 51 | { 52 | self.start = Some(web_time::Instant::now()); 53 | } 54 | } 55 | 56 | /// The measured time between the last `.start()` and `.pause()` calls. 57 | pub fn time(&self) -> Duration { 58 | self.time 59 | } 60 | 61 | /// The measured time in milliseconds between the last `.start()` and `.pause()` calls. 62 | pub fn time_ms(&self) -> f64 { 63 | self.time.as_secs_f64() * 1000.0 64 | } 65 | } 66 | 67 | impl Display for Timer { 68 | fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { 69 | write!(f, "{}ms", self.time_ms()) 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/data/mod.rs: -------------------------------------------------------------------------------- 1 | //! Data structures modified with guaranteed deterministic behavior after deserialization. 2 | 3 | pub use self::arena::{Arena, Index}; 4 | pub use self::coarena::Coarena; 5 | pub(crate) use self::modified_objects::{HasModifiedFlag, ModifiedObjects}; 6 | 7 | pub mod arena; 8 | mod coarena; 9 | pub(crate) mod graph; 10 | mod modified_objects; 11 | pub mod pubsub; 12 | -------------------------------------------------------------------------------- /src/data/modified_objects.rs: -------------------------------------------------------------------------------- 1 | use std::marker::PhantomData; 2 | use std::ops::Deref; 3 | 4 | /// Contains handles of modified objects. 5 | /// 6 | /// This is a wrapper over a `Vec` to ensure we don’t forget to set the object’s 7 | /// MODIFIED flag when adding it to this set. 8 | /// It is possible to bypass the wrapper with `.as_mut_internal`. But this should only 9 | /// be done for internal engine usage (like the physics pipeline). 10 | #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] 11 | #[derive(Clone, Debug)] 12 | pub(crate) struct ModifiedObjects(Vec, PhantomData); 13 | 14 | impl Default for ModifiedObjects { 15 | fn default() -> Self { 16 | Self(Vec::new(), PhantomData) 17 | } 18 | } 19 | 20 | pub(crate) trait HasModifiedFlag { 21 | fn has_modified_flag(&self) -> bool; 22 | fn set_modified_flag(&mut self); 23 | } 24 | 25 | impl Deref for ModifiedObjects { 26 | type Target = Vec; 27 | fn deref(&self) -> &Self::Target { 28 | &self.0 29 | } 30 | } 31 | 32 | impl ModifiedObjects { 33 | pub fn with_capacity(capacity: usize) -> Self { 34 | Self(Vec::with_capacity(capacity), PhantomData) 35 | } 36 | 37 | /// Remove every handle from this set. 38 | /// 39 | /// Note that the corresponding object MODIFIED flags won’t be reset automatically by this function. 40 | pub fn clear(&mut self) { 41 | self.0.clear() 42 | } 43 | 44 | /// Pushes a object handle to this set after checking that it doesn’t have the MODIFIED 45 | /// flag set. 46 | /// 47 | /// This will also set the object’s MODIFIED flag. 48 | pub fn push_once(&mut self, handle: Handle, object: &mut Object) { 49 | if !object.has_modified_flag() { 50 | self.push_unchecked(handle, object); 51 | } 52 | } 53 | 54 | /// Pushes an object handle to this set without checking if the object already has the MODIFIED 55 | /// flags. 56 | /// 57 | /// Only use in situation where you are certain (due to other contextual information) that 58 | /// the object isn’t already in the set. 59 | /// 60 | /// This will also set the object’s MODIFIED flag. 61 | pub fn push_unchecked(&mut self, handle: Handle, object: &mut Object) { 62 | object.set_modified_flag(); 63 | self.0.push(handle); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/dynamics/ccd/mod.rs: -------------------------------------------------------------------------------- 1 | // TODO: not sure why it complains about PredictedImpacts being unused, 2 | // making it private or pub(crate) triggers a different error. 3 | #[allow(unused_imports)] 4 | pub use self::ccd_solver::{CCDSolver, PredictedImpacts}; 5 | pub use self::toi_entry::TOIEntry; 6 | 7 | mod ccd_solver; 8 | mod toi_entry; 9 | -------------------------------------------------------------------------------- /src/dynamics/coefficient_combine_rule.rs: -------------------------------------------------------------------------------- 1 | use crate::math::Real; 2 | 3 | /// Rules used to combine two coefficients. 4 | /// 5 | /// This is used to determine the effective restitution and 6 | /// friction coefficients for a contact between two colliders. 7 | /// Each collider has its combination rule of type 8 | /// `CoefficientCombineRule`. And the rule 9 | /// actually used is given by `max(first_combine_rule as usize, second_combine_rule as usize)`. 10 | #[derive(Default, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] 11 | #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] 12 | pub enum CoefficientCombineRule { 13 | /// The two coefficients are averaged. 14 | #[default] 15 | Average = 0, 16 | /// The smallest coefficient is chosen. 17 | Min = 1, 18 | /// The two coefficients are multiplied. 19 | Multiply = 2, 20 | /// The greatest coefficient is chosen. 21 | Max = 3, 22 | } 23 | 24 | impl CoefficientCombineRule { 25 | pub(crate) fn combine( 26 | coeff1: Real, 27 | coeff2: Real, 28 | rule_value1: CoefficientCombineRule, 29 | rule_value2: CoefficientCombineRule, 30 | ) -> Real { 31 | let effective_rule = rule_value1.max(rule_value2); 32 | 33 | match effective_rule { 34 | CoefficientCombineRule::Average => (coeff1 + coeff2) / 2.0, 35 | CoefficientCombineRule::Min => coeff1.min(coeff2), 36 | CoefficientCombineRule::Multiply => coeff1 * coeff2, 37 | CoefficientCombineRule::Max => coeff1.max(coeff2), 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/dynamics/joint/impulse_joint/impulse_joint.rs: -------------------------------------------------------------------------------- 1 | use crate::dynamics::{GenericJoint, ImpulseJointHandle, RigidBodyHandle}; 2 | use crate::math::{Real, SpacialVector}; 3 | 4 | #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] 5 | #[derive(Clone, Debug, PartialEq)] 6 | /// An impulse-based joint attached to two bodies. 7 | pub struct ImpulseJoint { 8 | /// Handle to the first body attached to this joint. 9 | pub body1: RigidBodyHandle, 10 | /// Handle to the second body attached to this joint. 11 | pub body2: RigidBodyHandle, 12 | 13 | /// The joint’s description. 14 | pub data: GenericJoint, 15 | 16 | /// The impulses applied by this joint. 17 | pub impulses: SpacialVector, 18 | 19 | // A joint needs to know its handle to simplify its removal. 20 | pub(crate) handle: ImpulseJointHandle, 21 | } 22 | -------------------------------------------------------------------------------- /src/dynamics/joint/impulse_joint/mod.rs: -------------------------------------------------------------------------------- 1 | pub use self::impulse_joint::ImpulseJoint; 2 | pub use self::impulse_joint_set::{ImpulseJointHandle, ImpulseJointSet}; 3 | pub(crate) use self::impulse_joint_set::{JointGraphEdge, JointIndex}; 4 | 5 | mod impulse_joint; 6 | mod impulse_joint_set; 7 | -------------------------------------------------------------------------------- /src/dynamics/joint/mod.rs: -------------------------------------------------------------------------------- 1 | pub use self::fixed_joint::*; 2 | pub use self::generic_joint::*; 3 | pub use self::impulse_joint::*; 4 | pub use self::motor_model::MotorModel; 5 | pub use self::multibody_joint::*; 6 | pub use self::prismatic_joint::*; 7 | pub use self::revolute_joint::*; 8 | pub use self::rope_joint::*; 9 | pub use self::spring_joint::*; 10 | 11 | #[cfg(feature = "dim3")] 12 | pub use self::spherical_joint::*; 13 | 14 | mod fixed_joint; 15 | mod generic_joint; 16 | mod impulse_joint; 17 | mod motor_model; 18 | mod multibody_joint; 19 | mod prismatic_joint; 20 | mod revolute_joint; 21 | mod rope_joint; 22 | 23 | #[cfg(feature = "dim3")] 24 | mod spherical_joint; 25 | mod spring_joint; 26 | -------------------------------------------------------------------------------- /src/dynamics/joint/motor_model.rs: -------------------------------------------------------------------------------- 1 | use crate::math::Real; 2 | 3 | /// The spring-like model used for constraints resolution. 4 | #[derive(Default, Copy, Clone, Debug, PartialEq, Eq)] 5 | #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] 6 | pub enum MotorModel { 7 | /// The solved spring-like equation is: 8 | /// `acceleration = stiffness * (pos - target_pos) + damping * (vel - target_vel)` 9 | #[default] 10 | AccelerationBased, 11 | /// The solved spring-like equation is: 12 | /// `force = stiffness * (pos - target_pos) + damping * (vel - target_vel)` 13 | ForceBased, 14 | } 15 | 16 | impl MotorModel { 17 | /// Combines the coefficients used for solving the spring equation. 18 | /// 19 | /// Returns the coefficients (erp_inv_dt, cfm_coeff, cfm_gain). 20 | pub fn combine_coefficients( 21 | self, 22 | dt: Real, 23 | stiffness: Real, 24 | damping: Real, 25 | ) -> (Real, Real, Real) { 26 | match self { 27 | MotorModel::AccelerationBased => { 28 | let erp_inv_dt = stiffness * crate::utils::inv(dt * stiffness + damping); 29 | let cfm_coeff = crate::utils::inv(dt * dt * stiffness + dt * damping); 30 | (erp_inv_dt, cfm_coeff, 0.0) 31 | } 32 | MotorModel::ForceBased => { 33 | let erp_inv_dt = stiffness * crate::utils::inv(dt * stiffness + damping); 34 | let cfm_gain = crate::utils::inv(dt * dt * stiffness + dt * damping); 35 | (erp_inv_dt, 0.0, cfm_gain) 36 | } 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/dynamics/joint/multibody_joint/mod.rs: -------------------------------------------------------------------------------- 1 | //! MultibodyJoints using the reduced-coordinates formalism or using constraints. 2 | 3 | pub use self::multibody::Multibody; 4 | pub use self::multibody_ik::InverseKinematicsOption; 5 | pub use self::multibody_joint::MultibodyJoint; 6 | pub use self::multibody_joint_set::{ 7 | MultibodyIndex, MultibodyJointHandle, MultibodyJointSet, MultibodyLinkId, 8 | }; 9 | pub use self::multibody_link::MultibodyLink; 10 | pub use self::unit_multibody_joint::{unit_joint_limit_constraint, unit_joint_motor_constraint}; 11 | 12 | mod multibody; 13 | mod multibody_joint_set; 14 | mod multibody_link; 15 | mod multibody_workspace; 16 | 17 | mod multibody_ik; 18 | mod multibody_joint; 19 | mod unit_multibody_joint; 20 | -------------------------------------------------------------------------------- /src/dynamics/joint/multibody_joint/multibody_workspace.rs: -------------------------------------------------------------------------------- 1 | use crate::dynamics::RigidBodyVelocity; 2 | use crate::math::Real; 3 | use na::DVector; 4 | 5 | /// A temporary workspace for various updates of the multibody. 6 | #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] 7 | #[derive(Clone, Debug)] 8 | pub(crate) struct MultibodyWorkspace { 9 | pub accs: Vec, 10 | pub ndofs_vec: DVector, 11 | } 12 | 13 | impl MultibodyWorkspace { 14 | /// Create an empty workspace. 15 | pub fn new() -> Self { 16 | MultibodyWorkspace { 17 | accs: Vec::new(), 18 | ndofs_vec: DVector::zeros(0), 19 | } 20 | } 21 | 22 | /// Resize the workspace so it is enough for `nlinks` links. 23 | pub fn resize(&mut self, nlinks: usize, ndofs: usize) { 24 | self.accs.resize(nlinks, RigidBodyVelocity::zero()); 25 | self.ndofs_vec = DVector::zeros(ndofs) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/dynamics/mod.rs: -------------------------------------------------------------------------------- 1 | //! Structures related to dynamics: bodies, impulse_joints, etc. 2 | 3 | pub use self::ccd::CCDSolver; 4 | pub use self::coefficient_combine_rule::CoefficientCombineRule; 5 | pub use self::integration_parameters::IntegrationParameters; 6 | pub use self::island_manager::IslandManager; 7 | pub(crate) use self::joint::JointGraphEdge; 8 | pub(crate) use self::joint::JointIndex; 9 | pub use self::joint::*; 10 | pub use self::rigid_body_components::*; 11 | pub(crate) use self::rigid_body_set::ModifiedRigidBodies; 12 | // #[cfg(not(feature = "parallel"))] 13 | pub(crate) use self::solver::IslandSolver; 14 | // #[cfg(feature = "parallel")] 15 | // pub(crate) use self::solver::ParallelIslandSolver; 16 | pub use parry::mass_properties::MassProperties; 17 | 18 | pub use self::rigid_body::{RigidBody, RigidBodyBuilder}; 19 | pub use self::rigid_body_set::{BodyPair, RigidBodySet}; 20 | 21 | mod ccd; 22 | mod coefficient_combine_rule; 23 | mod integration_parameters; 24 | mod island_manager; 25 | mod joint; 26 | mod rigid_body_components; 27 | mod solver; 28 | 29 | mod rigid_body; 30 | mod rigid_body_set; 31 | -------------------------------------------------------------------------------- /src/dynamics/solver/contact_constraint/mod.rs: -------------------------------------------------------------------------------- 1 | pub(crate) use generic_one_body_constraint::*; 2 | // pub(crate) use generic_one_body_constraint_element::*; 3 | pub(crate) use contact_constraints_set::{ 4 | ConstraintsCounts, ContactConstraintTypes, ContactConstraintsSet, 5 | }; 6 | pub(crate) use generic_two_body_constraint::*; 7 | pub(crate) use generic_two_body_constraint_element::*; 8 | pub(crate) use one_body_constraint::*; 9 | pub(crate) use one_body_constraint_element::*; 10 | #[cfg(feature = "simd-is-enabled")] 11 | pub(crate) use one_body_constraint_simd::*; 12 | pub(crate) use two_body_constraint::*; 13 | pub(crate) use two_body_constraint_element::*; 14 | #[cfg(feature = "simd-is-enabled")] 15 | pub(crate) use two_body_constraint_simd::*; 16 | 17 | mod contact_constraints_set; 18 | mod generic_one_body_constraint; 19 | mod generic_one_body_constraint_element; 20 | mod generic_two_body_constraint; 21 | mod generic_two_body_constraint_element; 22 | mod one_body_constraint; 23 | mod one_body_constraint_element; 24 | #[cfg(feature = "simd-is-enabled")] 25 | mod one_body_constraint_simd; 26 | mod two_body_constraint; 27 | mod two_body_constraint_element; 28 | #[cfg(feature = "simd-is-enabled")] 29 | mod two_body_constraint_simd; 30 | -------------------------------------------------------------------------------- /src/dynamics/solver/joint_constraint/mod.rs: -------------------------------------------------------------------------------- 1 | pub use joint_velocity_constraint::{JointSolverBody, MotorParameters, WritebackId}; 2 | 3 | pub use any_joint_constraint::JointConstraintTypes; 4 | pub use joint_constraint_builder::JointTwoBodyConstraintHelper; 5 | pub use joint_constraints_set::JointConstraintsSet; 6 | pub use joint_generic_constraint::{JointGenericOneBodyConstraint, JointGenericTwoBodyConstraint}; 7 | pub use joint_generic_constraint_builder::{ 8 | JointGenericOneBodyConstraintBuilder, JointGenericTwoBodyConstraintBuilder, 9 | JointGenericVelocityOneBodyExternalConstraintBuilder, 10 | JointGenericVelocityOneBodyInternalConstraintBuilder, 11 | }; 12 | 13 | mod any_joint_constraint; 14 | mod joint_constraint_builder; 15 | mod joint_constraints_set; 16 | mod joint_generic_constraint; 17 | mod joint_generic_constraint_builder; 18 | mod joint_velocity_constraint; 19 | -------------------------------------------------------------------------------- /src/dynamics/solver/mod.rs: -------------------------------------------------------------------------------- 1 | // #[cfg(not(feature = "parallel"))] 2 | pub(crate) use self::island_solver::IslandSolver; 3 | // #[cfg(feature = "parallel")] 4 | // pub(crate) use self::parallel_island_solver::{ParallelIslandSolver, ThreadContext}; 5 | // #[cfg(feature = "parallel")] 6 | // pub(self) use self::parallel_solver_constraints::ParallelSolverConstraints; 7 | // #[cfg(feature = "parallel")] 8 | // pub(self) use self::parallel_velocity_solver::ParallelVelocitySolver; 9 | // #[cfg(not(feature = "parallel"))] 10 | use self::solver_constraints_set::SolverConstraintsSet; 11 | // #[cfg(not(feature = "parallel"))] 12 | use self::velocity_solver::VelocitySolver; 13 | 14 | use contact_constraint::*; 15 | use interaction_groups::*; 16 | pub(crate) use joint_constraint::MotorParameters; 17 | pub use joint_constraint::*; 18 | use solver_body::SolverBody; 19 | use solver_constraints_set::{AnyConstraintMut, ConstraintTypes}; 20 | use solver_vel::SolverVel; 21 | 22 | mod categorization; 23 | mod contact_constraint; 24 | mod interaction_groups; 25 | // #[cfg(not(feature = "parallel"))] 26 | mod island_solver; 27 | mod joint_constraint; 28 | // #[cfg(feature = "parallel")] 29 | // mod parallel_island_solver; 30 | // #[cfg(feature = "parallel")] 31 | // mod parallel_solver_constraints; 32 | // #[cfg(feature = "parallel")] 33 | // mod parallel_velocity_solver; 34 | mod solver_body; 35 | // #[cfg(not(feature = "parallel"))] 36 | mod solver_constraints_set; 37 | mod solver_vel; 38 | // #[cfg(not(feature = "parallel"))] 39 | mod velocity_solver; 40 | 41 | // TODO: SAFETY: restrict with bytemuck::AnyBitPattern to make this safe. 42 | pub unsafe fn reset_buffer(buffer: &mut Vec, len: usize) { 43 | buffer.clear(); 44 | buffer.reserve(len); 45 | buffer.as_mut_ptr().write_bytes(u8::MAX, len); 46 | buffer.set_len(len); 47 | } 48 | -------------------------------------------------------------------------------- /src/dynamics/solver/solver_body.rs: -------------------------------------------------------------------------------- 1 | use crate::dynamics::{RigidBody, RigidBodyVelocity}; 2 | use crate::math::{AngularInertia, Isometry, Point, Real, Vector}; 3 | use crate::prelude::RigidBodyDamping; 4 | 5 | #[cfg(feature = "dim2")] 6 | use crate::num::Zero; 7 | 8 | #[derive(Copy, Clone, Debug)] 9 | pub(crate) struct SolverBody { 10 | pub position: Isometry, 11 | pub integrated_vels: RigidBodyVelocity, 12 | pub im: Vector, 13 | pub sqrt_ii: AngularInertia, 14 | pub world_com: Point, 15 | pub ccd_thickness: Real, 16 | pub damping: RigidBodyDamping, 17 | pub local_com: Point, 18 | } 19 | 20 | impl Default for SolverBody { 21 | fn default() -> Self { 22 | Self { 23 | position: Isometry::identity(), 24 | integrated_vels: RigidBodyVelocity::zero(), 25 | im: na::zero(), 26 | sqrt_ii: AngularInertia::zero(), 27 | world_com: Point::origin(), 28 | ccd_thickness: 0.0, 29 | damping: RigidBodyDamping::default(), 30 | local_com: Point::origin(), 31 | } 32 | } 33 | } 34 | 35 | impl SolverBody { 36 | pub fn from(rb: &RigidBody) -> Self { 37 | Self { 38 | position: rb.pos.position, 39 | integrated_vels: RigidBodyVelocity::zero(), 40 | im: rb.mprops.effective_inv_mass, 41 | sqrt_ii: rb.mprops.effective_world_inv_inertia_sqrt, 42 | world_com: rb.mprops.world_com, 43 | ccd_thickness: rb.ccd.ccd_thickness, 44 | damping: rb.damping, 45 | local_com: rb.mprops.local_mprops.local_com, 46 | } 47 | } 48 | 49 | pub fn copy_from(&mut self, rb: &RigidBody) { 50 | self.position = rb.pos.position; 51 | self.integrated_vels = RigidBodyVelocity::zero(); 52 | self.im = rb.mprops.effective_inv_mass; 53 | self.sqrt_ii = rb.mprops.effective_world_inv_inertia_sqrt; 54 | self.world_com = rb.mprops.world_com; 55 | self.ccd_thickness = rb.ccd.ccd_thickness; 56 | self.damping = rb.damping; 57 | self.local_com = rb.mprops.local_mprops.local_com; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/dynamics/solver/solver_vel.rs: -------------------------------------------------------------------------------- 1 | use crate::math::{AngVector, Vector, SPATIAL_DIM}; 2 | use crate::utils::SimdRealCopy; 3 | use na::{DVectorView, DVectorViewMut, Scalar}; 4 | use std::ops::{AddAssign, Sub, SubAssign}; 5 | 6 | #[derive(Copy, Clone, Debug, Default)] 7 | #[repr(C)] 8 | //#[repr(align(64))] 9 | pub struct SolverVel { 10 | // The linear velocity of a solver body. 11 | pub linear: Vector, 12 | // The angular velocity, multiplied by the inverse sqrt angular inertia, of a solver body. 13 | pub angular: AngVector, 14 | } 15 | 16 | impl SolverVel { 17 | pub fn as_slice(&self) -> &[N; SPATIAL_DIM] { 18 | unsafe { std::mem::transmute(self) } 19 | } 20 | 21 | pub fn as_mut_slice(&mut self) -> &mut [N; SPATIAL_DIM] { 22 | unsafe { std::mem::transmute(self) } 23 | } 24 | 25 | pub fn as_vector_slice(&self) -> DVectorView { 26 | DVectorView::from_slice(&self.as_slice()[..], SPATIAL_DIM) 27 | } 28 | 29 | pub fn as_vector_slice_mut(&mut self) -> DVectorViewMut { 30 | DVectorViewMut::from_slice(&mut self.as_mut_slice()[..], SPATIAL_DIM) 31 | } 32 | } 33 | 34 | impl SolverVel { 35 | pub fn zero() -> Self { 36 | Self { 37 | linear: na::zero(), 38 | angular: na::zero(), 39 | } 40 | } 41 | } 42 | 43 | impl AddAssign for SolverVel { 44 | fn add_assign(&mut self, rhs: Self) { 45 | self.linear += rhs.linear; 46 | self.angular += rhs.angular; 47 | } 48 | } 49 | 50 | impl SubAssign for SolverVel { 51 | fn sub_assign(&mut self, rhs: Self) { 52 | self.linear -= rhs.linear; 53 | self.angular -= rhs.angular; 54 | } 55 | } 56 | 57 | impl Sub for SolverVel { 58 | type Output = Self; 59 | 60 | fn sub(self, rhs: Self) -> Self { 61 | SolverVel { 62 | linear: self.linear - rhs.linear, 63 | angular: self.angular - rhs.angular, 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/geometry/broad_phase_multi_sap/broad_phase_pair_event.rs: -------------------------------------------------------------------------------- 1 | use crate::geometry::ColliderHandle; 2 | 3 | #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] 4 | #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] 5 | /// A pair of collider handles. 6 | pub struct ColliderPair { 7 | /// The handle of the first collider involved in this pair. 8 | pub collider1: ColliderHandle, 9 | /// The handle of the second ocllider involved in this pair. 10 | pub collider2: ColliderHandle, 11 | } 12 | 13 | impl ColliderPair { 14 | /// Creates a new pair of collider handles. 15 | pub fn new(collider1: ColliderHandle, collider2: ColliderHandle) -> Self { 16 | ColliderPair { 17 | collider1, 18 | collider2, 19 | } 20 | } 21 | 22 | /// Swaps the two collider handles in `self`. 23 | pub fn swap(self) -> Self { 24 | Self::new(self.collider2, self.collider1) 25 | } 26 | 27 | /// Constructs a pair of artificial handles that are not guaranteed to be valid.. 28 | pub fn zero() -> Self { 29 | Self { 30 | collider1: ColliderHandle::from_raw_parts(0, 0), 31 | collider2: ColliderHandle::from_raw_parts(0, 0), 32 | } 33 | } 34 | } 35 | 36 | impl Default for ColliderPair { 37 | fn default() -> Self { 38 | ColliderPair::zero() 39 | } 40 | } 41 | 42 | /// An event emitted by the broad-phase. 43 | pub enum BroadPhasePairEvent { 44 | /// A potential new collision pair has been detected by the broad-phase. 45 | AddPair(ColliderPair), 46 | /// The two colliders are guaranteed not to touch any more. 47 | DeletePair(ColliderPair), 48 | } 49 | -------------------------------------------------------------------------------- /src/geometry/broad_phase_multi_sap/mod.rs: -------------------------------------------------------------------------------- 1 | pub use self::broad_phase_multi_sap::BroadPhaseMultiSap; 2 | pub use self::broad_phase_pair_event::{BroadPhasePairEvent, ColliderPair}; 3 | 4 | use self::sap_axis::*; 5 | use self::sap_endpoint::*; 6 | use self::sap_layer::*; 7 | use self::sap_proxy::*; 8 | use self::sap_region::*; 9 | use self::sap_utils::*; 10 | 11 | mod broad_phase_multi_sap; 12 | mod broad_phase_pair_event; 13 | mod sap_axis; 14 | mod sap_endpoint; 15 | mod sap_layer; 16 | mod sap_proxy; 17 | mod sap_region; 18 | mod sap_utils; 19 | -------------------------------------------------------------------------------- /src/geometry/broad_phase_multi_sap/sap_endpoint.rs: -------------------------------------------------------------------------------- 1 | use super::SENTINEL_VALUE; 2 | use crate::math::Real; 3 | 4 | #[derive(Copy, Clone, Debug, PartialEq)] 5 | #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] 6 | pub struct SAPEndpoint { 7 | pub value: Real, 8 | pub packed_flag_proxy: u32, 9 | } 10 | 11 | const START_FLAG_MASK: u32 = 0b1 << 31; 12 | const PROXY_MASK: u32 = u32::MAX ^ START_FLAG_MASK; 13 | const START_SENTINEL_TAG: u32 = u32::MAX; 14 | const END_SENTINEL_TAG: u32 = u32::MAX ^ START_FLAG_MASK; 15 | 16 | impl SAPEndpoint { 17 | pub fn start_endpoint(value: Real, proxy: u32) -> Self { 18 | Self { 19 | value, 20 | packed_flag_proxy: proxy | START_FLAG_MASK, 21 | } 22 | } 23 | 24 | pub fn end_endpoint(value: Real, proxy: u32) -> Self { 25 | Self { 26 | value, 27 | packed_flag_proxy: proxy & PROXY_MASK, 28 | } 29 | } 30 | 31 | pub fn start_sentinel() -> Self { 32 | Self { 33 | value: -SENTINEL_VALUE, 34 | packed_flag_proxy: START_SENTINEL_TAG, 35 | } 36 | } 37 | 38 | pub fn end_sentinel() -> Self { 39 | Self { 40 | value: SENTINEL_VALUE, 41 | packed_flag_proxy: END_SENTINEL_TAG, 42 | } 43 | } 44 | 45 | pub fn is_sentinel(self) -> bool { 46 | self.packed_flag_proxy & PROXY_MASK == PROXY_MASK 47 | } 48 | 49 | pub fn proxy(self) -> u32 { 50 | self.packed_flag_proxy & PROXY_MASK 51 | } 52 | 53 | pub fn is_start(self) -> bool { 54 | (self.packed_flag_proxy & START_FLAG_MASK) != 0 55 | } 56 | 57 | pub fn is_end(self) -> bool { 58 | (self.packed_flag_proxy & START_FLAG_MASK) == 0 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/pipeline/debug_render_pipeline/mod.rs: -------------------------------------------------------------------------------- 1 | pub use self::debug_render_backend::{DebugRenderBackend, DebugRenderObject}; 2 | pub use self::debug_render_pipeline::{DebugRenderMode, DebugRenderPipeline}; 3 | pub use self::debug_render_style::{DebugColor, DebugRenderStyle}; 4 | 5 | mod debug_render_backend; 6 | mod debug_render_pipeline; 7 | mod debug_render_style; 8 | mod outlines; 9 | -------------------------------------------------------------------------------- /src/pipeline/debug_render_pipeline/outlines.rs: -------------------------------------------------------------------------------- 1 | use crate::geometry::{Ball, Cuboid}; 2 | #[cfg(feature = "dim3")] 3 | use crate::geometry::{Cone, Cylinder}; 4 | use crate::math::{Point, Real, Vector}; 5 | use std::any::TypeId; 6 | use std::collections::HashMap; 7 | 8 | #[cfg(feature = "dim2")] 9 | pub fn instances(nsubdivs: u32) -> HashMap>> { 10 | let mut result = HashMap::new(); 11 | result.insert( 12 | TypeId::of::(), 13 | Cuboid::new(Vector::repeat(0.5)).to_polyline(), 14 | ); 15 | result.insert(TypeId::of::(), Ball::new(0.5).to_polyline(nsubdivs)); 16 | result 17 | } 18 | 19 | #[cfg(feature = "dim3")] 20 | #[allow(clippy::type_complexity)] 21 | pub fn instances(nsubdivs: u32) -> HashMap>, Vec<[u32; 2]>)> { 22 | let mut result = HashMap::new(); 23 | result.insert( 24 | TypeId::of::(), 25 | Cuboid::new(Vector::repeat(0.5)).to_outline(), 26 | ); 27 | result.insert(TypeId::of::(), Ball::new(0.5).to_outline(nsubdivs)); 28 | result.insert( 29 | TypeId::of::(), 30 | Cone::new(0.5, 0.5).to_outline(nsubdivs), 31 | ); 32 | result.insert( 33 | TypeId::of::(), 34 | Cylinder::new(0.5, 0.5).to_outline(nsubdivs), 35 | ); 36 | result 37 | } 38 | -------------------------------------------------------------------------------- /src/pipeline/mod.rs: -------------------------------------------------------------------------------- 1 | //! Structure for combining the various physics components to perform an actual simulation. 2 | 3 | pub use collision_pipeline::CollisionPipeline; 4 | pub use event_handler::{ActiveEvents, ChannelEventCollector, EventHandler}; 5 | pub use physics_hooks::{ActiveHooks, ContactModificationContext, PairFilterContext, PhysicsHooks}; 6 | pub use physics_pipeline::PhysicsPipeline; 7 | pub use query_pipeline::{ 8 | generators as query_pipeline_generators, QueryFilter, QueryFilterFlags, QueryPipeline, 9 | }; 10 | 11 | #[cfg(feature = "debug-render")] 12 | pub use self::debug_render_pipeline::{ 13 | DebugColor, DebugRenderBackend, DebugRenderMode, DebugRenderObject, DebugRenderPipeline, 14 | DebugRenderStyle, 15 | }; 16 | 17 | mod collision_pipeline; 18 | mod event_handler; 19 | mod physics_hooks; 20 | mod physics_pipeline; 21 | mod query_pipeline; 22 | mod user_changes; 23 | 24 | #[cfg(feature = "debug-render")] 25 | mod debug_render_pipeline; 26 | -------------------------------------------------------------------------------- /src_testbed/Inconsolata.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dimforge/rapier/cd7fc6e11f26db67c51db0713a53d4e3951dfe3f/src_testbed/Inconsolata.otf -------------------------------------------------------------------------------- /src_testbed/debug_render.rs: -------------------------------------------------------------------------------- 1 | #![allow(clippy::unnecessary_cast)] // Casts are needed for switching between f32/f64. 2 | 3 | use crate::harness::Harness; 4 | use bevy::gizmos::gizmos::Gizmos; 5 | use bevy::prelude::*; 6 | use rapier::math::{Point, Real}; 7 | use rapier::pipeline::{ 8 | DebugColor, DebugRenderBackend, DebugRenderMode, DebugRenderObject, DebugRenderPipeline, 9 | }; 10 | 11 | #[derive(Resource)] 12 | pub struct DebugRenderPipelineResource { 13 | pub pipeline: DebugRenderPipeline, 14 | pub enabled: bool, 15 | } 16 | 17 | #[derive(Default)] 18 | pub struct RapierDebugRenderPlugin {} 19 | 20 | impl Plugin for RapierDebugRenderPlugin { 21 | fn build(&self, app: &mut App) { 22 | app.insert_resource(DebugRenderPipelineResource { 23 | pipeline: DebugRenderPipeline::new( 24 | Default::default(), 25 | !DebugRenderMode::RIGID_BODY_AXES & !DebugRenderMode::COLLIDER_AABBS, 26 | ), 27 | enabled: false, 28 | }) 29 | .add_systems(Update, debug_render_scene); 30 | } 31 | } 32 | 33 | struct BevyLinesRenderBackend<'w, 's> { 34 | gizmos: Gizmos<'w, 's>, 35 | } 36 | 37 | impl<'w, 's> DebugRenderBackend for BevyLinesRenderBackend<'w, 's> { 38 | #[cfg(feature = "dim2")] 39 | fn draw_line( 40 | &mut self, 41 | _: DebugRenderObject, 42 | a: Point, 43 | b: Point, 44 | color: DebugColor, 45 | ) { 46 | self.gizmos.line( 47 | [a.x as f32, a.y as f32, 1.0e-8].into(), 48 | [b.x as f32, b.y as f32, 1.0e-8].into(), 49 | Color::hsla(color[0], color[1], color[2], color[3]), 50 | ) 51 | } 52 | #[cfg(feature = "dim3")] 53 | fn draw_line( 54 | &mut self, 55 | _: DebugRenderObject, 56 | a: Point, 57 | b: Point, 58 | color: DebugColor, 59 | ) { 60 | self.gizmos.line( 61 | [a.x as f32, a.y as f32, a.z as f32].into(), 62 | [b.x as f32, b.y as f32, b.z as f32].into(), 63 | Color::hsla(color[0], color[1], color[2], color[3]), 64 | ) 65 | } 66 | } 67 | 68 | fn debug_render_scene( 69 | mut debug_render: ResMut, 70 | harness: NonSend, 71 | gizmos: Gizmos, 72 | ) { 73 | if debug_render.enabled { 74 | let mut backend = BevyLinesRenderBackend { gizmos }; 75 | debug_render.pipeline.render( 76 | &mut backend, 77 | &harness.physics.bodies, 78 | &harness.physics.colliders, 79 | &harness.physics.impulse_joints, 80 | &harness.physics.multibody_joints, 81 | &harness.physics.narrow_phase, 82 | ); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src_testbed/harness/plugin.rs: -------------------------------------------------------------------------------- 1 | use crate::harness::RunState; 2 | use crate::physics::PhysicsEvents; 3 | use crate::PhysicsState; 4 | 5 | pub trait HarnessPlugin { 6 | fn run_callbacks( 7 | &mut self, 8 | physics: &mut PhysicsState, 9 | events: &PhysicsEvents, 10 | harness_state: &RunState, 11 | ); 12 | fn step(&mut self, physics: &mut PhysicsState, run_state: &RunState); 13 | fn profiling_string(&self) -> String; 14 | } 15 | -------------------------------------------------------------------------------- /src_testbed/lib.rs: -------------------------------------------------------------------------------- 1 | #![allow(clippy::too_many_arguments)] 2 | 3 | extern crate nalgebra as na; 4 | 5 | pub use crate::graphics::{BevyMaterial, GraphicsManager}; 6 | pub use crate::harness::plugin::HarnessPlugin; 7 | pub use crate::physics::PhysicsState; 8 | pub use crate::plugin::TestbedPlugin; 9 | pub use crate::testbed::{Testbed, TestbedApp, TestbedGraphics, TestbedState}; 10 | pub use bevy::prelude::KeyCode; 11 | 12 | #[cfg(all(feature = "dim2", feature = "other-backends"))] 13 | mod box2d_backend; 14 | #[cfg(feature = "dim2")] 15 | mod camera2d; 16 | #[cfg(feature = "dim3")] 17 | mod camera3d; 18 | mod debug_render; 19 | mod graphics; 20 | pub mod harness; 21 | mod mouse; 22 | pub mod objects; 23 | pub mod physics; 24 | #[cfg(all(feature = "dim3", feature = "other-backends"))] 25 | mod physx_backend; 26 | mod plugin; 27 | mod save; 28 | mod settings; 29 | mod testbed; 30 | pub mod ui; 31 | 32 | #[cfg(feature = "dim2")] 33 | pub mod math { 34 | pub type Isometry = na::Isometry2; 35 | pub type Vector = na::Vector2; 36 | pub type Point = na::Point2; 37 | pub type Translation = na::Translation2; 38 | } 39 | 40 | #[cfg(feature = "dim3")] 41 | pub mod math { 42 | pub type Isometry = na::Isometry3; 43 | pub type Vector = na::Vector3; 44 | pub type Point = na::Point3; 45 | pub type Translation = na::Translation3; 46 | } 47 | -------------------------------------------------------------------------------- /src_testbed/mouse.rs: -------------------------------------------------------------------------------- 1 | use crate::math::Point; 2 | use bevy::prelude::*; 3 | use bevy::window::PrimaryWindow; 4 | 5 | #[derive(Component)] 6 | pub struct MainCamera; 7 | 8 | #[derive(Default, Copy, Clone, Debug, Resource)] 9 | pub struct SceneMouse { 10 | #[cfg(feature = "dim2")] 11 | pub point: Option>, 12 | #[cfg(feature = "dim3")] 13 | pub ray: Option<(Point, crate::math::Vector)>, 14 | } 15 | 16 | pub fn track_mouse_state( 17 | mut scene_mouse: ResMut, 18 | windows: Query<&Window, With>, 19 | camera: Query<(&GlobalTransform, &Camera), With>, 20 | ) { 21 | if let Ok(window) = windows.get_single() { 22 | for (camera_transform, camera) in camera.iter() { 23 | if let Some(cursor) = window.cursor_position() { 24 | let ndc_cursor = ((cursor / Vec2::new(window.width(), window.height()) * 2.0) 25 | - Vec2::ONE) 26 | * Vec2::new(1.0, -1.0); 27 | let ndc_to_world = 28 | camera_transform.compute_matrix() * camera.clip_from_view().inverse(); 29 | let ray_pt1 = 30 | ndc_to_world.project_point3(Vec3::new(ndc_cursor.x, ndc_cursor.y, -1.0)); 31 | 32 | #[cfg(feature = "dim2")] 33 | { 34 | scene_mouse.point = Some(Point::new(ray_pt1.x, ray_pt1.y)); 35 | } 36 | #[cfg(feature = "dim3")] 37 | { 38 | let ray_pt2 = 39 | ndc_to_world.project_point3(Vec3::new(ndc_cursor.x, ndc_cursor.y, 1.0)); 40 | let ray_dir = ray_pt2 - ray_pt1; 41 | scene_mouse.ray = Some((na::Vector3::from(ray_pt1).into(), ray_dir.into())); 42 | } 43 | } 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src_testbed/objects/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod node; 2 | -------------------------------------------------------------------------------- /src_testbed/plugin.rs: -------------------------------------------------------------------------------- 1 | use crate::graphics::BevyMaterial; 2 | use crate::harness::Harness; 3 | use crate::physics::PhysicsState; 4 | use crate::GraphicsManager; 5 | use bevy::prelude::*; 6 | // use bevy::render::render_resource::RenderPipelineDescriptor; 7 | use bevy_egui::EguiContexts; 8 | 9 | pub trait TestbedPlugin { 10 | fn init_plugin(&mut self); 11 | fn init_graphics( 12 | &mut self, 13 | graphics: &mut GraphicsManager, 14 | commands: &mut Commands, 15 | meshes: &mut Assets, 16 | materials: &mut Assets, 17 | components: &mut Query<&mut Transform>, 18 | harness: &mut Harness, 19 | ); 20 | fn clear_graphics(&mut self, graphics: &mut GraphicsManager, commands: &mut Commands); 21 | fn run_callbacks(&mut self, harness: &mut Harness); 22 | fn step(&mut self, physics: &mut PhysicsState); 23 | fn draw( 24 | &mut self, 25 | graphics: &mut GraphicsManager, 26 | commands: &mut Commands, 27 | meshes: &mut Assets, 28 | materials: &mut Assets, 29 | components: &mut Query<&mut Transform>, 30 | harness: &mut Harness, 31 | ); 32 | fn update_ui( 33 | &mut self, 34 | ui_context: &EguiContexts, 35 | harness: &mut Harness, 36 | graphics: &mut GraphicsManager, 37 | commands: &mut Commands, 38 | meshes: &mut Assets, 39 | materials: &mut Assets, 40 | components: &mut Query<&mut Transform>, 41 | ); 42 | fn profiling_string(&self) -> String; 43 | } 44 | -------------------------------------------------------------------------------- /src_testbed/save.rs: -------------------------------------------------------------------------------- 1 | #[cfg(feature = "dim2")] 2 | use crate::camera2d::OrbitCamera; 3 | #[cfg(feature = "dim3")] 4 | use crate::camera3d::OrbitCamera; 5 | use crate::settings::ExampleSettings; 6 | use crate::testbed::{RapierSolverType, RunMode, TestbedStateFlags}; 7 | use serde::{Deserialize, Serialize}; 8 | 9 | #[derive(Serialize, Deserialize, PartialEq, Debug, Default, Clone)] 10 | pub struct SerializableTestbedState { 11 | pub running: RunMode, 12 | pub flags: TestbedStateFlags, 13 | pub selected_example: usize, 14 | pub selected_backend: usize, 15 | pub example_settings: ExampleSettings, 16 | pub solver_type: RapierSolverType, 17 | pub physx_use_two_friction_directions: bool, 18 | pub camera: OrbitCamera, 19 | } 20 | 21 | #[cfg(feature = "dim2")] 22 | #[derive(Serialize, Deserialize, PartialEq, Debug, Default, Clone)] 23 | pub struct SerializableCameraState { 24 | pub zoom: f32, 25 | pub center: na::Point2, 26 | } 27 | 28 | #[cfg(feature = "dim3")] 29 | #[derive(Serialize, Deserialize, PartialEq, Debug, Default, Clone)] 30 | pub struct SerializableCameraState { 31 | pub distance: f32, 32 | pub position: na::Point3, 33 | pub center: na::Point3, 34 | } 35 | --------------------------------------------------------------------------------