This commit is contained in:
damouse 2017-02-14 21:58:19 -06:00
parent a9691fc88a
commit 36599e89f6
80 changed files with 20 additions and 272 deletions

View file

@ -19,4 +19,4 @@ Note that the controller portion of this app comes in a smartphone flavor too. S
- Multiplayer
- Canvas Streaming
- Lobbies

View file

@ -1,89 +0,0 @@
MIN_TIMESTEP = 0.001;
MAX_TIMESTEP = 1;
function ComplementaryOrientation() {
this.accelerometer = new THREE.Vector3();
this.gyroscope = new THREE.Vector3();
window.addEventListener('devicemotion', this.onDeviceMotionChange_.bind(this));
window.addEventListener('orientationchange', this.onScreenOrientationChange_.bind(this));
this.filter = new ComplementaryFilter(0.98);
this.posePredictor = new PosePredictor(0.050);
this.filterToWorldQ = new THREE.Quaternion();
// Set the filter to world transform, but only for Android.
if (Util.isIOS()) {
this.filterToWorldQ.setFromAxisAngle(new THREE.Vector3(1, 0, 0), Math.PI/2);
} else {
this.filterToWorldQ.setFromAxisAngle(new THREE.Vector3(1, 0, 0), -Math.PI/2);
}
this.worldToScreenQ = new THREE.Quaternion();
this.setScreenTransform_();
}
ComplementaryOrientation.prototype.onDeviceMotionChange_ = function(deviceMotion) {
var accGravity = deviceMotion.accelerationIncludingGravity;
var rotRate = deviceMotion.rotationRate;
var timestampS = deviceMotion.timeStamp / 1000;
var deltaS = timestampS - this.previousTimestampS;
if (deltaS <= MIN_TIMESTEP || deltaS > MAX_TIMESTEP) {
console.warn('Invalid timestamps detected. Time step between successive ' +
'gyroscope sensor samples is very small or not monotonic');
this.previousTimestampS = timestampS;
return;
}
this.accelerometer.set(-accGravity.x, -accGravity.y, -accGravity.z);
this.gyroscope.set(rotRate.alpha, rotRate.beta, rotRate.gamma);
// In iOS, rotationRate is reported in degrees, so we first convert to
// radians.
if (Util.isIOS()) {
this.gyroscope.multiplyScalar(Math.PI / 180);
}
this.filter.addAccelMeasurement(this.accelerometer, timestampS);
this.filter.addGyroMeasurement(this.gyroscope, timestampS);
this.previousTimestampS = timestampS;
};
ComplementaryOrientation.prototype.onScreenOrientationChange_ =
function(screenOrientation) {
this.setScreenTransform_();
};
ComplementaryOrientation.prototype.setScreenTransform_ = function() {
this.worldToScreenQ.set(0, 0, 0, 1);
switch (window.orientation) {
case 0:
break;
case 90:
this.worldToScreenQ.setFromAxisAngle(new THREE.Vector3(0, 0, 1), -Math.PI/2);
break;
case -90:
this.worldToScreenQ.setFromAxisAngle(new THREE.Vector3(0, 0, 1), Math.PI/2);
break;
case 180:
break;
}
};
ComplementaryOrientation.prototype.getOrientation = function() {
// Convert from filter space to the the same system used by the
// deviceorientation event.
var orientation = this.filter.getOrientation();
// Predict orientation.
this.predictedQ = this.posePredictor.getPrediction(orientation, this.gyroscope, this.previousTimestampS);
// Convert to THREE coordinate system: -Z forward, Y up, X right.
var out = new THREE.Quaternion();
out.copy(this.filterToWorldQ);
out.multiply(this.predictedQ);
out.multiply(this.worldToScreenQ);
return out;
};

View file

