leetvr / hotham Goto Github PK
View Code? Open in Web Editor NEWHotham is a tool for creating incredible standalone VR games.
License: Apache License 2.0
Hotham is a tool for creating incredible standalone VR games.
License: Apache License 2.0
The player is aware that now they need to do something. Deploy their mechs and defend against aliens.
The user sees the asteroid in front of them, in the centre of their guardian space
Make the simulator great again!
Music is great! Let's have some of that.
The bindgen bindings keep getting regenerated over and over again. This is.. frustrating.
It's kind of cool when things move in games, doesn't it?
animation.rs
Animation
, with channel etc.Model
to use Node
sSkin
etc.Vertex
model.vert
cgmath
has been great to get us started but it's starting to produce a bit of friction.
cgmath
dependency from toml
Using legion
, there's been a lot to love, but there's also been some pretty annoying issues.
system
macros aren't picked up by rust-analyzer
legion
but a lot of it isn't well documented. hecs
is a bit more barebones.legion
doesn't look to be actively maintained and I DO NOT want to be maintaining a fork of an ECS - I'm just not smart enough for that. :PEveryone loves logging!
tracing
load_sound
doesn't belong in lib.rs
Currently, Buffer
is just a fancy wrapper around a vk::Buffer
handle. It'd be nice if we could improve its ergonomics a bit.
We need some way of creating "if this/then that" sequences.
Things need to know when they're touching other things
Great! We picked an ECS, legion. Now comes the fun part - implementing it.
I think the best place to start is Hotham::Program
. Ultimately one of the most important things in hotham is making sure that the interface a developer will use to create an app is as simple as possible.
The asteroid could look something like:
struct Asteroid {
model: Model,
transform: Transform,
// new functionality like physics, sound etc. will go here
}
struct Transform {
position: Vector3<f32>,
rotation: Quaternion<f32>,
scale: Vector3<f32>,
}
let mut world = World::new();
let asteroid = Asteroid {
model: asteroid_model,
transform: Transform {
position: vec3(0.0, 1.0, 0.0),
rotation: Default::default(),
scale: vec3(1.0, 1.0, 1.0),
}
}
world.push(asteroid);
That's pretty straightforward. The refinery is the same, except we need to make sure its parent is the asteroid, somehow.
struct Refinery {
model: Model,
transform: Transform,
}
struct Transform {
position: Vector3<f32>,
rotation: Quaternion<f32>,
scale: Vector3<f32>,
parent: Option<Box<Transform>>, // ??
}
This is pretty different from our current Node
based structure, which is just lifted from gltf
. We'll need to approach the migration of Node
to legion
based components separately.
What's even trickier is things like Hands, for instance.
struct Hand {
model: Model,
transform: Transform,
animation: Animation,
}
We'd then have something like a HandsSystem
that takes the current XR state and updates the Animation
and Transform
components accordingly.
#131 resulted in a massive refactoring of so much of Hotham's internal systems. That's meant the previous App
API we had is now deceased. We now need a rewrite
The player needs to know what they need to do next. Otherwise, how will they do it?
After a bunch of work, hotham
is dangerously close to being ready for other human beings to use.
Here's a list of things that need to be done first.
Looks like OpenXR has added Android support over here. Let's use that instead.
Cargo.toml
dependencyCurrently things in hotham look terrible. Let's fix that!
rendering_system
that takes a path to a gltf file and outputs the render to a fileMaterial
structPushConsts
Pipeline
SceneParams
Vec<Primitive>
VertexBuffer
and IndexBuffer
into Primitive
Material
to Primitive
texture_descriptor_set
to Primitive
Vertex
Material
Our hands will need to be used to grab things
RigidBody
in hands scenarioCollider
and RigidBody
to handsCollider
and RigidBody
to asteroidHand
with RigidBody
Transform
s based on the position of their RigidBody
HandsSystem
, check to see if the hand is gripped, and if there are any collisonsGrabbedEntity
in Hand
and set its RigidBody type to kinematicGrabbedEntity
GrabbedEntity
along with the Hand
Well this is going to be really fun.
When attempting to integrate legion I discovered that Node
, the core structure in Hotham
is completely incompatible. This is because, in essence Node
is doing what legion
wants to do - hold all the data and behaviour of the system in one place. Specifically, it's because Node
looks like this:
struct Node {
parent: Weak<Node>, // not 'static + Sized + Send + Sync !
children: Vec<Rc<Node>>, // 'static + Sized + Send + Sync !
}
The solution is to break Node
apart into its various Component
s (structs) and System
s (functions).
In essence, this is far closer to the actual representation of a gltf
file: a discrete set of components with loose references to each-other, rather than an OOP-style graph structure like I've currently got.
Onwards!
Transform
componenttransform
systemSkin
componentJoint
componentskinning
systemMesh
componentrender
systemprepare_frame
functionXrContext
resourceRenderer
a resourceVulkanContext
a resourceVulkanContext
from Renderer
The user needs to see where their mech will end up when they let go.
How can we integrate if it's not done continuously?
Now that we've split apart Node
, we now need to get gltf-importer
to integrate with our new system.
Mesh
Transform
Skin
The user has held on to a projection, is about to place it somewhere. Give them a gentle instruction on what to do
Now that we've got static gltf
models rendering, let's try something a bit more challenging.
hands
systemOnce the player has released the projection, the mech needs to fly off the platform and head down to the Asteroid
One of the most important things when releasing complex software is providing examples. Not only does it provide users with a transparent way to see "how" to do things with the software, it gives users confidence in "what" can be done with the software.
Since Hotham is first and foremost a VR game engine, we need to prove that we can make VR games with it. What better game to make than Beat Saber?
This will require careful planning - it'd be very easy to get derailed and stuck in the weeds here. Beat Saber is a big and complex game, but there should be a way to cut it down to its simplest elements and recreate them.
The mech needs to land on the Asteroid in a.. convincing fashion.
Many of the systems in this phase require "physics". What is the Minimum Physics we need for the game?
Now that we've successfully ported most of our code to legion
, it's time to integrate everything.
For our first pass, we'll just try rendering the Asteroid and the refinery.
App
to run the legion
schedule.Renderer
accordinglyhotham-asteroid
to return the asteroid and the refinery parented to itWe're now starting to have a large number of actors within our system. We need an efficient way of organising them.
It's currently taking forever to load a model, and texture paths are completely hard coded.
We know what the point of this game is, but the user is probably completely in the dark. Having some audio to tell the user what's going to happen is super useful.
The player can see a refinery on the asteroid. It's clear to the player that this is important, and needs to be protected
Rendering a single asteroid is fun! You know what's better than a single asteroid?
Multiple.. things!
Model
SceneObject
load_models
Program::init()
return Vec<SceneObject>
scene_object
sscene_objects
to App
Renderer
to have push_constants
model.*
hotham
push_constant
for matrixscene_objects
to Renderer::draw()
scene_object
in prepare_frame
descriptor_set
, index_buffer
and vertex_buffer
from scene_object
When the user triggers some kind of input on the touch controllers, we want this to drive the animation
Clippy will probably get mad.
add_panel_to_world
(10/7) --> hotham/src/components/panel.rs:79:1
|
79 | / pub fn add_panel_to_world(
80 | | text: &str,
81 | | width: u32,
82 | | height: u32,
... |
89 | | world: &mut World,
90 | | ) -> Entity {
| |___________^
|
load_node
(8/7) --> hotham/src/gltf_loader.rs:88:1
|
88 | / fn load_node(
89 | | node_data: &gltf::Node,
90 | | gltf_buffer: &[u8],
91 | | vulkan_context: &VulkanContext,
... |
96 | | images: &[gltf::image::Data],
97 | | ) -> Result<()> {
| |_______________^
|
new
(8/7)warning: this function has too many arguments (8/7)
--> hotham/src/image.rs:17:5
|
17 | / pub fn new(
18 | | handle: vk::Image,
19 | | view: vk::ImageView,
20 | | device_memory: vk::DeviceMemory,
... |
25 | | layer_count: u32,
26 | | ) -> Self {
| |_____________^
|
create_texture_image
(9/7) --> hotham/src/resources/vulkan_context.rs:467:5
|
467 | / pub fn create_texture_image(
468 | | &self,
469 | | name: &str,
470 | | image_buf: &[u8], // Clippy &Vec<u8>, ptr_arg for texture.rs
... |
476 | | offsets: Vec<vk::DeviceSize>,
477 | | ) -> Result<(Image, vk::Sampler)> {
| |_____________________________________^
|
create_textures_descriptor_sets
(8/7) --> hotham/src/resources/vulkan_context.rs:802:5
|
802 | / pub fn create_textures_descriptor_sets(
803 | | &self,
804 | | set_layout: vk::DescriptorSetLayout,
805 | | material_name: &str,
... |
810 | | emissive_map: &Texture,
811 | | ) -> VkResult<Vec<vk::DescriptorSet>> {
| |_________________________________________^
warning: very complex type used. Consider factoring parts into type
definitions
--> hotham/src/texture.rs:183:6
|
183 | ) -> Result<(Vec<u8>, u32, u32, vk::Format, u32, u32, Vec<vk::DeviceSize>)> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
--> hotham/src/vertex.rs:35:12
|
35 | t: (
| ____________^
36 | | Vector3<f32>,
37 | | Vector3<f32>,
38 | | Vector2<f32>,
... |
41 | | Vector4<f32>,
42 | | ),
| |_________^
|
--> examples/crab-saber/src/systems/mod.rs:15:9
|
15 | PreparedQuery<With<Visible, With<Cube, (&'a Colour, &'a RigidBody, &'a Collider)>>>,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
impl Send for AudioContext
warning: this implementation is unsound, as some fields in `AudioContext` are `!Send`
--> hotham/src/resources/audio_context.rs:97:1
|
97 | unsafe impl Send for AudioContext {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: `#[warn(clippy::non_send_fields_in_send_ty)]` on by default
note: the type of field `stream` is `!Send`
--> hotham/src/resources/audio_context.rs:22:5
|
22 | pub stream: Arc<Mutex<Stream>>,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: use a thread-safe type that implements `Send`
This is the important part. The player needs to be able to interact with their Mech.
Looks like we may have to set the colour profile manually for the Quest with XR_FB_color_space.
#[deny(docs)]
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.