I want to create hexagonal tiles similar to Civilization that I can click on the tiles and move things in and out of them with a drag and drop system. The code I've written throws an error after I run the program:
Mesh is missing requested attribute: Vertex_Normal (MeshVertexAttributeId(1), pipeline type: Some("bevy_sprite::mesh2d::material::Material2dPipeline<bevy_sprite::mesh2d::color_material::ColorMaterial>"))
I'm unsure as to why this throws an error since the program runs fine when I create a basic mesh from quad (meshes.add(Mesh::from(shape::Quad::default())).into()
) but I want a 2D hexagon.
Here is my setup code:
fn setup(
mut commands: Commands,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<ColorMaterial>>,
asset_server: Res<AssetServer>
) {
let vertices = vec![
[-0.8660, 0.5000],
[ 0.8660, 0.5000],
[-1.0000, 0.0000],
[ 1.0000, 0.0000],
[-0.8660,-0.5000],
[ 0.8660,-0.5000]];
let indeces = Indices::U16(vec![
0, 1, 2,
1, 3, 2,
2, 3, 4,
3, 5, 4
]);
let mut mesh = Mesh::new(PrimitiveTopology::TriangleList);
mesh.insert_attribute(Mesh::ATTRIBUTE_POSITION, vertices);
mesh.set_indices(Some(indeces));
commands.spawn_bundle(OrthographicCameraBundle::new_2d());
commands.spawn_bundle(MaterialMesh2dBundle {
mesh: meshes.add(mesh).into(),
transform: Transform::default().with_scale(Vec3::splat(128.)),
material: materials.add(asset_server.load(TILE_SPRITE).into()),
..default()
});
}
This is my main:
const TILE_SPRITE: &str = "tile.png";
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_startup_system(setup)
.run();
}
With the default shader in bevy
your mesh must also have normals and uvs for each vertex.
You could either provide your own shader or add the required attributes, similar to the method shown in this answer.
Apart from that it seems that the positions and indices you provided are incorrect. Even if you use bevy in 2D mode you still have to provide the positions using three coordinates (with z
beeing set to zero). You can see what happens otherwise in the RenderDoc screenshot below:
Here is a small sample with the corrected indices and positions, as well as placeholder values for UVs and normals, that should help you get started:
use bevy::{
prelude::*,
render::mesh::{Indices, PrimitiveTopology},
sprite::MaterialMesh2dBundle,
};
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_startup_system(setup)
.run();
}
fn setup(
mut commands: Commands,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<ColorMaterial>>,
_asset_server: Res<AssetServer>,
) {
let vertices = vec![
[-0.8660, 0.5000, 0f32],
[0.8660, 0.5000, 0f32],
[-1.0000, 0.0000, 0f32],
[1.0000, 0.0000, 0f32],
[-0.8660, -0.5000, 0f32],
[0.8660, -0.5000, 0f32],
];
let normals = vec![
[0f32, 0f32, 1f32],
[0f32, 0f32, 1f32],
[0f32, 0f32, 1f32],
[0f32, 0f32, 1f32],
[0f32, 0f32, 1f32],
[0f32, 0f32, 1f32],
];
let uvs = vec![
[0.0000, 0.0000],
[0.0000, 0.0000],
[0.0000, 0.0000],
[0.0000, 0.0000],
[0.0000, 0.0000],
[0.0000, 0.0000],
];
let indices = Indices::U16(vec![1, 0, 2, 3, 1, 2, 3, 2, 4, 3, 4, 5]);
let mut mesh = Mesh::new(PrimitiveTopology::TriangleList);
mesh.insert_attribute(Mesh::ATTRIBUTE_POSITION, vertices);
mesh.insert_attribute(Mesh::ATTRIBUTE_NORMAL, normals);
mesh.insert_attribute(Mesh::ATTRIBUTE_UV_0, uvs);
mesh.set_indices(Some(indices));
let mut camera = OrthographicCameraBundle::new_2d();
camera.orthographic_projection.scale = 1f32;
commands.spawn_bundle(camera);
commands.spawn_bundle(MaterialMesh2dBundle {
mesh: meshes.add(mesh).into(),
transform: Transform::default().with_scale(Vec3::splat(128.)),
material: materials.add(Color::rgb(0.3, 0.5, 0.3).into()),
..default()
});
}
Please note, that in order for your Sprite to show up, you will have to change the UV coordinates (I did leave them at 0, 0
, because I do not know how you would like to map your sprite / texture to the hexagon).