master
mitchellhansen 9 months ago
parent 78222ad55a
commit 85b79a86ed

Binary file not shown.

@ -0,0 +1,60 @@
use bevy::prelude::{Component, Reflect, Resource};
use fj_core::objects::{Sketch, Solid};
use fj_math::{Point, Vector};
use fj_interop::mesh::Mesh as FjMesh;
use fj_core::storage::Handle as FjHandle;
#[derive(Component)]
struct FjSolidWrapper {
handle: fj_core::storage::Handle<Solid>,
}
#[derive(Component, Debug)]
pub struct FjMeshWrapper {
pub mesh: FjMesh<Point<3>>,
pub handle: FjHandle<Solid>,
pub sketch: Sketch,
}
pub(crate) trait ToPoint3 {
fn to_point3(&self) -> Point<3>;
}
impl ToPoint3 for bevy::prelude::Vec3 {
fn to_point3(&self) -> fj_math::Point<3> {
fj_math::Point { coords: Vector { components: [fj_math::Scalar::from_u64(0),fj_math::Scalar::from_u64(0),fj_math::Scalar::from_u64(0)] } }
}
}
pub(crate) trait ToVec3 {
fn to_vec3(&self) -> bevy::prelude::Vec3;
}
impl ToVec3 for fj_math::Point<3> {
fn to_vec3(&self) -> bevy::prelude::Vec3 {
bevy::prelude::Vec3::new(self.x.into_f32(), self.y.into_f32(), self.z.into_f32())
}
}
impl ToVec3 for fj_math::Vector<3> {
fn to_vec3(&self) -> bevy::prelude::Vec3 {
bevy::prelude::Vec3::new(self.x.into_f32(), self.y.into_f32(), self.z.into_f32())
}
}
pub(crate) trait ToVec2 {
fn to_vec2(&self) -> bevy::prelude::Vec2;
}
impl crate::interop::ToVec2 for fj_math::Point<2> {
fn to_vec2(&self) -> bevy::prelude::Vec2 {
bevy::prelude::Vec2::new(self.u.into_f32(), self.v.into_f32())
}
}
impl crate::interop::ToVec2 for fj_math::Vector<2> {
fn to_vec2(&self) -> bevy::prelude::Vec2 {
bevy::prelude::Vec2::new(self.u.into_f32(), self.v.into_f32())
}
}

