|
| 1 | +use macroquad::models::Vertex; |
| 2 | +use macroquad::prelude::*; |
| 3 | +use nalgebra::{Point3, UnitVector3, Vector3}; |
| 4 | +use parry3d::math::Real; |
| 5 | +use parry3d::query::IntersectResult; |
| 6 | +use parry3d::shape::{Cuboid, TriMesh}; |
| 7 | + |
| 8 | +#[macroquad::main("parry3d::query::PlaneIntersection")] |
| 9 | +async fn main() { |
| 10 | + let trimesh = Cuboid::new(Vector3::repeat(1.0)).to_trimesh(); |
| 11 | + |
| 12 | + let camera_pos = Vec3::new(-1.5f32, 2.5f32, -3f32); |
| 13 | + |
| 14 | + let mesh = mquad_mesh_from_points(&trimesh, camera_pos); |
| 15 | + let trimesh = TriMesh::new(trimesh.0, trimesh.1); |
| 16 | + |
| 17 | + for _ in 1.. { |
| 18 | + clear_background(BLACK); |
| 19 | + |
| 20 | + let elapsed_time = get_time(); |
| 21 | + |
| 22 | + // Animated rotation for the intersection plane. |
| 23 | + let bias = -1.2 * (elapsed_time as f32 / 3f32).sin(); |
| 24 | + let rotation = Quat::from_axis_angle(Vec3::Z, (elapsed_time as f32 * 40f32).to_radians()); |
| 25 | + let up_plane_vector = rotation * Vec3::Y; |
| 26 | + |
| 27 | + // Get the intersection polyline. |
| 28 | + let intersection_result = trimesh.intersection_with_local_plane( |
| 29 | + &UnitVector3::new_normalize(Vector3::new( |
| 30 | + up_plane_vector.x, |
| 31 | + up_plane_vector.y, |
| 32 | + up_plane_vector.z, |
| 33 | + )), |
| 34 | + bias, |
| 35 | + 0.0005, |
| 36 | + ); |
| 37 | + |
| 38 | + // Initialize 3D camera. |
| 39 | + set_camera(&Camera3D { |
| 40 | + position: camera_pos, |
| 41 | + up: Vec3::new(0f32, 1f32, 0f32), |
| 42 | + target: Vec3::new(0.5f32, 0f32, 0.5f32), |
| 43 | + ..Default::default() |
| 44 | + }); |
| 45 | + |
| 46 | + // Draw involved shapes. |
| 47 | + let plane_center = up_plane_vector * bias; |
| 48 | + draw_line_3d(plane_center, plane_center + up_plane_vector, GREEN); |
| 49 | + draw_mesh(&mesh); |
| 50 | + draw_grid_ex(10, 0.333, BLUE, RED, plane_center, rotation); |
| 51 | + |
| 52 | + /* |
| 53 | + * |
| 54 | + * Render the intersection. |
| 55 | + * |
| 56 | + */ |
| 57 | + match intersection_result { |
| 58 | + IntersectResult::Intersect(points) => { |
| 59 | + draw_polyline( |
| 60 | + points |
| 61 | + .segments() |
| 62 | + .map(|s| (mquad_from_na(s.a), mquad_from_na(s.b))) |
| 63 | + .collect(), |
| 64 | + Color::new(0f32, 1f32, 0f32, 1f32), |
| 65 | + ); |
| 66 | + set_default_camera(); |
| 67 | + draw_text("Intersection found!"); |
| 68 | + } |
| 69 | + IntersectResult::Negative => { |
| 70 | + set_default_camera(); |
| 71 | + draw_text("No intersection found, the shape is below the plane."); |
| 72 | + } |
| 73 | + IntersectResult::Positive => { |
| 74 | + set_default_camera(); |
| 75 | + draw_text("No intersection found, the shape is above the plane."); |
| 76 | + } |
| 77 | + } |
| 78 | + next_frame().await |
| 79 | + } |
| 80 | +} |
| 81 | + |
| 82 | +fn mquad_mesh_from_points(trimesh: &(Vec<Point3<Real>>, Vec<[u32; 3]>), camera_pos: Vec3) -> Mesh { |
| 83 | + let (points, indices) = trimesh; |
| 84 | + // Transform the parry mesh into a mquad Mesh |
| 85 | + let (mquad_points, mquad_indices) = ( |
| 86 | + points |
| 87 | + .iter() |
| 88 | + .map(|p| Vertex { |
| 89 | + position: mquad_from_na(*p), |
| 90 | + uv: Vec2::new(p.x, p.y), |
| 91 | + color: DARKGRAY, |
| 92 | + }) |
| 93 | + .collect(), |
| 94 | + indices.iter().flatten().map(|v| *v as u16).collect(), |
| 95 | + ); |
| 96 | + |
| 97 | + // Macroquad doesn´t support adding normals to vertices, so we'll bake a color into these vertices. |
| 98 | + // See https://github.com/not-fl3/macroquad/issues/321. |
| 99 | + |
| 100 | + // Compute the normal of each vertex, making them unique |
| 101 | + let vertices: Vec<Vertex> = mquad_compute_normals(&mquad_points, &mquad_indices, camera_pos); |
| 102 | + // Regenerate the index for each vertex. |
| 103 | + let indices: Vec<u16> = (0..vertices.len() * 3) |
| 104 | + .into_iter() |
| 105 | + .map(|i| i as u16) |
| 106 | + .collect(); |
| 107 | + let mesh = Mesh { |
| 108 | + vertices, |
| 109 | + indices, |
| 110 | + texture: None, |
| 111 | + }; |
| 112 | + mesh |
| 113 | +} |
| 114 | + |
| 115 | +fn mquad_compute_normals(points: &Vec<Vertex>, indices: &Vec<u16>, cam_pos: Vec3) -> Vec<Vertex> { |
| 116 | + let mut vertices: Vec<Vertex> = Vec::<Vertex>::new(); |
| 117 | + for indices in indices.chunks(3) { |
| 118 | + let v0 = &points[indices[0] as usize]; |
| 119 | + let v1 = &points[indices[1] as usize]; |
| 120 | + let v2 = &points[indices[2] as usize]; |
| 121 | + let normal = (v0.position - v2.position) |
| 122 | + .cross(v1.position - v2.position) |
| 123 | + .normalize(); |
| 124 | + let brightness_mod = 0.2 + (0.8 / 2.) * (normal.dot(cam_pos) + 1.); |
| 125 | + |
| 126 | + for &i in indices.iter() { |
| 127 | + let mut color = points[i as usize].color; |
| 128 | + color.r *= brightness_mod; |
| 129 | + color.g *= brightness_mod; |
| 130 | + color.b *= brightness_mod; |
| 131 | + |
| 132 | + vertices.push(Vertex { |
| 133 | + position: points[i as usize].position, |
| 134 | + uv: Vec2::ZERO, |
| 135 | + color: color, |
| 136 | + }); |
| 137 | + } |
| 138 | + } |
| 139 | + vertices |
| 140 | +} |
| 141 | + |
| 142 | +fn draw_polyline(polygon: Vec<(Vec3, Vec3)>, color: Color) { |
| 143 | + for i in 0..polygon.len() { |
| 144 | + let a = polygon[i].0; |
| 145 | + let b = polygon[i].1; |
| 146 | + draw_line_3d(a, b, color); |
| 147 | + } |
| 148 | +} |
| 149 | + |
| 150 | +fn mquad_from_na(a: Point3<Real>) -> Vec3 { |
| 151 | + Vec3::new(a.x, a.y, a.z) |
| 152 | +} |
| 153 | + |
| 154 | +fn draw_text(text: &str) { |
| 155 | + macroquad::text::draw_text(text, 10.0, 48.0 + 18.0, 30.0, WHITE); |
| 156 | +} |
0 commit comments