Skip to content

Commit 629fdbc

Browse files
committed
init
1 parent 7ace81f commit 629fdbc

File tree

992 files changed

+2141721
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

992 files changed

+2141721
-0
lines changed

DataStore.js

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
// this is intended to be a generic key value store in the context of low latency real-time
2+
// streaming - additions to this code should bear that in mind, application specific logic
3+
// that may not be useful to other contexts, should remain in the plugin itself, this should
4+
// eventually integrated to library perhaps
5+
6+
class DataStore {
7+
8+
constructor() {
9+
// saved checkpoint
10+
this.snapshot = {};
11+
// deltas from snapshot in order
12+
this.log = [];
13+
// current store state
14+
this.state = {};
15+
this.state['objects'] = {};
16+
// TODO: additional child that may need to be initialized at startup
17+
18+
// track statistics of usage
19+
// TODO: integrate with the functions to track usage stats
20+
// TODO: integrate optional timing profiling
21+
this.stats = {};
22+
23+
// ttl timers for scheduled events
24+
this.timers = {};
25+
this.timers['lock'] = {};
26+
this.timers['remove'] = {};
27+
28+
// three examples of metadata:
29+
// 1) stream || static || dynamic
30+
// stream - it should be broadcast at rate
31+
// static - store object at fixed location
32+
// dynamic - movable, broadcast deltas
33+
// 2) compressed - have a few encodings and decoding available, such as 16 bit floats,
34+
// or dropping the third direction, or both, among others, such as
35+
// KTX compression, or zip, etc for large binaries
36+
// 3) physics
37+
// ... arbitrary binary data as a payload
38+
this.metadata = {};
39+
40+
// callbacks
41+
42+
}
43+
44+
// compare(self, kvstore):
45+
// return DeepDiff(self.state, kvstore, exclude_types={}, exclude_paths={}) == {}
46+
47+
// def delta(self, kvstore):
48+
// return DeepDiff(self.state, kvstore, exclude_types={}, exclude_paths={})
49+
50+
// // TODO fix timers
51+
// def put(self, key, value, lock_ttl = None, remove_ttl = None):
52+
// if lock_ttl != None:
53+
// if self.timers['lock'][key]:
54+
// sched.cancel(self.timers['lock'][key])
55+
56+
// self.timers['lock'][key] = sched.enter(lock_ttl, 1, self.unlock, argument=(key,))
57+
58+
// if remove_ttl != None:
59+
// if self.timers['remove'][key]:
60+
// sched.cancel(self.timers['remove'][key])
61+
62+
// self.timers['remove'][key] = sched.enter(remove_ttl, 1, self.remove, argument=(key,))
63+
64+
// self.state[key] = value
65+
66+
clear() {
67+
// immediately create a snapshot of state prior to clearing
68+
this.snapshot = this.state;
69+
70+
// TODO: finish this function
71+
72+
}
73+
74+
//Checks if object is locked, true if free, false if locked
75+
check(key) {
76+
//If the object or lockid doesn't even exist yet, then it is unlocked.
77+
if (!(key in this.state['objects']) || !('lockid' in this.state['objects'][key])) {
78+
return true;
79+
}
80+
81+
//Else check to see if lockid is blank.
82+
return this.state['objects'][key]['lockid'] == '';
83+
}
84+
85+
setObjectData(key, data) {
86+
this.state['objects'][key]['state'] = data;
87+
this.state['objects'][key]['dirty'] = true;
88+
}
89+
90+
exists(key) {
91+
return key in this.state['objects'];
92+
}
93+
94+
add(key) {
95+
this.state['objects'][key] = {};
96+
}
97+
98+
// return key from state
99+
get(key) {
100+
return this.state['objects'][key];
101+
}
102+
103+
remove(key) {
104+
delete this.state['objects'][key];
105+
}
106+
107+
// attempt to acquire lock, returns true or false
108+
acquire(key, lockid) {
109+
return this.state['objects'][key]['lockid'] === -1 || this.state['objects'][key]['lockid'] === lockid;
110+
}
111+
112+
lock(key, lockid) {
113+
this.state['objects'][key]['lockid'] = lockid;
114+
}
115+
116+
unlock(key) {
117+
this.state['objects'][key]['lockid'] = -1;
118+
}
119+
120+
// check if active
121+
active(key) {
122+
return this.state['objects'][key]["active"];
123+
}
124+
125+
activate(key) {
126+
if (key in this.state['objects']) {
127+
this.state['objects'][key]["active"] = true;
128+
} else {
129+
console.log("Fun Fact: Tried activating an object that doesn't exist.")
130+
}
131+
}
132+
133+
deactivate(key) {
134+
if (key in this.state['objects']) {
135+
this.state['objects'][key]["active"] = false;
136+
} else {
137+
console.log("Fun Fact: Tried deactivating object that doesn't exist.")
138+
}
139+
}
140+
141+
}
142+
143+
module.exports = DataStore;

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2021 Future Reality Lab
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
# NYU-FRL-XR
2+
3+
Software for NYU Future Reality Lab webXR-based XR experience.
4+
5+
# How to setup the environment
6+
7+
install Node.js and npm if you haven't. Then in the command line, do
8+
```sh
9+
npm install
10+
cd server
11+
npm install
12+
source patch
13+
```
14+
15+
# How to run on your local computer
16+
17+
1. At the root folder, do ``./startserver``
18+
2. Go to chrome://flags/ in your Google Chrome browser
19+
3. Search: ***"Insecure origins treated as secure"*** and enable the flag
20+
4. Add http://[your-computer's-ip-address]:2024 to the text box. For example http://10.19.127.1:2024
21+
5. Relaunch the chrome browser on your computer and go to http://localhost:2024
22+
23+
# How to run in VR
24+
25+
1. Run the program locally on your computer
26+
2. Open the browser on your VR headset
27+
3. Go to chrome://flags/
28+
4. Search: ***"Insecure origins treated as secure"*** and enable the flag
29+
5. Add http://[your-computer's-ip-address]:2024 to the text box. For example http://10.19.127.1:2024
30+
7. Relaunch the browser on your VR headset and go to http://[your-computer's-ip-address]:2024
31+
32+
# How to debug in VR
33+
34+
1. On your Oculus app, go to *Devices*, select your headset from the device list, and wait for it to connect. Then select *Developer Mode* and turn on *Developer Mode*.
35+
2. Connect your quest with your computer using your Oculus Quest cable.
36+
3. Go to chrome://inspect#devices on your computer
37+
4. Go to your VR headset and accept *Allow USB Debugging* when prompted on the headset
38+
5. On the chrome://inspect#devices on your computer, you should be able to see your device under the *Remote Target* and its active programs. You can then inspect the *NYU-FRL-XR* window on your computer.
39+
40+
# How to create your own demo
41+
42+
1. Go to the [scenes folder](https://github.com/futurerealitylab/NYU-FRL-XR/tree/master/js/scenes/) and create a .js file based on the template of [demoSimplest.js](https://github.com/futurerealitylab/NYU-FRL-XR/tree/master/js/scenes/demoSimplest.js)
43+
2. Change the name and the content of the demo to whatever you like!
44+
3. Go to [scenes.js](https://github.com/futurerealitylab/NYU-FRL-XR/tree/master/js/scenes/scenes.js), add the name of your demo and its path to the returned value of [```scenes```](https://github.com/futurerealitylab/NYU-FRL-XR/tree/master/js/scenes/scenes.js#L11)
45+
4. Note that the [```enableSceneReloading```](https://github.com/futurerealitylab/NYU-FRL-XR/tree/master/js/scenes/scenes.js#L10) is set to true so that you can hot-reload the changes in your demo.
46+
47+
# How to enable your hand-tracking
48+
49+
1. Enable the experimental feature in the browser (Oculus Browser 11)
50+
2. Visit chrome://flags/
51+
3. Enable WebXR experiences with joint tracking (#webxr-hands)
52+
4. Enable WebXR Layers depth sorting (#webxr-depth-sorting)
53+
5. Enable WebXR Layers (#webxr-layers)
54+
6. Enable phase sync support (#webxr-phase-sync)
55+
7. Enable "Auto Enable Hands or Controllers" (Quest Settings (Gear Icon) -> Device -> Hands and Controllers)
56+
8. Enter the VR experience
57+
58+
# Notes on customizing your avatar
59+
1. To change the initial position of your avatar: go to [js/util/inline-viewer-helper.js](https://github.com/futurerealitylab/NYU-FRL-XR/tree/master/js/util/inline-viewer-helper.js) and change the values of [```this.lookYaw```](https://github.com/futurerealitylab/NYU-FRL-XR/tree/master/js/util/inline-viewer-helper.js#L46), [```this.walkPosition```](https://github.com/futurerealitylab/NYU-FRL-XR/tree/master/js/util/inline-viewer-helper.js#L47), [```this.lookPitch```](https://github.com/futurerealitylab/NYU-FRL-XR/tree/master/js/util/inline-viewer-helper.js#L49). Notice that [```this.viewerHeight```](https://github.com/futurerealitylab/NYU-FRL-XR/tree/master/js/util/inline-viewer-helper.js#L50) (the avatar's height) is set to be 1.6m from the [```inlineViewerHelper.setHeight(1.6)```](https://github.com/futurerealitylab/NYU-FRL-XR/tree/master/js/immersive-pre.js#L503) in [js/immersive-pre.js](https://github.com/futurerealitylab/NYU-FRL-XR/tree/master/js/immersive-pre.js). You can change this if you like.
60+
2. To customize your own avatar: go to [js/primitive/avatar.js](https://github.com/futurerealitylab/NYU-FRL-XR/tree/master/js/primitive/avatar.js). You can change the GLTF models used in the [```Headset```](https://github.com/futurerealitylab/NYU-FRL-XR/tree/master/js/primitive/avatar.js#L101) and the [```Controller```](https://github.com/futurerealitylab/NYU-FRL-XR/tree/master/js/primitive/avatar.js#L114) classes. You can add additional arguments to the [```initAvatar```](https://github.com/futurerealitylab/NYU-FRL-XR/tree/master/js/primitive/avatar.js#L8) function to specify the avatar's look, and pass those values from the [```addPawn```](https://github.com/futurerealitylab/NYU-FRL-XR/tree/master/js/util/croquetlib.js#L162) function.
61+
62+
# How to connect an Arduino Camera
63+
1. Get the url you use to stream the camera feed (example: 'http://192.168.1.189/640x480.jpg'), and make sure the computer hosting the server is under the same LAN as the Arducam.
64+
2. Set up the environment by opening the terminal located in the folder and type ```pip install -r requirements.txt``` (or ```pip3 install -r requirements.txt``` based on your version of pip)
65+
3. Replace the url on line 19 of track.py (inside the urlopen() function) with your own url from the Arducam.
66+
4. After starting the server, open the terminal and locate to the current folder, type ```python track.py``` (or ```python3 track.py```)
67+
5. The default information from the camera contains the positional data and the context of the QR code inside the camera feed, if any, and the radius and positional data of the largest green object. To engineer your own CV method, consider the variable ```frame``` inside track.py, it is the pixel data of your current camera feed. After your own engineering, to make communication with the server regarding the new information, wrap the information into a JSON-formatted dictionary and send it by using ```requests.post('http://localhost:2024/your-own-function', json=your-data-dictionary)```. Then under server/main.js, open up a new app.route("/your-own-function").post(function (req, res), make sure to match the name with the name you defined in the python code, and receive the information by ```req.body```.
68+
6. If you're using a different computer for camera feed fetching and processing, make sure to change the url from http://localhost:2024/your-own-function to that of your own server (or the public server).

css/common.css

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
body {
2+
background-color: #F5E6D6;
3+
font: 1rem/1.4 -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen,
4+
Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
5+
}
6+
7+
header {
8+
position: relative;
9+
z-index: 2;
10+
left: 0px;
11+
text-align: left;
12+
max-width: 422px;
13+
padding: 0.5em;
14+
background-color: rgba(255, 255, 255, 0.8);
15+
margin-bottom: 0.5em;
16+
border-radius: 2px;
17+
border-top-left-radius:10px;
18+
border-top-right-radius:10px;
19+
border-bottom-left-radius:10px;
20+
border-bottom-right-radius:10px;
21+
}
22+
23+
details summary {
24+
font-size: 1em;
25+
font-weight: bold;
26+
}
27+
28+
details[open] summary {
29+
font-size: 1.4em;
30+
font-weight: bold;
31+
}
32+
33+
header h1 {
34+
margin-top: 0px;
35+
}
36+
37+
canvas {
38+
position: absolute;
39+
z-index: 0;
40+
width: 100%;
41+
height: 100%;
42+
left: 0;
43+
top: 0;
44+
right: 0;
45+
bottom: 0;
46+
margin: 0;
47+
touch-action: none;
48+
}
49+
50+
.back {
51+
float: right;
52+
text-decoration: none;
53+
}
54+
55+
.back:hover {
56+
text-decoration: underline;
57+
}
58+
59+
.back::before {
60+
display: inline-block;
61+
content: attr(data-index) "<";
62+
font-weight: bold;
63+
white-space: nowrap;
64+
margin-right: 0.2em;
65+
margin-left: 0.2em;
66+
}
67+
68+
/* Used for the 'barebones' samples */
69+
.barebones-button {
70+
font-family: "Karla", sans-serif;
71+
border: rgb(80, 168, 252) 2px solid;
72+
border-radius: 2px;
73+
box-sizing: border-box;
74+
background: none;
75+
height: 55px;
76+
min-width: 176px;
77+
display: inline-block;
78+
position: relative;
79+
cursor: pointer;
80+
font-size: 18px;
81+
color: rgb(80, 168, 252);
82+
background-color: rgba(255, 255, 255, 0.7);
83+
}

0 commit comments

Comments
 (0)