From f13405e5d210a0e2f30bc81364c994b8816789d7 Mon Sep 17 00:00:00 2001 From: Ryan Butler Date: Mon, 27 Nov 2023 19:19:41 -0500 Subject: [PATCH] Social VR demo scaffold (#7) --- .gitattributes | 1 + Cargo.lock | 379 +++++++++++++++++++++++++++- Cargo.toml | 13 +- apps/rvid/client/src/lib.rs | 10 +- apps/social/README.md | 45 ++++ apps/social/client/Cargo.toml | 18 ++ apps/social/client/src/dev_tools.rs | 82 ++++++ apps/social/client/src/humanoid.rs | 40 +++ apps/social/client/src/lib.rs | 128 ++++++++++ apps/social/client/src/main.rs | 3 + apps/social/manifest.yaml | 36 +++ apps/social/server/Cargo.toml | 10 + apps/social/server/src/main.rs | 1 + assets/malek.gltf | 3 + 14 files changed, 761 insertions(+), 8 deletions(-) create mode 100644 apps/social/README.md create mode 100644 apps/social/client/Cargo.toml create mode 100644 apps/social/client/src/dev_tools.rs create mode 100644 apps/social/client/src/humanoid.rs create mode 100644 apps/social/client/src/lib.rs create mode 100644 apps/social/client/src/main.rs create mode 100644 apps/social/manifest.yaml create mode 100644 apps/social/server/Cargo.toml create mode 100644 apps/social/server/src/main.rs create mode 100644 assets/malek.gltf diff --git a/.gitattributes b/.gitattributes index 0ce959a..c05bc27 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,2 +1,3 @@ *.gltf filter=lfs diff=lfs merge=lfs -text +*.glb filter=lfs diff=lfs merge=lfs -text *.png filter=lfs diff=lfs merge=lfs -text diff --git a/Cargo.lock b/Cargo.lock index a45ad0a..1561814 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -202,6 +202,25 @@ dependencies = [ "num-traits", ] +[[package]] +name = "arboard" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aafb29b107435aa276664c1db8954ac27a6e105cdad3c88287a199eb0e313c08" +dependencies = [ + "clipboard-win", + "core-graphics", + "image", + "log", + "objc", + "objc-foundation", + "objc_id", + "parking_lot", + "thiserror", + "winapi", + "x11rb", +] + [[package]] name = "arrayref" version = "0.3.7" @@ -357,6 +376,45 @@ dependencies = [ "bevy_internal", ] +[[package]] +name = "bevy-inspector-egui" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d65b98d6fca1209c36c4d403c377f303aad22d940281fe1a9e431217516f0622" +dependencies = [ + "bevy-inspector-egui-derive", + "bevy_app", + "bevy_asset", + "bevy_core", + "bevy_core_pipeline", + "bevy_ecs", + "bevy_egui", + "bevy_hierarchy", + "bevy_log", + "bevy_math", + "bevy_pbr", + "bevy_reflect", + "bevy_render", + "bevy_utils", + "bevy_window", + "egui", + "image", + "once_cell", + "pretty-type-name", + "smallvec", +] + +[[package]] +name = "bevy-inspector-egui-derive" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec800b7cf98151b5dbff80f0eb6dffcb4bcfceef6e457888b395ead4eb7e75ba" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", +] + [[package]] name = "bevy_a11y" version = "0.12.0" @@ -562,6 +620,19 @@ dependencies = [ "syn 2.0.39", ] +[[package]] +name = "bevy_egui" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85450af551b7e1cb766f710763b60a12a82ffd6323945a8f776c6334c59ccdc1" +dependencies = [ + "arboard", + "bevy", + "egui", + "thread_local", + "webbrowser", +] + [[package]] name = "bevy_encase_derive" version = "0.12.0" @@ -754,11 +825,19 @@ dependencies = [ "glam", ] +[[package]] +name = "bevy_mod_inverse_kinematics" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed76d18aa51b0df6dd39c6cda2cf87c1ebbb0e033272edb7dd22285a9b90fb02" +dependencies = [ + "bevy", +] + [[package]] name = "bevy_oxr" version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5498a8ca77f31b4c09c9c7ce066c746365b33d22fbd5d243f388118c11e01c67" +source = "git+https://github.com/awtterpip/bevy_oxr?rev=1cf8663#1cf866324b25ef67ac4db68acfb011171e2a869e" dependencies = [ "anyhow", "ash", @@ -1351,6 +1430,17 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" +[[package]] +name = "clipboard-win" +version = "4.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7191c27c2357d9b7ef96baac1773290d4ca63b24205b82a3fd8a0637afcf0362" +dependencies = [ + "error-code", + "str-buf", + "winapi", +] + [[package]] name = "cmake" version = "0.1.50" @@ -1625,7 +1715,7 @@ dependencies = [ "autocfg", "cfg-if", "crossbeam-utils", - "memoffset", + "memoffset 0.9.0", "scopeguard", ] @@ -1687,12 +1777,41 @@ dependencies = [ "winrt", ] +[[package]] +name = "ecolor" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfdf4e52dbbb615cfd30cf5a5265335c217b5fd8d669593cea74a517d9c605af" +dependencies = [ + "bytemuck", +] + +[[package]] +name = "egui" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8bd69fed5fcf4fbb8225b24e80ea6193b61e17a625db105ef0c4d71dde6eb8b7" +dependencies = [ + "ahash", + "epaint", + "nohash-hasher", +] + [[package]] name = "either" version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" +[[package]] +name = "emath" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ef2b29de53074e575c18b694167ccbe6e5191f7b25fe65175a0d905a32eeec0" +dependencies = [ + "bytemuck", +] + [[package]] name = "encase" version = "0.6.1" @@ -1725,6 +1844,21 @@ dependencies = [ "syn 2.0.39", ] +[[package]] +name = "epaint" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58067b840d009143934d91d8dcb8ded054d8301d7c11a517ace0a99bb1e1595e" +dependencies = [ + "ab_glyph", + "ahash", + "bytemuck", + "ecolor", + "emath", + "nohash-hasher", + "parking_lot", +] + [[package]] name = "equivalent" version = "1.0.1" @@ -1750,6 +1884,16 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "error-code" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64f18991e7bf11e7ffee451b5318b5c1a73c52d0d0ada6e5a3017c8c1ced6a21" +dependencies = [ + "libc", + "str-buf", +] + [[package]] name = "euclid" version = "0.22.9" @@ -1884,6 +2028,15 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b" +[[package]] +name = "form_urlencoded" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +dependencies = [ + "percent-encoding", +] + [[package]] name = "futures-core" version = "0.3.29" @@ -1925,6 +2078,16 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "gethostname" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb65d4ba3173c56a500b555b532f72c42e8d1fe64962b518897f8959fae2c177" +dependencies = [ + "libc", + "winapi", +] + [[package]] name = "getrandom" version = "0.2.11" @@ -2180,6 +2343,25 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df" +[[package]] +name = "home" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5444c27eef6923071f7ebcc33e3444508466a76f7a2b93da00ed6e19f30c1ddb" +dependencies = [ + "windows-sys 0.48.0", +] + +[[package]] +name = "idna" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + [[package]] name = "image" version = "0.24.7" @@ -2192,6 +2374,7 @@ dependencies = [ "num-rational", "num-traits", "png", + "tiff", ] [[package]] @@ -2322,6 +2505,22 @@ dependencies = [ "walkdir", ] +[[package]] +name = "jni" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97" +dependencies = [ + "cesu8", + "cfg-if", + "combine", + "jni-sys", + "log", + "thiserror", + "walkdir", + "windows-sys 0.45.0", +] + [[package]] name = "jni-sys" version = "0.3.0" @@ -2337,6 +2536,12 @@ dependencies = [ "libc", ] +[[package]] +name = "jpeg-decoder" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc0000e42512c92e31c2252315bda326620a4e034105e900c98ec492fa077b3e" + [[package]] name = "js-sys" version = "0.3.65" @@ -2491,6 +2696,15 @@ version = "2.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" +[[package]] +name = "memoffset" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4" +dependencies = [ + "autocfg", +] + [[package]] name = "memoffset" version = "0.9.0" @@ -2634,6 +2848,18 @@ dependencies = [ "libc", ] +[[package]] +name = "nix" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b" +dependencies = [ + "bitflags 1.3.2", + "cfg-if", + "libc", + "memoffset 0.7.1", +] + [[package]] name = "nix" version = "0.27.1" @@ -2645,6 +2871,12 @@ dependencies = [ "libc", ] +[[package]] +name = "nohash-hasher" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451" + [[package]] name = "nom" version = "7.1.3" @@ -2773,6 +3005,17 @@ dependencies = [ "objc_exception", ] +[[package]] +name = "objc-foundation" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1add1b659e36c9607c7aab864a76c7a4c2760cd0cd2e120f3fb8b952c7e22bf9" +dependencies = [ + "block", + "objc", + "objc_id", +] + [[package]] name = "objc-sys" version = "0.2.0-beta.2" @@ -2808,6 +3051,15 @@ dependencies = [ "cc", ] +[[package]] +name = "objc_id" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c92d4ddb4bd7b50d730c215ff871754d0da6b2178849f8a2a2ab69712d0c073b" +dependencies = [ + "objc", +] + [[package]] name = "object" version = "0.32.1" @@ -3070,6 +3322,12 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +[[package]] +name = "pretty-type-name" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f73cdaf19b52e6143685c3606206e114a4dfa969d6b14ec3894c88eb38bd4b" + [[package]] name = "proc-macro-crate" version = "1.3.1" @@ -3448,6 +3706,24 @@ dependencies = [ "serde", ] +[[package]] +name = "social-client" +version = "0.0.0" +dependencies = [ + "bevy", + "bevy-inspector-egui", + "bevy_egui", + "bevy_mod_inverse_kinematics", + "bevy_oxr", + "color-eyre", + "egui", + "openxr 0.17.1 (git+https://github.com/Ralith/openxrs?rev=361b27e)", +] + +[[package]] +name = "social-server" +version = "0.0.0" + [[package]] name = "spirv" version = "0.2.0+1.5.4" @@ -3464,6 +3740,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" +[[package]] +name = "str-buf" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e08d8363704e6c71fc928674353e6b7c23dcea9d82d7012c8faf2a3a025f8d0" + [[package]] name = "svg_fmt" version = "0.4.1" @@ -3577,6 +3859,17 @@ dependencies = [ "once_cell", ] +[[package]] +name = "tiff" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d172b0f4d3fba17ba89811858b9d3d97f928aece846475bbda076ca46736211" +dependencies = [ + "flate2", + "jpeg-decoder", + "weezl", +] + [[package]] name = "tinytemplate" version = "1.2.1" @@ -3739,12 +4032,27 @@ dependencies = [ "static_assertions", ] +[[package]] +name = "unicode-bidi" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" + [[package]] name = "unicode-ident" version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +[[package]] +name = "unicode-normalization" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +dependencies = [ + "tinyvec", +] + [[package]] name = "unicode-width" version = "0.1.11" @@ -3767,6 +4075,17 @@ dependencies = [ "rand", ] +[[package]] +name = "url" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "143b538f18257fac9cad154828a57c6bf5157e1aa604d4816b5995bf6de87ae5" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + [[package]] name = "uuid" version = "0.8.2" @@ -3913,6 +4232,29 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "webbrowser" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82b2391658b02c27719fc5a0a73d6e696285138e8b12fba9d4baa70451023c71" +dependencies = [ + "core-foundation", + "home", + "jni 0.21.1", + "log", + "ndk-context", + "objc", + "raw-window-handle", + "url", + "web-sys", +] + +[[package]] +name = "weezl" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9193164d4de03a926d909d3bc7c30543cecb35400c02114792c2cae20d5e2dbb" + [[package]] name = "wgpu" version = "0.17.2" @@ -4043,6 +4385,15 @@ dependencies = [ "winapi", ] +[[package]] +name = "winapi-wsapoll" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44c17110f57155602a80dca10be03852116403c9ff3cd25b079d666f2aa3df6e" +dependencies = [ + "winapi", +] + [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" @@ -4391,6 +4742,28 @@ dependencies = [ "pkg-config", ] +[[package]] +name = "x11rb" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1641b26d4dec61337c35a1b1aaf9e3cba8f46f0b43636c609ab0291a648040a" +dependencies = [ + "gethostname", + "nix 0.26.4", + "winapi", + "winapi-wsapoll", + "x11rb-protocol", +] + +[[package]] +name = "x11rb-protocol" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82d6c3f9a0fb6701fab8f6cea9b0c0bd5d6876f1f89f7fada07e558077c344bc" +dependencies = [ + "nix 0.26.4", +] + [[package]] name = "xi-unicode" version = "0.3.0" diff --git a/Cargo.toml b/Cargo.toml index 5de105d..5e46466 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,10 +3,13 @@ resolver = "2" members = [ "apps/rvid/client", "apps/rvid/server", + "apps/social/client", + "apps/social/server", "crates/nexus-voicechat", "crates/universal-capture", ] + # These settings will apply to all members of the workspace that opt in to them [workspace.package] version = "0.0.0" @@ -17,12 +20,20 @@ rust-version = "1.74.0" [workspace.dependencies] bevy = "0.12" -bevy_oxr = "0.1.0" +bevy_oxr = { git = "https://github.com/awtterpip/bevy_oxr", rev = "1cf8663" } color-eyre = "0.6" eyre = "0.6" # Adds `links` support openxr = { git = "https://github.com/Ralith/openxrs", rev = "361b27e" } +bevy_mod_inverse_kinematics = "0.5" +bevy_egui = "0.23" +egui = "0.23" +bevy-inspector-egui = "0.21.0" [profile.dev] # Enable a small amount of optimization in debug mode opt-level = 1 + +# Enable high optimizations for dependencies, but not for our code: +[profile.dev.package."*"] +opt-level = 2 diff --git a/apps/rvid/client/src/lib.rs b/apps/rvid/client/src/lib.rs index 471d5d1..f53b016 100644 --- a/apps/rvid/client/src/lib.rs +++ b/apps/rvid/client/src/lib.rs @@ -65,13 +65,15 @@ fn hands( ) { let mut func = || -> color_eyre::Result<()> { let frame_state = *frame_state.lock().unwrap(); - - let right_controller = oculus_controller + let grip_space = oculus_controller .grip_space + .as_ref() + .expect("missing grip space on controller"); + + let right_controller = grip_space .right .relate(&xr_input.stage, frame_state.predicted_display_time)?; - let left_controller = oculus_controller - .grip_space + let left_controller = grip_space .left .relate(&xr_input.stage, frame_state.predicted_display_time)?; gizmos.rect( diff --git a/apps/social/README.md b/apps/social/README.md new file mode 100644 index 0000000..69b33b4 --- /dev/null +++ b/apps/social/README.md @@ -0,0 +1,45 @@ +# Nexus Social Demo + +Demos an MVP (Minimal Viable Product) for a social VR experience using the bevy +game engine. + +Current goals for MVP: +- All code in Rust, with bevy game engine for client. +- Basic networking, data can be marked as synchronized. Clients have authority. + Rollback systems are not necessary. +- Realtime Voice. +- Self-hostable server. +- Mirrors. +- Dynamically loading gltf avatar from URL +- Basic IK support +- Windows PCVR & Desktop, Linux PCVR & Desktop, MacOS Desktop, Standalone Quest. + +Future Goals: +- FBT is not supported yet, but we should write the code with an exepectation that we + will add support. +- Web is initially unsupported, due to potential incompatibility with networking. + long term, we want to support web, at least in desktop mode. + +## Project Status + +This is an ambitious project, please consider it to be vaporware until proven otherwise. + +## How to run + +We don't have binaries published yet. For now, build the code. +Run the [server](server/) on a computer accessbile over the network. Then run +[client](client/) either standalone on your quest or natively on your computer. + +## How to Build + +Be sure that you have already followed the first time setup instructions from the [toplevel README](../../README.md). + +### Building for Quest Standalone + +Plug in headset to PC, allow usb debugging, and then: +```sh +adb connect # Optional, allows wireless debugging +x devices # ensure your device is listed +x run --device -p openxr-6dof --release +``` + diff --git a/apps/social/client/Cargo.toml b/apps/social/client/Cargo.toml new file mode 100644 index 0000000..8e4b251 --- /dev/null +++ b/apps/social/client/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "social-client" +version.workspace = true +license.workspace = true +repository.workspace = true +edition.workspace = true +rust-version.workspace = true +description = "A social vr demo in bevy" + +[dependencies] +bevy.workspace = true +bevy_oxr.workspace = true +color-eyre.workspace = true +openxr.workspace = true +bevy_mod_inverse_kinematics.workspace = true +egui.workspace = true +bevy_egui.workspace = true +bevy-inspector-egui.workspace = true diff --git a/apps/social/client/src/dev_tools.rs b/apps/social/client/src/dev_tools.rs new file mode 100644 index 0000000..4ee01b8 --- /dev/null +++ b/apps/social/client/src/dev_tools.rs @@ -0,0 +1,82 @@ +//! Plugins related to developer tooling. + +use bevy::{ + app::PluginGroupBuilder, + diagnostic::{FrameTimeDiagnosticsPlugin, LogDiagnosticsPlugin}, + prelude::{App, Local, Plugin, PluginGroup, PostUpdate, With, World}, + window::PrimaryWindow, +}; +use bevy_egui::EguiContext; +use bevy_inspector_egui::{ + bevy_inspector::hierarchy::SelectedEntities, DefaultInspectorConfigPlugin, +}; + +#[derive(Default)] +pub struct DevToolsPlugins; + +impl PluginGroup for DevToolsPlugins { + fn build(self) -> PluginGroupBuilder { + PluginGroupBuilder::start::() + .add(DefaultInspectorConfigPlugin) + .add(bevy_egui::EguiPlugin) + .add(InspectorUiPlugin) + .add(LogDiagnosticsPlugin::default()) + .add(FrameTimeDiagnosticsPlugin) + } +} + +#[derive(Default)] +pub struct InspectorUiPlugin; + +impl Plugin for InspectorUiPlugin { + fn build(&self, app: &mut App) { + app.add_systems(PostUpdate, inspector_ui); + } +} + +fn inspector_ui(world: &mut World, mut selected_entities: Local) { + let mut egui_context = world + .query_filtered::<&mut EguiContext, With>() + .single(world) + .clone(); + + egui::SidePanel::left("hierarchy") + .default_width(200.0) + .show(egui_context.get_mut(), |ui| { + egui::ScrollArea::vertical().show(ui, |ui| { + ui.heading("Hierarchy"); + + bevy_inspector_egui::bevy_inspector::hierarchy::hierarchy_ui( + world, + ui, + &mut selected_entities, + ); + + ui.label("Press escape to toggle UI"); + ui.allocate_space(ui.available_size()); + }); + }); + + egui::SidePanel::right("inspector") + .default_width(250.0) + .show(egui_context.get_mut(), |ui| { + egui::ScrollArea::vertical().show(ui, |ui| { + ui.heading("Inspector"); + + match selected_entities.as_slice() { + &[entity] => { + bevy_inspector_egui::bevy_inspector::ui_for_entity( + world, entity, ui, + ); + } + entities => { + bevy_inspector_egui::bevy_inspector::ui_for_entities_shared_components( + world, entities, ui, + ); + } + } + + ui.allocate_space(ui.available_size()); + }); + }); +} diff --git a/apps/social/client/src/humanoid.rs b/apps/social/client/src/humanoid.rs new file mode 100644 index 0000000..bc37df8 --- /dev/null +++ b/apps/social/client/src/humanoid.rs @@ -0,0 +1,40 @@ +use bevy::prelude::{Component, Entity, Event, EventReader, Plugin, Update}; + +#[derive(Default)] +pub struct HumanoidPlugin; + +impl Plugin for HumanoidPlugin { + fn build(&self, app: &mut bevy::prelude::App) { + app.add_event::() + .add_systems(Update, auto_rig_assignment); + // + } +} + +#[derive(Component)] +pub struct Viewpoint {} + +#[derive(Component)] +pub struct HumanoidRig { + pub entities: Data, +} + +pub struct Data { + pub head: T, + pub hand_l: T, + pub hand_r: T, + // TODO: Specify rest of skeleton +} + +/// When fired, runs [`auto_rig_assignment`] +#[derive(Event)] +pub struct AutoAssignRigEvent { + pub mesh: Entity, +} + +/// Attempts to automatically assign the rig to the mesh in [`AutoAssignRigEvent`]. +pub fn auto_rig_assignment(mut evts: EventReader) { + for _evt in evts.read() { + // TODO + } +} diff --git a/apps/social/client/src/lib.rs b/apps/social/client/src/lib.rs new file mode 100644 index 0000000..0702f3e --- /dev/null +++ b/apps/social/client/src/lib.rs @@ -0,0 +1,128 @@ +use bevy::prelude::*; +use bevy::transform::components::Transform; +use bevy_mod_inverse_kinematics::InverseKinematicsPlugin; +use bevy_oxr::input::XrInput; +use bevy_oxr::resources::XrFrameState; +use bevy_oxr::xr_input::oculus_touch::OculusController; +use bevy_oxr::xr_input::{QuatConv, Vec3Conv}; +use bevy_oxr::DefaultXrPlugins; +use color_eyre::Result; + +use crate::dev_tools::DevToolsPlugins; + +mod dev_tools; +mod humanoid; + +const ASSET_FOLDER: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/../../../assets/"); + +#[bevy_main] +pub fn main() { + color_eyre::install().unwrap(); + + info!("Running `social-client`"); + App::new() + .add_plugins(DefaultXrPlugins.set(AssetPlugin { + file_path: ASSET_FOLDER.to_string(), + ..Default::default() + })) + .add_plugins(InverseKinematicsPlugin) + .add_plugins(DevToolsPlugins) + .add_systems(Startup, setup) + .add_systems(Update, hands.map(ignore_on_err)) + .run(); +} + +pub fn ignore_on_err(_result: Result<()>) {} + +pub fn panic_on_err(result: Result<()>) { + if let Err(err) = result { + panic!("{err}"); + } +} + +pub fn log_on_err(result: Result<()>) { + if let Err(err) = result { + error!("{err}"); + } +} + +/// set up a simple 3D scene +fn setup( + mut commands: Commands, + mut meshes: ResMut>, + mut materials: ResMut>, + assets: Res, +) { + // plane + commands.spawn(PbrBundle { + mesh: meshes.add(shape::Plane::from_size(5.0).into()), + material: materials.add(Color::rgb(0.3, 0.5, 0.3).into()), + ..default() + }); + // cube + commands.spawn(PbrBundle { + mesh: meshes.add(Mesh::from(shape::Cube { size: 0.1 })), + material: materials.add(Color::rgb(0.8, 0.7, 0.6).into()), + transform: Transform::from_xyz(0.0, 0.5, 0.0), + ..default() + }); + // light + commands.spawn(PointLightBundle { + point_light: PointLight { + intensity: 1500.0, + shadows_enabled: true, + ..default() + }, + transform: Transform::from_xyz(4.0, 8.0, 4.0), + ..default() + }); + // camera + commands.spawn((Camera3dBundle { + transform: Transform::from_xyz(-2.0, 2.5, 5.0).looking_at(Vec3::ZERO, Vec3::Y), + ..default() + },)); + // Avatar + commands.spawn(SceneBundle { + scene: assets.load("malek.gltf#Scene0"), + transform: Transform::from_xyz(0.0, 0.0, 0.0).with_rotation(Quat::from_euler( + EulerRot::XYZ, + 0.0, + 180.0_f32.to_radians(), + 0.0, + )), + ..default() + }); +} + +fn hands( + mut gizmos: Gizmos, + oculus_controller: Res, + frame_state: Res, + xr_input: Res, +) -> Result<()> { + let frame_state = *frame_state.lock().unwrap(); + let grip_space = oculus_controller + .grip_space + .as_ref() + .expect("missing grip space on controller"); + + let right_controller = grip_space + .right + .relate(&xr_input.stage, frame_state.predicted_display_time)?; + let left_controller = grip_space + .left + .relate(&xr_input.stage, frame_state.predicted_display_time)?; + gizmos.rect( + right_controller.0.pose.position.to_vec3(), + right_controller.0.pose.orientation.to_quat(), + Vec2::new(0.05, 0.2), + Color::YELLOW_GREEN, + ); + gizmos.rect( + left_controller.0.pose.position.to_vec3(), + left_controller.0.pose.orientation.to_quat(), + Vec2::new(0.05, 0.2), + Color::YELLOW_GREEN, + ); + Ok(()) +} diff --git a/apps/social/client/src/main.rs b/apps/social/client/src/main.rs new file mode 100644 index 0000000..52e2a1c --- /dev/null +++ b/apps/social/client/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + social_client::main() +} diff --git a/apps/social/manifest.yaml b/apps/social/manifest.yaml new file mode 100644 index 0000000..83ae980 --- /dev/null +++ b/apps/social/manifest.yaml @@ -0,0 +1,36 @@ +android: + runtime_libs: + - "../../../assets/runtime_libs" + manifest: + package: "com.github.nexussocial.social-demo.client" + uses_feature: + - name: "android.hardware.vr.headtracking" + required: true + - name: "oculus.software.handtracking" + required: false + - name: "com.oculus.experimental.enabled" + required: false + uses_permission: + - name: "com.oculus.permission.HAND_TRACKING" + application: + label: "Nexus Social VR Demo Client" + theme: "@android:style/Theme.DeviceDefault.NoActionBar.Fullscreen" + meta_data: + - name: "com.oculus.intent.category.VR" + value: "vr_only" + - name: "com.samsung.android.vr.application.mode" + value: "vr_only" + - name: "com.oculus.supportedDevices" + value: "quest|quest2|quest3" + activities: + - config_changes: "density|keyboard|keyboardHidden|navigation|orientation|screenLayout|screenSize|uiMode" + launch_mode: "singleTask" + orientation: "landscape" + intent_filters: + - actions: + - "android.intent.action.MAIN" + categories: + - "com.oculus.intent.category.VR" + - "android.intent.category.LAUNCHER" + sdk: + target_sdk_version: 32 diff --git a/apps/social/server/Cargo.toml b/apps/social/server/Cargo.toml new file mode 100644 index 0000000..f4a3296 --- /dev/null +++ b/apps/social/server/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "social-server" +version.workspace = true +license.workspace = true +repository.workspace = true +edition.workspace = true +rust-version.workspace = true +description = "A server for the social vr bevy demo" + +[dependencies] diff --git a/apps/social/server/src/main.rs b/apps/social/server/src/main.rs new file mode 100644 index 0000000..f328e4d --- /dev/null +++ b/apps/social/server/src/main.rs @@ -0,0 +1 @@ +fn main() {} diff --git a/assets/malek.gltf b/assets/malek.gltf new file mode 100644 index 0000000..8414815 --- /dev/null +++ b/assets/malek.gltf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:befac83c28386ffd90b8fe01926af35d950238b246550df567c5372a287c6d0d +size 17852288