diff --git a/Cargo.lock b/Cargo.lock index e7c6e38..92dca2d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -157,6 +157,12 @@ dependencies = [ "rustc-demangle", ] +[[package]] +name = "base64" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" + [[package]] name = "base64" version = "0.21.7" @@ -253,6 +259,12 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" +[[package]] +name = "byteorder-lite" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" + [[package]] name = "bytes" version = "1.6.0" @@ -785,6 +797,45 @@ dependencies = [ "web-sys", ] +[[package]] +name = "gltf" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3ce1918195723ce6ac74e80542c5a96a40c2b26162c1957a5cd70799b8cacf7" +dependencies = [ + "base64 0.13.1", + "byteorder", + "gltf-json", + "image 0.25.2", + "lazy_static", + "serde_json", + "urlencoding", +] + +[[package]] +name = "gltf-derive" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14070e711538afba5d6c807edb74bcb84e5dbb9211a3bf5dea0dfab5b24f4c51" +dependencies = [ + "inflections", + "proc-macro2", + "quote", + "syn 2.0.68", +] + +[[package]] +name = "gltf-json" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6176f9d60a7eab0a877e8e96548605dedbde9190a7ae1e80bbcc1c9af03ab14" +dependencies = [ + "gltf-derive", + "serde", + "serde_derive", + "serde_json", +] + [[package]] name = "glutin_wgl_sys" version = "0.5.0" @@ -1034,6 +1085,20 @@ dependencies = [ "tiff", ] +[[package]] +name = "image" +version = "0.25.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99314c8a2152b8ddb211f924cdae532d8c5e4c8bb54728e12fff1b0cd5963a10" +dependencies = [ + "bytemuck", + "byteorder-lite", + "num-traits", + "png", + "zune-core", + "zune-jpeg", +] + [[package]] name = "indexmap" version = "2.2.6" @@ -1044,6 +1109,12 @@ dependencies = [ "hashbrown", ] +[[package]] +name = "inflections" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a257582fdcde896fd96463bf2d40eefea0580021c0712a0e2b028b60b47a837a" + [[package]] name = "ipnet" version = "2.9.0" @@ -1265,7 +1336,8 @@ dependencies = [ "env_logger", "getrandom", "glam", - "image", + "gltf", + "image 0.24.9", "lazy_static", "log", "pollster", @@ -1748,7 +1820,7 @@ version = "0.11.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62" dependencies = [ - "base64", + "base64 0.21.7", "bytes", "encoding_rs", "futures-core", @@ -1813,7 +1885,7 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" dependencies = [ - "base64", + "base64 0.21.7", ] [[package]] @@ -2327,6 +2399,12 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "urlencoding" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" + [[package]] name = "vcpkg" version = "0.2.15" @@ -2374,7 +2452,7 @@ dependencies = [ "console_log", "getrandom", "glam", - "image", + "image 0.24.9", "log", "mini_gpu", "pollster", @@ -3105,6 +3183,12 @@ dependencies = [ "syn 2.0.68", ] +[[package]] +name = "zune-core" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f423a2c17029964870cfaabb1f13dfab7d092a62a29a89264f4d36990ca414a" + [[package]] name = "zune-inflate" version = "0.2.54" @@ -3113,3 +3197,12 @@ checksum = "73ab332fe2f6680068f3582b16a24f90ad7096d5d39b974d1c0aff0125116f02" dependencies = [ "simd-adler32", ] + +[[package]] +name = "zune-jpeg" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16099418600b4d8f028622f73ff6e3deaabdff330fb9a2a131dea781ee8b0768" +dependencies = [ + "zune-core", +] diff --git a/Cargo.toml b/Cargo.toml index 2fd7812..c852310 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,6 +23,7 @@ reqwest = "0.11.20" anyhow = "1.0.75" regex = "1.9.5" lazy_static = "1.4.0" +gltf = "1.4.1" [target.'cfg(target_arch = "wasm32")'.dependencies] web-sys = { version = "0.3.69", features = ["Document", "Window", "Element", "Location"] } diff --git a/examples/wasm/model.glb b/examples/wasm/model.glb new file mode 100644 index 0000000..60f95e1 Binary files /dev/null and b/examples/wasm/model.glb differ diff --git a/examples/wasm/pkg/wasm_bg.js b/examples/wasm/pkg/wasm_bg.js index a431bee..34d4531 100644 --- a/examples/wasm/pkg/wasm_bg.js +++ b/examples/wasm/pkg/wasm_bg.js @@ -247,6 +247,13 @@ function __wbg_adapter_64(arg0, arg1, arg2) { wasm._dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__hf21ab624e941c700(arg0, arg1, addHeapObject(arg2)); } +function passArray8ToWasm0(arg, malloc) { + const ptr = malloc(arg.length * 1, 1) >>> 0; + getUint8Memory0().set(arg, ptr / 1); + WASM_VECTOR_LEN = arg.length; + return ptr; +} + let cachedUint32Memory0 = null; function getUint32Memory0() { @@ -268,7 +275,7 @@ function handleError(f, args) { wasm.__wbindgen_exn_store(addHeapObject(e)); } } -function __wbg_adapter_599(arg0, arg1, arg2, arg3) { +function __wbg_adapter_600(arg0, arg1, arg2, arg3) { wasm.wasm_bindgen__convert__closures__invoke2_mut__ha68be6068ceadf9b(arg0, arg1, addHeapObject(arg2), addHeapObject(arg3)); } @@ -311,6 +318,17 @@ export class MiniGPUWeb { const ret = wasm.minigpuweb_loop_render(this.__wbg_ptr); return takeObject(ret); } + /** + * @param {string} key + * @param {Uint8Array} value + */ + update_obj_map(key, value) { + const ptr0 = passStringToWasm0(key, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); + const len0 = WASM_VECTOR_LEN; + const ptr1 = passArray8ToWasm0(value, wasm.__wbindgen_malloc); + const len1 = WASM_VECTOR_LEN; + wasm.minigpuweb_update_obj_map(this.__wbg_ptr, ptr0, len0, ptr1, len1); + } } export function __wbindgen_object_drop_ref(arg0) { @@ -327,6 +345,11 @@ export function __wbindgen_cb_drop(arg0) { return ret; }; +export function __wbindgen_object_clone_ref(arg0) { + const ret = getObject(arg0); + return addHeapObject(ret); +}; + export function __wbg_minigpuweb_new(arg0) { const ret = MiniGPUWeb.__wrap(arg0); return addHeapObject(ret); @@ -337,11 +360,6 @@ export function __wbindgen_is_undefined(arg0) { return ret; }; -export function __wbindgen_object_clone_ref(arg0) { - const ret = getObject(arg0); - return addHeapObject(ret); -}; - export function __wbindgen_string_new(arg0, arg1) { const ret = getStringFromWasm0(arg0, arg1); return addHeapObject(ret); @@ -1722,7 +1740,7 @@ export function __wbg_new_81740750da40724f(arg0, arg1) { const a = state0.a; state0.a = 0; try { - return __wbg_adapter_599(a, state0.b, arg0, arg1); + return __wbg_adapter_600(a, state0.b, arg0, arg1); } finally { state0.a = a; } @@ -1840,52 +1858,52 @@ export function __wbindgen_closure_wrapper309(arg0, arg1, arg2) { return addHeapObject(ret); }; -export function __wbindgen_closure_wrapper2726(arg0, arg1, arg2) { +export function __wbindgen_closure_wrapper2733(arg0, arg1, arg2) { const ret = makeMutClosure(arg0, arg1, 1196, __wbg_adapter_43); return addHeapObject(ret); }; -export function __wbindgen_closure_wrapper2728(arg0, arg1, arg2) { +export function __wbindgen_closure_wrapper2735(arg0, arg1, arg2) { const ret = makeMutClosure(arg0, arg1, 1196, __wbg_adapter_43); return addHeapObject(ret); }; -export function __wbindgen_closure_wrapper3136(arg0, arg1, arg2) { +export function __wbindgen_closure_wrapper3143(arg0, arg1, arg2) { const ret = makeMutClosure(arg0, arg1, 1244, __wbg_adapter_48); return addHeapObject(ret); }; -export function __wbindgen_closure_wrapper3137(arg0, arg1, arg2) { +export function __wbindgen_closure_wrapper3144(arg0, arg1, arg2) { const ret = makeMutClosure(arg0, arg1, 1244, __wbg_adapter_51); return addHeapObject(ret); }; -export function __wbindgen_closure_wrapper3138(arg0, arg1, arg2) { +export function __wbindgen_closure_wrapper3145(arg0, arg1, arg2) { const ret = makeMutClosure(arg0, arg1, 1244, __wbg_adapter_51); return addHeapObject(ret); }; -export function __wbindgen_closure_wrapper3139(arg0, arg1, arg2) { +export function __wbindgen_closure_wrapper3146(arg0, arg1, arg2) { const ret = makeMutClosure(arg0, arg1, 1244, __wbg_adapter_51); return addHeapObject(ret); }; -export function __wbindgen_closure_wrapper3140(arg0, arg1, arg2) { +export function __wbindgen_closure_wrapper3147(arg0, arg1, arg2) { const ret = makeMutClosure(arg0, arg1, 1244, __wbg_adapter_51); return addHeapObject(ret); }; -export function __wbindgen_closure_wrapper3141(arg0, arg1, arg2) { +export function __wbindgen_closure_wrapper3148(arg0, arg1, arg2) { const ret = makeMutClosure(arg0, arg1, 1244, __wbg_adapter_51); return addHeapObject(ret); }; -export function __wbindgen_closure_wrapper3142(arg0, arg1, arg2) { +export function __wbindgen_closure_wrapper3149(arg0, arg1, arg2) { const ret = makeMutClosure(arg0, arg1, 1244, __wbg_adapter_51); return addHeapObject(ret); }; -export function __wbindgen_closure_wrapper3224(arg0, arg1, arg2) { +export function __wbindgen_closure_wrapper3231(arg0, arg1, arg2) { const ret = makeMutClosure(arg0, arg1, 1309, __wbg_adapter_64); return addHeapObject(ret); }; diff --git a/examples/wasm/pkg/wasm_bg.wasm b/examples/wasm/pkg/wasm_bg.wasm index 2f52148..602412c 100644 Binary files a/examples/wasm/pkg/wasm_bg.wasm and b/examples/wasm/pkg/wasm_bg.wasm differ diff --git a/examples/wasm/src/lib.rs b/examples/wasm/src/lib.rs index 3efdf7a..724eb3c 100644 --- a/examples/wasm/src/lib.rs +++ b/examples/wasm/src/lib.rs @@ -1,3 +1,5 @@ +use std::collections::HashMap; + use components::{controller::map::MapController, materials::sprite::SpriteMaterialConfig, perspective_camera::PerspectiveCamera}; use entity::{sprite_entity, Entity}; use image::{ImageBuffer, Rgba}; @@ -17,7 +19,11 @@ pub struct MiniGPUWeb { camera_controller: MapController, now_window_id: winit::window::WindowId, event_loop: Option>, + assets_buffer_map:HashMap>, } + +const WIDTH: u32 = 800; +const HEIGHT: u32 = 600; #[wasm_bindgen] impl MiniGPUWeb { #[wasm_bindgen(constructor)] @@ -34,6 +40,7 @@ impl MiniGPUWeb { event_loop: Some(event_loop), now_window_id, camera_controller, + assets_buffer_map:HashMap::new(), } } @@ -52,9 +59,10 @@ impl MiniGPUWeb { let dst = doc.get_element_by_id("wasm-example")?; let canvas = window.canvas().unwrap(); let canvas_ele = web_sys::Element::from(canvas); - let canvas_html: HtmlCanvasElement = canvas_ele.dyn_into().unwrap(); - canvas_html.set_width(800); - canvas_html.set_height(600); + let canvas_html: HtmlCanvasElement = canvas_ele.dyn_into().unwrap(); + let style = canvas_html.style(); + style.set_property("width", &format!("{}px", WIDTH)).expect("设置宽度失败"); + style.set_property("height", &format!("{}px", HEIGHT)).expect("设置高度失败"); dst.append_child(&canvas_html).ok()?; Some(()) }) @@ -65,8 +73,8 @@ impl MiniGPUWeb { let mut mini_gpu_instance = mini_gpu::MiniGPU::new( mini_gpu::MiniGPUConfig { - width: 800, - height: 600, + width: WIDTH*2, + height: HEIGHT*2, }, window, ) @@ -122,6 +130,10 @@ impl MiniGPUWeb { .unwrap(); } + #[wasm_bindgen] + pub fn update_obj_map(&mut self,key:String,value:Vec){ + self.assets_buffer_map.insert(key,value); + } } fn create_solid_color_image(width: u32, height: u32, color: [u8; 4]) -> image::DynamicImage { @@ -191,13 +203,6 @@ fn make_test_mesh(mini_gpu: &mut MiniGPU) { vec![0.0, 1.0, 1.0, 1.0], entity_line_id, ); - - fn update_obj_map(key:String,value:&[u8]){ - // let mut map = HashMap::new(); - // map.insert("cube.mtl".to_string(), "examples/models/cube/cube.mtl"); - // map.insert("cube.obj".to_string(), "examples/models/cube/cube.obj"); - // map - } } async fn make_obj_mesh(mini_gpu: &mut MiniGPU) { diff --git a/src/utils/gltf.rs b/src/utils/gltf.rs new file mode 100644 index 0000000..34a0e5c --- /dev/null +++ b/src/utils/gltf.rs @@ -0,0 +1,193 @@ +use std::{fs::File, io::{BufReader, Cursor}}; + +use anyhow::Ok; +use tobj::Model; +use wgpu::util::DeviceExt; +use gltf::{ Gltf}; + +use crate::{ + components::{material::MaterialTrait, materials, mesh::Mesh}, + entity::Entity, + mini_gpu::MiniGPU, + renderer::Renderer, +}; + +use super::{resource::{load_path, load_texture}, texture::Texture}; + +#[repr(C)] +#[derive(Copy, Clone, Debug, bytemuck::Pod, bytemuck::Zeroable)] +pub struct ModelVertex { + pub position: [f32; 3], + pub tex_coord: [f32; 2], + pub normal: [f32; 3], +} + +pub async fn load_gltf(glb_model: &[u8] , mini_gpu: &mut MiniGPU) -> anyhow::Result { + // check obj_materials result + let gltf = Gltf::from_slice(glb_model)?; + let materials = if let materials = gltf.materials() { + for material in materials { + material.pbr_metallic_roughness().base_color_texture().map + } + let materials = + make_material_map(path.parent().unwrap(), obj_materials, + &std::collections::HashMap::new() + , &mini_gpu.renderer).await?; + + let parent_id = &mini_gpu.scene.add_default_entity(); + + append_mesh_children(*parent_id, mini_gpu, models, materials); + Ok(*parent_id) +} + +pub async fn load_obj_by_url( + obj_path: &str, + dir_buffer_map: &std::collections::HashMap, + mini_gpu: &mut MiniGPU, +) -> anyhow::Result { + let obj_text = dir_buffer_map.get(obj_path).unwrap(); + let mut obj_reader = BufReader::new(Cursor::new(obj_text)); + let (models, obj_materials) = tobj::load_obj_buf_async( + &mut obj_reader, + &tobj::LoadOptions { + triangulate: true, + single_index: true, + ..Default::default() + }, + |p| async move { + let mtl_text = dir_buffer_map.get(&p).unwrap(); + tobj::load_mtl_buf(&mut BufReader::new(Cursor::new(mtl_text))) + }, + ) + .await?; + + // check obj_materials result + let materials = make_material_map( + std::path::Path::new(obj_path).parent().unwrap(), + obj_materials, + dir_buffer_map, + &mini_gpu.renderer, + ) + .await?; + + let parent_id = &mini_gpu.scene.add_default_entity(); + + append_mesh_children(*parent_id, mini_gpu, models, materials); + Ok(*parent_id) +} + +pub async fn make_material_map<'a>( + material_path: &'a std::path::Path, + obj_materials: Result, gltf::Error>, + dir_buffer_map: &'a std::collections::HashMap, + renderer: &Renderer, +) -> anyhow::Result>> { + let mut materials: Vec> = Vec::new(); + for m in obj_materials? { + let mut m_string = m.name(); + m. + + let diffuse_texture:Texture = Texture::from_bytes(&renderer.device, &renderer.queue, &buffer, diffuse_path_string)?; + + let material = materials::image::Image::new( + materials::image::ImageConfig { + name: m.name, + width: diffuse_texture.size.width, + height: diffuse_texture.size.height, + texture: Some(diffuse_texture), + ..Default::default() + }, + &renderer, + ); + materials.push(Box::new(material)); + break; + } + Ok(materials) +} + +pub fn append_mesh_children( + parent: usize, + mini_gpu: &mut MiniGPU, + models: Vec, + materials: Vec>, +) -> usize { + let mut i = 0; + let material_ids: Vec = materials + .into_iter() + .map(|m| mini_gpu.scene.add_component(m)) + .collect(); + models.into_iter().for_each(|model| { + let material_index = material_ids[model.mesh.material_id.unwrap_or(0)]; + let mesh = build_mesh(&mini_gpu.renderer, model.mesh); + let mut child = Entity::new(); + child.name = model.name; + let mesh_index = mini_gpu.scene.add_component(mesh); + child.set_component_index("mesh", mesh_index); + child.set_component_index("material", material_index); + let _ = &mini_gpu.scene.add_entity_child(parent, child); + i += 1; + }); + parent +} + +pub fn build_mesh(renderer: &Renderer, mesh: tobj::Mesh) -> Mesh { + let mut vertices: Vec = Vec::new(); + (0..mesh.positions.len() / 3).for_each(|i| { + vertices.append(&mut vec![ + mesh.positions[i * 3], + mesh.positions[i * 3 + 1], + mesh.positions[i * 3 + 2], + mesh.texcoords[i * 2], + mesh.texcoords[i * 2 + 1], + mesh.normals[i * 3], + mesh.normals[i * 3 + 1], + mesh.normals[i * 3 + 2], + ]) + }); + // let mut mesh = Mesh::new(vertices, indices, renderer); + let vertex_buffer = renderer + .device + .create_buffer_init(&wgpu::util::BufferInitDescriptor { + label: Some("Mesh Vertex Buffer"), + contents: bytemuck::cast_slice(&vertices), + usage: wgpu::BufferUsages::VERTEX, + }); + let index_buffer = renderer + .device + .create_buffer_init(&wgpu::util::BufferInitDescriptor { + label: Some("Mesh Index Buffer"), + contents: bytemuck::cast_slice(&mesh.indices), + usage: wgpu::BufferUsages::INDEX, + }); + Mesh { + vertex_buffer, + index_buffer, + num_indices: mesh.indices.len() as u32, + vertex_buffer_layout: get_buffer_layout(), + } +} + +pub fn get_buffer_layout() -> wgpu::VertexBufferLayout<'static> { + use std::mem; + wgpu::VertexBufferLayout { + array_stride: mem::size_of::() as wgpu::BufferAddress, + step_mode: wgpu::VertexStepMode::Vertex, + attributes: &[ + wgpu::VertexAttribute { + offset: 0, + shader_location: 0, + format: wgpu::VertexFormat::Float32x3, + }, + wgpu::VertexAttribute { + offset: mem::size_of::<[f32; 3]>() as wgpu::BufferAddress, + shader_location: 1, + format: wgpu::VertexFormat::Float32x2, + }, + wgpu::VertexAttribute { + offset: mem::size_of::<[f32; 5]>() as wgpu::BufferAddress, + shader_location: 2, + format: wgpu::VertexFormat::Float32x3, + }, + ], + } +} diff --git a/src/utils/mod.rs b/src/utils/mod.rs index ecb3d5e..2633fe9 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -4,3 +4,4 @@ pub mod obj; //i need a group first ,so i can pack the meshs into a group pub mod resource; pub mod test_xyz; pub mod texture; +pub mod gltf; \ No newline at end of file