Skip to content

Commit

Permalink
many crosshairs fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
namel committed Oct 28, 2016
1 parent dc15213 commit 4b7938c
Show file tree
Hide file tree
Showing 7 changed files with 136 additions and 60 deletions.
2 changes: 1 addition & 1 deletion examples/ambisonic.html
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>veri - simple</title>
<title>veri - ambisonic</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<style>
Expand Down
2 changes: 1 addition & 1 deletion examples/animated-buttons.html
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>veri - simple</title>
<title>veri - animated buttons</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<style>
Expand Down
23 changes: 21 additions & 2 deletions examples/animated-crosshairs.html
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>veri - simple</title>
<title>veri - animated crosshairs</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<style>
Expand Down Expand Up @@ -43,7 +43,26 @@
},
light: {
position: Veri.vec3(2, 2, 2)
}
},
crosshairs: {
debug: true,
type: "animated-crosshairs",
targets: [ {
name: "play",
direction: Veri.rot3(0, -100)
}],
hitRadius: 10,
hitTime: 6000,
sprite: {
src: "../resources/sprite/circle.png",
distance: 200,
columns: 8,
rows: 8,
count: 60,
objWidth: 60,
objHeight: 60
}
},
});

veri.start();
Expand Down
2 changes: 1 addition & 1 deletion examples/monoscopic.html
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>veri - simple</title>
<title>veri - monoscopic</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<style>
Expand Down
6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "veri",
"version": "0.9.2",
"version": "0.9.3",
"description": "Enables functionality for VR videos, including 360, stereoscopic, 3D objects, interaction and control, crosshairs, and ambisonic audio.",
"keywords": [
"vr",
Expand All @@ -10,7 +10,9 @@
"webvr",
"360",
"vive",
"oculus"
"oculus",
"crosshairs",
"veri"
],
"homepage": "https://namel.github.io/veri/",
"bugs": {
Expand Down
154 changes: 101 additions & 53 deletions src/crosshairs.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,68 +25,94 @@ class Crosshairs {
return `[${v.x}, ${v.y}, ${v.z}]`;
}

init(_scene, _params, _eventEmitter) {
this.scene = _scene;
this.params = _params;
this.eventEmitter = _eventEmitter;
init(scene, params, eventEmitter) {
this.scene = scene;
this.params = params;
this.eventEmitter = eventEmitter;

// check the crosshairs type
if (params.type !== 'animated-crosshairs' && params.type !== 'animated-buttons') {
var msg = 'unknown crosshairs type';
console.log(msg);
throw new Error(msg);
}
}

updateSprite(percent, position) {
updateSprite(percent, direction, position) {

// load the sprite image now if this hasn't happened yet
var sprite = this.params.sprite;
if (!this.spriteLoadingStarted) {

// instantiate a loader
var loader = new THREE.TextureLoader();
loader.crossOrigin = "";

// load a resource
this.spriteLoadingStarted = true;
loader.load(this.params.sprite.src, function(_spriteTexture) {
this.spriteTexture = _spriteTexture;
this.spriteTexture.wrapS = this.spriteTexture.wrapT = THREE.RepeatWrapping;
this.spriteTexture.repeat.set(1 / this.params.sprite.columns, 1 / this.params.sprite.rows);
loader.load(sprite.src, spriteTexture => {
sprite.texture = spriteTexture;
sprite.texture.wrapS = sprite.texture.wrapT = THREE.RepeatWrapping;

if (!sprite.width || !sprite.height) {
sprite.texture.repeat.set(1 / sprite.columns, 1 / sprite.rows);
} else {
var repeatX = sprite.width / sprite.texture.image.width;
var repeatY = sprite.height / sprite.texture.image.height;
sprite.texture.repeat.set(repeatX, repeatY);
}
var geometry = new THREE.PlaneGeometry(sprite.objWidth, sprite.objHeight, 1, 1);
var spriteMaterial = new THREE.MeshBasicMaterial({
transparent: true,
map: this.spriteTexture,
map: sprite.texture,
side: THREE.DoubleSide
});
var geometry = new THREE.PlaneGeometry(50, 50, 1, 1);
this.crosshairsSprite = new THREE.Mesh(geometry, spriteMaterial);
this.scene.add(this.crosshairsSprite);

sprite.mesh = new THREE.Mesh(geometry, spriteMaterial);
sprite.mesh.position.copy(direction).multiplyScalar(sprite.distance);
sprite.mesh.lookAt(new THREE.Vector3(0, 0, 0));
this.scene.add(sprite.mesh);
console.log("crosshairs sprite finished loading");
});
}

if (!this.crosshairsSprite) {
// no mesh? try later
if (!sprite.mesh) {
return;
}

// TODO: position and orientation are similar here and below
// and in the general case of objects. This code should be
// in a common lib
this.crosshairsSprite.position.copy(position).multiplyScalar(200);
var cameraRotationQuaternion = (new THREE.Quaternion())
.setFromUnitVectors(new THREE.Vector3(0, 0, 1), position);
this.crosshairsSprite.rotation.setFromQuaternion(cameraRotationQuaternion);
// option to remove the sprite
sprite.mesh.visible = !sprite.hide;

// if the crosshairs sprite direction changes, update position and rotation
if (direction) {
if (direction instanceof THREE.Euler) {
direction = (new THREE.Vector3(0, 1, 0)).applyEuler(direction);
}
sprite.mesh.position.copy(direction).multiplyScalar(sprite.distance);
sprite.mesh.lookAt(new THREE.Vector3(0, 0, 0));
}

// update the sprite
var imageIndex = Math.floor(this.params.sprite.count * percent);
var col = imageIndex % this.params.sprite.columns;
var row = (Math.floor(imageIndex / this.params.sprite.columns));
this.spriteTexture.offset.x = col / this.params.sprite.columns;
this.spriteTexture.offset.y = 1 - row / this.params.sprite.rows;
if (this.spriteTexture.offset.y !== window.oldY ||
this.spriteTexture.offset.x !== window.oldX) {
window.oldY = this.spriteTexture.offset.y;
window.oldX = this.spriteTexture.offset.x;
var imageIndex = Math.floor(sprite.count * percent);

sprite.texture.offset.x = (imageIndex % sprite.columns) / sprite.columns;
sprite.texture.offset.y = 1 - (Math.floor(imageIndex / sprite.columns) + 1) / sprite.rows;

if (sprite.texture.offset.y !== window.oldY ||
sprite.texture.offset.x !== window.oldX) {
window.oldY = sprite.texture.offset.y;
window.oldX = sprite.texture.offset.x;
if (this.params.debug) {
console.log(`setting sprites to ${this.spriteTexture.offset.x} ${this.spriteTexture.offset.y}`);
var offset = sprite.texture.offset;
console.log(`percent=${percent} setting sprites to ${offset.x} ${offset.y}`);
}
}

// debug
if (this.params.debug && this.debugCounter % 90 === 0) {
console.log(`sprite position = ${this.showVec(this.crosshairsSprite.position)}`);
console.log(`sprite rotation = ${this.showVec(this.crosshairsSprite.rotation)}`);
console.log(`sprite position = ${this.showVec(sprite.mesh.position)}`);
console.log(`sprite rotation = ${this.showVec(sprite.mesh.rotation)}`);
}
}

Expand Down Expand Up @@ -122,56 +148,78 @@ class Crosshairs {
this.debugCounter++;
var targets = this.params.targets;
var nextTarget = null;
var nextTargetObj = null;

for (var t in targets) {
if (targets.hasOwnProperty(t)) {
var target = this.params.targets[t];
var angle = target.direction.angleTo(cameraDirection);

// target may be disabled
if (target.disabled)
continue;

var targetDirection = (new THREE.Vector3(0, 1, 0)).applyEuler(target.direction);
var angle = targetDirection.angleTo(cameraDirection);
var angleDegrees = Math.floor(angle / Math.PI * 1800) / 10;
var hitRadius = target.hitRadius ? target.hitRadius : this.params.hitRadius;

// show angle to targets for debugging purposes
if (this.debugCounter % 90 === 0) {
console.log(`angle to ${target.name} is ${angle / Math.PI * 180}`);
}
if (this.debugCounter % 90 === 0)
console.log(`crosshairs: angle to target [${target.name}] is ${angleDegrees}\u00B0`);

if (angle <= this.params.hitRadius) {
if (angleDegrees <= hitRadius) {
if (nextTarget !== null) {
console.log('ERROR! overlapping targets');
}
nextTarget = target.name;
nextTargetObj = target;
}
}
}

// emit events
this.hitPercent = 0;
if (nextTarget !== null && this.lastTarget === null) {
if (this.eventEmitter) this.eventEmitter.emitEvent('vr.targetEnter', [nextTarget]);
if (this.eventEmitter) this.eventEmitter.emit('targetEnter', [nextTarget]);
this.hitStart = (new Date()).getTime();
} else if (nextTarget === null && this.lastTarget !== null) {
if (this.eventEmitter) this.eventEmitter.emitEvent('vr.targetExit', [this.lastTarget]);
if (this.eventEmitter) this.eventEmitter.emit('targetExit', [this.lastTarget]);
this.hitStart = 0;
} else if (nextTarget !== null) {
if (this.eventEmitter) this.eventEmitter.emitEvent('vr.targetStay', [nextTarget]);
var hitTime = nextTargetObj.hitTime ? nextTargetObj.hitTime : this.params.hitTime;
if (this.eventEmitter) this.eventEmitter.emit('targetStay', [nextTarget]);
var elapsed = (new Date()).getTime() - this.hitStart;
if (elapsed < this.params.hitTime) {
this.hitPercent = elapsed / this.params.hitTime;
} else if (elapsed >= this.params.hitTime) {
if (this.eventEmitter) this.eventEmitter.emitEvent('vr.targetSelected', [nextTarget]);
console.log('target selected ', nextTarget);
if (elapsed < hitTime) {
this.hitPercent = elapsed / hitTime;
} else if (elapsed >= hitTime) {
if (this.eventEmitter) this.eventEmitter.emit('targetSelected', [nextTarget]);
console.log(`target selected ${nextTarget}`);
this.hitStart = 0;
this.hitPercent = 1.0;
nextTarget = null;
}
}
this.lastTarget = nextTarget;

// move the crosshairs
if (this.lastPercent !== this.hitPercent) {
this.lastPercent = this.hitPercent;
if (this.params.sprite) {
this.updateSprite(this.hitPercent, cameraDirection);
} else {
this.updateCrosshairs(this.hitPercent, cameraDirection);
// update crosshairs and target buttons
if (this.params.type === 'animated-buttons') {

// update each button to its percent
for (var tid of Object.keys(targets)) {
var hitPercentArg = (nextTargetObj === targets[tid]) ? this.hitPercent : 0;
this.updateSprite(hitPercentArg, targets[tid].sprite.direction, targets[tid].sprite);
}

// update the crosshairs
this.updateSprite(0, cameraDirection, this.params.sprite);
} else if (this.params.type === 'animated-crosshairs') {
if (this.lastPercent !== this.hitPercent) {
this.lastPercent = this.hitPercent;
if (this.params.sprite) {
this.updateSprite(this.hitPercent, cameraDirection, this.params.sprite);
} else {
this.updateCrosshairs(this.hitPercent, cameraDirection);
}
}
}
}
Expand Down
7 changes: 7 additions & 0 deletions src/veri.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,13 @@ class Veri {
return new THREE.Vector3(x, y, z);
}

// convenience function to return an instance of an Euler rotation
static rot3(theta, phi) {
var thetaRad = theta / 180 * Math.PI;
var phiRad = phi / 180 * Math.PI;
return new THREE.Euler(thetaRad + Math.PI / 2, phiRad, 0, 'YXZ');
};

// do next animation frame
doAnimationFrame() {
window.requestAnimationFrame(this.doAnimationFrame.bind(this));
Expand Down

0 comments on commit 4b7938c

Please sign in to comment.