Rust物理引擎库bevy_rapier3d的使用,3D游戏开发中的高性能碰撞检测与刚体模拟

Rust物理引擎库bevy_rapier3d的使用,3D游戏开发中的高性能碰撞检测与刚体模拟

Rapier Logo

安装

在项目目录中运行以下Cargo命令:

cargo add bevy_rapier3d

或者在Cargo.toml中添加:

bevy_rapier3d = "0.30.0"

示例代码

以下是一个完整的bevy_rapier3d使用示例,展示了如何创建带有物理特性的3D对象:

use bevy::prelude::*;
use bevy_rapier3d::prelude::*;

fn main() {
    App::new()
        .add_plugins(DefaultPlugins)
        // 添加Rapier物理插件
        .add_plugin(RapierPhysicsPlugin::<NoUserData>::default())
        // 可选:添加Rapier调试渲染插件
        .add_plugin(RapierDebugRenderPlugin::default())
        .add_startup_system(setup)
        .add_system(move_cube)
        .run();
}

fn setup(
    mut commands: Commands,
    mut meshes: ResMut<Assets<Mesh>>,
    mut materials: ResMut<Assets<StandardMaterial>>,
) {
    // 添加光照
    commands.spawn_bundle(PointLightBundle {
        point_light: PointLight {
            intensity: 1500.0,
            shadows_enabled: true,
            ..default()
        },
        transform: Transform::from_xyz(4.0, 8.0, 4.0),
        ..default()
    });

    // 添加相机
    commands.spawn_bundle(Camera3dBundle {
        transform: Transform::from_xyz(-10.0, 3.0, 0.0)
            .looking_at(Vec3::ZERO, Vec3::Y),
        ..default()
    });

    // 添加地面(静态碰撞体)
    commands
        .spawn_bundle(PbrBundle {
            mesh: meshes.add(Mesh::from(shape::Plane { size: 10.0 })),
            material: materials.add(Color::rgb(0.3, 0.5, 0.3).into()),
            ..default()
        })
        .insert(Collider::cuboid(5.0, 0.1, 5.0)); // 碰撞体尺寸

    // 添加立方体(动态刚体)
    commands
        .spawn_bundle(PbrBundle {
            mesh: meshes.add(Mesh::from(shape::Cube { size: 极狐 1.0 })),
            material: materials.add(Color::rgb(0.8, 0.7, 0.6).into()),
            transform: Transform::from_xyz(0.0, 4.0, 0.0),
            ..default()
        })
        .insert(RigidBody::Dynamic)
        .insert(Collider::cuboid(0.5, 0.5, 0.5))
        .insert(ExternalForce {
            force: Vec3::new(0.0, 0.0, 0.0),
            torque: Vec3::new(0.0, 0.0, 0.0),
        })
        .insert(ExternalImpulse {
            impulse: Vec3::new(0.0, 0.0, 0.0),
            torque_impulse: Vec3::new(0.0, 0.0, 0.0),
        });
}

// 系统:控制立方体移动
fn move_cube(
    keyboard_input: Res<极狐 Input<KeyCode>>,
    mut query: Query<&mut ExternalForce, With<RigidBody>>,
) {
    for mut force in query.iter_mut() {
        let mut direction = Vec3::ZERO;
        
        if keyboard_input.pressed(KeyCode::W) {
            direction.z -= 1.0;
        }
        if keyboard_input.pressed(KeyCode::S) {
            direction.z += 1.0;
        }
        if keyboard_input.pressed(KeyCode::A) {
            direction.x -= 1.0;
        }
        if keyboard_input.pressed(KeyCode::D) {
            direction.x += 1.0;
        }
        
        force.force = direction * 10.0;
    }
}

功能说明

  1. 物理模拟

    • RapierPhysicsPlugin 提供完整的物理模拟功能
    • 支持动态和静态刚体
    • 高性能碰撞检测
  2. 碰撞体类型

    • 立方体(Cuboid)
    • 球体(Sphere)
    • 胶囊体(Capsule)
    • 三角形网格(TriMesh)
    • 高度场(HeightField)等
  3. 物理特性

    • 质量属性
    • 摩擦力
    • 恢复系数(弹性)
    • 阻尼等
  4. 力与冲量

    • ExternalForce 持续施加力
    • ExternalImpulse 施加瞬间冲量

调试渲染

RapierDebugRenderPlugin 可以在开发时可视化碰撞体和物理特性。

性能优化

bevy_rapier3d基于Rapier物理引擎,专为高性能设计:

  • 使用并行计算
  • 高效的碰撞检测算法
  • 针对游戏优化的解算器

完整示例代码

use bevy::prelude::*;
use bevy_rapier3d::prelude::*;

