Rust 3D游戏开发插件bevy_mod_raycast的使用:实现高效射线检测与拾取功能
Rust 3D游戏开发插件bevy_mod_raycast的使用:实现高效射线检测与拾取功能
bevy_mod_raycast
是一个用于Bevy游戏引擎的网格射线检测小插件。
快速开始
使用Raycast
系统参数,你甚至不需要添加插件,可以直接在ECS中进行射线检测:
use bevy_mod_raycast::prelude::*;
fn my_raycast_system(mut raycast: Raycast) {
let ray = Ray3d::new(Vec3::ZERO, Vec3::X); // 创建一条从原点沿X轴方向的射线
let hits = raycast.cast_ray(ray, &RaycastSettings::default()); // 执行射线检测
}
完整示例代码
下面是一个完整的Bevy应用示例,展示了如何使用bevy_mod_raycast
实现3D场景中的对象拾取功能:
use bevy::prelude::*;
use bevy_mod_raycast::prelude::*;
fn main() {
App::new()
.add_plugins(DefaultPlugins)
// 添加射线检测插件
.add_plugins(DefaultRaycastingPlugin::default())
// 添加系统
.add_systems(Startup, setup_scene)
.add_systems(Update, (handle_raycast, rotate_cube))
.run();
}
// 场景设置
fn setup_scene(
mut commands: Commands,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<StandardMaterial>>,
) {
// 相机
commands.spawn((
Camera3dBundle {
transform: Transform::from_xyz(0.0, 0.0, 5.0).looking_at(Vec3::ZERO, Vec3::Y),
..default()
},
RaycastSource::<RaycastSet>::new_transform_empty(), // 使相机成为射线源
));
// 立方体
commands.spawn((
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, 0.0, 极0.0),
..default()
},
RaycastMesh::<RaycastSet>::default(), // 使立方体可被射线检测
));
// 光源
commands.spawn(PointLightBundle {
point_light: PointLight {
intensity: 1500.0,
shadows_enabled: true,
..default()
},
transform: Transform::from_xyz(4.0, 8.0, 4.0),
..default()
});
}
// 射线检测处理系统
fn handle_raycast(
mut cursor: EventReader<CursorMoved>,
mut raycast: Raycast,
mut materials: ResMut<Assets<StandardMaterial>>,
cubes: Query<&Handle<StandardMaterial>>,
) {
// 获取鼠标位置变化事件
for event in cursor.read() {
// 执行射线检测
let hits = raycast.cast_ray(
Ray3d::from_screenspace(
event.position,
Camera::default(),
&GlobalTransform::default(),
),
&RaycastSettings::default(),
);
// 改变被选中物体的颜色
if let Some(hit) = hits.first() {
if let Ok(material_handle) = cubes.get(hit.entity()) {
if let Some(material) = materials.get_mut(material_handle) {
material.base_color = Color::rgb(0.9, 0.3, 0.3);
}
}
} else {
for cube in &cubes {
if let Some(material) = materials.get_mut(cube) {
material.base_color = Color::rgb(0.8, 0.7, 0.6);
}
}
}
}
}
// 立方体旋转动画
fn rotate_c极ube(mut cubes: Query<&mut Transform, With<RaycastMesh<RaycastSet>>>) {
for mut transform in &mut cubes {
transform.rotate_y(0.01);
}
}
// 定义射线检测组
#[derive(Reflect)]
struct RaycastSet;
版本支持
下表显示了bevy_mod_raycast
与Bevy版本的对应关系:
bevy | bevy_mod_raycast |
---|---|
0.14 | 0.18 |
0.13 | 0.17 |
0.12 | 0.16 |
0.11 | 0.9 - 0.15 |
0.10 | 0.8 |
0.9 | 0.7 |
0.8 | 0.6 |
0.7 | 0.4 - 0.5 |
0.6 | 0.3 |
0.5 | 0.2 |
0.4 | 0.1 |
安装
在项目目录中运行以下Cargo命令:
cargo add bevy_mod_raycast
或在Cargo.toml中添加:
bevy_mod_raycast = "0.18.0"
1 回复
Rust 3D游戏开发插件bevy_mod_raycast的使用:实现高效射线检测与拾取功能
完整示例代码
下面是一个完整的bevy_mod_raycast使用示例,实现了鼠标拾取3D物体的功能:
use bevy::prelude::*;
use bevy_mod_raycast::*;
fn main() {
App::new()
.add_plugins(DefaultPlugins)
// 添加默认的射线拾取插件
.add_plugins(DefaultRaycastingPlugin::default())
.add_systems(Startup, setup_scene)
.add_systems(Update, handle_picks)
.run();
}
// 定义自定义的RaycastSet用于分组
#[derive(Reflect)]
struct MyRaycastSet;
fn setup_scene(
mut commands: Commands,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<StandardMaterial>>,
) {
// 创建可拾取的立方体
commands.spawn((
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, 0.5, 0.0),
..default()
},
// 使这个立方体可以被MyRaycastSet组的射线检测到
RaycastMesh::<MyRaycastSet>::default(),
));
// 创建可拾取的球体
commands.spawn((
PbrBundle {
mesh: meshes.add(Mesh::from(shape::UVSphere {
radius: 0.5,
sectors: 32,
stacks: 32
})),
material: materials.add(Color::rgb(0.3, 0.5, 0.9).into()),
transform: Transform::from_xyz(2.0, 0.5, 0.0),
..default()
},
RaycastMesh::<MyRaycastSet>::default(),
));
// 创建光源
commands.spawn(PointLightBundle {
point_light: PointLight {
intensity: 1500.0,
shadows_enabled: true,
..default()
},
transform: Transform::from_xyz(4.0, 8.0, 4.0),
..default()
});
// 创建相机并设置射线源
commands.spawn((
Camera3dBundle {
transform: Transform::from_xyz(0.0, 2.0, 5.0).looking_at(Vec3::ZERO, Vec3::Y),
..default()
},
// 添加射线源组件,用于从相机发射射线
RaycastSource::<MyRaycastSet>::new(),
));
}
fn handle_picks(
mut cursor_events: EventReader<CursorMoved>,
mut raycast: Raycast,
mut pick_events: EventReader<RaycastMeshEvent<MyRaycastSet>>,
mut materials: ResMut<Assets<StandardMaterial>>,
picked_entities: Query<&Handle<StandardMaterial>>,
) {
// 更新射线位置跟随鼠标移动
for event in cursor_events.read() {
raycast.update_raycast(event.position);
}
// 处理拾取事件
for pick_event in pick_events.read() {
if let Some((entity, _intersection)) = &pick_event.intersection {
// 改变被拾取物体的颜色
if let Ok(material_handle) = picked_entities.get(*entity) {
if let Some(material) = materials.get_mut(material_handle) {
material.base_color = Color::rgb(1.0, 0.0, 0.0); // 变为红色
}
}
}
}
}
代码说明
-
自定义RaycastSet:
#[derive(Reflect)] struct MyRaycastSet;
定义了一个自定义的射线检测组,用于区分不同类型的射线检测
-
可拾取物体设置:
RaycastMesh::<MyRaycastSet>::default()
为物体添加这个组件使其可以被MyRaycastSet组的射线检测到
-
射线源设置:
RaycastSource::<MyRaycastSet>::new()
为相机添加这个组件使其成为射线源
-
射线更新:
raycast.update_raycast(event.position);
在鼠标移动时更新射线位置
-
拾取事件处理:
EventReader<RaycastMeshEvent<MyRaycastSet>>
监听MyRaycastSet组的拾取事件,当射线与物体相交时会触发
-
拾取反馈:
material.base_color = Color::rgb(1.0, 0.0, 0.0);
当物体被拾取时改变其颜色作为视觉反馈
这个完整示例展示了如何使用bevy_mod_raycast实现基本的3D物体拾取功能,包括场景设置、射线源管理、拾取检测和交互反馈等完整流程。