How can I manually create meshes in bevy with vertices?
Asked Answered
H

2

19

What do I have to do to to create a mesh for bevy with the following vertices:

let mut vertices : Vec<[f32; 3]> = Vec::new();

    vertices.push([0.0, 0.0, 0.0]);
    vertices.push([1.0, 2.0, 1.0]);
    vertices.push([2.0, 0.0, 0.0]);

I then want to spawn a MeshBundle like so

commands
    .spawn(MeshBundle {
        mesh: mesh,
        transform: Transform::from_translation(Vec3::new(0.0, 0.0, 0.0)),
        ..Default::default()
    });
Hyperthermia answered 17/3, 2021 at 16:20 Comment(4)
Why is this Question getting donvoted?Hyperthermia
Probably because there is no question in your post, and there’s no indication of what your problem is, or why the examples of code you have aren’t sufficient.Indigent
As a beginner wanting to develop procedural geometry, I believe I understand the gist of what this question is asking. I think, if the question lacks clarity, we should suggest edits rather than down-vote.Zoroaster
Also found it very insightful to see how the existing Bevy shapes have been constructed, for example the Box shape under: github.com/bevyengine/bevy/blob/main/crates/bevy_render/src/… And as a bonus, if you create your own shapes in a similar fashion, they'll be very reusable.Sill
O
20

This answer has been updated for the latest bevy = "0.11" and uses the default shaders.

The code below demonstrates how to:

  1. Define vertex positions for a bevy::render::pipeline::PrimitiveTopology::TriangleList
  2. Assign vertex normals and uv coordinates to the vertices
  3. Create a triangle using the 3 vertices we defined

It is based on the built in shapes in bevy, which can be found here.

use bevy::prelude::*;
use bevy::render::mesh::{self, PrimitiveTopology};

fn main() {
    App::new()
        .insert_resource(Msaa::Sample4)
        .add_plugins(DefaultPlugins)
        .add_systems(Startup, setup)
        .run();
}

fn setup(
    mut commands: Commands,
    mut meshes: ResMut<Assets<Mesh>>,
    mut materials: ResMut<Assets<StandardMaterial>>,
) {
    let mut mesh = Mesh::new(PrimitiveTopology::TriangleList);

    // Positions of the vertices
    // See https://bevy-cheatbook.github.io/features/coords.html
    mesh.insert_attribute(
        Mesh::ATTRIBUTE_POSITION,
        vec![[0., 0., 0.], [1., 2., 1.], [2., 0., 0.]],
    );

    // In this example, normals and UVs don't matter,
    // so we just use the same value for all of them
    mesh.insert_attribute(Mesh::ATTRIBUTE_NORMAL, vec![[0., 1., 0.]; 3]);
    mesh.insert_attribute(Mesh::ATTRIBUTE_UV_0, vec![[0., 0.]; 3]);

    // A triangle using vertices 0, 2, and 1.
    // Note: order matters. [0, 1, 2] will be flipped upside down, and you won't see it from behind!
    mesh.set_indices(Some(mesh::Indices::U32(vec![0, 2, 1])));

    commands.spawn(PbrBundle {
        mesh: meshes.add(mesh),
        material: materials.add(Color::rgb(0.3, 0.5, 0.3).into()),
        ..default()
    });

    commands.spawn(PointLightBundle {
        point_light: PointLight {
            intensity: 1500.0,
            shadows_enabled: true,
            ..default()
        },
        transform: Transform::from_xyz(4.0, 8.0, 4.0),
        ..default()
    });

    commands.spawn(Camera3dBundle {
        transform: Transform::from_xyz(-2.0, 2.5, 5.0).looking_at(Vec3::ZERO, Vec3::Y),
        ..default()
    });
}

You will have to define your own positions, uvs and normals according to your use case. Some shaders won't need all of these mesh attributes.

Overburden answered 20/3, 2021 at 16:46 Comment(3)
Optionally, for more complicated geometry, instead of setting normals manually with mesh.insert_attribute(Mesh::ATTRIBUTE_NORMAL,...), you can do: mesh.duplicate_vertices(); mesh.compute_flat_normals(); after mesh.set_indices(...). Note the warnings about increasing the vertex count.Ouidaouija
@Ouidaouija looking great, juste curious why you need to duplicate_vertices() ?Ferrari
@PhilippeParé It's because by default the normals are interpolated. You do have the option in WGSL to disable this using flat interpolation, but then all meshes rendered using that shader would loose the interpolated normals as discussed here. So if you want to mix flat and smooth shaded meshes using the same shader, duplicating vertices is the only option you have.Overburden
C
4

@frankenapps answer updated for bevy = 0.7

use bevy::prelude::*;
use bevy::render::mesh::{self, PrimitiveTopology};

fn main() {
    App::new()
        .insert_resource(Msaa { samples: 4 })
        .add_plugins(DefaultPlugins)
        .add_startup_system(setup)
        .run();
}

/// set up a simple 3D scene
fn setup(
    mut commands: Commands,
    mut meshes: ResMut<Assets<Mesh>>,
    mut materials: ResMut<Assets<StandardMaterial>>,
    ) {
    let vertices = [
        ([0.0, 0.0, 0.0], [0.0, 1.0, 0.0], [1.0, 1.0]),
        ([1.0, 2.0, 1.0], [0.0, 1.0, 0.0], [1.0, 1.0]),
        ([2.0, 0.0, 0.0], [0.0, 1.0, 0.0], [1.0, 1.0]),
    ];

    let indices = mesh::Indices::U32(vec![0, 2, 1, 0, 3, 2]);

    let mut positions = Vec::new();
    let mut normals = Vec::new();
    let mut uvs = Vec::new();
    for (position, normal, uv) in vertices.iter() {
        positions.push(*position);
        normals.push(*normal);
        uvs.push(*uv);
    }

    let mut mesh = Mesh::new(PrimitiveTopology::TriangleList);
    mesh.set_indices(Some(indices));
    mesh.insert_attribute(Mesh::ATTRIBUTE_POSITION, positions);
    mesh.insert_attribute(Mesh::ATTRIBUTE_NORMAL, normals);
    mesh.insert_attribute(Mesh::ATTRIBUTE_UV_0, uvs);

    // add entities to the world
    // plane
    commands.spawn_bundle(PbrBundle {
        mesh: meshes.add(mesh),
        material: materials.add(Color::rgb(0.3, 0.5, 0.3).into()),
        ..default()
    });
    // light
    commands.spawn_bundle(PointLightBundle {
        point_light: PointLight {
            intensity: 1500.0,
            shadows_enabled: true,
            ..default()
        },
        transform: Transform::from_xyz(4.0, 8.0, 4.0),
        ..default()
    });
    // camera
    commands.spawn_bundle(PerspectiveCameraBundle {
        transform: Transform::from_xyz(-2.0, 2.5, 5.0)
            .looking_at(Vec3::ZERO, Vec3::Y),
            ..default()
    });
}
Caenogenesis answered 5/6, 2022 at 7:50 Comment(1)
thanks for the contribution! fyi usually with api updates we'd submit an edit instead of creating a new answer.. I still gave you a vote though :)Virulence

© 2022 - 2024 — McMap. All rights reserved.