fn main() {
    App::new()
        .add_plugins(DefaultPlugins)
        .add_plugin(RapierPhysicsPlugin::<NoUserData>::default())
        .add_plugin(RapierDebugRenderPlugin::default())
        .add_startup_system(setup_scene)
        .add_startup_system(setup_physics)
        .add_system(apply_gravity)
        .add_system(jump_controls)
        .run();
}

// 设置场景
fn setup_scene(
    mut commands: Commands,
    mut meshes: ResMut<Assets<Mesh>>,
    mut materials: ResMut<Assets<StandardMaterial>>,
) {
    // 相机
    commands.spawn_bundle(Camera3dBundle {
        transform: Transform::from_xyz(0.0, 2.0, 10.0).looking_at(Vec3::ZERO, Vec3::Y),
        ..default()
    });

    // 光照
    commands.spawn_bundle(DirectionalLightBundle {
        directional_light: DirectionalLight {
            illuminance: 10000.0,
            shadows_enabled: true,
            ..default()
        },
        transform: Transform::from_xyz(3.0, 10.0, 5.0).looking_at(Vec3::ZERO, Vec3::Y),
        ..default()
    });
}

// 设置物理场景
fn setup_physics(
    mut commands: Commands,
    mut meshes: ResMut<Assets<Mesh>>,
    mut materials: ResMut<Assets<StandardMaterial>>,
) {
    // 地面
    commands
        .spawn_bundle(PbrBundle {
            mesh: meshes.add(Mesh::from(shape::Plane { size: 10.0 })),
            material: materials.add(Color::rgb(0.3, 0.5, 0.3).into()),
            transform: Transform::from_xyz(0.0, -2.0, 0.0),
            ..default()
        })
        .insert(Collider::cuboid(5.0, 0.1, 5.0))
        .insert(RigidBody::Fixed);

    // 玩家角色(胶囊体)
    commands
        .spawn_bundle(PbrBundle {
            mesh: meshes.add(Mesh::from(shape::Capsule {
                radius: 0.5,
                depth: 1.0,
                ..default()
            })),
            material: materials.add(Color::rgb(0.8, 0.2, 0.2).into()),
            transform: Transform::from_xyz(0.0, 4.0, 0.0),
            ..default()
        })
        .insert(RigidBody::Dynamic)
        .insert(Collider::capsule_y(0.5, 0.5))
        .insert(Velocity::default())
        .insert(GravityScale(1.0))
        .insert(Player);
}

// 玩家标记组件
#[derive(Component)]
struct Player;

// 应用重力系统
fn apply_gravity(mut query: Query<&mut Velocity, With<Player>>) {
    for mut velocity in query.iter_mut() {
        velocity.linvel.y -= 0.1; // 简单重力模拟
    }
}

// 跳跃控制系统
fn jump_controls(
    keyboard_input: Res<Input<KeyCode>>,
    mut query: Query<&mut Velocity, With<Player>>,
) {
    if keyboard_input.just_pressed(KeyCode::Space) {
        for mut velocity in query.iter_mut() {
            velocity.linvel.y = 5.0; // 跳跃力
        }
    }
}

许可证: Apache-2.0


1 回复

Rust物理引擎库bevy_rapier3d的使用 - 3D游戏开发中的高性能碰撞检测与刚体模拟

完整示例Demo

下面是一个完整的bevy_rapier3d物理场景示例,包含了相机控制、物理交互和调试渲染:

use bevy::prelude::*;
use bevy_rapier3d::prelude::*;

fn main() {
    App::new()
        .add_plugins(DefaultPlugins)
        // 添加物理插件
        .add_plugins(RapierPhysicsPlugin::<NoUserData>::default())
        // 添加调试渲染插件(按F1切换显示)
        .add_plugins(RapierDebugRenderPlugin::default())
        // 添加系统
        .add_systems(Startup, (setup_scene, setup_camera))
        .add_systems(Update, (keyboard_input_system, mouse_click_system))
        .run();
}

// 设置场景
fn setup_scene(
    mut commands: Commands,
    mut meshes: ResMut<Assets<Mesh>>,
    mut materials: ResMut<Assets<StandardMaterial>>,
) {
    // 添加光源
    commands.spawn(DirectionalLightBundle {
        directional_light: DirectionalLight {
            shadows_enabled: true,
            ..default()
        },
        transform: Transform::from_xyz(4.0, 8.0, 4.0).looking_at(Vec3::ZERO, Vec3::Y),
        ..default()
    });

    // 创建地面
    commands.spawn((
        PbrBundle {
            mesh: meshes.add(Mesh::from(shape::Plane::from_size(20.0))),
            material: materials.add(Color::rgb(0.3, 0.5, 0.3).into()),
            transform: Transform::from_xyz(0.0, -2.0, 0.0),
            ..default()
        },
        Collider::cuboid(10.0, 0.1, 10.0),
        RigidBody::Fixed,
    ));

    // 创建物理对象
    spawn_physics_objects(&mut commands, &mut meshes, &mut materials);
}

