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

Example bounding sphere using macroquad #259

Merged
merged 29 commits into from
Sep 20, 2024
Merged
Show file tree
Hide file tree
Changes from 25 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
44c81cc
example for projection (+ bug detected)
Vrixyz Jul 31, 2024
9526e75
simpler project example
Vrixyz Jul 31, 2024
113046d
use lissajous trajectory + small polish pass
Vrixyz Jul 31, 2024
ed6a112
zoom in
Vrixyz Aug 14, 2024
8c09f1a
Merge branch 'master' into projection_example
Vrixyz Aug 14, 2024
b181c65
scrape plane intersection
Vrixyz Aug 14, 2024
2a68514
expose cuboid::to_trimesh for parry2d + add 2d example for projectpoint
Vrixyz Aug 14, 2024
065f6b6
fix local point inside the shape
Vrixyz Aug 14, 2024
174f012
common macroquad code in their example
Vrixyz Aug 14, 2024
3955d44
use a shaded cube for project_point2d too.
Vrixyz Aug 14, 2024
4bbe298
lighter cube
Vrixyz Sep 3, 2024
2dcadc9
fix plane intersection code with common code
Vrixyz Sep 3, 2024
d61b05b
removed a few unused variables
Vrixyz Sep 3, 2024
8ab7b5c
2d examples use common macroquad code
Vrixyz Sep 3, 2024
8057422
add example for convex hull
Vrixyz Sep 3, 2024
feda1a6
3d example for convex hull
Vrixyz Sep 3, 2024
39d7f8e
3d example for convex hull
Vrixyz Sep 3, 2024
aa711e6
add example for aabb2d
Vrixyz Sep 3, 2024
335639f
example for aabb in 3d
Vrixyz Sep 3, 2024
35c557f
remove a few unused code
Vrixyz Sep 3, 2024
1bf510f
bounding sphere example using macroquad
Vrixyz Sep 4, 2024
359b76b
add a note about float imprecisions
Vrixyz Sep 4, 2024
607ac1f
simpler aabb 3d function
Vrixyz Sep 4, 2024
cafcad4
Merge branch 'example_aabb' into example_bounding_sphere
Vrixyz Sep 4, 2024
cfd62f4
3d example for bounding spheres
Vrixyz Sep 4, 2024
abf04f3
Merge branch 'master' into example_bounding_sphere
Vrixyz Sep 20, 2024
4c8e1ae
Merge branch 'master' into example_bounding_sphere
Vrixyz Sep 20, 2024
b68ed9d
revert a few unneeded changes
Vrixyz Sep 20, 2024
098ddf3
pr feedback
Vrixyz Sep 20, 2024
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
125 changes: 95 additions & 30 deletions crates/parry2d/examples/aabb2d.rs
Original file line number Diff line number Diff line change
@@ -1,36 +1,101 @@
mod common_macroquad;

extern crate nalgebra as na;

use common_macroquad::{draw_polyline, lissajous_2d, mquad_from_na, na_from_mquad};
use macroquad::prelude::*;
use na::Isometry2;
use parry2d::bounding_volume::BoundingVolume;
use parry2d::bounding_volume::{Aabb, BoundingVolume};
use parry2d::shape::Ball;

