Merge pull request #18 from alexichepura/quest

Android, Meta Quest support
This commit is contained in:
ForTehLose
2023-10-18 13:22:48 -04:00
committed by GitHub
7 changed files with 219 additions and 0 deletions

3
examples/android/.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
/target
/Cargo.lock
/runtime_libs

View File

@@ -0,0 +1,67 @@
[package]
name = "bevy_openxr_android"
version = "0.1.0"
edition = "2021"
description = "Example for building an Android OpenXR app with Bevy"
publish = false
license = "MIT OR Apache-2.0"
[lib]
name = "bevy_openxr_android"
crate-type = ["staticlib", "cdylib"]
[package.metadata.android]
package = "org.bevyengine.example_openxr_android"
build_targets = ["aarch64-linux-android"]
runtime_libs = "runtime_libs"
apk_name = "bevyopenxr"
# assets = "assets"
# res = "assets/android-res"
icon = "@mipmap/ic_launcher"
label = "Bevy Openxr Android"
strip = "strip"
[package.metadata.android.sdk]
target_sdk_version = 32
# [package.metadata.android.application]
# icon = "@mipmap/ic_launcher"
# label = "Bevy Example"
[dependencies]
bevy_openxr = { path = "../..", default-features = false }
bevy = { git = "https://github.com/bevyengine/bevy.git" }
openxr = { git = "https://github.com/Ralith/openxrs", features = ["mint"] }
[profile.release]
lto = "fat"
codegen-units = 1
panic = "abort"
[package.metadata.android.application.activity]
theme = "@android:style/Theme.Black.NoTitleBar.Fullscreen"
config_changes = "density|keyboard|keyboardHidden|navigation|orientation|screenLayout|screenSize|uiMode"
launch_mode = "singleTask"
orientation = "landscape"
resizeable_activity = false
[[package.metadata.android.application.activity.intent_filter]]
actions = ["android.intent.action.MAIN"]
categories = [
"com.oculus.intent.category.VR",
"android.intent.category.LAUNCHER",
]
# !! IMPORTANT !!
#
# When creating your own apps, make sure to generate your own keystore, rather than using our example one!
# You can use `keytool` like so:
# keytool -genkey -v -keystore my-release-key.keystore -keyalg RSA -keysize 2048 -validity 10000
#
# For more information on key signing and why it's so important, check out this article:
# https://developer.android.com/studio/publish/app-signing
#
# !! IMPORTANT !!
[package.metadata.android.signing.release]
path = "./hotham_examples.keystore"
keystore_password = "chomsky-vigilant-spa"

View File

@@ -0,0 +1,46 @@
# Bevy OpenXR Android example
## Setup
Get libopenxr_loader.so from the Oculus OpenXR Mobile SDK and add it to `examples/android/runtime_libs/arm64-v8a`
https://developer.oculus.com/downloads/package/oculus-openxr-mobile-sdk/
`examples/android/runtime_libs/arm64-v8a/libopenxr_loader.so`
Running on Meta Quest can be done with https://github.com/rust-mobile/cargo-apk.
```sh
cargo apk run --release
```
## Notes
### Relase mode
More optimisations enabled in Cargo.toml for the release mode.
This gives more performance but longer build time.
```toml
[profile.release]
lto = "fat"
codegen-units = 1
panic = "abort"
```
### Cargo apk
If you see error like `Error: String `` is not a PID`, try to install cargo apk with a fix in branch.
```sh
cargo install --git https://github.com/rust-mobile/cargo-apk --branch=adb-logcat-uid
```
### Temporary JNIEnv log
This message is logged every frame. It's not yet fixed.
```sh
I JniUtils-inl: Creating temporary JNIEnv. This is a heavy operation and should be infrequent. To optimize, use JNI AttachCurrentThread on calling threa
```
### Android keystore
Release mode requires keystore. See Cargo.toml `package.metadata.android.signing.release`.
When creating your own apps, make sure to generate your own keystore, rather than using our example one!
You can use `keytool` like so:
```sh
keytool -genkey -v -keystore my-release-key.keystore -keyalg RSA -keysize 2048 -validity 10000
```
For more information on key signing and why it's so important, check out this article:
https://developer.android.com/studio/publish/app-signing

Binary file not shown.

View File

