From e850210ce071fa90d468b1e633e3b525fbc0d196 Mon Sep 17 00:00:00 2001 From: ottah <48205674+ottah@users.noreply.github.com> Date: Sun, 18 Feb 2024 05:46:38 +0000 Subject: [PATCH] Expose barycentric coord and triangle index (#103) --- src/primitives.rs | 27 ++++++++++++++++++++++++++- src/raycast.rs | 17 +++++++++++++---- 2 files changed, 39 insertions(+), 5 deletions(-) diff --git a/src/primitives.rs b/src/primitives.rs index afc5073..79a5b15 100644 --- a/src/primitives.rs +++ b/src/primitives.rs @@ -12,8 +12,10 @@ pub enum Primitive3d { pub struct IntersectionData { position: Vec3, normal: Vec3, + barycentric_coord: Vec3, distance: f32, triangle: Option, + triangle_index: Option, } impl From for IntersectionData { @@ -22,18 +24,29 @@ impl From for IntersectionData { position: data.position(), normal: data.normal(), distance: data.distance(), + barycentric_coord: Vec3::ZERO, triangle: None, + triangle_index: None, } } } impl IntersectionData { - pub fn new(position: Vec3, normal: Vec3, distance: f32, triangle: Option) -> Self { + pub fn new( + position: Vec3, + normal: Vec3, + barycentric: Vec3, + distance: f32, + triangle: Option, + triangle_index: Option, + ) -> Self { Self { position, normal, + barycentric_coord: barycentric, distance, triangle, + triangle_index, } } @@ -49,6 +62,12 @@ impl IntersectionData { self.normal } + /// Get the intersection data's barycentric coord. + #[must_use] + pub fn barycentric_coord(&self) -> Vec3 { + self.barycentric_coord + } + /// Get the intersection data's distance. #[must_use] pub fn distance(&self) -> f32 { @@ -60,6 +79,12 @@ impl IntersectionData { pub fn triangle(&self) -> Option { self.triangle } + + /// Get the intersection data's triangle index. + #[must_use] + pub fn triangle_index(&self) -> Option { + self.triangle_index + } } /// Encapsulates Ray3D, preventing use of struct literal syntax. This allows us to guarantee that diff --git a/src/raycast.rs b/src/raycast.rs index b4b879c..bf928af 100644 --- a/src/raycast.rs +++ b/src/raycast.rs @@ -1,6 +1,6 @@ use std::f32::EPSILON; -use bevy_math::{Mat4, Vec3A}; +use bevy_math::{Mat4, Vec3, Vec3A}; use bevy_render::{ mesh::{Indices, Mesh, VertexAttributeValues}, render_resource::PrimitiveTopology, @@ -117,6 +117,7 @@ pub fn ray_mesh_intersection( // positions for each triangle, so we'll take indices in chunks of three, where each // chunk of three indices are references to the three vertices of a triangle. for index in indices.chunks(3) { + let triangle_index = Some(index[0].into_usize()); let tri_vertex_positions = [ Vec3A::from(vertex_positions[index[0].into_usize()]), Vec3A::from(vertex_positions[index[1].into_usize()]), @@ -140,6 +141,7 @@ pub fn ray_mesh_intersection( pick_intersection = Some(IntersectionData::new( mesh_transform.transform_point3(i.position()), mesh_transform.transform_vector3(i.normal()), + i.barycentric_coord(), mesh_transform .transform_vector3(mesh_space_ray.direction() * i.distance()) .length(), @@ -150,12 +152,14 @@ pub fn ray_mesh_intersection( mesh_transform.transform_point3a(tri.v2), ]) }), + triangle_index, )); min_pick_distance = i.distance(); } } } else { for i in (0..vertex_positions.len()).step_by(3) { + let triangle_index = Some(i); let tri_vertex_positions = [ Vec3A::from(vertex_positions[i]), Vec3A::from(vertex_positions[i + 1]), @@ -179,6 +183,7 @@ pub fn ray_mesh_intersection( pick_intersection = Some(IntersectionData::new( mesh_transform.transform_point3(i.position()), mesh_transform.transform_vector3(i.normal()), + i.barycentric_coord(), mesh_transform .transform_vector3(mesh_space_ray.direction() * i.distance()) .length(), @@ -189,6 +194,7 @@ pub fn ray_mesh_intersection( mesh_transform.transform_point3a(tri.v2), ]) }), + triangle_index, )); min_pick_distance = i.distance(); } @@ -213,10 +219,11 @@ fn triangle_intersection( let distance = *ray_hit.distance(); if distance > 0.0 && distance < max_distance { let position = ray.position(distance); + let u = ray_hit.uv_coords().0; + let v = ray_hit.uv_coords().1; + let w = 1.0 - u - v; + let barycentric = Vec3::new(u, v, w); let normal = if let Some(normals) = tri_normals { - let u = ray_hit.uv_coords().0; - let v = ray_hit.uv_coords().1; - let w = 1.0 - u - v; normals[1] * u + normals[2] * v + normals[0] * w } else { (tri_vertices.v1() - tri_vertices.v0()) @@ -226,8 +233,10 @@ fn triangle_intersection( let intersection = IntersectionData::new( position, normal.into(), + barycentric, distance, Some(tri_vertices.to_triangle()), + None, ); return Some(intersection); }