@ -1,12 +1,17 @@
pub mod mesh;
pub mod interop;
// Importing Bevy ECS components and systems // Importing Bevy ECS components and systems
use crate::mesh::create_rectangle_mesh;
use bevy::ecs::component::Component; use bevy::ecs::component::Component;
use bevy::ecs::system::{Commands, Query}; use bevy::ecs::system::{Commands, Query};
use bevy::ecs::entity::Entity; use bevy::ecs::entity::Entity;
use bevy::ecs::query::Without; use bevy::ecs::query::Without;
use bevy::ecs::system::ResMut; use bevy::ecs::system::ResMut;
use crate::interop::{ToPoint3, ToVec3};
// Importing Bevy assets and rendering related components // Importing Bevy assets and rendering related components
use bevy::prelude::{Mesh, shape}; use bevy::prelude::*;
use bevy::render::mesh::{Indices, PrimitiveTopology}; use bevy::render::mesh::{Indices, PrimitiveTopology};
use bevy::asset::Assets; use bevy::asset::Assets;
use bevy::pbr::{PbrBundle, StandardMaterial}; use bevy::pbr::{PbrBundle, StandardMaterial};
@ -30,38 +35,17 @@ use fj_interop::mesh::Mesh as FjMesh;
use fj_math::{Aabb, Line, Point, Scalar, Vector}; use fj_math::{Aabb, Line, Point, Scalar, Vector};
use std::ops::Deref; use std::ops::Deref;
use bevy::a11y::accesskit::Size;
use bevy::math::Vec3; use bevy::math::Vec3;
use bevy::ui::ZIndex::Global;
use fj_core::geometry::{GlobalPath, SurfacePath}; use fj_core::geometry::{GlobalPath, SurfacePath};
use fj_core::objects::Object::Surface;
use fj_core::operations::holes::AddHole;
use fj_core::operations::split::{SplitEdge, SplitFace, SplitHalfEdge};
use rand::Rng; use rand::Rng;
use crate::interop::FjMeshWrapper;
use crate::mesh::{convert_mesh, LineList};
trait ToVec3 {
fn to_vec3(&self) -> bevy::prelude::Vec3;
}
impl ToVec3 for fj_math::Point<3> {
fn to_vec3(&self) -> bevy::prelude::Vec3 {
bevy::prelude::Vec3::new(self.x.into_f32(), self.y.into_f32(), self.z.into_f32())
}
}
impl ToVec3 for fj_math::Vector<3> {
fn to_vec3(&self) -> bevy::prelude::Vec3 {
bevy::prelude::Vec3::new(self.x.into_f32(), self.y.into_f32(), self.z.into_f32())
}
}
#[derive(Component)]
struct FjSolidWrapper {
handle: fj_core::storage::Handle<Solid>,
}
#[derive(Component, Debug)]
pub struct FjMeshWrapper {
pub mesh: FjMesh<Point<3>>,
pub handle: FjHandle<Solid>,
pub sketch: Sketch,
}
#[derive(Component)] #[derive(Component)]
struct FjConvertedFlag; struct FjConvertedFlag;
@ -74,78 +58,16 @@ impl Plugin for FjRenderPlugin {
} }
} }
fn generate_uv_mapping(fj_mesh: &FjMesh<Point<3>>) -> Vec<[f32; 2]> {
let mut uvs = Vec::new();
for vertex in fj_mesh.vertices() {
let x = vertex.coords.x.into_f32();
let y = vertex.coords.y.into_f32();
// Here we're using x and y coordinates as u and v
uvs.push([x, y]);
uvs.push([x, y]);
uvs.push([x, y]);
uvs.push([x, y]);
uvs.push([x, y]);
uvs.push([x, y]);
}
uvs
}
fn generate_normals(fj_mesh: &FjMesh<Point<3>>) -> Vec<[f32; 3]> {
let mut normals = Vec::new();
for triangle in fj_mesh.triangles() {
let normal = triangle.inner.normal();
normals.push([normal.x.into_f32(), normal.y.into_f32(), normal.z.into_f32()]);
normals.push([normal.x.into_f32(), normal.y.into_f32(), normal.z.into_f32()]);
normals.push([normal.x.into_f32(), normal.y.into_f32(), normal.z.into_f32()]);
}
normals
}
fn generate_positions(fj_mesh: &FjMesh<Point<3>>) -> Vec<[f32; 3]> {
let mut positions = Vec::new();
// Iterate through each triangle
for triangle in fj_mesh.triangles() {
// For each vertex index in the triangle
for vertex_index in triangle.inner.points() {
positions.push([vertex_index.x.into_f32(), vertex_index.y.into_f32(), vertex_index.z.into_f32()]);
}
}
positions
}
fn generate_indices(fj_mesh: &FjMesh<Point<3>>) -> Vec<u32> {
let mut num_positions = 0;
// Count the total number of positions (3 per triangle)
for triangle in fj_mesh.triangles() {
num_positions += 3;
}
// Generate the indices [0, 1, 2, ..., num_positions-1]
(0..num_positions as u32).collect()
}
// Need to take a solid, and return all the data needed to create a Bevy Mesh from scratch
pub fn convert_mesh(fj_mesh: &FjMesh<Point<3>>) -> Mesh {
let mut mesh = Mesh::new(PrimitiveTopology::TriangleList);
mesh.insert_attribute(Mesh::ATTRIBUTE_POSITION, generate_positions(&fj_mesh));
mesh.insert_attribute(Mesh::ATTRIBUTE_NORMAL, generate_normals(&fj_mesh));
// mesh.insert_attribute(Mesh::ATTRIBUTE_UV_0, generate_uv_mapping(&fj_mesh));
mesh.set_indices(Some(Indices::U32(generate_indices(&fj_mesh))));
mesh
}
fn update_fj_model_system( fn update_fj_model_system(
mut commands: Commands, mut commands: Commands,
query: Query<(Entity, &FjMeshWrapper), Without<FjConvertedFlag>>, query: Query<(Entity, &FjMeshWrapper), Without<FjConvertedFlag>>,
mut meshes: ResMut<Assets<Mesh>>, mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<StandardMaterial>>, mut materials: ResMut<Assets<StandardMaterial>>,
asset_server: Res<AssetServer>
) { ) {
for (entity, solid) in &query { for (entity, solid) in &query {
let bevy_mesh = convert_mesh(&solid.mesh); let bevy_mesh = convert_mesh(&solid.mesh);
commands.entity(entity).insert( commands.entity(entity).insert(
( (
@ -161,144 +83,236 @@ fn update_fj_model_system(
} }
} }
fn render_line<const T: usize>(mut commands: &mut Commands,
fj_model: &FjMeshWrapper,
mut meshes: &mut ResMut<Assets<Mesh>>,
mut materials: &mut ResMut<Assets<StandardMaterial>>,
line: Line<T>) {
let origin = line.origin().to_xyz();
let direction = line.direction().to_xyz();
let opposite_corner = Vec3::new(
origin.x.into_f32() + direction.x.into_f32() + 0.01,
origin.y.into_f32() + direction.y.into_f32() + 0.01,
origin.z.into_f32() + direction.z.into_f32() + 0.01,
);
let mut rng = rand::thread_rng();
let red: f32 = rng.gen_range(0.0..1.0);
let green: f32 = rng.gen_range(0.0..1.0);
let blue: f32 = rng.gen_range(0.0..1.0);
commands.spawn(( // line on base of sweep
PbrBundle {
mesh: meshes.add(Mesh::from(shape::Box::from_corners(opposite_corner.into(), origin.to_vec3()))),
material: materials.add(Color::rgb(red, green, blue).into()),
transform: Transform::from_xyz(0.0, 0.0, 0.0),
..default()
},
// RaycastPickTarget::default(), // <- Needed for the raycast backend.
// PickableBundle::default() // <- This one too
));
commands.spawn(( // vertex
PbrBundle {
mesh: meshes.add(Mesh::from(shape::Cube { size: 0.025 })),
material: materials.add(Color::rgb(1.0, 1.0, 1.0).into()),
transform: Transform::from_xyz(origin.to_xyz().x.into_f32(), origin.to_xyz().y.into_f32(), origin.to_xyz().z.into_f32()),
..default()
},
// RaycastPickTarget::default(), // <- Needed for the raycast backend.
// PickableBundle::default() // <- This one too
));
}
fn add_debug_info_to_entity(mut commands: &mut Commands, fn add_debug_info_to_entity(mut commands: &mut Commands,
fj_model: &FjMeshWrapper, fj_model: &FjMeshWrapper,
mut meshes: &mut ResMut<Assets<Mesh>>, mut meshes: &mut ResMut<Assets<Mesh>>,
mut materials: &mut ResMut<Assets<StandardMaterial>>, mut materials: &mut ResMut<Assets<StandardMaterial>>,
) { ) {
for region in fj_model.sketch.regions() { // for region in fj_model.sketch.regions() {
for cycle in region.all_cycles() { // for cycle in region.all_cycles() {
for half_edge in cycle.half_edges() { // for half_edge in cycle.half_edges() {
match half_edge.path() { // match half_edge.path() {
SurfacePath::Circle(x) => {} // SurfacePath::Circle(x) => {}
SurfacePath::Line(x) => { // SurfacePath::Line(x) => {
render_line(commands, fj_model, meshes, materials, x) // render_line(commands, fj_model, meshes, materials, x)
} // }
} // }
// 1d point // // 1d point
half_edge.boundary().inner[0].coords; // half_edge.boundary().inner[0].coords;
half_edge.boundary().inner[1].coords; // half_edge.boundary().inner[1].coords;
} // }
} // }
//
// }
for shell in fj_model.handle.shells(){
} }
for shell in fj_model.handle.shells() { for shell in fj_model.handle.shells() {
println!("{:?}. shell", shell); println!("{:?}. shell", shell);
for face in shell.faces() { for face in shell.faces() {
println!("{:?}. face", face); println!("{:?}. face", face);
let surface = face.surface(); let surface = face.surface();
let geom = surface.geometry(); let geom = surface.geometry();
let geom_sweep_vector = geom.v; let geom_sweep_vector = geom.v;
for edge in face.region().exterior().half_edges(){
match edge.path() {
SurfacePath::Circle(_) => {}
SurfacePath::Line(x) => {
let mut rng = rand::thread_rng();
let color = Color::rgb(1.0, 0.,0.).into();
let mut origin = geom.point_from_surface_coords(x.origin()).to_xyz();
let direction = geom.vector_from_surface_coords(x.direction()).to_xyz();
let opposite_corner = Point{ coords: Vector{
components: [
Scalar::from(origin.x.into_f32()) + direction.x,
Scalar::from(origin.y.into_f32()) + direction.y,
Scalar::from(origin.z.into_f32()) + direction.z,
]
}};
let line = GlobalPath::line_from_points([origin, opposite_corner]);
match line.0 {
GlobalPath::Circle(_) => {}
GlobalPath::Line(x) => {
render_line(commands, fj_model, meshes, materials, x, color);
}
}
}
}
}
match geom.u { match geom.u {
GlobalPath::Circle(x) => { GlobalPath::Circle(x) => {
x.aabb(); x.aabb();
} }
GlobalPath::Line(x) => { GlobalPath::Line(x) => {
render_line(commands, fj_model, meshes, materials, x);
let origin = x.origin();
let direction = x.direction();
let opposite_corner = Vec3::new(
origin.x.into_f32() + direction.x.into_f32() + 0.01,
origin.y.into_f32() + direction.y.into_f32() + 0.01,
origin.z.into_f32() + direction.z.into_f32() + 0.01,
);
let mut rng = rand::thread_rng(); let mut rng = rand::thread_rng();
let red: f32 = rng.gen_range(0.0..1.0); let red: f32 = rng.gen_range(0.0..1.0);
let green: f32 = rng.gen_range(0.0..1.0); let green: f32 = rng.gen_range(0.0..1.0);
let blue: f32 = rng.gen_range(0.0..1.0); let blue: f32 = rng.gen_range(0.0..1.0);
commands.spawn(( // line on top of sweep, just offset by the sweep vector // let color = Color::rgb(red, green, blue).into();
PbrBundle { // render_line(commands, fj_model, meshes, materials, x, color);
mesh: meshes.add(Mesh::from(shape::Box::from_corners(opposite_corner.into(), origin.to_vec3()))),
material: materials.add(Color::rgb(red, green, blue).into()), // let origin = x.origin();
transform: Transform::from_xyz(geom_sweep_vector.x.into_f32(), geom_sweep_vector.y.into_f32(), geom_sweep_vector.z.into_f32()), // let direction = x.direction();
..default() // let opposite_corner = Vec3::new(
}, // origin.x.into_f32() + direction.x.into_f32(),
// RaycastPickTarget::default(), // <- Needed for the raycast backend. // origin.y.into_f32() + direction.y.into_f32(),
// PickableBundle::default() // <- This one too // origin.z.into_f32() + direction.z.into_f32(),
)); // );
commands.spawn(( // line following the sweep //
PbrBundle { // commands.spawn(( // line on top of sweep, just offset by the sweep vector
mesh: meshes.add(Mesh::from(shape::Box::from_corners(origin.to_vec3() + geom_sweep_vector.to_vec3(), origin.to_vec3() + 0.01))), // PbrBundle {
material: materials.add(Color::rgb(red, green, blue).into()), // // mesh: meshes.add(Mesh::from(LineList {
transform: Transform::from_xyz(0.0, 0.0, 0.0), // // lines: vec![
..default() // // (opposite_corner.into(), origin.to_vec3()),
}, // // ],
// RaycastPickTarget::default(), // <- Needed for the raycast backend. // // })),
// PickableBundle::default() // <- This one too // mesh: meshes.add(create_rectangle_mesh(opposite_corner, origin.to_vec3(), 0.01, 0.01)),
)); // material: materials.add(Color::rgb(red, green, blue).into()),
commands.spawn(( // swept vertex // transform: Transform::from_xyz(geom_sweep_vector.x.into_f32(), geom_sweep_vector.y.into_f32(), geom_sweep_vector.z.into_f32()),
PbrBundle { // ..default()
mesh: meshes.add(Mesh::from(shape::Cube { size: 0.025 })), // },
material: materials.add(Color::rgb(1.0, 1.0, 1.0).into()), // // RaycastPickTarget::default(), // <- Needed for the raycast backend.
transform: Transform::from_xyz( // // PickableBundle::default() // <- This one too
origin.to_xyz().x.into_f32() + geom_sweep_vector.to_vec3().x, // ));
origin.to_xyz().y.into_f32() + geom_sweep_vector.to_vec3().y, // commands.spawn(( // line following the sweep
origin.to_xyz().z.into_f32() + geom_sweep_vector.to_vec3().z, // PbrBundle {
), // mesh: meshes.add(create_rectangle_mesh(origin.to_vec3() + geom_sweep_vector.to_vec3(), origin.to_vec3(), 0.01, 0.01)),
// transform: Transform::from_scale(origin.to_vec3() + geom_sweep_vector.to_vec3()), // material: materials.add(Color::rgb(red, green, blue).into()),
..default() // transform: Transform::from_xyz(0.0, 0.0, 0.0),
}, // ..default()
// RaycastPickTarget::default(), // <- Needed for the raycast backend. // },
// PickableBundle::default(), // <- This one too // // RaycastPickTarget::default(), // <- Needed for the raycast backend.
// // PickableBundle::default() // <- This one too
// I want to insert a component when dragging starts, that contains // ));
// data about the exact ray hit location. // commands.spawn(( // swept vertex
// On::<Pointer<DragStart>>::run(run), // PbrBundle {
// On::<Pointer<DragStart>>::target_insert(DragCaster::default()), // mesh: meshes.add(Mesh::from(shape::Cube { size: 0.025 })),
// On::<Pointer<Drag>>::target_component_mut::<DragCaster>(|drag, mut caster| { // material: materials.add(Color::rgb(1.0, 1.0, 1.0).into()),
// caster.hit_location = drag.hit.position.unwrap(); // transform: Transform::from_xyz(
// // origin.to_xyz().x.into_f32() + geom_sweep_vector.to_vec3().x,
// // (*transform).translation = transform.translation + Vec3::new(-drag.delta.x / 100.0, 0.0, drag.delta.y / 100.0); // origin.to_xyz().y.into_f32() + geom_sweep_vector.to_vec3().y,
// }), // origin.to_xyz().z.into_f32() + geom_sweep_vector.to_vec3().z,
// On::<Pointer<Drag>>::target_component_mut::<DragCaster>(|drag, mut caster| { // ),
// drag.distance // // transform: Transform::from_scale(origin.to_vec3() + geom_sweep_vector.to_vec3()),
// // (*transform).translation = transform.translation + Vec3::new(-drag.delta.x / 100.0, 0.0, drag.delta.y / 100.0); // ..default()
// }), // },
)); // // RaycastPickTarget::default(), // <- Needed for the raycast backend.
// // PickableBundle::default(), // <- This one too
//
// // I want to insert a component when dragging starts, that contains
// // data about the exact ray hit location.
// // On::<Pointer<DragStart>>::run(run),
// // On::<Pointer<DragStart>>::target_insert(DragCaster::default()),
// // On::<Pointer<Drag>>::target_component_mut::<DragCaster>(|drag, mut caster| {
// // caster.hit_location = drag.hit.position.unwrap();
// //
// // // (*transform).translation = transform.translation + Vec3::new(-drag.delta.x / 100.0, 0.0, drag.delta.y / 100.0);
// // }),
// // On::<Pointer<Drag>>::target_component_mut::<DragCaster>(|drag, mut caster| {
// // drag.distance
// // // (*transform).translation = transform.translation + Vec3::new(-drag.delta.x / 100.0, 0.0, drag.delta.y / 100.0);
// // }),
// ));
} }
} }
} }
} }
} }
fn render_line<const T: usize>(mut commands: &mut Commands,
fj_model: &FjMeshWrapper,
mut meshes: &mut ResMut<Assets<Mesh>>,
mut materials: &mut ResMut<Assets<StandardMaterial>>,
line: Line<T>,
color: Color) {
let origin = line.origin().to_xyz();
let direction = line.direction().to_xyz();
let opposite_corner = Vec3::new(
origin.x.into_f32() + direction.x.into_f32(),
origin.y.into_f32() + direction.y.into_f32(),
origin.z.into_f32() + direction.z.into_f32(),
);
commands.spawn(( // line on base of sweep
PbrBundle {
mesh: meshes.add(Mesh::from(create_rectangle_mesh(opposite_corner, origin.to_vec3(), 0.01, 0.01))),
// mesh: meshes.add(Mesh::from(shape::Box::from_corners(opposite_corner.into(), origin.to_vec3()))),
material: materials.add(StandardMaterial::from(color)),
transform: Transform::from_xyz(0.0, 0.0, 0.0),
..default()
},
// RaycastPickTarget::default(), // <- Needed for the raycast backend.
// PickableBundle::default() // <- This one too
));
commands.spawn(( // vertex
PbrBundle {
mesh: meshes.add(Mesh::from(shape::Cube { size: 0.025 })),
material: materials.add(Color::rgb(1.0, 1.0, 1.0).into()),
transform: Transform::from_xyz(origin.to_xyz().x.into_f32(), origin.to_xyz().y.into_f32(), origin.to_xyz().z.into_f32()),
..default()
},
// RaycastPickTarget::default(), // <- Needed for the raycast backend.
// PickableBundle::default() // <- This one too
));
}
/*
// Root node
commands.spawn(NodeBundle {
style: Style {
flex_direction: FlexDirection::Column,
justify_content: JustifyContent::Center,
align_items: AlignItems::Center,
..Default::default()
},
..Default::default()
}).with_children(|parent| {
// Text node
parent.spawn(TextBundle {
text: Text::from_section(
"This is some text",
TextStyle {
font: asset_server.load("fonts/FiraMono-Medium.ttf"),
font_size: 40.0,
color: Color::WHITE,
},
),
..Default::default()
});
// Checkbox (custom implementation)
parent.spawn(NodeBundle {
style: Style {
justify_content: JustifyContent::Center,
align_items: AlignItems::Center,
..Default::default()
},
..Default::default()
}).with_children(|parent| {
parent.spawn(TextBundle {
text: Text::from_section(
"X", // Simulating a checked state
TextStyle {
font: asset_server.load("fonts/FiraSans-Bold.ttf"),
font_size: 20.0,
color: Color::BLACK,
},
),
..Default::default()
});
});
});
*/

@ -0,0 +1,162 @@
use bevy::math::Vec3;
use bevy::prelude::Mesh;
use bevy::render::mesh::{Indices, PrimitiveTopology};
use fj_math::Point;
use fj_interop::mesh::Mesh as FjMesh;
use fj_core::storage::Handle as FjHandle;
#[derive(Debug, Clone)]
pub struct LineList {
pub lines: Vec<(Vec3, Vec3)>,
}
impl From<LineList> for Mesh {
fn from(line: LineList) -> Self {
let vertices: Vec<_> = line.lines.into_iter().flat_map(|(a, b)| [a, b]).collect();
// This tells wgpu that the positions are list of lines
// where every pair is a start and end point
Mesh::new(PrimitiveTopology::LineList)
// Add the vertices positions as an attribute
.with_inserted_attribute(Mesh::ATTRIBUTE_POSITION, vertices)
}
}
fn generate_uv_mapping(fj_mesh: &FjMesh<Point<3>>) -> Vec<[f32; 2]> {
let mut uvs = Vec::new();
for vertex in fj_mesh.vertices() {
let x = vertex.coords.x.into_f32();
let y = vertex.coords.y.into_f32();
// Here we're using x and y coordinates as u and v
uvs.push([x, y]);
uvs.push([x, y]);
uvs.push([x, y]);
uvs.push([x, y]);
uvs.push([x, y]);
uvs.push([x, y]);
}
uvs
}
fn generate_normals(fj_mesh: &FjMesh<Point<3>>) -> Vec<[f32; 3]> {
let mut normals = Vec::new();
for triangle in fj_mesh.triangles() {
let normal = triangle.inner.normal();
normals.push([normal.x.into_f32(), normal.y.into_f32(), normal.z.into_f32()]);
normals.push([normal.x.into_f32(), normal.y.into_f32(), normal.z.into_f32()]);
normals.push([normal.x.into_f32(), normal.y.into_f32(), normal.z.into_f32()]);
}
normals
}
fn generate_positions(fj_mesh: &FjMesh<Point<3>>) -> Vec<[f32; 3]> {
let mut positions = Vec::new();
// Iterate through each triangle
for triangle in fj_mesh.triangles() {
// For each vertex index in the triangle
for vertex_index in triangle.inner.points() {
positions.push([vertex_index.x.into_f32(), vertex_index.y.into_f32(), vertex_index.z.into_f32()]);
}
}
positions
}
fn generate_indices(fj_mesh: &FjMesh<Point<3>>) -> Vec<u32> {
let mut num_positions = 0;
// Count the total number of positions (3 per triangle)
for triangle in fj_mesh.triangles() {
num_positions += 3;
}
// Generate the indices [0, 1, 2, ..., num_positions-1]
(0..num_positions as u32).collect()
}
// Need to take a solid, and return all the data needed to create a Bevy Mesh from scratch
pub fn convert_mesh(fj_mesh: &FjMesh<Point<3>>) -> Mesh {
let mut mesh = Mesh::new(PrimitiveTopology::TriangleList);
mesh.insert_attribute(Mesh::ATTRIBUTE_POSITION, generate_positions(&fj_mesh));
mesh.insert_attribute(Mesh::ATTRIBUTE_NORMAL, generate_normals(&fj_mesh));
// mesh.insert_attribute(Mesh::ATTRIBUTE_UV_0, generate_uv_mapping(&fj_mesh));
mesh.set_indices(Some(Indices::U32(generate_indices(&fj_mesh))));
mesh
}
pub fn create_rectangle_mesh(p1: Vec3, p2: Vec3, width: f32, height: f32) -> Mesh {
// Calculate direction vector from p1 to p2
let direction = (p2 - p1).normalize();
// Create arbitrary up vector
let up = Vec3::Y;
// Right vector for the rectangle width
let right = direction.cross(up).normalize() * width * 0.5;
// Up vector for rectangle height, ensuring it's perpendicular
let up_perpendicular = direction.cross(right).normalize() * height * 0.5;
let vertices = [
p1 - right - up_perpendicular, // Bottom-left of p1 face
p1 + right - up_perpendicular, // Bottom-right of p1 face
p1 + right + up_perpendicular, // Top-right of p1 face
p1 - right + up_perpendicular, // Top-left of p1 face
p2 - right - up_perpendicular, // Bottom-left of p2 face
p2 + right - up_perpendicular, // Bottom-right of p2 face
p2 + right + up_perpendicular, // Top-right of p2 face
p2 - right + up_perpendicular, // Top-left of p2 face
];
// Calculate face normals
let front_normal = (vertices[1] - vertices[0]).cross(vertices[3] - vertices[0]).normalize();
let back_normal = (vertices[5] - vertices[4]).cross(vertices[7] - vertices[4]).normalize();
let right_normal = (vertices[5] - vertices[1]).cross(vertices[2] - vertices[1]).normalize();
let left_normal = (vertices[0] - vertices[4]).cross(vertices[7] - vertices[4]).normalize();
let top_normal = (vertices[2] - vertices[3]).cross(vertices[7] - vertices[3]).normalize();
let bottom_normal = (vertices[1] - vertices[0]).cross(vertices[4] - vertices[0]).normalize();
let normals = vec![
bottom_normal, bottom_normal, top_normal, top_normal, // Bottom and top for first quad
bottom_normal, bottom_normal, top_normal, top_normal, // Bottom and top for second quad
front_normal, front_normal, front_normal, front_normal, // Front face normals
back_normal, back_normal, back_normal, back_normal, // Back face normals
right_normal, right_normal, right_normal, right_normal, // Right face normals
left_normal, left_normal, left_normal, left_normal, // Left face normals
];
// Convert positions and normals to the format expected by Bevy
// Creating a mesh
let mut mesh = Mesh::new(PrimitiveTopology::TriangleList);
// Insert positions
let positions: Vec<[f32; 3]> = vertices.iter().map(|v| [v.x, v.y, v.z]).collect();
mesh.insert_attribute(Mesh::ATTRIBUTE_POSITION, positions);
// Insert normals (optional here, assuming all outwards for simplicity)
let normals: Vec<[f32; 3]> = normals.iter().map(|n| [n.x, n.y, n.z]).collect();
mesh.insert_attribute(Mesh::ATTRIBUTE_NORMAL, normals);
// Define two triangles for each face of the rectangle mesh
let indices = Indices::U32(vec![
// Front face
0, 2, 1, 0, 3, 2,
// Back face
4, 6, 5, 4, 7, 6,
// Top face
2, 3, 6, 6, 3, 7,
// Bottom face
0, 1, 5, 0, 5, 4,
// Right face
1, 2, 6, 1, 6, 5,
// Left face
0, 4, 7, 0, 7, 3,
]);
mesh.set_indices(Some(indices));
mesh
}
Loading…
Cancel
Save