@ -1,72 +0,0 @@
// Create a three.js scene in which the camera is controlled by the orientation
// from the complementary filter.
var co = new ComplementaryOrientation();
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );
camera.position.z = -1;
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
var geometry = new THREE.SphereGeometry( 1, 16, 16 );
var material = new THREE.MeshBasicMaterial( {color: 'red', wireframe: true} );
var sphereX = new THREE.Mesh( geometry, material );
sphereX.position.set(5, 0, 0);
scene.add( sphereX );
var geometry = new THREE.SphereGeometry( 1, 16, 16 );
var material = new THREE.MeshBasicMaterial( {color: 'green', wireframe: true} );
var sphereY = new THREE.Mesh( geometry, material );
sphereY.position.set(0, 5, 0);
scene.add( sphereY );
var geometry = new THREE.SphereGeometry( 1, 16, 16 );
var material = new THREE.MeshBasicMaterial( {color: 'blue', wireframe: true} );
var sphereZ = new THREE.Mesh( geometry, material );
sphereZ.position.set(0, 0, 5);
scene.add( sphereZ );
var geometry = new THREE.SphereGeometry( 1, 16, 16 );
var material = new THREE.MeshBasicMaterial( {color: 'cyan', wireframe: true} );
var sphereBottom = new THREE.Mesh( geometry, material );
sphereBottom.position.set(0, -5, 0);
scene.add( sphereBottom );
// Add a repeating grid as a skybox.
var boxWidth = 10;
var texture = THREE.ImageUtils.loadTexture(
'img/box.png'
);
texture.wrapS = THREE.RepeatWrapping;
texture.wrapT = THREE.RepeatWrapping;
texture.repeat.set(boxWidth, boxWidth);
var geometry = new THREE.BoxGeometry(boxWidth, boxWidth, boxWidth);
var material = new THREE.MeshBasicMaterial({
map: texture,
color: 0xffffff,
side: THREE.BackSide
});
var skybox = new THREE.Mesh(geometry, material);
scene.add(skybox);
function render() {
camera.quaternion.copy(co.getOrientation());
requestAnimationFrame( render );
renderer.render( scene, camera );
}
render();
window.addEventListener('resize', function() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
});

View file

@ -1,76 +0,0 @@
/*
* Copyright 2015 Google Inc. All Rights Reserved.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
var DEBUG = false;
/**
* Given an orientation and the gyroscope data, predicts the future orientation
* of the head. This makes rendering appear faster.
*
* Also see: http://msl.cs.uiuc.edu/~lavalle/papers/LavYerKatAnt14.pdf
*
* @param {Number} predictionTimeS time from head movement to the appearance of
* the corresponding image.
*/
function PosePredictor(predictionTimeS) {
this.predictionTimeS = predictionTimeS;
// The quaternion corresponding to the previous state.
this.previousQ = new THREE.Quaternion();
// Previous time a prediction occurred.
this.previousTimestampS = null;
// The delta quaternion that adjusts the current pose.
this.deltaQ = new THREE.Quaternion();
// The output quaternion.
this.outQ = new THREE.Quaternion();
}
PosePredictor.prototype.getPrediction = function(currentQ, gyro, timestampS) {
if (!this.previousTimestampS) {
this.previousQ.copy(currentQ);
this.previousTimestampS = timestampS;
return currentQ;
}
// Calculate axis and angle based on gyroscope rotation rate data.
var axis = new THREE.Vector3();
axis.copy(gyro);
axis.normalize();
var angularSpeed = gyro.length();
// If we're rotating slowly, don't do prediction.
if (angularSpeed < THREE.Math.degToRad(20)) {
if (DEBUG) {
console.log('Moving slowly, at %s deg/s: no prediction',
THREE.Math.radToDeg(angularSpeed).toFixed(1));
}
this.outQ.copy(currentQ);
this.previousQ.copy(currentQ);
return this.outQ;
}
// Get the predicted angle based on the time delta and latency.
var deltaT = timestampS - this.previousTimestampS;
var predictAngle = angularSpeed * this.predictionTimeS;
this.deltaQ.setFromAxisAngle(axis, predictAngle);
this.outQ.copy(this.previousQ);
this.outQ.multiply(this.deltaQ);
this.previousQ.copy(currentQ);
return this.outQ;
};

View file

@ -1,12 +0,0 @@
function SensorSample(sample, timestampS) {
this.set(sample, timestampS);
};
SensorSample.prototype.set = function(sample, timestampS) {
this.sample = sample;
this.timestampS = timestampS;
};
SensorSample.prototype.copy = function(sensorSample) {
this.set(sensorSample.sample, sensorSample.timestampS);
};

View file