@@ -0,0 +1,83 @@
use bevy::diagnostic::{FrameTimeDiagnosticsPlugin, LogDiagnosticsPlugin};
use bevy::prelude::*;
use bevy::transform::components::Transform;
use bevy_openxr::xr_input::debug_gizmos::OpenXrDebugRenderer;
use bevy_openxr::xr_input::prototype_locomotion::{proto_locomotion, PrototypeLocomotionConfig};
use bevy_openxr::xr_input::trackers::{
OpenXRController, OpenXRLeftController, OpenXRRightController, OpenXRTracker,
};
use bevy_openxr::DefaultXrPlugins;
#[bevy_main]
fn main() {
App::new()
.add_plugins(DefaultXrPlugins)
.add_plugins(OpenXrDebugRenderer)
.add_plugins(LogDiagnosticsPlugin::default())
.add_plugins(FrameTimeDiagnosticsPlugin)
.add_systems(Startup, setup)
.add_systems(Update, proto_locomotion)
.add_systems(Startup, spawn_controllers_example)
.insert_resource(PrototypeLocomotionConfig::default())
.run();
}
/// set up a simple 3D scene
fn setup(
mut commands: Commands,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<StandardMaterial>>,
) {
// 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()
});
// cube
commands.spawn(PbrBundle {
mesh: meshes.add(Mesh::from(shape::Cube { size: 0.1 })),
material: materials.add(Color::rgb(0.8, 0.0, 0.0).into()),
transform: Transform::from_xyz(0.0, 0.5, 1.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()
// },));
}
fn spawn_controllers_example(mut commands: Commands) {
//left hand
commands.spawn((
OpenXRLeftController,
OpenXRController,
OpenXRTracker,
SpatialBundle::default(),
));
//right hand
commands.spawn((
OpenXRRightController,
OpenXRController,
OpenXRTracker,
SpatialBundle::default(),
));
}

View File

@@ -42,6 +42,9 @@ pub fn initialize_xr_graphics(
let xr_entry = super::xr_entry(); let xr_entry = super::xr_entry();
#[cfg(target_os = "android")]
xr_entry.initialize_android_loader().unwrap();
let available_extensions = xr_entry.enumerate_extensions()?; let available_extensions = xr_entry.enumerate_extensions()?;
assert!(available_extensions.khr_vulkan_enable2); assert!(available_extensions.khr_vulkan_enable2);
info!("available xr exts: {:#?}", available_extensions); info!("available xr exts: {:#?}", available_extensions);
@@ -82,8 +85,16 @@ pub fn initialize_xr_graphics(
let blend_mode = xr_instance.enumerate_environment_blend_modes(xr_system_id, VIEW_TYPE)?[0]; let blend_mode = xr_instance.enumerate_environment_blend_modes(xr_system_id, VIEW_TYPE)?[0];
#[cfg(not(target_os = "android"))]
let vk_target_version = vk::make_api_version(0, 1, 2, 0); let vk_target_version = vk::make_api_version(0, 1, 2, 0);
#[cfg(not(target_os = "android"))]
let vk_target_version_xr = xr::Version::new(1, 2, 0); let vk_target_version_xr = xr::Version::new(1, 2, 0);
#[cfg(target_os = "android")]
let vk_target_version = vk::make_api_version(0, 1, 1, 0);
#[cfg(target_os = "android")]
let vk_target_version_xr = xr::Version::new(1, 1, 0);
let reqs = xr_instance.graphics_requirements::<xr::Vulkan>(xr_system_id)?; let reqs = xr_instance.graphics_requirements::<xr::Vulkan>(xr_system_id)?;
if vk_target_version_xr < reqs.min_api_version_supported if vk_target_version_xr < reqs.min_api_version_supported
|| vk_target_version_xr.major() > reqs.max_api_version_supported.major() || vk_target_version_xr.major() > reqs.max_api_version_supported.major()
@@ -102,6 +113,8 @@ pub fn initialize_xr_graphics(
let device_extensions = vec![ let device_extensions = vec![
ash::extensions::khr::Swapchain::name(), ash::extensions::khr::Swapchain::name(),
ash::extensions::khr::DrawIndirectCount::name(), ash::extensions::khr::DrawIndirectCount::name(),
#[cfg(target_os = "android")]
ash::extensions::khr::TimelineSemaphore::name(),
]; ];
info!( info!(
"creating vulkan instance with these extensions: {:#?}", "creating vulkan instance with these extensions: {:#?}",

View File

@@ -201,10 +201,17 @@ impl PluginGroup for DefaultXrPlugins {
.add_before::<RenderPlugin, _>(OpenXrPlugin) .add_before::<RenderPlugin, _>(OpenXrPlugin)
.add_after::<OpenXrPlugin, _>(OpenXrInput::new(XrControllerType::OculusTouch)) .add_after::<OpenXrPlugin, _>(OpenXrInput::new(XrControllerType::OculusTouch))
.set(WindowPlugin { .set(WindowPlugin {
#[cfg(not(target_os = "android"))]
primary_window: Some(Window { primary_window: Some(Window {
present_mode: PresentMode::AutoNoVsync, present_mode: PresentMode::AutoNoVsync,
..default() ..default()
}), }),
#[cfg(target_os = "android")]
primary_window: None,
#[cfg(target_os = "android")]
exit_condition: bevy::window::ExitCondition::DontExit,
#[cfg(target_os = "android")]
close_when_requested: true,
..default() ..default()
}) })
} }