diff --git a/src/lib.rs b/src/lib.rs index ff6e18a..7029751 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -105,7 +105,7 @@ fn test() { ///from the same run and share the same faceID. These faces will be planar ///within the output tolerance. /// -///The halfedgeTangent vector is used to specify the weighted tangent vectors of +///The halfedge_tangent vector is used to specify the weighted tangent vectors of ///each halfedge for the purpose of using the Refine methods to create a ///smoothly-interpolated surface. They can also be output when calculated ///automatically by the Smooth functions. @@ -155,6 +155,11 @@ pub struct MeshGL { /// none are given, they will be filled in with Manifold's coplanar face /// calculation based on mesh tolerance. pub face_id: Vec, + /// Optional: The X-Y-Z-W weighted tangent vectors for smooth Refine(). If + /// non-empty, must be exactly four times as long as Mesh.triVerts. Indexed + /// as 4 * (3 * tri + i) + j, i < 3, j < 4, representing the tangent value + /// Mesh.triVerts[tri][i] along the CCW edge. If empty, mesh is faceted. + pub halfedge_tangent: Vec, /// Tolerance for mesh simplification. When creating a Manifold, the tolerance /// used will be the maximum of this and a baseline tolerance from the size of /// the bounding box. Any edge shorter than tolerance may be collapsed. @@ -175,6 +180,7 @@ impl Default for MeshGL { run_original_id: Vec::default(), run_transform: Vec::default(), face_id: Vec::default(), + halfedge_tangent: Vec::default(), } } } @@ -189,7 +195,7 @@ impl MeshGL { } } -#[derive(Default, Debug)] +#[derive(Default, Debug, Clone)] pub struct MeshBool { meshbool_impl: MeshBoolImpl, } @@ -327,6 +333,12 @@ impl MeshBool { let mut tri_verts: Vec = vec![0; 3 * num_tri]; + let out_halfedge_tangent = meshbool_impl + .halfedge_tangent + .iter() + .flat_map(|t| [t.x as f32, t.y as f32, t.z as f32, t.w as f32]) + .collect::>(); + // Sort the triangles into runs let mut face_id: Vec = vec![0; num_tri]; let mut tri_new2old: Vec<_> = (0..num_tri).map(|i| i as i32).collect(); @@ -403,6 +415,7 @@ impl MeshBool { return MeshGL { num_prop: out_num_prop, + halfedge_tangent: out_halfedge_tangent, vert_properties, tri_verts, merge_from_vert: Vec::default(), @@ -483,6 +496,7 @@ impl MeshBool { MeshGL { num_prop: out_num_prop, + halfedge_tangent: out_halfedge_tangent, vert_properties, tri_verts, merge_from_vert, diff --git a/src/mesh_fixes.rs b/src/mesh_fixes.rs index 2a7e9cf..fc5dcda 100644 --- a/src/mesh_fixes.rs +++ b/src/mesh_fixes.rs @@ -1,5 +1,5 @@ use crate::shared::Halfedge; -use nalgebra::{Matrix3, Vector3}; +use nalgebra::{Matrix3, Vector3, Vector4}; use std::mem; #[inline] @@ -18,6 +18,28 @@ pub fn transform_normal(transform: Matrix3, mut normal: Vector3) -> Ve normal } +pub struct TransformTangents<'a> { + pub tangent: &'a mut [Vector4], + pub edge_offset: i32, + pub transform: Matrix3, + pub invert: bool, + pub old_tangents: &'a [Vector4], + pub halfedge: &'a [Halfedge], +} + +impl<'a> TransformTangents<'a> { + pub fn call(&mut self, edge_out: i32) { + let edge_in = if self.invert { + self.halfedge[flip_halfedge(edge_out) as usize].paired_halfedge + } else { + edge_out + }; + self.tangent[(edge_out + self.edge_offset) as usize] = (self.transform + * self.old_tangents[edge_in as usize].xyz()) + .push(self.old_tangents[edge_in as usize].w); + } +} + pub struct FlipTris<'a> { pub halfedge: &'a mut [Halfedge], } diff --git a/src/meshboolimpl.rs b/src/meshboolimpl.rs index b7e2512..d374544 100644 --- a/src/meshboolimpl.rs +++ b/src/meshboolimpl.rs @@ -1,7 +1,7 @@ use crate::collider::Collider; use crate::common::{AABB, sun_acos}; use crate::disjoint_sets::DisjointSets; -use crate::mesh_fixes::{FlipTris, transform_normal}; +use crate::mesh_fixes::{FlipTris, TransformTangents, transform_normal}; use crate::parallel::exclusive_scan_in_place; use crate::shared::{Halfedge, TriRef, max_epsilon, next_halfedge, normal_transform}; use crate::utils::{atomic_add_i32, mat3, mat4, next3_i32, next3_usize}; @@ -59,6 +59,7 @@ pub struct MeshBoolImpl { // function pub vert_normal: Vec>, pub face_normal: Vec>, + pub halfedge_tangent: Vec>, pub mesh_relation: MeshRelationD, pub collider: Collider, } @@ -231,12 +232,10 @@ impl MeshBoolImpl { return manifold; } - // if (!manifold::all_of(meshGL.halfedgeTangent.begin(), - // meshGL.halfedgeTangent.end(), - // [](Precision x) { return std::isfinite(x); })) { - // MakeEmpty(Error::InvalidConstruction); - // return; - // } + if mesh_gl.halfedge_tangent.iter().any(|x| !x.is_finite()) { + manifold.make_empty(ManifoldError::InvalidConstruction); + return manifold; + } let mut prop2vert: Vec; if !mesh_gl.merge_from_vert.is_empty() { @@ -278,12 +277,11 @@ impl MeshBoolImpl { } } - // halfedgeTangent_.resize_nofill(meshGL.halfedgeTangent.len() / 4); - // for i in 0..halfedgeTangent_.len() { - // for j in [0, 1, 2, 3] { - // halfedgeTangent_[i][j] = meshGL.halfedgeTangent[4 * i + j]; - // } - // } + manifold.halfedge_tangent = mesh_gl + .halfedge_tangent + .chunks(4) + .map(|t| [t[0] as f64, t[1] as f64, t[2] as f64, t[3] as f64].into()) + .collect::>>(); let mut tri_ref: Vec = unsafe { vec_uninit(mesh_gl.num_tri()) }; @@ -852,6 +850,7 @@ impl MeshBoolImpl { self.halfedge = Vec::default(); self.vert_normal = Vec::default(); self.face_normal = Vec::default(); + self.halfedge_tangent = Vec::default(); self.mesh_relation = MeshRelationD::default(); self.status = status; } @@ -883,6 +882,9 @@ impl MeshBoolImpl { result.properties = self.properties.clone(); result.bbox = self.bbox; result.halfedge = self.halfedge.clone(); + result + .halfedge_tangent + .resize(self.halfedge_tangent.len(), Default::default()); result.mesh_relation.original_id = -1; for m in &mut result.mesh_relation.mesh_id_transform { @@ -906,6 +908,21 @@ impl MeshBoolImpl { } let invert = mat3(transform).determinant() < 0.0; + + if self.halfedge_tangent.len() > 0 { + let mut t = TransformTangents { + tangent: &mut result.halfedge_tangent, + edge_offset: 0, + transform: mat3(transform), + invert, + old_tangents: &self.halfedge_tangent, + halfedge: &self.halfedge, + }; + for i in 0..self.halfedge_tangent.len() { + t.call(i as i32); + } + } + if invert { for tri in 0..result.num_tri() { FlipTris { @@ -1185,6 +1202,7 @@ impl Default for MeshBoolImpl { properties: Vec::default(), vert_normal: Vec::default(), face_normal: Vec::default(), + halfedge_tangent: Vec::default(), mesh_relation: MeshRelationD::default(), collider: Collider::default(), }