// 设置相机
fn setup_camera(mut commands: Commands) {
    commands.spawn(Camera3dBundle {
        transform: Transform::from_xyz(-10.0, 10.0, 10.0).looking_at(Vec3::ZERO, Vec3::Y),
        ..default()
    });
}

// 生成物理对象
fn spawn_physics_objects(
    commands: &mut Commands,
    meshes: &mut ResMut<Assets<Mesh>>,
    materials: &mut ResMut<Assets<StandardMaterial>>,
) {
    // 创建动态球体
    for i in 0..5 {
        commands.spawn((
            PbrBundle {
                mesh: meshes.add(Mesh::from(shape::UVSphere {
                    radius: 0.5,
                    ..default()
                })),
                material: materials.add(Color::rgb(0.8, 0.2, 0.2).into()),
                transform: Transform::from_xyz(i as f32 * 2.0 - 4.0, 5.0, 0.0),
                ..default()
            },
            Collider::ball(0.5),
            RigidBody::Dynamic,
            Restitution::coefficient(0.7), // 弹性系数
        ));
    }

    // 创建堆叠的立方体
    for y in 0..3 {
        for x in 0..3 {
            commands.spawn((
                PbrBundle {
                    mesh: meshes.add(Mesh::from(shape::Cube { size: 1.0 })),
                    material: materials.add(Color::rgb(0.2, 0.2, 0.8).into()),
                    transform: Transform::from_xyz(x as f32 - 1.0, y as f32 + 0.5, 3.0),
                    ..default()
                },
                Collider::cuboid(0.5, 0.5, 0.5),
                RigidBody::Dynamic,
                Friction::coefficient(0.3), // 摩擦系数
            ));
        }
    }
}

// 键盘输入系统
fn keyboard_input_system(
    keyboard_input: Res<Input<KeyCode>>,
    mut query: Query<&mut ExternalForce, With<RigidBody>>,
) {
    if keyboard_input.just_pressed(KeyCode::Space) {
        for mut ext_force in &mut query {
            ext_force.force = Vec3::new(0.0, 10.0, 0.0); // 向上施加力
        }
    }
}

// 鼠标点击系统
fn mouse_click_system(
    mut commands: Commands,
    mouse_input: Res<Input<MouseButton>>,
    rapier_context: Res<RapierContext>,
    camera_query: Query<(&Camera, &GlobalTransform)>,
    mut meshes: ResMut<Assets<Mesh>>,
    mut materials: ResMut<Assets<StandardMaterial>>,
) {
    if mouse_input.just_pressed(MouseButton::Left) {
        let (camera, camera_transform) = camera_query.single();
        
        if let Some(ray) = camera.viewport_to_world(camera_transform, Vec2::new(0.5, 0.5)) {
            let max_dist = 100.0;
            let filter = QueryFilter::default();
            
            // 射线检测
            if let Some((_entity, _toi)) = rapier_context.cast_ray(
                ray.origin,
                ray.direction,
                max_dist,
                true,
                filter,
            ) {
                // 在点击位置生成球体
                commands.spawn((
                    PbrBundle {
                        mesh: meshes.add(Mesh::from(shape::UVSphere {
                            radius: 0.3,
                            ..default()
                        })),
                        material: materials.add(Color::rgb(0.8, 0.8, 0.2).into()),
                        transform: Transform::from_translation(ray.origin + ray.direction * 5.0),
                        ..default()
                    },
                    Collider::ball(0.3),
                    RigidBody::Dynamic,
                ));
            }
        }
    }
}

示例说明

这个完整示例展示了bevy_rapier3d的主要功能:

  1. 物理系统初始化:通过RapierPhysicsPlugin添加物理模拟
  2. 调试渲染:使用RapierDebugRenderPlugin可视化碰撞体
  3. 场景设置
    • 创建地面作为固定刚体
    • 生成动态球体和立方体堆
  4. 交互功能
    • 按空格键对所有刚体施加向上的力
    • 鼠标左键点击在视线方向生成新的球体
  5. 物理属性设置
    • 设置弹性系数(Restitution)
    • 设置摩擦系数(Friction)

要运行此示例,请确保Cargo.toml中包含正确的依赖项:

[dependencies]
bevy = "0.11"
bevy_rapier3d = "0.22"
回到顶部