Is merge working correctly?
Hi there!
Basically I'm trying to merge two meshes together, a sphere and a cube.
I'm getting this:
Visualization:
I am using Bevy, here's the relevant bits:
Cargo.toml:
[dependencies]
cgmath = "0.18"
three-d-asset = "0.9.2"
thiserror = "2.0.9"
[dev-dependencies]
bevy = "0.15.1"
bevy_panorbit_camera = "0.21.2"
three-d-asset = {version="0.9.2", features = ["obj"] }
Code:
use bevy::{asset::RenderAssetUsages, prelude::*, render::mesh::{Indices, PrimitiveTopology}};
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_plugins(bevy_panorbit_camera::PanOrbitCameraPlugin)
.add_systems(Startup, setup)
.run();
}
/// set up a simple 3D scene
fn setup(
mut commands: Commands,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<StandardMaterial>>,
) {
// circular base
commands.spawn((
Mesh3d(meshes.add(Circle::new(4.0))),
MeshMaterial3d(materials.add(Color::WHITE)),
Transform::from_rotation(Quat::from_rotation_x(-std::f32::consts::FRAC_PI_2)),
));
// light
commands.spawn((
PointLight {
shadows_enabled: true,
..default()
},
Transform::from_xyz(4.0, 8.0, 4.0),
));
// camera
commands.spawn((
Camera3d::default(),
Transform::from_xyz(-2.5, 4.5, 9.0).looking_at(Vec3::ZERO, Vec3::Y),
bevy_panorbit_camera::PanOrbitCamera::default(),
));
let mut sphere = tri_mesh::Mesh::new(&three_d_asset::TriMesh::sphere(16));
sphere.scale(2.0);
sphere.translate(tri_mesh::vec3(0.0, 1.5, 0.0));
let mut cube = tri_mesh::Mesh::new(&three_d_asset::TriMesh::cube());
cube.scale(1.5);
cube.merge_with(&sphere);
let mesh = to_bevy_mesh(cube);
commands.spawn((
Mesh3d(meshes.add(mesh)),
MeshMaterial3d(materials.add(Color::srgba(0.5, 0.5, 1.0, 1.0))),
Transform::from_xyz(0.0, 2.0, 0.0),
));
}
fn to_bevy_mesh(mesh: tri_mesh::Mesh) -> Mesh {
let mut positions = Vec::new();
let mut normals = Vec::new();
let mut indices = Vec::new();
for vertex_id in mesh.vertex_iter() {
let position = mesh.vertex_position(vertex_id);
positions.push(Vec3::new(position.x as f32, position.y as f32, position.z as f32));
let normal = mesh.vertex_normal(vertex_id);
normals.push(Vec3::new(normal.x as f32, normal.y as f32, normal.z as f32));
}
for face_id in mesh.face_iter() {
let (v0, v1, v2) = mesh.face_vertices(face_id);
indices.push(*v0);
indices.push(*v1);
indices.push(*v2);
}
let mut mesh = Mesh::new(PrimitiveTopology::TriangleList, RenderAssetUsages::default());
mesh.insert_attribute(Mesh::ATTRIBUTE_POSITION, positions);
mesh.insert_attribute(Mesh::ATTRIBUTE_NORMAL, normals);
mesh.insert_indices(Indices::U32(indices));
mesh
}
I've double checked and I'm pretty sure I'm grabbing the positions, normals and vertices correctly (btw, really easy to get that info, thank you!)
I'm also getting weird behavior with split. Perhaps I'm doing something wrong or missing a step?
Edit:
I also confirmed that they are positioned reasonably by using .append()
Edit 2:
It is also worth noting that I upgraded the dependencies, but I seriously doubt those are the problem.
Edit 3:
I've ruled out that it's scale and translate.
Sorry for the late reply, I didn't have the time to investigate, but thought I owed you an answer at least.
There's unit tests for most of the functionality but the merge (and split) functionality is so complex, so it's probably no guarantee that it works. At some point I had a running example with merge where you could see the result, however, for maintainability I removed it again. So what I'm trying to say is that it might be broken completely, but probably it's just not working in your case. As I already said, it's a really complex operation, so maybe try with some different meshes, preferably simple meshes with large polygons, and see if you can get that to work.
At least, I don't think you're doing anything wrong 🙂