fn main() {
/*
* Initialize the shapes.
*/
let ball1 = Ball::new(0.5);
let ball2 = Ball::new(1.0);

let ball1_pos = Isometry2::translation(0.0, 1.0);
let ball2_pos = Isometry2::identity();

/*
* Compute their axis-aligned bounding boxes.
*/
let aabb_ball1 = ball1.aabb(&ball1_pos);
let aabb_ball2 = ball2.aabb(&ball2_pos);

// Merge the two boxes.
let bounding_aabb = aabb_ball1.merged(&aabb_ball2);

// Enlarge the ball2 aabb.
let loose_aabb_ball2 = aabb_ball2.loosened(1.0);

// Intersection and inclusion tests.
assert!(aabb_ball1.intersects(&aabb_ball2));
assert!(bounding_aabb.contains(&aabb_ball1));
assert!(bounding_aabb.contains(&aabb_ball2));
assert!(!aabb_ball2.contains(&bounding_aabb));
assert!(!aabb_ball1.contains(&bounding_aabb));
assert!(loose_aabb_ball2.contains(&aabb_ball2));
const RENDER_SCALE: f32 = 30.0;

#[macroquad::main("parry2d::utils::point_in_poly2d")]
async fn main() {
let render_pos = Vec2::new(300.0, 300.0);

loop {
let elapsed_time = get_time() as f32 * 0.7;
clear_background(BLACK);

/*
* Initialize the shapes.
*/
let ball1 = Ball::new(0.5);
let ball2 = Ball::new(1.0);

let ball1_pos = na_from_mquad(lissajous_2d(elapsed_time)) * 5f32;
let ball2_pos = Isometry2::identity();

/*
* Compute their axis-aligned bounding boxes.
*/
let aabb_ball1 = ball1.aabb(&ball1_pos.into());
let aabb_ball2 = ball2.aabb(&ball2_pos);

// Merge the two boxes.
let bounding_aabb = aabb_ball1.merged(&aabb_ball2);

// Enlarge the ball2 aabb.
let loose_aabb_ball2 = aabb_ball2.loosened(2f32);

// Intersection test
let color = if aabb_ball1.intersects(&aabb_ball2) {
RED
} else {
GREEN
};

assert!(bounding_aabb.contains(&aabb_ball1));
assert!(bounding_aabb.contains(&aabb_ball2));
assert!(loose_aabb_ball2.contains(&aabb_ball2));

let ball1_translation = mquad_from_na(ball1_pos.coords.into()) * RENDER_SCALE + render_pos;
draw_circle(
ball1_translation.x,
ball1_translation.y,
ball1.radius * RENDER_SCALE,
color,
);
let ball2_translation =
mquad_from_na(ball2_pos.translation.vector.into()) * RENDER_SCALE + render_pos;
draw_circle(
ball2_translation.x,
ball2_translation.y,
ball2.radius * RENDER_SCALE,
color,
);

draw_aabb(aabb_ball1, render_pos, color);
draw_aabb(aabb_ball2, render_pos, color);
draw_aabb(bounding_aabb, render_pos, YELLOW);

// Inclusion test
let color_included: Color = if loose_aabb_ball2.contains(&aabb_ball1) {
BLUE
} else {
MAGENTA
};
draw_aabb(loose_aabb_ball2, render_pos, color_included);
next_frame().await
}
}

fn draw_aabb(aabb: Aabb, offset: Vec2, color: Color) {
let mins = mquad_from_na(aabb.mins) * RENDER_SCALE + offset;
let maxs = mquad_from_na(aabb.maxs) * RENDER_SCALE + offset;

let line = vec![
Vec2::new(mins.x, mins.y),
Vec2::new(mins.x, maxs.y),
Vec2::new(maxs.x, maxs.y),
Vec2::new(maxs.x, mins.y),
Vec2::new(mins.x, mins.y),
];
let drawable_line = line
.iter()
.zip(line.iter().cycle().skip(1).take(line.len()))
.map(|item| (item.0.clone(), item.1.clone()))
.collect();
draw_polyline(drawable_line, color);
}
155 changes: 125 additions & 30 deletions crates/parry2d/examples/bounding_sphere2d.rs
Original file line number Diff line number Diff line change
@@ -1,36 +1,131 @@
mod common_macroquad;

extern crate nalgebra as na;

use common_macroquad::{draw_polyline, lissajous_2d, mquad_from_na, na_from_mquad};
use macroquad::prelude::*;
use na::{Isometry2, Vector2};
use parry2d::bounding_volume::BoundingVolume;
use parry2d::bounding_volume::{Aabb, BoundingVolume};
use parry2d::shape::Ball;
use parry2d::shape::Cuboid;

fn main() {
/*
* Initialize the shapes.
*/
let cube1 = Cuboid::new(Vector2::repeat(0.5));
let cube2 = Cuboid::new(Vector2::new(1.0, 0.5));

let cube1_pos = Isometry2::translation(0.0, 1.0);
let cube2_pos = Isometry2::identity();

/*
* Compute their bounding spheres.
*/
let bounding_sphere_cube1 = cube1.bounding_sphere(&cube1_pos);
let bounding_sphere_cube2 = cube2.bounding_sphere(&cube2_pos);

// Merge the two spheres.
let bounding_bounding_sphere = bounding_sphere_cube1.merged(&bounding_sphere_cube2);

// Enlarge the cube2 bounding sphere.
let loose_bounding_sphere_cube2 = bounding_sphere_cube2.loosened(1.0);

// Intersection and inclusion tests.
assert!(bounding_sphere_cube1.intersects(&bounding_sphere_cube2));
assert!(bounding_bounding_sphere.contains(&bounding_sphere_cube1));
assert!(bounding_bounding_sphere.contains(&bounding_sphere_cube2));
assert!(!bounding_sphere_cube2.contains(&bounding_bounding_sphere));
assert!(!bounding_sphere_cube1.contains(&bounding_bounding_sphere));
assert!(loose_bounding_sphere_cube2.contains(&bounding_sphere_cube2));
const RENDER_SCALE: f32 = 30.0;

#[macroquad::main("parry2d::utils::point_in_poly2d")]
async fn main() {
let render_pos = Vec2::new(300.0, 300.0);

loop {
let elapsed_time = get_time() as f32 * 0.7;
clear_background(BLACK);

/*
* Initialize the shapes.
*/
let cube1: Cuboid = Cuboid::new(Vector2::repeat(0.5));
let cube2 = Cuboid::new(Vector2::new(1., 0.5));

let cube1_pos = na_from_mquad(lissajous_2d(elapsed_time)) * 5f32;
let cube1_pos = Isometry2::translation(cube1_pos.x, cube1_pos.y);
let cube2_pos = Isometry2::identity();

/*
* Compute their bounding spheres.
*/
let bounding_sphere_cube1 = cube1.bounding_sphere(&cube1_pos);
let bounding_sphere_cube2 = cube2.bounding_sphere(&cube2_pos);

// Merge the two spheres.
let bounding_bounding_sphere = bounding_sphere_cube1.merged(&bounding_sphere_cube2);

// Enlarge the cube2 bounding sphere.
let loose_bounding_sphere_cube2 = bounding_sphere_cube2.loosened(3.0);

// Intersection test
let color = if bounding_sphere_cube1.intersects(&bounding_sphere_cube2) {
RED
} else {
GREEN
};

// Due to float imprecisions, it's dangerous to assume that both shapes will be
// contained in the merged.
// You can leverage `BoundingVolume::loosened` with an epsilon for expected results.
//
// These might fail:
// assert!(bounding_bounding_sphere.contains(&bounding_sphere_cube1));
// assert!(bounding_bounding_sphere.contains(&bounding_sphere_cube2));

assert!(loose_bounding_sphere_cube2.contains(&bounding_sphere_cube1));
assert!(loose_bounding_sphere_cube2.contains(&bounding_sphere_cube2));

let cube1_translation =
mquad_from_na(cube1_pos.translation.vector.into()) * RENDER_SCALE + render_pos;
draw_cuboid(cube1, cube1_translation, color);

let cube2_translation =
mquad_from_na(cube2_pos.translation.vector.into()) * RENDER_SCALE + render_pos;
draw_cuboid(cube2, cube2_translation, color);
draw_circle_lines(
bounding_sphere_cube1.center.x * RENDER_SCALE + render_pos.x,
bounding_sphere_cube1.center.y * RENDER_SCALE + render_pos.y,
bounding_sphere_cube1.radius * RENDER_SCALE,
2f32,
color,
);
draw_circle_lines(
bounding_sphere_cube2.center.x * RENDER_SCALE + render_pos.x,
bounding_sphere_cube2.center.y * RENDER_SCALE + render_pos.y,
bounding_sphere_cube2.radius * RENDER_SCALE,
2f32,
color,
);
draw_circle_lines(
bounding_bounding_sphere.center.x * RENDER_SCALE + render_pos.x,
bounding_bounding_sphere.center.y * RENDER_SCALE + render_pos.y,
bounding_bounding_sphere.radius * RENDER_SCALE,
2f32,
YELLOW,
);

// Inclusion test
let color_included: Color = if loose_bounding_sphere_cube2.contains(&bounding_sphere_cube1)
{
BLUE
} else {
MAGENTA
};
draw_circle_lines(
loose_bounding_sphere_cube2.center.x * RENDER_SCALE + render_pos.x,
loose_bounding_sphere_cube2.center.y * RENDER_SCALE + render_pos.y,
loose_bounding_sphere_cube2.radius * RENDER_SCALE,
2f32,
color_included,
);
next_frame().await
}
}

fn draw_cuboid(cuboid: Cuboid, pos: Vec2, color: Color) {
let aabb = cuboid.local_aabb();
draw_aabb(aabb, pos, color)
}

fn draw_aabb(aabb: Aabb, offset: Vec2, color: Color) {
let mins = mquad_from_na(aabb.mins) * RENDER_SCALE + offset;
let maxs = mquad_from_na(aabb.maxs) * RENDER_SCALE + offset;

let line = vec![
Vec2::new(mins.x, mins.y),
Vec2::new(mins.x, maxs.y),
Vec2::new(maxs.x, maxs.y),
Vec2::new(maxs.x, mins.y),
Vec2::new(mins.x, mins.y),
];
let drawable_line = line
.iter()
.zip(line.iter().cycle().skip(1).take(line.len()))
.map(|item| (item.0.clone(), item.1.clone()))
.collect();
draw_polyline(drawable_line, color);
}
103 changes: 103 additions & 0 deletions crates/parry2d/examples/common_macroquad.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
#[allow(unused, dead_code)]
use std::f32::consts::{FRAC_PI_2, FRAC_PI_4, FRAC_PI_6};

use macroquad::prelude::*;
use macroquad::{
color::{Color, WHITE},
math::Vec2,
shapes::draw_line,
};
use nalgebra::Point2;
use parry2d::math::Real;
use parry2d::shape::TriMesh;

fn main() {
println!(
"This module contains helper functions to use macroquad,
isolated from the rest of the examples for the sake of simplicity."
);
}

pub fn mquad_from_na(a: Point2<Real>) -> Vec2 {
Vec2::new(a.x, a.y)
}

pub fn na_from_mquad(a: Vec2) -> Point2<Real> {
Point2::new(a.x, a.y)
}

pub fn draw_polyline(polygon: Vec<(Vec2, Vec2)>, color: Color) {
for i in 0..polygon.len() {
let a = polygon[i].0;
let b = polygon[i].1;
draw_line_2d(a, b, color);
}
}

pub fn easy_draw_text(text: &str) {
macroquad::text::draw_text(text, 10.0, 48.0 + 18.0, 30.0, WHITE);
}

pub fn lissajous_2d(t: f32) -> Vec2 {
// Some hardcoded parameters to have a pleasing lissajous trajectory.
lissajous_2d_with_params(t, 3.0, 2.0, FRAC_PI_2, FRAC_PI_4)
}
pub fn lissajous_2d_with_params(t: f32, a: f32, b: f32, delta_x: f32, delta_y: f32) -> Vec2 {
// Some hardcoded parameters to have a pleasing lissajous trajectory.

let x = (a * t + delta_x).sin();
let y = (b * t + delta_y).sin();
Vec2::new(x, y) * 0.75f32
}

pub fn draw_line_2d(a: Vec2, b: Vec2, color: Color) {
draw_line(a.x, a.y, b.x, b.y, 2f32, color);
}

pub fn draw_trimesh2(trimesh: &TriMesh, offset: Vec2) {
let vertices = trimesh.vertices();
for v in trimesh.indices() {
let v0 = mquad_from_na(vertices[v[0] as usize]) + offset;
let v1 = mquad_from_na(vertices[v[1] as usize]) + offset;
let v2 = mquad_from_na(vertices[v[2] as usize]) + offset;

draw_line(v0.x, v0.y, v1.x, v1.y, 2f32, WHITE);
draw_line(v0.x, v0.y, v2.x, v2.y, 2f32, WHITE);
draw_line(v2.x, v2.y, v1.x, v1.y, 2f32, WHITE);
}
}

pub fn draw_polygon(polygon: &[Point2<f32>], scale: f32, shift: Point2<f32>, color: Color) {
for i in 0..polygon.len() {
let a = polygon[i];
let b = polygon[(i + 1) % polygon.len()];
draw_line(
a.x * scale + shift.x,
a.y * scale + shift.y,
b.x * scale + shift.x,
b.y * scale + shift.y,
2.0,
color,
);
}
}

pub fn draw_point(point: Point2<f32>, scale: f32, shift: Point2<f32>, color: Color) {
let edge_len = 0.15;
draw_line(
(point.x - edge_len) * scale + shift.x,
point.y * scale + shift.y,
(point.x + edge_len) * scale + shift.x,
point.y * scale + shift.y,
2.0,
color,
);
draw_line(
point.x * scale + shift.x,
(point.y - edge_len) * scale + shift.y,
point.x * scale + shift.x,
(point.y + edge_len) * scale + shift.y,
2.0,
color,
);
}
Loading
Loading