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
use crate::mesh::create_rectangle_mesh;
use bevy::ecs::component::Component;
use bevy::ecs::system::{Commands, Query};
use bevy::ecs::entity::Entity;
use bevy::ecs::query::Without;
use bevy::ecs::system::ResMut;
use crate::interop::{ToPoint3, ToVec3};
// Importing Bevy assets and rendering related components
use bevy::prelude::{Mesh, shape};
use bevy::prelude::*;
use bevy::render::mesh::{Indices, PrimitiveTopology};
use bevy::asset::Assets;
use bevy::pbr::{PbrBundle, StandardMaterial};
@ -30,39 +35,18 @@ use fj_interop::mesh::Mesh as FjMesh;
use fj_math::{Aabb, Line, Point, Scalar, Vector};
use std::ops::Deref;
use bevy::a11y::accesskit::Size;
use bevy::math::Vec3;
use bevy::ui::ZIndex::Global;
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;
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())
}
}
use crate::interop::FjMeshWrapper;
use crate::mesh::{convert_mesh, LineList};
#[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)]
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(
mut commands: Commands,
query: Query<(Entity, &FjMeshWrapper), Without<FjConvertedFlag>>,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<StandardMaterial>>,
asset_server: Res<AssetServer>
) {
for (entity, solid) in &query {
let bevy_mesh = convert_mesh(&solid.mesh);
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,
fj_model: &FjMeshWrapper,
mut meshes: &mut ResMut<Assets<Mesh>>,
mut materials: &mut ResMut<Assets<StandardMaterial>>,
) {
for region in fj_model.sketch.regions() {
for cycle in region.all_cycles() {
for half_edge in cycle.half_edges() {
match half_edge.path() {
SurfacePath::Circle(x) => {}
SurfacePath::Line(x) => {
render_line(commands, fj_model, meshes, materials, x)
}
}
// 1d point
half_edge.boundary().inner[0].coords;
half_edge.boundary().inner[1].coords;
}
}
// for region in fj_model.sketch.regions() {
// for cycle in region.all_cycles() {
// for half_edge in cycle.half_edges() {
// match half_edge.path() {
// SurfacePath::Circle(x) => {}
// SurfacePath::Line(x) => {
// render_line(commands, fj_model, meshes, materials, x)
// }
// }
// // 1d point
// half_edge.boundary().inner[0].coords;
// half_edge.boundary().inner[1].coords;
// }
// }
//
// }
for shell in fj_model.handle.shells(){
}
for shell in fj_model.handle.shells() {
println!("{:?}. shell", shell);
for face in shell.faces() {
println!("{:?}. face", face);
let surface = face.surface();
let geom = surface.geometry();
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 {
GlobalPath::Circle(x) => {
x.aabb();
}
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 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 top of sweep, just offset by the sweep vector
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(geom_sweep_vector.x.into_f32(), geom_sweep_vector.y.into_f32(), geom_sweep_vector.z.into_f32()),
..default()
},
// RaycastPickTarget::default(), // <- Needed for the raycast backend.
// PickableBundle::default() // <- This one too
));
commands.spawn(( // line following the sweep
// let color = Color::rgb(red, green, blue).into();
// render_line(commands, fj_model, meshes, materials, x, color);
// let origin = x.origin();
// let direction = x.direction();
// 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 top of sweep, just offset by the sweep vector
// PbrBundle {
// // mesh: meshes.add(Mesh::from(LineList {
// // lines: vec![
// // (opposite_corner.into(), origin.to_vec3()),
// // ],
// // })),
// mesh: meshes.add(create_rectangle_mesh(opposite_corner, origin.to_vec3(), 0.01, 0.01)),
// material: materials.add(Color::rgb(red, green, blue).into()),
// transform: Transform::from_xyz(geom_sweep_vector.x.into_f32(), geom_sweep_vector.y.into_f32(), geom_sweep_vector.z.into_f32()),
// ..default()
// },
// // RaycastPickTarget::default(), // <- Needed for the raycast backend.
// // PickableBundle::default() // <- This one too
// ));
// commands.spawn(( // line following the sweep
// PbrBundle {
// mesh: meshes.add(create_rectangle_mesh(origin.to_vec3() + geom_sweep_vector.to_vec3(), origin.to_vec3(), 0.01, 0.01)),
// 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(( // swept 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() + geom_sweep_vector.to_vec3().x,
// origin.to_xyz().y.into_f32() + geom_sweep_vector.to_vec3().y,
// origin.to_xyz().z.into_f32() + geom_sweep_vector.to_vec3().z,
// ),
// // transform: Transform::from_scale(origin.to_vec3() + geom_sweep_vector.to_vec3()),
// ..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(shape::Box::from_corners(origin.to_vec3() + geom_sweep_vector.to_vec3(), origin.to_vec3() + 0.01))),
material: materials.add(Color::rgb(red, green, blue).into()),
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(( // swept vertex
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() + geom_sweep_vector.to_vec3().x,
origin.to_xyz().y.into_f32() + geom_sweep_vector.to_vec3().y,
origin.to_xyz().z.into_f32() + geom_sweep_vector.to_vec3().z,
),
// transform: Transform::from_scale(origin.to_vec3() + geom_sweep_vector.to_vec3()),
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
// 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);
// }),
// 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