From 7d8798bf53456398ac223c4290b23d638eac1fd9 Mon Sep 17 00:00:00 2001 From: SeanOMik Date: Fri, 8 Mar 2024 00:21:28 -0500 Subject: [PATCH] render: process GltfScenes and Node local transforms --- Cargo.lock | 3 +- examples/testbed/Cargo.toml | 5 +- .../assets/pos-testing/child-node-cubes.glb | Bin 0 -> 24332 bytes .../pos-testing/separate-nodes-two-cubes.glb | Bin 0 -> 24300 bytes examples/testbed/assets/sponza/.gitignore | 2 + examples/testbed/assets/sponza/README.md | 1 + examples/testbed/src/main.rs | 140 ++++++++------ lyra-game/src/render/material.rs | 10 +- lyra-game/src/render/renderer.rs | 178 ++++++++++++------ lyra-game/src/render/texture.rs | 27 +-- lyra-game/src/scene/mesh.rs | 36 +++- lyra-game/src/scene/mod.rs | 3 - lyra-game/src/scene/model.rs | 41 ---- 13 files changed, 248 insertions(+), 198 deletions(-) create mode 100644 examples/testbed/assets/pos-testing/child-node-cubes.glb create mode 100644 examples/testbed/assets/pos-testing/separate-nodes-two-cubes.glb create mode 100644 examples/testbed/assets/sponza/.gitignore create mode 100644 examples/testbed/assets/sponza/README.md delete mode 100644 lyra-game/src/scene/model.rs diff --git a/Cargo.lock b/Cargo.lock index 925ea0f..c7c50da 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1845,7 +1845,9 @@ dependencies = [ "gltf", "image", "infer", + "instant", "lyra-ecs", + "lyra-math", "mime", "notify", "notify-debouncer-full", @@ -3101,7 +3103,6 @@ dependencies = [ "async-std", "fps_counter", "lyra-engine", - "lyra-scripting", "tracing", ] diff --git a/examples/testbed/Cargo.toml b/examples/testbed/Cargo.toml index 877d0b4..79687cc 100644 --- a/examples/testbed/Cargo.toml +++ b/examples/testbed/Cargo.toml @@ -6,8 +6,9 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -lyra-engine = { path = "../../", version = "0.0.1", features = ["lua_scripting"] } -lyra-scripting = { path = "../../lyra-scripting", features = ["lua", "teal"] } +lyra-engine = { path = "../../", version = "0.0.1" } +#lyra-engine = { path = "../../", version = "0.0.1", features = ["lua_scripting"] } +#lyra-scripting = { path = "../../lyra-scripting", features = ["lua", "teal"] } #lyra-ecs = { path = "../../lyra-ecs"} anyhow = "1.0.75" async-std = "1.12.0" diff --git a/examples/testbed/assets/pos-testing/child-node-cubes.glb b/examples/testbed/assets/pos-testing/child-node-cubes.glb new file mode 100644 index 0000000000000000000000000000000000000000..eb0be46f4f4acf987864a454ce7ac4a72c552587 GIT binary patch literal 24332 zcmeGkO>Y}TbnLjT)21|ON~sEn)e0n3T-RQIZ0rMZnh)ZV#8ndYgAmo5c;l?(k7&Iv zDOQRL7Z8_%xFYcjIDkML5HUwC9N>bGiYg8uBqVx7C0rY$wMwm|S=`RT#Y8x&#$t(NB#~62v6z|) zDPbiBl!%&$sYCIono>g-V_`KGQ4*=4R3fIt)rh*d5o*ZGt466{>frA}1Weloqu_(> zAQ}uuB2gLrDr=T*8d}NjLZMn;D(Q1ZK`+Q@%dG2dp=pN?1QqahZONS0Ev-~CmS?N= z;%Y^&frf^>q}BA%YN=|@>+4qCgm^S$10uQ(J%+fI9hnJjnFk*NXbSN*Eu7fEUL44m z=zsGidKh1v5c0unkFpa)9t+bb80*|A#@Ijw*<5F}$6MPl1yf-&O*>K!cl9j+Ff@zuJyjFTS+Y4-*YH_BSk3CL1?Wkoly8TuP?8XPJcWqtn68eS@# z>C#%I2&3rq@%pM^>3n8t%Mg!R)wDfuD*-2#tL3$7MXy-4rbJXpBC%e9%UeMs8qBzb zXbAqmnX-Y`!o_Ha|6}KD``5-tV{kdcv~{@%gR`IZZsN*e#FZV^Vfc4i=S1GO7nQG(AY zIh|6K6u+L^gw&9_Jx!b`;+_|Zl1RcGO_HQX*BHB;oq+{GbJ!`H`{39vc=p1FT{`x{ zg$``r4Hqmyokp{S^Gv;GYurqKz!;Z1z>?j+A z^B{YQJ;_e9J~;QWQ>>r$uwFR#va{?6^TQJQ2$U0SfSm+&15g6&y{j{?oIHO1I8;t% zC&y-yh9!6uz+2D0^bUZeej~dwJ0O(=3B(hpvG{&?aCZwj&$449^XtApe;OHJQeV$VYqOZY|84o% z!jIQ~`$m1n=MMz?rA(9A$fGY>|D-=&>!4+tt-%Oe4|H<&_eWUZ%GnPbK}W+mw$(}K z4+hUM{|oO=3JW%4AG_O02nGUu?B0jt&$nIS$Wb=jNeKA;N1K`Nm2z=#b!3mOgoD;o_%tA1#}M@C}2O z&GfBPIURWSf%78L1lro@%70>fgzK_zSlrqRrwi&Ydlro@a9q`bJQU;VVpp*eU zsKn>Hlrrc{8Ej3x`IXoUAf8v#5}KCKw1lQ5H12buB{VIeX$c*q&1$&4jh?#EUO!qw z`)Q{s?&PJXZuHcRp1RRfH+t%ZdsOL13bavIqLcxp4DiQGlro@{0i_J^W06t@8A=&Y z%79V^{5QRnGN6r@2@j<>JNM`fcR}a{Yak{G4zfD{>BH|I@Gy!h_(wk zH%ZFa zdvQ@mxC@Rk!UNkl9L5U#BgCW0&vv_mBSq-qt!}y_$K`>(uO8rc^9VnLUDPjVZJnD) zg`>&OyZh$h;p|@DJUrZvqf_upCk`nKP!Qsg$GXsqG{8ljv3~()je8;h literal 0 HcmV?d00001 diff --git a/examples/testbed/assets/pos-testing/separate-nodes-two-cubes.glb b/examples/testbed/assets/pos-testing/separate-nodes-two-cubes.glb new file mode 100644 index 0000000000000000000000000000000000000000..a10cc1aa206ccc70b5461984a8c7d40d86e2432a GIT binary patch literal 24300 zcmeGkO>Y}TbnKYcX;YdsrBsEA)e0n3+;qKm?AQn5G#|tziK`^)2O;21vT;`ON3>p- zlqh8j7Z4XfT#@(%96%rrh?pZ64sbz8MHL4SQYCssCJ-kh3-#;(j1rq*SxUe_%-yDpdXs%~ml&6Kn9%PVHBTB}PX z5RopI_3DytO8H9#=~l8&=}RW%n0!k&>qe~#%xa$^Z^Y#KA}Elvii_3d?A*Fs)ha-f zXLwsouGW@xY*1qH`HlJQ`np`v>nmK?l^AX;=wQV%wQ9YrS=`dx#s0pGqNb8+T1^dP z2I84SEYTNNlBxc<8dp;pRZS`Bm@>Z+6AI&C!*Kx>_9;qSM!OZw(oI7vJ5Dau8VhB8 z##qvq%+Bj&79TOtcD3a zUY8As*&6f+B2#f?#vX#9Oq!{ta~dK)zu7|AQ~_!}x+xf-&L4)fz`Ph&&di zQ86szmdl`7mT4?BEUd1}R|_-w*?eJ&kLXlkdU9w&&cayCj@}q96sAXBSLCb;-awFy zMHESFj|s+%kD!0xc%KhuGZ~YG&3?bl)SfouU=zA*IRog-i@H`>E$eVS;GC{C%tf5u zI7quUfVff7N^U?F8q3SNdCkz@kh9=W#i;1Bw^#9E;7pfRt0fpkw~yCX3`^%TQ(J_1 z)N7{WfmaDQu~@6D)~b5dax}rLPa&~Ug$r0kBO1)Oxp)lzz?q5xSLfWtc#QvJ=N$Xj zMu!t{!NRolxCn!@pZ0d*>S4sy9oAv^cUtE}-nRsF)3rV`JTx&hy+Z+v^G*f-TX49d z_MvYVob>+AZHq&2V5qi-#yb)COkB8a=@WXjWWoJX9T)&!AQYCD`E48~iKUq(yrUCr=TBR;Y2&fl~fXJd5sSw`E}_;?EpQE zCoyndgNKV$Jbjqn?ueDDLKlMeVbtCGiZkSJD;YD&@SKvfnY5bW*K>=I8AxwW6L*Su z=Y^{Fr{InzJ-o))<@^*p_3c5oZ0>_&yWrUiAN1(h3l}=DeK%at5VpfbdpkJj`XlsU zJ&21s!d-9(5kIgE4~!SHUC0S|a%7P%4xx+JZ9(0ZJFp(G$9Yi&=n;MdZSiK|o9nCK z;W8jA4(?lk2it_5mTv)`9eTi?1cmJan=d-_AVhu}+JX@IkRF7{mvi+aEJ9&WkPqt& zptmjo&4z*yk0REEUZepo>Wqch?G@E9jp`1 zo$L&IjD=Yg&QW%p^{^A5t_Mnly?1r$r4z@_9fQh={P@T;(y&C20C?;C3-16(={NGr zlauTM;Af$XLkYEDICKv5I+SSWsTST1H1@&TU*7=etc{J;vCfZQE`0R^Af2n@H-UKk z6qeAB_wH;#=UIMaXm&01;OC(pCUtcTH8)Ge55B9MU;63#@871M4uvDpZYgIo2YL8q z^PlV|t3F!JZuTl{E#l|w?p9dj%9#&cL07|Bw&f>uN26z1___DTg$0MPi{0@PqLD}! zyZh1Tvn^LRa)b@~36XI4h@JahKDF&LGIZF__zB@qs3Z63QctI+b2-}%HBb5o>@Lux ztDnE??{O18{&>TZvvav7>wf;`h(8EL_OQb*DM>{Z{WvE3XQU;VVz{et`404n*pp*fn4ET3?DP=$@146hi1KKV`xj)MNQSOg& zf4JG4a(}er9IiqiF-CY`8;65ffq#T}*!=9Y zyEsyWF5c>;yK-C}==BRvR_FX!q("assets/happy-tree.png").unwrap(); //let antique_camera_model = resman.request::("assets/AntiqueCamera.glb").unwrap(); //let cube_model = resman.request::("assets/cube-texture-bin.glb").unwrap(); - let cube_model = resman.request::("assets/texture-sep/texture-sep.gltf").unwrap(); - let crate_model = resman.request::("assets/crate/crate.gltf").unwrap(); - //let sponza_model = resman.request::("assets/sponza/Sponza.gltf").unwrap(); + let cube_gltf = resman.request::("assets/texture-sep/texture-sep.gltf").unwrap(); + let crate_gltf = resman.request::("assets/crate/crate.gltf").unwrap(); + + let separate_gltf = resman.request::("assets/pos-testing/separate-nodes-two-cubes.glb").unwrap(); + drop(resman); + + let cube_mesh = &cube_gltf.data_ref() + .unwrap().meshes[0]; + let crate_mesh = &crate_gltf.data_ref() + .unwrap().meshes[0]; + + let separate_scene = &separate_gltf.data_ref() + .unwrap().scenes[0]; + + /* let sponza_model = resman.request::("assets/sponza/Sponza.gltf").unwrap(); drop(resman); - /* world.spawn(( - ModelComponent(antique_camera_model), - Transform::from_xyz(0.0, -5.0, -10.0), - )); */ + let sponza_scene = &sponza_model.data_ref() + .unwrap().scenes[0]; - /* world.spawn(( - ModelComponent(sponza_model), + world.spawn(( + sponza_scene.clone(), Transform::from_xyz(0.0, 0.0, 0.0), )); */ - { - let cube_tran = Transform::from_xyz(-3.5, 0.0, -8.0); + world.spawn(( + separate_scene.clone(), + Transform::from_xyz(0.0, -5.0, -10.0), + )); + + /* { + let cube_tran = Transform::from_xyz(-5.9026427, -1.8953488, -10.0); //cube_tran.rotate_y(math::Angle::Degrees(180.0)); world.spawn(( cube_tran, - ModelComponent(crate_model.clone()), + crate_mesh.clone(), CubeFlag, )); - } + } */ { let mut light_tran = Transform::from_xyz(1.5, 2.5, 0.0); @@ -124,11 +146,11 @@ async fn main() { specular: 1.3, }, light_tran, - ModelComponent(cube_model.clone()), + cube_mesh.clone(), )); } - { + /* { let mut light_tran = Transform::from_xyz(-3.5, 0.2, -4.5); light_tran.scale = Vec3::new(0.5, 0.5, 0.5); world.spawn(( @@ -146,9 +168,31 @@ async fn main() { specular: 1.0, }, Transform::from(light_tran), - ModelComponent(cube_model.clone()), + cube_mesh.clone(), )); } + + { + let mut light_tran = Transform::from_xyz(2.0, 2.5, -9.5); + light_tran.scale = Vec3::new(0.5, 0.5, 0.5); + world.spawn(( + PointLight { + color: Vec3::new(0.0, 0.0, 1.0), + + intensity: 3.3, + + constant: 1.0, + linear: 0.09, + quadratic: 0.032, + + ambient: 0.2, + diffuse: 1.0, + specular: 1.3, + }, + Transform::from(light_tran), + cube_mesh.clone(), + )); + } */ /* { let mut light_tran = Transform::from_xyz(-5.0, 2.5, -9.5); @@ -172,28 +216,6 @@ async fn main() { )); } */ - { - let mut light_tran = Transform::from_xyz(2.0, 2.5, -9.5); - light_tran.scale = Vec3::new(0.5, 0.5, 0.5); - world.spawn(( - PointLight { - color: Vec3::new(0.0, 0.0, 1.0), - - intensity: 3.3, - - constant: 1.0, - linear: 0.09, - quadratic: 0.032, - - ambient: 0.2, - diffuse: 1.0, - specular: 1.3, - }, - Transform::from(light_tran), - ModelComponent(cube_model), - )); - } - let mut camera = CameraComponent::new_3d(); camera.transform.translation += math::Vec3::new(0.0, 0.0, 5.5); world.spawn(( camera, FreeFlyCamera::default() )); @@ -211,7 +233,7 @@ async fn main() { Ok(()) }; - let fps_plugin = move |game: &mut Game| { + let _fps_plugin = move |game: &mut Game| { let world = game.world_mut(); world.add_resource(fps_counter::FPSCounter::new()); }; @@ -246,54 +268,54 @@ async fn main() { }; let action_handler_plugin = |game: &mut Game| { - /* let action_handler = ActionHandler::builder() + let action_handler = ActionHandler::builder() .add_layout(LayoutId::from(0)) - .add_action(CommonActionLabel::MoveForwardBackward, Action::new(ActionKind::Axis)) - .add_action(CommonActionLabel::MoveLeftRight, Action::new(ActionKind::Axis)) - .add_action(CommonActionLabel::MoveUpDown, Action::new(ActionKind::Axis)) - .add_action(CommonActionLabel::LookLeftRight, Action::new(ActionKind::Axis)) - .add_action(CommonActionLabel::LookUpDown, Action::new(ActionKind::Axis)) - .add_action(CommonActionLabel::LookRoll, Action::new(ActionKind::Axis)) + .add_action(ACTLBL_MOVE_FORWARD_BACKWARD, Action::new(ActionKind::Axis)) + .add_action(ACTLBL_MOVE_LEFT_RIGHT, Action::new(ActionKind::Axis)) + .add_action(ACTLBL_MOVE_UP_DOWN, Action::new(ActionKind::Axis)) + .add_action(ACTLBL_LOOK_LEFT_RIGHT, Action::new(ActionKind::Axis)) + .add_action(ACTLBL_LOOK_UP_DOWN, Action::new(ActionKind::Axis)) + .add_action(ACTLBL_LOOK_ROLL, Action::new(ActionKind::Axis)) .add_mapping(ActionMapping::builder(LayoutId::from(0), ActionMappingId::from(0)) - .bind(CommonActionLabel::MoveForwardBackward, &[ + .bind(ACTLBL_MOVE_FORWARD_BACKWARD, &[ ActionSource::Keyboard(KeyCode::W).into_binding_modifier(1.0), ActionSource::Keyboard(KeyCode::S).into_binding_modifier(-1.0) ]) - .bind(CommonActionLabel::MoveLeftRight, &[ + .bind(ACTLBL_MOVE_LEFT_RIGHT, &[ ActionSource::Keyboard(KeyCode::A).into_binding_modifier(-1.0), ActionSource::Keyboard(KeyCode::D).into_binding_modifier(1.0) ]) - .bind(CommonActionLabel::MoveUpDown, &[ + .bind(ACTLBL_MOVE_UP_DOWN, &[ ActionSource::Keyboard(KeyCode::C).into_binding_modifier(1.0), ActionSource::Keyboard(KeyCode::Z).into_binding_modifier(-1.0) ]) - .bind(CommonActionLabel::LookLeftRight, &[ + .bind(ACTLBL_LOOK_LEFT_RIGHT, &[ ActionSource::Mouse(MouseInput::Axis(MouseAxis::X)).into_binding(), ActionSource::Keyboard(KeyCode::Left).into_binding_modifier(-1.0), ActionSource::Keyboard(KeyCode::Right).into_binding_modifier(1.0), //ActionSource::Gamepad(GamepadFormat::DualAxis, GamepadInput::Axis(GamepadAxis::RThumbstickX)).into_binding(), ]) - .bind(CommonActionLabel::LookUpDown, &[ + .bind(ACTLBL_LOOK_UP_DOWN, &[ ActionSource::Mouse(MouseInput::Axis(MouseAxis::Y)).into_binding(), ActionSource::Keyboard(KeyCode::Up).into_binding_modifier(-1.0), ActionSource::Keyboard(KeyCode::Down).into_binding_modifier(1.0), //ActionSource::Gamepad(GamepadFormat::DualAxis, GamepadInput::Axis(GamepadAxis::RThumbstickY)).into_binding(), ]) - .bind(CommonActionLabel::LookRoll, &[ + .bind(ACTLBL_LOOK_ROLL, &[ ActionSource::Keyboard(KeyCode::E).into_binding_modifier(-1.0), ActionSource::Keyboard(KeyCode::Q).into_binding_modifier(1.0), ]) .finish() - ); + ).finish(); let world = game.world_mut(); - world.add_resource(action_handler); */ + world.add_resource(action_handler); game.with_plugin(InputActionPlugin); }; - let script_test_plugin = |game: &mut Game| { + /* let script_test_plugin = |game: &mut Game| { game.with_plugin(LuaScriptingPlugin); let world = game.world_mut(); @@ -306,13 +328,13 @@ async fn main() { let scripts = ScriptList::new(vec![script]); world.spawn((scripts,)); - }; + }; */ Game::initialize().await .with_plugin(lyra_engine::DefaultPlugins) .with_startup_system(setup_sys.into_system()) .with_plugin(action_handler_plugin) - .with_plugin(script_test_plugin) + //.with_plugin(script_test_plugin) //.with_plugin(fps_plugin) .with_plugin(jiggle_plugin) .with_plugin(FreeFlyCameraPlugin) diff --git a/lyra-game/src/render/material.rs b/lyra-game/src/render/material.rs index dec5b12..b53149b 100755 --- a/lyra-game/src/render/material.rs +++ b/lyra-game/src/render/material.rs @@ -10,11 +10,11 @@ pub struct MaterialSpecular { } impl MaterialSpecular { - pub fn from_resource(device: &wgpu::Device, queue: &wgpu::Queue, bg_layout: Arc, value: &lyra_resource::Specular) -> Self { - let tex = value.texture.as_ref().map(|t| t.data_ref()) + pub fn from_resource(device: &wgpu::Device, queue: &wgpu::Queue, bg_layout: Arc, value: &lyra_resource::gltf::Specular) -> Self { + let tex = value.texture.as_ref().and_then(|t| t.data_ref()) .map(|i| RenderTexture::from_image(device, queue, bg_layout.clone(), &i.image, None).unwrap()); - let color_tex = value.color_texture.as_ref().map(|t| t.data_ref()) + let color_tex = value.color_texture.as_ref().and_then(|t| t.data_ref()) .map(|i| RenderTexture::from_image(device, queue, bg_layout, &i.image, None).unwrap()); Self { @@ -38,8 +38,8 @@ pub struct Material { } impl Material { - pub fn from_resource(device: &wgpu::Device, queue: &wgpu::Queue, bg_layout: Arc, value: &lyra_resource::Material) -> Self { - let diffuse_texture = value.base_color_texture.as_ref().map(|t| t.data_ref()) + pub fn from_resource(device: &wgpu::Device, queue: &wgpu::Queue, bg_layout: Arc, value: &lyra_resource::gltf::Material) -> Self { + let diffuse_texture = value.base_color_texture.as_ref().and_then(|t| t.data_ref()) .map(|i| RenderTexture::from_image(device, queue, bg_layout.clone(), &i.image, None).unwrap()); let specular = value.specular.as_ref().map(|s| MaterialSpecular::from_resource(device, queue, bg_layout.clone(), s)); diff --git a/lyra-game/src/render/renderer.rs b/lyra-game/src/render/renderer.rs index 48d77d2..e8cba97 100755 --- a/lyra-game/src/render/renderer.rs +++ b/lyra-game/src/render/renderer.rs @@ -5,10 +5,13 @@ use std::borrow::Cow; use glam::Vec3; use instant::Instant; use itertools::izip; -use lyra_ecs::Entity; +use lyra_ecs::query::filter::{Has, Or}; +use lyra_ecs::{Entity, Tick}; use lyra_ecs::query::{Entities, TickOf}; use lyra_ecs::World; -use tracing::{debug, warn}; +use lyra_resource::gltf::GltfScene; +use tracing::{debug, debug_span, warn}; +use uuid::Uuid; use wgpu::{BindGroupLayout, Limits}; use wgpu::util::DeviceExt; use winit::window::Window; @@ -16,7 +19,7 @@ use winit::window::Window; use crate::math::Transform; use crate::render::material::MaterialUniform; use crate::render::render_buffer::BufferWrapperBuilder; -use crate::scene::{ModelComponent, CameraComponent}; +use crate::scene::CameraComponent; use super::camera::{RenderCamera, CameraUniform}; use super::desc_buf_lay::DescVertexBufferLayout; @@ -28,7 +31,10 @@ use super::transform_buffer_storage::TransformBuffers; use super::vertex::Vertex; use super::{render_pipeline::FullRenderPipeline, render_buffer::BufferStorage, render_job::RenderJob}; -use lyra_resource::Mesh; +use lyra_resource::{gltf::Mesh, ResHandle}; + +type MeshHandle = ResHandle; +type SceneHandle = ResHandle; pub trait Renderer { fn prepare(&mut self, main_world: &mut World); @@ -265,16 +271,19 @@ impl BasicRenderer { s } - fn update_mesh_buffers(&mut self, _entity: Entity, mesh: &Mesh) { - if let Some(buffers) = self.mesh_buffers.get_mut(&mesh.uuid) { + /// Checks if the mesh buffers in the GPU need to be updated. + fn check_mesh_buffers(&mut self, _entity: Entity, meshh: &ResHandle) { + let mesh_uuid = meshh.uuid(); + + if let (Some(mesh), Some(buffers)) = (meshh.data_ref(), self.mesh_buffers.get_mut(&mesh_uuid)) { // check if the buffer sizes dont match. If they dont, completely remake the buffers let vertices = mesh.position().unwrap(); if buffers.buffer_vertex.count() != vertices.len() { - debug!("Recreating buffers for mesh {}", mesh.uuid.to_string()); - let (vert, idx) = self.create_vertex_index_buffers(mesh); + debug!("Recreating buffers for mesh {}", mesh_uuid.to_string()); + let (vert, idx) = self.create_vertex_index_buffers(&mesh); // have to re-get buffers because of borrow checker - let buffers = self.mesh_buffers.get_mut(&mesh.uuid).unwrap(); + let buffers = self.mesh_buffers.get_mut(&mesh_uuid).unwrap(); buffers.buffer_indices = idx; buffers.buffer_vertex = vert; @@ -292,8 +301,8 @@ impl BasicRenderer { if let Some(index_buffer) = buffers.buffer_indices.as_ref() { let aligned_indices = match mesh.indices.as_ref().unwrap() { // U16 indices need to be aligned to u32, for wpgu, which are 4-bytes in size. - lyra_resource::MeshIndices::U16(v) => bytemuck::pod_align_to::(v).1, - lyra_resource::MeshIndices::U32(v) => bytemuck::pod_align_to::(v).1, + lyra_resource::gltf::MeshIndices::U16(v) => bytemuck::pod_align_to::(v).1, + lyra_resource::gltf::MeshIndices::U32(v) => bytemuck::pod_align_to::(v).1, }; let index_buffer = index_buffer.1.buffer(); @@ -327,8 +336,8 @@ impl BasicRenderer { let indices = match mesh.indices.as_ref() { Some(indices) => { let (idx_type, len, contents) = match indices { - lyra_resource::MeshIndices::U16(v) => (wgpu::IndexFormat::Uint16, v.len(), bytemuck::cast_slice(v)), - lyra_resource::MeshIndices::U32(v) => (wgpu::IndexFormat::Uint32, v.len(), bytemuck::cast_slice(v)), + lyra_resource::gltf::MeshIndices::U16(v) => (wgpu::IndexFormat::Uint16, v.len(), bytemuck::cast_slice(v)), + lyra_resource::gltf::MeshIndices::U32(v) => (wgpu::IndexFormat::Uint32, v.len(), bytemuck::cast_slice(v)), }; let index_buffer = self.device.create_buffer_init( @@ -354,7 +363,11 @@ impl BasicRenderer { fn create_mesh_buffers(&mut self, mesh: &Mesh) -> MeshBufferStorage { let (vertex_buffer, buffer_indices) = self.create_vertex_index_buffers(mesh); - let material = Material::from_resource(&self.device, &self.queue, self.bgl_texture.clone(), &mesh.material()); + let material = mesh.material.as_ref() + .expect("Material resource not loaded yet") + .data_ref() + .unwrap(); + let material = Material::from_resource(&self.device, &self.queue, self.bgl_texture.clone(), &material); let uni = MaterialUniform::from(&material); self.queue.write_buffer(&self.material_buffer.inner_buf, 0, bytemuck::bytes_of(&uni)); debug!("Wrote material to buffer"); @@ -367,7 +380,7 @@ impl BasicRenderer { } /// Processes the mesh for the renderer, storing and creating buffers as needed. Returns true if a new mesh was processed. - fn process_mesh(&mut self, entity: Entity, transform: Transform, mesh: &Mesh) -> bool { + fn process_mesh(&mut self, entity: Entity, transform: Transform, mesh: &Mesh, mesh_uuid: Uuid) -> bool { if self.transform_buffers.should_expand() { self.transform_buffers.expand_buffers(&self.device); } @@ -376,15 +389,48 @@ impl BasicRenderer { entity, || ( transform.calculate_mat4(), glam::Mat3::from_quat(transform.rotation) )); #[allow(clippy::map_entry)] - if !self.mesh_buffers.contains_key(&mesh.uuid) { + if !self.mesh_buffers.contains_key(&mesh_uuid) { // create the mesh's buffers let buffers = self.create_mesh_buffers(mesh); - self.mesh_buffers.insert(mesh.uuid, buffers); - self.entity_meshes.insert(entity, mesh.uuid); + self.mesh_buffers.insert(mesh_uuid, buffers); + self.entity_meshes.insert(entity, mesh_uuid); true } else { false } } + + fn interpolate_transforms(&mut self, now: Instant, last_epoch: Tick, entity: Entity, transform: &Transform, transform_epoch: Tick) -> Transform { + let cached = match self.entity_last_transforms.get_mut(&entity) { + Some(last) if transform_epoch == last_epoch => { + last.from_transform = last.to_transform; + last.to_transform = *transform; + last.last_updated_at = Some(last.cached_at); + last.cached_at = now; + + last.clone() + }, + Some(last) => last.clone(), + None => { + let cached = CachedTransform { + last_updated_at: None, + cached_at: now, + from_transform: *transform, + to_transform: *transform, + }; + self.entity_last_transforms.insert(entity, cached.clone()); + cached + } + }; + + let fixed_time = match cached.last_updated_at { + Some(last_updated_at) => cached.cached_at - last_updated_at, + None => now - cached.cached_at + }.as_secs_f32(); + let accumulator = (now - cached.cached_at).as_secs_f32(); + let alpha = accumulator / fixed_time; + + cached.from_transform.lerp(cached.to_transform, alpha) + } } impl Renderer for BasicRenderer { @@ -395,57 +441,71 @@ impl Renderer for BasicRenderer { let now_inst = Instant::now(); - for (entity, model, model_epoch, transform, transform_epoch) in main_world.view_iter::<(Entities, &ModelComponent, TickOf, &Transform, TickOf)>() { + let view = main_world.filtered_view_iter::<(Entities, &Transform, TickOf), Or, Has>>(); + for (entity, transform, transform_epoch) in view { alive_entities.insert(entity); - let cached = match self.entity_last_transforms.get_mut(&entity) { - Some(last) if transform_epoch == last_epoch => { - last.from_transform = last.to_transform; - last.to_transform = *transform; - last.last_updated_at = Some(last.cached_at); - last.cached_at = now_inst; + let mesh_view = main_world.view_one::<(&MeshHandle, TickOf)>(entity); + if let Some((mesh_han, mesh_epoch)) = mesh_view.get() { + let interop_pos = self.interpolate_transforms(now_inst, last_epoch, entity, &transform, transform_epoch); - last.clone() - }, - Some(last) => last.clone(), - None => { - let cached = CachedTransform { - last_updated_at: None, - cached_at: now_inst, - from_transform: *transform, - to_transform: *transform, - }; - self.entity_last_transforms.insert(entity, cached.clone()); - cached + if let Some(mesh) = mesh_han.data_ref() { + // if process mesh did not just create a new mesh, and the epoch + // shows that the scene has changed, verify that the mesh buffers + // dont need to be resent to the gpu. + if !self.process_mesh(entity, interop_pos, &*mesh, mesh_han.uuid()) + && mesh_epoch == last_epoch { + self.check_mesh_buffers(entity, &mesh_han); + } + + let material = mesh.material.as_ref().unwrap() + .data_ref().unwrap(); + let shader = material.shader_uuid.unwrap_or(0); + let job = RenderJob::new(entity, shader, mesh_han.uuid(), interop_pos); + self.render_jobs.push_back(job); } - }; - //debug!("Transform: {:?}, comp: {:?}", cached.to_transform.translation, transform.transform.translation); - - let fixed_time = match cached.last_updated_at { - Some(last_updated_at) => cached.cached_at - last_updated_at, - None => now_inst - cached.cached_at - }.as_secs_f32(); - let accumulator = (now_inst - cached.cached_at).as_secs_f32(); - let alpha = accumulator / fixed_time; + } - let transform_val = cached.from_transform.lerp(cached.to_transform, alpha); + let scene_view = main_world.view_one::<(&SceneHandle, TickOf)>(entity); + if let Some((scene_han, scene_epoch)) = scene_view.get() { + // TODO: Rendering scenes - let model = model.data_ref(); - for mesh in model.meshes.iter() { - if !self.process_mesh(entity, transform_val, mesh) && model_epoch == last_epoch { - self.update_mesh_buffers(entity, mesh); + let scene_scope = debug_span!("scene", uuid = scene_han.uuid().to_string()); + let _enter = scene_scope.enter(); + + if let Some(scene) = scene_han.data_ref() { + let interop_pos = self.interpolate_transforms(now_inst, last_epoch, entity, &transform, transform_epoch); + let meshes = scene.collect_world_meshes(); + + for (mesh_han, mesh_pos) in meshes.into_iter() { + if let Some(mesh) = mesh_han.data_ref() { + let mesh_interp = interop_pos + mesh_pos; + + let mesh_scope = debug_span!("mesh", uuid = mesh_han.uuid().to_string()); + let _enter = mesh_scope.enter(); + + debug!("mesh at {:?}", mesh_interp.translation); + + // if process mesh did not just create a new mesh, and the epoch + // shows that the scene has changed, verify that the mesh buffers + // dont need to be resent to the gpu. + if !self.process_mesh(entity, mesh_interp, &*mesh, mesh_han.uuid()) + && scene_epoch == last_epoch { + self.check_mesh_buffers(entity, &mesh_han); + debug!("updating mesh buffers"); + } + + let material = mesh.material.as_ref().unwrap() + .data_ref().unwrap(); + let shader = material.shader_uuid.unwrap_or(0); + let job = RenderJob::new(entity, shader, mesh_han.uuid(), interop_pos); + self.render_jobs.push_back(job); + } + } } - - let shader = mesh.material().shader_uuid.unwrap_or(0); - let job = RenderJob::new(entity, shader, mesh.uuid, transform_val); - self.render_jobs.push_back(job); } } - /* for (entity, mesh, mesh_epoch, transform) in main_world.query::<(Entities, &MeshComponent, EpochOf, &TransformComponent)>().iter() { - debug!("TODO: Process MeshComponents"); // TODO: Process MeshComponents - } */ - // collect dead entities self.transform_buffers.tick(); diff --git a/lyra-game/src/render/texture.rs b/lyra-game/src/render/texture.rs index aa99388..0237a23 100755 --- a/lyra-game/src/render/texture.rs +++ b/lyra-game/src/render/texture.rs @@ -5,25 +5,6 @@ use lyra_resource::{ResHandle, Texture}; use super::render_buffer::BindGroupPair; -/* #[derive(Clone)] -pub struct Texture { - texture_id: u32, - pub img: image::DynamicImage, -} - -impl Texture { - pub fn from_bytes(bytes: &[u8]) -> anyhow::Result { - let img = image::load_from_memory(bytes)?; - - Ok(Self { - texture_id: 0, - img, - }) - } -} */ - - - #[allow(dead_code)] pub struct RenderTexture { pub inner_texture: wgpu::Texture, @@ -153,8 +134,12 @@ impl RenderTexture { }) } - pub fn update_texture(&mut self, _device: &wgpu::Device, queue: &wgpu::Queue, texture: &Arc>) { - let texture = &texture.data_ref().image; + /// Updates the texture on the gpu with the provided texture. + /// + /// # Panics + /// Panics if `texture` is not loaded + pub fn update_texture(&mut self, _device: &wgpu::Device, queue: &wgpu::Queue, texture: &ResHandle) { + let texture = &texture.data_ref().unwrap().image; let rgba = texture.to_rgba8(); let dimensions = texture.dimensions(); let size = wgpu::Extent3d { diff --git a/lyra-game/src/scene/mesh.rs b/lyra-game/src/scene/mesh.rs index 7de1ef5..f7c7255 100755 --- a/lyra-game/src/scene/mesh.rs +++ b/lyra-game/src/scene/mesh.rs @@ -1,15 +1,37 @@ use lyra_ecs::Component; -use lyra_resource::Mesh; +use lyra_reflect::Reflect; +use lyra_resource::{gltf::Mesh, ResHandle}; -#[derive(Clone, Component)] +#[derive(Clone, Component, Reflect)] pub struct MeshComponent { - pub mesh: Mesh, + #[reflect(skip)] + pub mesh: ResHandle, +} + +impl From> for MeshComponent { + fn from(value: ResHandle) -> Self { + Self { + mesh: value + } + } +} + +impl std::ops::Deref for MeshComponent { + type Target = ResHandle; + + fn deref(&self) -> &Self::Target { + &self.mesh + } +} + +impl std::ops::DerefMut for MeshComponent { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.mesh + } } impl MeshComponent { - pub fn new(mesh: Mesh) -> Self { - Self { - mesh, - } + pub fn new(mesh: ResHandle) -> Self { + Self::from(mesh) } } \ No newline at end of file diff --git a/lyra-game/src/scene/mod.rs b/lyra-game/src/scene/mod.rs index 47898a1..090ad66 100644 --- a/lyra-game/src/scene/mod.rs +++ b/lyra-game/src/scene/mod.rs @@ -1,9 +1,6 @@ pub mod mesh; pub use mesh::*; -pub mod model; -pub use model::*; - pub mod camera; pub use camera::*; diff --git a/lyra-game/src/scene/model.rs b/lyra-game/src/scene/model.rs deleted file mode 100644 index 2c5a6b3..0000000 --- a/lyra-game/src/scene/model.rs +++ /dev/null @@ -1,41 +0,0 @@ -use lyra_ecs::Component; -use lyra_reflect::Reflect; -use lyra_resource::ResHandle; - -use crate::assets::Model; - -#[derive(Clone, Component, Reflect)] -pub struct ModelComponent(#[reflect(skip)] pub ResHandle); - -impl From> for ModelComponent { - fn from(value: ResHandle) -> Self { - ModelComponent(value) - } -} - -/* impl From for ModelComponent { - -} */ - -impl std::ops::Deref for ModelComponent { - type Target = ResHandle; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl std::ops::DerefMut for ModelComponent { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.0 - } -} - -/* impl ModelComponent { - pub fn new(model, material: Material) -> Self { - Self { - mesh, - material - } - } -} */ \ No newline at end of file