Merge pull request #18 from alexichepura/quest
Android, Meta Quest support
This commit is contained in:
3
examples/android/.gitignore
vendored
Normal file
3
examples/android/.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
/target
|
||||
/Cargo.lock
|
||||
/runtime_libs
|
||||
67
examples/android/Cargo.toml
Normal file
67
examples/android/Cargo.toml
Normal 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"
|
||||
46
examples/android/README.md
Normal file
46
examples/android/README.md
Normal 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
|
||||
BIN
examples/android/hotham_examples.keystore
Normal file
BIN
examples/android/hotham_examples.keystore
Normal file
Binary file not shown.
83
examples/android/src/lib.rs
Normal file
83
examples/android/src/lib.rs
Normal 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(),
|
||||
));
|
||||
}
|
||||
@@ -42,6 +42,9 @@ pub fn initialize_xr_graphics(
|
||||
|
||||
let xr_entry = super::xr_entry();
|
||||
|
||||
#[cfg(target_os = "android")]
|
||||
xr_entry.initialize_android_loader().unwrap();
|
||||
|
||||
let available_extensions = xr_entry.enumerate_extensions()?;
|
||||
assert!(available_extensions.khr_vulkan_enable2);
|
||||
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];
|
||||
|
||||
#[cfg(not(target_os = "android"))]
|
||||
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);
|
||||
|
||||
#[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)?;
|
||||
if vk_target_version_xr < reqs.min_api_version_supported
|
||||
|| vk_target_version_xr.major() > reqs.max_api_version_supported.major()
|
||||
@@ -102,6 +113,8 @@ pub fn initialize_xr_graphics(
|
||||
let device_extensions = vec![
|
||||
ash::extensions::khr::Swapchain::name(),
|
||||
ash::extensions::khr::DrawIndirectCount::name(),
|
||||
#[cfg(target_os = "android")]
|
||||
ash::extensions::khr::TimelineSemaphore::name(),
|
||||
];
|
||||
info!(
|
||||
"creating vulkan instance with these extensions: {:#?}",
|
||||
|
||||
@@ -201,10 +201,17 @@ impl PluginGroup for DefaultXrPlugins {
|
||||
.add_before::<RenderPlugin, _>(OpenXrPlugin)
|
||||
.add_after::<OpenXrPlugin, _>(OpenXrInput::new(XrControllerType::OculusTouch))
|
||||
.set(WindowPlugin {
|
||||
#[cfg(not(target_os = "android"))]
|
||||
primary_window: Some(Window {
|
||||
present_mode: PresentMode::AutoNoVsync,
|
||||
..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()
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user