-
Notifications
You must be signed in to change notification settings - Fork 0
Add bevy_gltf_render
#6
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: mat-prop4
Are you sure you want to change the base?
Conversation
|
You added a new feature but didn't update the readme. Please run |
| } | ||
| } | ||
|
|
||
| pub(crate) fn swap_marker_mesh_material_3d( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will require an entry in the migration guides, etc for people who are spawning gltf and managing materials, since it will introduce a delay in the appearance of StandardMaterial for SceneInstanceReady users (they will lose access to the StandardMaterial and instead have to use GltfMaterial) and lifecycle observer users (who will not see an On<Add, StandardMaterial> until after the scene has spawned and this system has run).
Also that migration guide will have to clearly note that removing the MarkerMeshMaterial3d is critical, or bevy will overwrite their materials (or add additional second materials if a user applied a custom material) on the next frame.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think there's another issue - a new StandardMaterial is created for each instance of a mesh with that material. So a glTF with a hundred mesh instances all using same material will end up creating a hundred duplicate StandardMaterial assets.
I've sketched out a potential alternative below - this gives the renderer a way to translate materials during load_gltf so there's no need for post-spawn fixup. It also means the glTF loader can print an error if the renderer hasn't provided a translator or fails during translation.
Unfortunately it's kinda ugly. But maybe as the asset pipeline and scene systems mature it can become more generic - some kind of BSN patch or a BSN -> BSN transform. Also might become simpler if MeshMaterial3d gets changed to a type erased handle, so insert_material is no longer required.
In bevy_gltf:
// Utility for letting renderers translate `GltfMaterial` into their own material type. The renderer
// should add this as a resource during `Plugin::build`.
#[derive(Resource)]
struct GltfMaterialTranslator {
// Create a material asset from a `GltfMaterial` and a label.
load_material: Box<dyn Fn(&GltfMaterial, &GltfAssetLabel, &mut LoadContext) -> Result<UntypedHandle, BevyError>>,
// Insert a material component using a label that was previously passed to `load_material`.
insert_material: Box<dyn Fn(&GltfAssetLabel, &mut LoadContext, &EntityWorldMut)> -> Result<(), BevyError>>,
}
struct GltfLoader {
...
material_translator: Option<GltfMaterialTranslator>,
}
fn load_material(..., material_translator: &Option<GltfMaterialTranslator>) {
let gltf_material: GltfMaterial = ...;
if let Some(material_translator) = material_translator {
match material_translator.load_material(&gltf_material, &material_label, load_context) {
Ok(handle) return handle;
Err(err) { warn!("{err}"); return /* TODO? Does `load_material` return a Result?*/; }
}
}
}
fn load_node(..., material_translator: &Option<GltfMaterialTranslator>) {
...
// Replaces where `MeshMaterial3d` is inserted into `mesh_entity`.
if let Some(material_translator) = material_translator {
if let Err(err) = material_translator.insert_material(&material_label, load_context, &mut mesh_entity) {
warn!("{err}");
}
}
...
}
impl Plugin for GltfPlugin {
fn finish(&self, app: &mut App) {
...
// Copy the material translator resource into the loader. This means we can access it in `GltfLoader::load`,
// which doesn't have access to world resources.
let material_translator = app.world().get_resource<GltfMaterialTranslator>().cloned();
if material_translator.is_none() {
warn!("Missing material translator");
}
...
GltfLoader { ..., material_translator }
}
}In bevy_pbr:
impl Plugin for PbrPlugin {
fn build(...) {
...
let gltf_material_translator = GltfMaterialTranslator {
load_material: |gltf_material, label, load_context| {
Ok(load_context
.labeled_asset_scope::<_, ()>(label.to_string(), |load_context| {
... create a StandardMaterial from the GltfMaterial ...
}).untyped())
},
insert_material: |label, load_context, entity| {
let handle = load_context.get_label_handle::<StandardMaterial>()
.ok_or_else(|| "TODO: error".into())?;
entity.insert(MeshMaterial3d(handle))
Ok(())
},
};
app.insert_resource(gltf_material_translator);
}
}
Objective
MaterialPropertiesfrombevy_pbrtobevy_materialbevyengine/bevy#21543bevy_gltfno longer depends onbevy_renderorbevy_pbrbevy_gltfno longer depends orbevy_pbrorbevy_render#5Solution
GltfMaterialtobevy_gltf, this is a subset of fields inbevy_pbr::StandardMaterial, and is whatbevy_gltfcurrently usesMarkerMeshMaterial3dtobevy_material, this has aHandleto theGltfMaterialbevy_gltf_rendercrate, that depends onbevy_gltfandbevy_pbrswap_marker_mesh_material_3dtobevy_gltf_renderthat:MarkerMeshMaterial3dStandardMaterialfrom theGltfMaterialMarkerMeshMaterial3dMeshMaterial3dwith the newGltfMaterialOnly downside is that if you forget to add
GltfRenderPluginthen it silently doesn't render.Please bikeshed
MarkerMeshMaterial3dAlternative
Define
GltfMaterialinbevy_materialSystem
swap_marker_mesh_material_3dinbevy_pbrThis is indirect, but also works.
See #5
Testing
cargo run --example load_gltf