Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

API Reorganization #99

Merged
merged 18 commits into from
Oct 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
# 0.15.0

- Changed: immediate and deferred raycasting APIs organized into respective modules.
- Added: the `DefaultRaycastingPlugin` now builds a ray using the mouse cursor every frame and
stores it in the `CursorRay` resource.
- Added: `RaycastMethod::Cursor` variant added to `RaycastSource` settings for the common use case
of using the mouse cursor.
- Added: `debug_cast_ray` mirrors the `cast_ray` method, but handles debug drawing the ray and any
intersections.
- Changed: removed unused `Reflect` derive from `RaycastSettings`. This struct is neither a resource
nor a component.

# 0.14.1

- Changed: relaxed type bounds on the generic raycast set type parameter in `RaycastSource<T>` and
Expand Down
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "bevy_mod_raycast"
version = "0.14.1"
version = "0.15.0-dev"
authors = ["Aevyrie <aevyrie@gmail.com>"]
edition = "2021"
license = "MIT"
Expand Down
15 changes: 9 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<div align="center">

# Simple Bevy Raycasting
# `bevy_mod_raycast`

A small [Bevy](https://github.com/bevyengine/bevy) plugin for mesh raycasting.

Expand All @@ -13,21 +13,23 @@ A small [Bevy](https://github.com/bevyengine/bevy) plugin for mesh raycasting.

## Getting Started

Using the [`Raycast`](https://docs.rs/bevy_mod_raycast/latest/bevy_mod_raycast/system_param/struct.Raycast.html) system param, you don't even need to add a plugin to your app. You can simply start raycasting:
Using the [`Raycast`](https://docs.rs/bevy_mod_raycast/latest/bevy_mod_raycast/system_param/struct.Raycast.html) system param, you don't even need to add a plugin, raycast immediately with the ECS:

```rs
use bevy_mod_raycast::prelude::*;

fn my_raycast_system(mut raycast: Raycast) {
let hits = raycast.cast_ray(Ray3d::default(), &RaycastSettings::default());
let ray = Ray3d::new(Vec3::ZERO, Vec3::X);
let hits = raycast.cast_ray(ray, &RaycastSettings::default());
}
```

- [Read the docs!](https://docs.rs/bevy_mod_raycast)
- 👉 [Read the docs!](https://docs.rs/bevy_mod_raycast)
- Play with the [examples](./examples).

## Bevy Version Support

<details>
<summary><h2>Bevy Version Support</h2></summary>
I intend to track the `main` branch of Bevy. PRs supporting this are welcome!

| bevy | bevy_mod_raycast |
Expand All @@ -39,4 +41,5 @@ I intend to track the `main` branch of Bevy. PRs supporting this are welcome!
| 0.7 | 0.4 - 0.5 |
| 0.6 | 0.3 |
| 0.5 | 0.2 |
| 0.4 | 0.1 |
| 0.4 | 0.1 |
</details>
6 changes: 3 additions & 3 deletions benches/ray_mesh_intersection.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use bevy::math::{Mat4, Vec3};
use bevy_mod_raycast::{Backfaces, Ray3d};
use bevy_mod_raycast::prelude::*;
use criterion::{black_box, criterion_group, criterion_main, Criterion};

fn ptoxznorm(p: u32, size: u32) -> (f32, f32) {
Expand Down Expand Up @@ -50,7 +50,7 @@ fn ray_mesh_intersection(c: &mut Criterion) {
let mesh = mesh_creation(vertices_per_side);

b.iter(|| {
black_box(bevy_mod_raycast::ray_mesh_intersection(
black_box(bevy_mod_raycast::prelude::ray_mesh_intersection(
&mesh_to_world,
&mesh.positions,
Some(&mesh.normals),
Expand All @@ -74,7 +74,7 @@ fn ray_mesh_intersection_no_intersection(c: &mut Criterion) {
let mesh = mesh_creation(vertices_per_side);

b.iter(|| {
black_box(bevy_mod_raycast::ray_mesh_intersection(
black_box(bevy_mod_raycast::prelude::ray_mesh_intersection(
&mesh_to_world,
&mesh.positions,
Some(&mesh.normals),
Expand Down
54 changes: 0 additions & 54 deletions examples/immediate.rs

This file was deleted.

118 changes: 40 additions & 78 deletions examples/minimal.rs
Original file line number Diff line number Diff line change
@@ -1,78 +1,40 @@
//! This example casts a ray from the camera using its transform, intersects a mesh, displays the
//! debug cursor at the intersection, and reports the intersection.
//!
//! It also demonstrates how normals are interpolated. Notice the debug cursor doesn't snap to the
//! faces of the low-poly sphere's faces, but smoothly interpolates using the mesh's normals.

use bevy::prelude::*;
use bevy_mod_raycast::{prelude::*, print_intersections};

fn main() {
App::new()
.add_plugins((
DefaultPlugins,
DefaultRaycastingPlugin::<MyRaycastSet>::default(),
))
.add_systems(Startup, setup)
.add_systems(Update, (rotator, print_intersections::<MyRaycastSet>))
.run();
}

// Mark our generic `RaycastMesh`s and `RaycastSource`s as part of the same "RaycastSet". This
// plugin uses generics to distinguish between groups of raycasters.
#[derive(Reflect)]
struct MyRaycastSet;

// Set up a simple scene with a sphere, camera, and light.
fn setup(
mut commands: Commands,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<StandardMaterial>>,
) {
// Overwrite the default plugin state with one that enables the debug cursor. This line can be
// removed if the debug cursor isn't needed as the state is set to default values when the
// default plugin is added.
commands.insert_resource(
bevy_mod_raycast::RaycastPluginState::<MyRaycastSet>::default().with_debug_cursor(),
);
commands.spawn((
Camera3dBundle {
projection: Projection::Orthographic(OrthographicProjection {
scale: 0.01,
..default()
}),
..default()
},
// Designate the camera as our ray casting source. Using `new_transform_empty()` means that
// the ray casting source will not be initialized with a valid ray. Instead, a ray will be
// calculated the first time the update_raycast system runs. Because we are setting this as
// a RaycastMethod::Transform source, the update_raycast system will look for a
// GlobalTransform on the camera entity, and build a ray using this transform. In this
// example, this means that as the camera rotates in the scene, the update_raycast system
// will build a valid ray every frame using the camera's updated position.
RaycastSource::<MyRaycastSet>::new_transform_empty(),
));
commands.spawn((
PbrBundle {
mesh: meshes.add(Mesh::try_from(shape::Icosphere::default()).unwrap()),
material: materials.add(Color::rgb(1.0, 1.0, 1.0).into()),
transform: Transform::from_translation(Vec3::new(0.0, 0.0, -5.0)),
..Default::default()
},
RaycastMesh::<MyRaycastSet>::default(), // Make this mesh ray cast-able
));
commands.spawn(PointLightBundle {
transform: Transform::from_translation(Vec3::new(4.0, 8.0, 4.0)),
..Default::default()
});
}

/// Rotate the camera up and down to show that the raycast intersection is updated every frame.
fn rotator(time: Res<Time>, mut query: Query<&mut Transform, With<RaycastSource<MyRaycastSet>>>) {
for mut transform in &mut query {
*transform = Transform::from_rotation(
Quat::from_rotation_x(time.elapsed_seconds().sin() * 0.2)
* Quat::from_rotation_y((time.elapsed_seconds() * 1.5).sin() * 0.1),
);
}
}
//! This example demonstrates how to use the [`Raycast`] system param to run raycasts on-demand, in
//! an immediate mode style. This is unlike using a deferred API, which runs a raycast based on
//! [`RaycastSource`] components once per frame.

use bevy::prelude::*;
use bevy_mod_raycast::prelude::*;

fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_systems(Startup, setup)
.add_systems(Update, raycast)
.run();
}

const DIST: Vec3 = Vec3::new(0.0, 0.0, -7.0);

fn raycast(mut raycast: Raycast, mut gizmos: Gizmos, time: Res<Time>) {
let t = time.elapsed_seconds();
let pos = Vec3::new(t.sin(), (t * 1.5).cos() * 2.0, t.cos()) * 1.5 + DIST;
let dir = (DIST - pos).normalize();
// This is all that is needed to raycast into the world! You can also use the normal, non-debug
// version (raycast.cast_ray) when you don't need to visualize the ray or intersections.
raycast.debug_cast_ray(Ray3d::new(pos, dir), &default(), &mut gizmos);
}

fn setup(
mut commands: Commands,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<StandardMaterial>>,
) {
commands.spawn(Camera3dBundle::default());
commands.spawn(PointLightBundle::default());
commands.spawn(PbrBundle {
mesh: meshes.add(Mesh::try_from(shape::Capsule::default()).unwrap()),
material: materials.add(Color::rgb(1.0, 1.0, 1.0).into()),
transform: Transform::from_translation(DIST),
..default()
});
}
57 changes: 57 additions & 0 deletions examples/minimal_deferred.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
//! This example demonstrates how to use the [`bevy_mod_raycast::deferred`]` API. Unlike the
//! [`Raycast`] system param, this API is declarative, and does not return a result immediately.
//! Instead, behavior is defined using components, and raycasting is done once per frame.

use bevy::prelude::*;
use bevy_mod_raycast::prelude::*;

fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_plugins(DeferredRaycastingPlugin::<MyRaycastSet>::default())
// Overrides default settings and enables the debug cursor
.insert_resource(RaycastPluginState::<MyRaycastSet>::default().with_debug_cursor())
.add_systems(Startup, setup)
.add_systems(Update, move_ray)
.run();
}

const DIST: Vec3 = Vec3::new(0.0, 0.0, -7.0);

#[derive(Reflect)]
struct MyRaycastSet; // Groups raycast sources with meshes, can use `()` instead.

#[derive(Component)]
struct MovingRaycaster;

fn move_ray(time: Res<Time>, mut query: Query<&mut Transform, With<MovingRaycaster>>) {
let t = time.elapsed_seconds();
let pos = Vec3::new(t.sin(), (t * 1.5).cos() * 2.0, t.cos()) * 1.5 + DIST;
let dir = (DIST - pos).normalize();
*query.single_mut() = Transform::from_translation(pos).looking_to(dir, Vec3::Y);
}

fn setup(
mut commands: Commands,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<StandardMaterial>>,
) {
commands.spawn(Camera3dBundle::default());
commands.spawn(PointLightBundle::default());
// Unlike the immediate mode API where the raycast is built every frame in a system, instead we
// spawn an entity and mark it as a raycasting source, using its `GlobalTransform`.
commands.spawn((
MovingRaycaster,
SpatialBundle::default(),
RaycastSource::<MyRaycastSet>::new_transform_empty(),
));
commands.spawn((
PbrBundle {
mesh: meshes.add(Mesh::try_from(shape::Capsule::default()).unwrap()),
material: materials.add(Color::rgb(1.0, 1.0, 1.0).into()),
transform: Transform::from_translation(DIST),
..default()
},
RaycastMesh::<MyRaycastSet>::default(), // Make this mesh ray cast-able
));
}
Loading