From c11b4a8261d875b7bf259ced183e7d7632840da8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moon=20Dav=C3=A9?= Date: Wed, 10 Jun 2026 18:18:22 -0400 Subject: [PATCH 1/2] import math after mewnala import --- crates/processing_pyo3/examples/gltf_load.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/processing_pyo3/examples/gltf_load.py b/crates/processing_pyo3/examples/gltf_load.py index dcdea0f6..870687fe 100644 --- a/crates/processing_pyo3/examples/gltf_load.py +++ b/crates/processing_pyo3/examples/gltf_load.py @@ -1,5 +1,5 @@ -import math from mewnala import * +import math gltf = None duck_geo = None From 5a4ba97c4d8971c47fca5fb5b30b12ef1e95df5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moon=20Dav=C3=A9?= Date: Wed, 10 Jun 2026 18:56:30 -0400 Subject: [PATCH 2/2] gltf loading ocnverts GltfMaterial into StandardMaterial --- crates/processing_render/src/gltf.rs | 83 +++++++++++++++++++--------- 1 file changed, 56 insertions(+), 27 deletions(-) diff --git a/crates/processing_render/src/gltf.rs b/crates/processing_render/src/gltf.rs index 84cd75f1..5539383d 100644 --- a/crates/processing_render/src/gltf.rs +++ b/crates/processing_render/src/gltf.rs @@ -8,14 +8,16 @@ use bevy::{ }, camera::visibility::RenderLayers, ecs::system::RunSystemOnce, - gltf::{Gltf, GltfMeshName}, + gltf::{Gltf, GltfMaterial, GltfMeshName}, + pbr::ExtendedMaterial, prelude::*, world_serialization::WorldInstanceSpawner, }; use crate::geometry::{BuiltinAttributes, Geometry, layout::VertexLayout}; use crate::graphics; -use crate::render::material::UntypedMaterial; +use crate::material::ProcessingMaterial; +use crate::render::material::{ProcessingExtendedMaterial, UntypedMaterial}; use processing_core::config::{Config, ConfigKey}; use processing_core::error::{ProcessingError, Result}; @@ -67,7 +69,6 @@ pub struct GltfHandle { handle: Handle, instance_id: bevy::world_serialization::InstanceId, graphics_entity: Entity, - base_path: String, } pub fn load( @@ -76,10 +77,10 @@ pub fn load( ) -> Result { let config = world.resource::().clone(); let base_path = match path.find('#') { - Some(idx) => path[..idx].to_string(), - None => path.clone(), + Some(idx) => &path[..idx], + None => path.as_str(), }; - let asset_path = resolve_asset_path(&config, &base_path); + let asset_path = resolve_asset_path(&config, base_path); let handle: Handle = world.get_asset_server().load(asset_path); block_on_load(world, |w| w.get_asset_server().load_state(&handle))?; @@ -122,7 +123,6 @@ pub fn load( handle, instance_id, graphics_entity, - base_path, }) .id(); Ok(entity) @@ -182,40 +182,69 @@ pub fn geometry( Ok(entity) } +/// Translate a bevy [`GltfMaterial`] into the [`StandardMaterial`] base of a +/// [`ProcessingExtendedMaterial`]. `GltfMaterial` mirrors `StandardMaterial`'s +/// fields, so we copy across the ones that drive shading and let the rest fall +/// back to defaults. +fn gltf_material_to_standard(m: &GltfMaterial) -> StandardMaterial { + StandardMaterial { + base_color: m.base_color, + base_color_channel: m.base_color_channel.clone(), + base_color_texture: m.base_color_texture.clone(), + emissive: m.emissive, + emissive_channel: m.emissive_channel.clone(), + emissive_texture: m.emissive_texture.clone(), + perceptual_roughness: m.perceptual_roughness, + metallic: m.metallic, + metallic_roughness_channel: m.metallic_roughness_channel.clone(), + metallic_roughness_texture: m.metallic_roughness_texture.clone(), + normal_map_channel: m.normal_map_channel.clone(), + normal_map_texture: m.normal_map_texture.clone(), + occlusion_channel: m.occlusion_channel.clone(), + occlusion_texture: m.occlusion_texture.clone(), + double_sided: m.double_sided, + cull_mode: m.cull_mode, + unlit: m.unlit, + alpha_mode: m.alpha_mode, + uv_transform: m.uv_transform, + ..default() + } +} + pub fn material( In((gltf_entity, name)): In<(Entity, String)>, world: &mut World, ) -> Result { - let handle = world + let gltf_handle = world .get::(gltf_entity) - .ok_or(ProcessingError::InvalidEntity)?; - let gltf_handle = handle.handle.clone(); - let base_path = handle.base_path.clone(); + .ok_or(ProcessingError::InvalidEntity)? + .handle + .clone(); - let material_index = { + let standard = { let gltf_assets = world.resource::>(); let gltf = gltf_assets .get(&gltf_handle) .ok_or_else(|| ProcessingError::GltfLoadError("GLTF asset not found".into()))?; - let named_handle = gltf.named_materials.get(name.as_str()).ok_or_else(|| { + let mat_handle = gltf.named_materials.get(name.as_str()).ok_or_else(|| { ProcessingError::GltfLoadError(format!("Material '{}' not found in GLTF", name)) })?; - gltf.materials - .iter() - .position(|h| h.id() == named_handle.id()) - .ok_or_else(|| { - ProcessingError::GltfLoadError(format!( - "Material '{}' not found in materials list", - name - )) - })? + + let gltf_materials = world.resource::>(); + let gltf_material = gltf_materials.get(mat_handle).ok_or_else(|| { + ProcessingError::GltfLoadError(format!("Material '{}' asset not loaded", name)) + })?; + gltf_material_to_standard(gltf_material) }; - let config = world.resource::().clone(); - let std_path = format!("{}#Material{}/std", base_path, material_index); - let asset_path = resolve_asset_path(&config, &std_path); - let handle: Handle = world.get_asset_server().load(asset_path); - block_on_load(world, |w| w.get_asset_server().load_state(&handle))?; + // wrap in the extended material the processing renderer's pipeline expects, so + // the draw systems attach a `MeshMaterial3d` and `material_set` can mutate it + let handle = world + .resource_mut::>() + .add(ExtendedMaterial { + base: standard, + extension: ProcessingMaterial { blend_state: None }, + }); let entity = world.spawn(UntypedMaterial(handle.untyped())).id(); Ok(entity) }