@ -16,11 +16,7 @@
"license": "MIT",
"homepage": "https://github.com/christianalfoni/webpack-express-boilerplate",
"scripts": {
"test": "",
"start": "node server",
"build": "rimraf dist && cross-env NODE_ENV=production webpack --config ./webpack.production.config.js --progress --profile --colors",
"eslint": "eslint .",
"jscs": "jscs ."
"start": "node src/server"
},
"dependencies": {
"babel-cli": "^6.4.0",

View file

@ -1,4 +1,4 @@
version: 1
type: light
use: node
command: node server
command: npm start

View file

@ -26,7 +26,7 @@ function loop() {
lastGyro.applyQuaternion(invGyroOnly);
lastGyro.normalize();
gyroHistory.push(lastGyro);
console.log('G: ', lastGyro);
// console.log('G: ', lastGyro);
} else {
gyroHistory.data = [];
}

View file

@ -3,9 +3,12 @@ const app = express();
var http = require('http').Server(app);
var io = require('socket.io')(http);
app.use('/assets', express.static('./app'));
app.get('/', (req, res) => { res.sendFile('index.html', { root: './app' }) })
app.get('/controller', (req, res) => { res.sendFile('controller.html', { root: './app' }) })
app.get('/', (req, res) => { res.sendFile('display.html', { root: 'views' }) })
app.get('/controller', (req, res) => { res.sendFile('controller.html', { root: 'views' }) })
for (var d of["stylesheets", "vendor", "sensors", "src"]) {
app.use('/assets', express.static(d));
}
io.on('connection', (socket) => {
socket.on("controller", (m) => io.emit('input', m))

View file

@ -5,17 +5,17 @@
<meta charset='utf-8' />
<meta http-equiv="X-UA-Compatible" content="chrome=1" />
<link rel="stylesheet" type="text/css" media="screen" href="/assets/stylesheets/controller.css">
<link rel="stylesheet" type="text/css" media="screen" href="/assets/controller.css">
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<script src="https://cdn.socket.io/socket.io-1.4.5.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.1/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script src="assets/vendor/three.min.js"></script>
<script src="assets/vendor/mathbox/build/mathbox-bundle.js"></script>
<script src="assets/vendor/cbuffer/cbuffer.js"></script>
<script src="assets/vendor/dat.gui/dat.gui.js"></script>
<script src="assets/three.min.js"></script>
<script src="assets/mathbox/build/mathbox-bundle.js"></script>
<script src="assets/cbuffer/cbuffer.js"></script>
<script src="assets/dat.gui/dat.gui.js"></script>
<script type='text/javascript' src='assets/controller.js'></script>
@ -24,9 +24,9 @@
<body ng-app="controller" ng-controller='RootController'>
<script src="assets/sensors/util.js"></script>
<script src="assets/sensors/complementary-filter.js"></script>
<script src="assets/sensors/plot-sensors.js"></script>
<script src="assets/util.js"></script>
<script src="assets/complementary-filter.js"></script>
<script src="assets/plot-sensors.js"></script>
<div class='container'>
<div class='row main-row'></div>

View file

@ -4,7 +4,7 @@
<head>
<meta charset='utf-8' />
<meta http-equiv="X-UA-Compatible" content="chrome=1" />
<link rel="stylesheet" type="text/css" media="screen" href="/assets/stylesheets/stylesheet.css">
<link rel="stylesheet" type="text/css" media="screen" href="assets/stylesheet.css">
<script src="https://cdn.socket.io/socket.io-1.4.5.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
@ -20,8 +20,6 @@
<div id='filechooser' style="visibility:hidden;">
<input type="file" id="files" name="files[]" multiple />
<output id="list"></output>
<script>
</script>
</div>
<div class="emscripten">
<progress value="0" max="100" id="progress" hidden=1></progress>
@ -29,7 +27,7 @@
<div class="emscripten_border">
<canvas class="emscripten" id="canvas" oncontextmenu="event.preventDefault()"></canvas>
</div>
<script type='text/javascript' src='assets/main.js'></script>
<script type='text/javascript' src='assets/display.js'></script>
<script async type="text/javascript" src="assets/mupen64plus-ui-console.js"></script>
</p>
</section>