gltf_extension_mesh_2d/
gltf_extension_mesh_2d.rs1use bevy::{
4 asset::LoadContext,
5 gltf::{
6 extensions::{ErasedGltfExtensionHandler, GltfExtensionHandler, GltfExtensionHandlers},
7 GltfPlugin,
8 },
9 mesh::{MeshVertexAttribute, MeshVertexBufferLayoutRef},
10 pbr::PbrPlugin,
11 prelude::*,
12 reflect::TypePath,
13 render::render_resource::*,
14 shader::ShaderRef,
15 sprite_render::{Material2d, Material2dKey, Material2dPlugin},
16};
17
18const SHADER_ASSET_PATH: &str = "shaders/custom_gltf_2d.wgsl";
20
21const ATTRIBUTE_BARYCENTRIC: MeshVertexAttribute =
27 MeshVertexAttribute::new("Barycentric", 2137464976, VertexFormat::Float32x3);
28
29fn main() {
30 App::new()
31 .insert_resource(GlobalAmbientLight {
32 color: Color::WHITE,
33 brightness: 2000.,
34 ..default()
35 })
36 .add_plugins((
37 DefaultPlugins
38 .set(
39 GltfPlugin::default()
40 .add_custom_vertex_attribute("_BARYCENTRIC", ATTRIBUTE_BARYCENTRIC),
45 )
46 .set(PbrPlugin {
47 gltf_enable_standard_materials: false,
48 ..Default::default()
49 }),
50 GltfToMesh2dPlugin,
51 ))
52 .add_systems(Startup, setup)
53 .run();
54}
55
56fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
57 commands.spawn((
58 WorldAssetRoot(
59 asset_server
60 .load(GltfAssetLabel::Scene(0).from_asset("models/barycentric/barycentric.gltf")),
61 ),
62 Transform::from_scale(150. * Vec3::ONE),
63 ));
64 commands.spawn(Camera2d);
65}
66
67struct GltfToMesh2dPlugin;
68
69impl Plugin for GltfToMesh2dPlugin {
70 fn build(&self, app: &mut App) {
71 #[cfg(target_family = "wasm")]
72 bevy::tasks::block_on(async {
73 app.world_mut()
74 .resource_mut::<GltfExtensionHandlers>()
75 .0
76 .write()
77 .await
78 .push(Box::new(GltfExtensionHandlerToMesh2d))
79 });
80 #[cfg(not(target_family = "wasm"))]
81 app.world_mut()
82 .resource_mut::<GltfExtensionHandlers>()
83 .0
84 .write_blocking()
85 .push(Box::new(GltfExtensionHandlerToMesh2d));
86
87 app.add_plugins(Material2dPlugin::<CustomMaterial>::default());
88 }
89}
90
91#[derive(Default, Clone)]
92struct GltfExtensionHandlerToMesh2d;
93
94impl GltfExtensionHandler for GltfExtensionHandlerToMesh2d {
95 fn dyn_clone(&self) -> Box<dyn ErasedGltfExtensionHandler> {
96 Box::new((*self).clone())
97 }
98
99 fn on_spawn_mesh_and_material(
100 &mut self,
101 load_context: &mut LoadContext<'_>,
102 _primitive: &gltf::Primitive,
103 _mesh: &gltf::Mesh,
104 _material: &gltf::Material,
105 entity: &mut EntityWorldMut,
106 _material_label: &str,
107 ) {
108 if let Some(mesh3d) = entity.get::<Mesh3d>() {
109 let material_handle =
110 load_context.add_labeled_asset("AColorMaterial".to_string(), CustomMaterial {});
111 let mesh_handle = mesh3d.0.clone();
112 entity
113 .remove::<Mesh3d>()
114 .insert((Mesh2d(mesh_handle), MeshMaterial2d(material_handle.clone())));
115 }
116 }
117}
118
119#[derive(Asset, TypePath, AsBindGroup, Debug, Clone)]
123struct CustomMaterial {}
124
125impl Material2d for CustomMaterial {
126 fn vertex_shader() -> ShaderRef {
127 SHADER_ASSET_PATH.into()
128 }
129 fn fragment_shader() -> ShaderRef {
130 SHADER_ASSET_PATH.into()
131 }
132
133 fn specialize(
134 descriptor: &mut RenderPipelineDescriptor,
135 layout: &MeshVertexBufferLayoutRef,
136 _key: Material2dKey<Self>,
137 ) -> Result<(), SpecializedMeshPipelineError> {
138 let vertex_layout = layout.0.get_layout(&[
139 Mesh::ATTRIBUTE_POSITION.at_shader_location(0),
140 Mesh::ATTRIBUTE_COLOR.at_shader_location(1),
141 ATTRIBUTE_BARYCENTRIC.at_shader_location(2),
142 ])?;
143 descriptor.vertex.buffers = vec![vertex_layout];
144 Ok(())
145 }
146}