mirror of
https://github.com/overte-org/overte.git
synced 2025-08-08 21:57:00 +02:00
Merge branch 'master' of https://github.com/highfidelity/hifi into orange
This commit is contained in:
commit
e72035ee3d
14 changed files with 407 additions and 140 deletions
|
@ -1,3 +1,4 @@
|
||||||
|
"use strict";
|
||||||
// handControllerGrab.js
|
// handControllerGrab.js
|
||||||
//
|
//
|
||||||
// Created by Eric Levin on 9/2/15
|
// Created by Eric Levin on 9/2/15
|
||||||
|
@ -801,6 +802,8 @@ function MyController(hand) {
|
||||||
this.isInitialGrab = false;
|
this.isInitialGrab = false;
|
||||||
this.doubleParentGrab = false;
|
this.doubleParentGrab = false;
|
||||||
|
|
||||||
|
this.checkForStrayChildren();
|
||||||
|
|
||||||
if (this.state == STATE_SEARCHING ? this.triggerSmoothedReleased() : this.bumperReleased()) {
|
if (this.state == STATE_SEARCHING ? this.triggerSmoothedReleased() : this.bumperReleased()) {
|
||||||
this.setState(STATE_RELEASE);
|
this.setState(STATE_RELEASE);
|
||||||
return;
|
return;
|
||||||
|
@ -1444,6 +1447,13 @@ function MyController(hand) {
|
||||||
this.heartBeat(this.grabbedEntity);
|
this.heartBeat(this.grabbedEntity);
|
||||||
|
|
||||||
var props = Entities.getEntityProperties(this.grabbedEntity, ["localPosition", "parentID", "position"]);
|
var props = Entities.getEntityProperties(this.grabbedEntity, ["localPosition", "parentID", "position"]);
|
||||||
|
if (!props.position) {
|
||||||
|
// server may have reset, taking our equipped entity with it. move back to "off" stte
|
||||||
|
this.setState(STATE_RELEASE);
|
||||||
|
this.callEntityMethodOnGrabbed("releaseGrab");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (props.parentID == MyAvatar.sessionUUID &&
|
if (props.parentID == MyAvatar.sessionUUID &&
|
||||||
Vec3.length(props.localPosition) > NEAR_PICK_MAX_DISTANCE * 2.0) {
|
Vec3.length(props.localPosition) > NEAR_PICK_MAX_DISTANCE * 2.0) {
|
||||||
// for whatever reason, the held/equipped entity has been pulled away. ungrab or unequip.
|
// for whatever reason, the held/equipped entity has been pulled away. ungrab or unequip.
|
||||||
|
@ -1751,6 +1761,17 @@ function MyController(hand) {
|
||||||
return data;
|
return data;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
this.checkForStrayChildren = function() {
|
||||||
|
// sometimes things can get parented to a hand and this script is unaware. Search for such entities and
|
||||||
|
// unhook them.
|
||||||
|
var handJointIndex = MyAvatar.getJointIndex(this.hand === RIGHT_HAND ? "RightHand" : "LeftHand");
|
||||||
|
var children = Entities.getChildrenIDsOfJoint(MyAvatar.sessionUUID, handJointIndex);
|
||||||
|
children.forEach(function(childID) {
|
||||||
|
print("disconnecting stray child of hand: (" + _this.hand + ") " + childID);
|
||||||
|
Entities.editEntity(childID, {parentID: NULL_UUID});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
this.deactivateEntity = function(entityID, noVelocity) {
|
this.deactivateEntity = function(entityID, noVelocity) {
|
||||||
var data = getEntityCustomData(GRAB_USER_DATA_KEY, entityID, {});
|
var data = getEntityCustomData(GRAB_USER_DATA_KEY, entityID, {});
|
||||||
if (data && data["refCount"]) {
|
if (data && data["refCount"]) {
|
||||||
|
|
|
@ -22,3 +22,4 @@ Script.load("grab.js");
|
||||||
Script.load("directory.js");
|
Script.load("directory.js");
|
||||||
Script.load("dialTone.js");
|
Script.load("dialTone.js");
|
||||||
Script.load("attachedEntitiesManager.js");
|
Script.load("attachedEntitiesManager.js");
|
||||||
|
Script.load("depthReticle.js");
|
||||||
|
|
|
@ -5,6 +5,8 @@
|
||||||
// Copyright 2016 High Fidelity, Inc.
|
// Copyright 2016 High Fidelity, Inc.
|
||||||
//
|
//
|
||||||
// When used in HMD, this script will make the reticle depth track to any clickable item in view.
|
// When used in HMD, this script will make the reticle depth track to any clickable item in view.
|
||||||
|
// This script also handles auto-hiding the reticle after inactivity, as well as having the reticle
|
||||||
|
// seek the look at position upon waking up.
|
||||||
//
|
//
|
||||||
// Distributed under the Apache License, Version 2.0.
|
// Distributed under the Apache License, Version 2.0.
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
@ -17,8 +19,89 @@ var desiredDepth = APPARENT_2D_OVERLAY_DEPTH;
|
||||||
var TIME_BETWEEN_DEPTH_CHECKS = 100;
|
var TIME_BETWEEN_DEPTH_CHECKS = 100;
|
||||||
var MINIMUM_DEPTH_ADJUST = 0.01;
|
var MINIMUM_DEPTH_ADJUST = 0.01;
|
||||||
var NON_LINEAR_DIVISOR = 2;
|
var NON_LINEAR_DIVISOR = 2;
|
||||||
|
var MINIMUM_SEEK_DISTANCE = 0.01;
|
||||||
|
|
||||||
Script.update.connect(function(deltaTime) {
|
var lastMouseMove = Date.now();
|
||||||
|
var lastMouseX = Reticle.position.x;
|
||||||
|
var lastMouseY = Reticle.position.y;
|
||||||
|
var HIDE_STATIC_MOUSE_AFTER = 3000; // 3 seconds
|
||||||
|
var shouldSeekToLookAt = false;
|
||||||
|
var fastMouseMoves = 0;
|
||||||
|
var averageMouseVelocity = 0;
|
||||||
|
var WEIGHTING = 1/20; // simple moving average over last 20 samples
|
||||||
|
var ONE_MINUS_WEIGHTING = 1 - WEIGHTING;
|
||||||
|
var AVERAGE_MOUSE_VELOCITY_FOR_SEEK_TO = 50;
|
||||||
|
|
||||||
|
Controller.mouseMoveEvent.connect(function(mouseEvent) {
|
||||||
|
var now = Date.now();
|
||||||
|
|
||||||
|
// if the reticle is hidden, show it...
|
||||||
|
if (!Reticle.visible) {
|
||||||
|
Reticle.visible = true;
|
||||||
|
if (HMD.active) {
|
||||||
|
shouldSeekToLookAt = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// even if the reticle is visible, if we're in HMD mode, and the person is moving their mouse quickly (shaking it)
|
||||||
|
// then they are probably looking for it, and we should move into seekToLookAt mode
|
||||||
|
if (HMD.active && !shouldSeekToLookAt) {
|
||||||
|
var dx = Reticle.position.x - lastMouseX;
|
||||||
|
var dy = Reticle.position.y - lastMouseY;
|
||||||
|
var dt = Math.max(1, (now - lastMouseMove)); // mSecs since last mouse move
|
||||||
|
var mouseMoveDistance = Math.sqrt((dx*dx) + (dy*dy));
|
||||||
|
var mouseVelocity = mouseMoveDistance / dt;
|
||||||
|
averageMouseVelocity = (ONE_MINUS_WEIGHTING * averageMouseVelocity) + (WEIGHTING * mouseVelocity);
|
||||||
|
if (averageMouseVelocity > AVERAGE_MOUSE_VELOCITY_FOR_SEEK_TO) {
|
||||||
|
shouldSeekToLookAt = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lastMouseMove = now;
|
||||||
|
lastMouseX = mouseEvent.x;
|
||||||
|
lastMouseY = mouseEvent.y;
|
||||||
|
});
|
||||||
|
|
||||||
|
function seekToLookAt() {
|
||||||
|
// if we're currently seeking the lookAt move the mouse toward the lookat
|
||||||
|
if (shouldSeekToLookAt) {
|
||||||
|
averageMouseVelocity = 0; // reset this, these never count for movement...
|
||||||
|
var lookAt2D = HMD.getHUDLookAtPosition2D();
|
||||||
|
var currentReticlePosition = Reticle.position;
|
||||||
|
var distanceBetweenX = lookAt2D.x - Reticle.position.x;
|
||||||
|
var distanceBetweenY = lookAt2D.y - Reticle.position.y;
|
||||||
|
var moveX = distanceBetweenX / NON_LINEAR_DIVISOR;
|
||||||
|
var moveY = distanceBetweenY / NON_LINEAR_DIVISOR;
|
||||||
|
var newPosition = { x: Reticle.position.x + moveX, y: Reticle.position.y + moveY };
|
||||||
|
var closeEnoughX = false;
|
||||||
|
var closeEnoughY = false;
|
||||||
|
if (moveX < MINIMUM_SEEK_DISTANCE) {
|
||||||
|
newPosition.x = lookAt2D.x;
|
||||||
|
closeEnoughX = true;
|
||||||
|
}
|
||||||
|
if (moveY < MINIMUM_SEEK_DISTANCE) {
|
||||||
|
newPosition.y = lookAt2D.y;
|
||||||
|
closeEnoughY = true;
|
||||||
|
}
|
||||||
|
Reticle.position = newPosition;
|
||||||
|
if (closeEnoughX && closeEnoughY) {
|
||||||
|
shouldSeekToLookAt = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function autoHideReticle() {
|
||||||
|
// if we haven't moved in a long period of time, and we're not pointing at some
|
||||||
|
// system overlay (like a window), then hide the reticle
|
||||||
|
if (Reticle.visible && !Reticle.pointingAtSystemOverlay) {
|
||||||
|
var now = Date.now();
|
||||||
|
var timeSinceLastMouseMove = now - lastMouseMove;
|
||||||
|
if (timeSinceLastMouseMove > HIDE_STATIC_MOUSE_AFTER) {
|
||||||
|
Reticle.visible = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkReticleDepth() {
|
||||||
var now = Date.now();
|
var now = Date.now();
|
||||||
var timeSinceLastDepthCheck = now - lastDepthCheckTime;
|
var timeSinceLastDepthCheck = now - lastDepthCheckTime;
|
||||||
if (timeSinceLastDepthCheck > TIME_BETWEEN_DEPTH_CHECKS) {
|
if (timeSinceLastDepthCheck > TIME_BETWEEN_DEPTH_CHECKS) {
|
||||||
|
@ -56,6 +139,9 @@ Script.update.connect(function(deltaTime) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function moveToDesiredDepth() {
|
||||||
// move the reticle toward the desired depth
|
// move the reticle toward the desired depth
|
||||||
if (desiredDepth != Reticle.depth) {
|
if (desiredDepth != Reticle.depth) {
|
||||||
|
|
||||||
|
@ -69,4 +155,13 @@ Script.update.connect(function(deltaTime) {
|
||||||
|
|
||||||
Reticle.setDepth(newDepth);
|
Reticle.setDepth(newDepth);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Script.update.connect(function(deltaTime) {
|
||||||
|
autoHideReticle(); // auto hide reticle for desktop or HMD mode
|
||||||
|
if (HMD.active) {
|
||||||
|
seekToLookAt(); // handle moving the reticle toward the look at
|
||||||
|
checkReticleDepth(); // make sure reticle is at correct depth
|
||||||
|
moveToDesiredDepth(); // move the fade the reticle to the desired depth
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -711,13 +711,32 @@ var intersection;
|
||||||
|
|
||||||
var SCALE_FACTOR = 200.0;
|
var SCALE_FACTOR = 200.0;
|
||||||
|
|
||||||
function rayPlaneIntersection(pickRay, point, normal) {
|
function rayPlaneIntersection(pickRay, point, normal) { //
|
||||||
|
//
|
||||||
|
// This version of the test returns the intersection of a line with a plane
|
||||||
|
//
|
||||||
|
var collides = Vec3.dot(pickRay.direction, normal);
|
||||||
|
|
||||||
var d = -Vec3.dot(point, normal);
|
var d = -Vec3.dot(point, normal);
|
||||||
var t = -(Vec3.dot(pickRay.origin, normal) + d) / Vec3.dot(pickRay.direction, normal);
|
var t = -(Vec3.dot(pickRay.origin, normal) + d) / collides;
|
||||||
|
|
||||||
return Vec3.sum(pickRay.origin, Vec3.multiply(pickRay.direction, t));
|
return Vec3.sum(pickRay.origin, Vec3.multiply(pickRay.direction, t));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function rayPlaneIntersection2(pickRay, point, normal) {
|
||||||
|
//
|
||||||
|
// This version of the test returns false if the ray is directed away from the plane
|
||||||
|
//
|
||||||
|
var collides = Vec3.dot(pickRay.direction, normal);
|
||||||
|
var d = -Vec3.dot(point, normal);
|
||||||
|
var t = -(Vec3.dot(pickRay.origin, normal) + d) / collides;
|
||||||
|
if (t < 0.0) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return Vec3.sum(pickRay.origin, Vec3.multiply(pickRay.direction, t));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function findClickedEntity(event) {
|
function findClickedEntity(event) {
|
||||||
var pickZones = event.isControl;
|
var pickZones = event.isControl;
|
||||||
|
|
||||||
|
@ -758,7 +777,8 @@ function findClickedEntity(event) {
|
||||||
var foundEntity = result.entityID;
|
var foundEntity = result.entityID;
|
||||||
return {
|
return {
|
||||||
pickRay: pickRay,
|
pickRay: pickRay,
|
||||||
entityID: foundEntity
|
entityID: foundEntity,
|
||||||
|
intersection: result.intersection
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -926,6 +946,7 @@ function mouseReleaseEvent(event) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function mouseClickEvent(event) {
|
function mouseClickEvent(event) {
|
||||||
|
var wantDebug = false;
|
||||||
if (isActive && event.isLeftButton) {
|
if (isActive && event.isLeftButton) {
|
||||||
var result = findClickedEntity(event);
|
var result = findClickedEntity(event);
|
||||||
if (result === null) {
|
if (result === null) {
|
||||||
|
@ -940,11 +961,15 @@ function mouseClickEvent(event) {
|
||||||
|
|
||||||
var properties = Entities.getEntityProperties(foundEntity);
|
var properties = Entities.getEntityProperties(foundEntity);
|
||||||
if (isLocked(properties)) {
|
if (isLocked(properties)) {
|
||||||
print("Model locked " + properties.id);
|
if (wantDebug) {
|
||||||
|
print("Model locked " + properties.id);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
var halfDiagonal = Vec3.length(properties.dimensions) / 2.0;
|
var halfDiagonal = Vec3.length(properties.dimensions) / 2.0;
|
||||||
|
|
||||||
print("Checking properties: " + properties.id + " " + " - Half Diagonal:" + halfDiagonal);
|
if (wantDebug) {
|
||||||
|
print("Checking properties: " + properties.id + " " + " - Half Diagonal:" + halfDiagonal);
|
||||||
|
}
|
||||||
// P P - Model
|
// P P - Model
|
||||||
// /| A - Palm
|
// /| A - Palm
|
||||||
// / | d B - unit vector toward tip
|
// / | d B - unit vector toward tip
|
||||||
|
@ -981,8 +1006,9 @@ function mouseClickEvent(event) {
|
||||||
} else {
|
} else {
|
||||||
selectionManager.addEntity(foundEntity, true);
|
selectionManager.addEntity(foundEntity, true);
|
||||||
}
|
}
|
||||||
|
if (wantDebug) {
|
||||||
print("Model selected: " + foundEntity);
|
print("Model selected: " + foundEntity);
|
||||||
|
}
|
||||||
selectionDisplay.select(selectedEntityID, event);
|
selectionDisplay.select(selectedEntityID, event);
|
||||||
|
|
||||||
if (Menu.isOptionChecked(MENU_AUTO_FOCUS_ON_SELECT)) {
|
if (Menu.isOptionChecked(MENU_AUTO_FOCUS_ON_SELECT)) {
|
||||||
|
|
|
@ -16,6 +16,11 @@ HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/";
|
||||||
SPACE_LOCAL = "local";
|
SPACE_LOCAL = "local";
|
||||||
SPACE_WORLD = "world";
|
SPACE_WORLD = "world";
|
||||||
|
|
||||||
|
function objectTranslationPlanePoint(position, dimensions) {
|
||||||
|
var newPosition = { x: position.x, y: position.y, z: position.z };
|
||||||
|
newPosition.y -= dimensions.y / 2.0;
|
||||||
|
return newPosition;
|
||||||
|
}
|
||||||
|
|
||||||
SelectionManager = (function() {
|
SelectionManager = (function() {
|
||||||
var that = {};
|
var that = {};
|
||||||
|
@ -2252,15 +2257,20 @@ SelectionDisplay = (function() {
|
||||||
var constrainMajorOnly = false;
|
var constrainMajorOnly = false;
|
||||||
var startPosition = null;
|
var startPosition = null;
|
||||||
var duplicatedEntityIDs = null;
|
var duplicatedEntityIDs = null;
|
||||||
|
|
||||||
var translateXZTool = {
|
var translateXZTool = {
|
||||||
mode: 'TRANSLATE_XZ',
|
mode: 'TRANSLATE_XZ',
|
||||||
|
pickPlanePosition: { x: 0, y: 0, z: 0 },
|
||||||
|
greatestDimension: 0.0,
|
||||||
|
startingDistance: 0.0,
|
||||||
|
startingElevation: 0.0,
|
||||||
onBegin: function(event) {
|
onBegin: function(event) {
|
||||||
SelectionManager.saveProperties();
|
SelectionManager.saveProperties();
|
||||||
startPosition = SelectionManager.worldPosition;
|
startPosition = SelectionManager.worldPosition;
|
||||||
var dimensions = SelectionManager.worldDimensions;
|
var dimensions = SelectionManager.worldDimensions;
|
||||||
|
|
||||||
var pickRay = Camera.computePickRay(event.x, event.y);
|
var pickRay = Camera.computePickRay(event.x, event.y);
|
||||||
initialXZPick = rayPlaneIntersection(pickRay, startPosition, {
|
initialXZPick = rayPlaneIntersection(pickRay, translateXZTool.pickPlanePosition, {
|
||||||
x: 0,
|
x: 0,
|
||||||
y: 1,
|
y: 1,
|
||||||
z: 0
|
z: 0
|
||||||
|
@ -2297,16 +2307,56 @@ SelectionDisplay = (function() {
|
||||||
visible: false
|
visible: false
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
elevation: function(origin, intersection) {
|
||||||
|
return (origin.y - intersection.y) / Vec3.distance(origin, intersection);
|
||||||
|
},
|
||||||
onMove: function(event) {
|
onMove: function(event) {
|
||||||
|
var wantDebug = false;
|
||||||
pickRay = Camera.computePickRay(event.x, event.y);
|
pickRay = Camera.computePickRay(event.x, event.y);
|
||||||
|
|
||||||
var pick = rayPlaneIntersection(pickRay, SelectionManager.worldPosition, {
|
var pick = rayPlaneIntersection2(pickRay, translateXZTool.pickPlanePosition, {
|
||||||
x: 0,
|
x: 0,
|
||||||
y: 1,
|
y: 1,
|
||||||
z: 0
|
z: 0
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// If the pick ray doesn't hit the pick plane in this direction, do nothing.
|
||||||
|
// this will happen when someone drags across the horizon from the side they started on.
|
||||||
|
if (!pick) {
|
||||||
|
if (wantDebug) {
|
||||||
|
print("Pick ray does not intersect XZ plane.");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var vector = Vec3.subtract(pick, initialXZPick);
|
var vector = Vec3.subtract(pick, initialXZPick);
|
||||||
|
|
||||||
|
// If the mouse is too close to the horizon of the pick plane, stop moving
|
||||||
|
var MIN_ELEVATION = 0.02; // largest dimension of object divided by distance to it
|
||||||
|
var elevation = translateXZTool.elevation(pickRay.origin, pick);
|
||||||
|
if (wantDebug) {
|
||||||
|
print("Start Elevation: " + translateXZTool.startingElevation + ", elevation: " + elevation);
|
||||||
|
}
|
||||||
|
if ((translateXZTool.startingElevation > 0.0 && elevation < MIN_ELEVATION) ||
|
||||||
|
(translateXZTool.startingElevation < 0.0 && elevation > -MIN_ELEVATION)) {
|
||||||
|
if (wantDebug) {
|
||||||
|
print("too close to horizon!");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the angular size of the object is too small, stop moving
|
||||||
|
var MIN_ANGULAR_SIZE = 0.01; // Radians
|
||||||
|
if (translateXZTool.greatestDimension > 0) {
|
||||||
|
var angularSize = Math.atan(translateXZTool.greatestDimension / Vec3.distance(pickRay.origin, pick));
|
||||||
|
if (wantDebug) {
|
||||||
|
print("Angular size = " + angularSize);
|
||||||
|
}
|
||||||
|
if (angularSize < MIN_ANGULAR_SIZE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// If shifted, constrain to one axis
|
// If shifted, constrain to one axis
|
||||||
if (event.isShifted) {
|
if (event.isShifted) {
|
||||||
if (Math.abs(vector.x) > Math.abs(vector.z)) {
|
if (Math.abs(vector.x) > Math.abs(vector.z)) {
|
||||||
|
@ -2368,7 +2418,7 @@ SelectionDisplay = (function() {
|
||||||
grid.snapToGrid(Vec3.sum(cornerPosition, vector), constrainMajorOnly),
|
grid.snapToGrid(Vec3.sum(cornerPosition, vector), constrainMajorOnly),
|
||||||
cornerPosition);
|
cornerPosition);
|
||||||
|
|
||||||
var wantDebug = false;
|
|
||||||
|
|
||||||
for (var i = 0; i < SelectionManager.selections.length; i++) {
|
for (var i = 0; i < SelectionManager.selections.length; i++) {
|
||||||
var properties = SelectionManager.savedProperties[SelectionManager.selections[i]];
|
var properties = SelectionManager.savedProperties[SelectionManager.selections[i]];
|
||||||
|
@ -2645,11 +2695,6 @@ SelectionDisplay = (function() {
|
||||||
pickRayPosition,
|
pickRayPosition,
|
||||||
planeNormal);
|
planeNormal);
|
||||||
|
|
||||||
// Overlays.editOverlay(normalLine, {
|
|
||||||
// start: initialPosition,
|
|
||||||
// end: Vec3.sum(Vec3.multiply(100000, planeNormal), initialPosition),
|
|
||||||
// });
|
|
||||||
|
|
||||||
SelectionManager.saveProperties();
|
SelectionManager.saveProperties();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -3751,7 +3796,7 @@ SelectionDisplay = (function() {
|
||||||
};
|
};
|
||||||
|
|
||||||
that.mousePressEvent = function(event) {
|
that.mousePressEvent = function(event) {
|
||||||
|
var wantDebug = false;
|
||||||
if (!event.isLeftButton) {
|
if (!event.isLeftButton) {
|
||||||
// if another mouse button than left is pressed ignore it
|
// if another mouse button than left is pressed ignore it
|
||||||
return false;
|
return false;
|
||||||
|
@ -3777,7 +3822,7 @@ SelectionDisplay = (function() {
|
||||||
|
|
||||||
if (result.intersects) {
|
if (result.intersects) {
|
||||||
|
|
||||||
var wantDebug = false;
|
|
||||||
if (wantDebug) {
|
if (wantDebug) {
|
||||||
print("something intersects... ");
|
print("something intersects... ");
|
||||||
print(" result.overlayID:" + result.overlayID + "[" + overlayNames[result.overlayID] + "]");
|
print(" result.overlayID:" + result.overlayID + "[" + overlayNames[result.overlayID] + "]");
|
||||||
|
@ -3874,7 +3919,10 @@ SelectionDisplay = (function() {
|
||||||
|
|
||||||
if (!somethingClicked) {
|
if (!somethingClicked) {
|
||||||
|
|
||||||
print("rotate handle case...");
|
if (wantDebug) {
|
||||||
|
print("rotate handle case...");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// After testing our stretch handles, then check out rotate handles
|
// After testing our stretch handles, then check out rotate handles
|
||||||
Overlays.editOverlay(yawHandle, {
|
Overlays.editOverlay(yawHandle, {
|
||||||
|
@ -3942,15 +3990,17 @@ SelectionDisplay = (function() {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
print("mousePressEvent()...... " + overlayNames[result.overlayID]);
|
if (wantDebug) {
|
||||||
|
print("mousePressEvent()...... " + overlayNames[result.overlayID]);
|
||||||
|
}
|
||||||
mode = "UNKNOWN";
|
mode = "UNKNOWN";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (wantDebug) {
|
||||||
print(" somethingClicked:" + somethingClicked);
|
print(" somethingClicked:" + somethingClicked);
|
||||||
print(" mode:" + mode);
|
print(" mode:" + mode);
|
||||||
|
}
|
||||||
|
|
||||||
if (somethingClicked) {
|
if (somethingClicked) {
|
||||||
|
|
||||||
|
@ -4093,12 +4143,25 @@ SelectionDisplay = (function() {
|
||||||
switch (result.overlayID) {
|
switch (result.overlayID) {
|
||||||
case selectionBox:
|
case selectionBox:
|
||||||
activeTool = translateXZTool;
|
activeTool = translateXZTool;
|
||||||
|
translateXZTool.pickPlanePosition = result.intersection;
|
||||||
|
translateXZTool.greatestDimension = Math.max(Math.max(SelectionManager.worldDimensions.x, SelectionManager.worldDimensions.y),
|
||||||
|
SelectionManager.worldDimensions.z);
|
||||||
|
if (wantDebug) {
|
||||||
|
print("longest dimension: " + translateXZTool.greatestDimension);
|
||||||
|
translateXZTool.startingDistance = Vec3.distance(pickRay.origin, SelectionManager.position);
|
||||||
|
print("starting distance: " + translateXZTool.startingDistance);
|
||||||
|
translateXZTool.startingElevation = translateXZTool.elevation(pickRay.origin, translateXZTool.pickPlanePosition);
|
||||||
|
print(" starting elevation: " + translateXZTool.startingElevation);
|
||||||
|
}
|
||||||
|
|
||||||
mode = translateXZTool.mode;
|
mode = translateXZTool.mode;
|
||||||
activeTool.onBegin(event);
|
activeTool.onBegin(event);
|
||||||
somethingClicked = true;
|
somethingClicked = true;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
print("mousePressEvent()...... " + overlayNames[result.overlayID]);
|
if (wantDebug) {
|
||||||
|
print("mousePressEvent()...... " + overlayNames[result.overlayID]);
|
||||||
|
}
|
||||||
mode = "UNKNOWN";
|
mode = "UNKNOWN";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -153,25 +153,6 @@ std::shared_ptr<Avatar> AvatarActionHold::getTarget(float deltaTimeStep, glm::qu
|
||||||
palmPosition = holdingAvatar->getLeftPalmPosition();
|
palmPosition = holdingAvatar->getLeftPalmPosition();
|
||||||
palmRotation = holdingAvatar->getLeftPalmRotation();
|
palmRotation = holdingAvatar->getLeftPalmRotation();
|
||||||
}
|
}
|
||||||
|
|
||||||
// In this case we are simulating the grab of another avatar.
|
|
||||||
// Because the hand controller velocity for their palms is not transmitted over the
|
|
||||||
// network, we have to synthesize our own.
|
|
||||||
|
|
||||||
if (_previousSet) {
|
|
||||||
// smooth linear velocity over two frames
|
|
||||||
glm::vec3 positionalDelta = palmPosition - _previousPositionalTarget;
|
|
||||||
linearVelocity = (positionalDelta + _previousPositionalDelta) / (deltaTimeStep + _previousDeltaTimeStep);
|
|
||||||
glm::quat deltaRotation = palmRotation * glm::inverse(_previousRotationalTarget);
|
|
||||||
float rotationAngle = glm::angle(deltaRotation);
|
|
||||||
if (rotationAngle > EPSILON) {
|
|
||||||
angularVelocity = glm::normalize(glm::axis(deltaRotation));
|
|
||||||
angularVelocity *= (rotationAngle / deltaTimeStep);
|
|
||||||
}
|
|
||||||
|
|
||||||
_previousPositionalDelta = positionalDelta;
|
|
||||||
_previousDeltaTimeStep = deltaTimeStep;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rotation = palmRotation * _relativeRotation;
|
rotation = palmRotation * _relativeRotation;
|
||||||
|
@ -278,6 +259,7 @@ void AvatarActionHold::doKinematicUpdate(float deltaTimeStep) {
|
||||||
});
|
});
|
||||||
|
|
||||||
forceBodyNonStatic();
|
forceBodyNonStatic();
|
||||||
|
activateBody(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AvatarActionHold::updateArguments(QVariantMap arguments) {
|
bool AvatarActionHold::updateArguments(QVariantMap arguments) {
|
||||||
|
|
|
@ -212,19 +212,21 @@ void ApplicationCompositor::displayOverlayTexture(RenderArgs* renderArgs) {
|
||||||
geometryCache->renderUnitQuad(batch, vec4(vec3(1), _alpha));
|
geometryCache->renderUnitQuad(batch, vec4(vec3(1), _alpha));
|
||||||
|
|
||||||
//draw the mouse pointer
|
//draw the mouse pointer
|
||||||
// Get the mouse coordinates and convert to NDC [-1, 1]
|
if (getReticleVisible()) {
|
||||||
vec2 canvasSize = qApp->getCanvasSize(); // desktop, use actual canvas...
|
// Get the mouse coordinates and convert to NDC [-1, 1]
|
||||||
vec2 mousePosition = toNormalizedDeviceScale(vec2(qApp->getMouse()), canvasSize);
|
vec2 canvasSize = qApp->getCanvasSize(); // desktop, use actual canvas...
|
||||||
// Invert the Y axis
|
vec2 mousePosition = toNormalizedDeviceScale(vec2(qApp->getMouse()), canvasSize);
|
||||||
mousePosition.y *= -1.0f;
|
// Invert the Y axis
|
||||||
|
mousePosition.y *= -1.0f;
|
||||||
|
|
||||||
Transform model;
|
Transform model;
|
||||||
model.setTranslation(vec3(mousePosition, 0));
|
model.setTranslation(vec3(mousePosition, 0));
|
||||||
vec2 mouseSize = CURSOR_PIXEL_SIZE / canvasSize;
|
vec2 mouseSize = CURSOR_PIXEL_SIZE / canvasSize;
|
||||||
model.setScale(vec3(mouseSize, 1.0f));
|
model.setScale(vec3(mouseSize, 1.0f));
|
||||||
batch.setModelTransform(model);
|
batch.setModelTransform(model);
|
||||||
bindCursorTexture(batch);
|
bindCursorTexture(batch);
|
||||||
geometryCache->renderUnitQuad(batch, vec4(1));
|
geometryCache->renderUnitQuad(batch, vec4(1));
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
|
|
||||||
#include "EntityItemID.h"
|
#include "EntityItemID.h"
|
||||||
#include <VariantMapToScriptValue.h>
|
#include <VariantMapToScriptValue.h>
|
||||||
|
#include <SpatialParentFinder.h>
|
||||||
|
|
||||||
#include "EntitiesLogging.h"
|
#include "EntitiesLogging.h"
|
||||||
#include "EntityActionFactoryInterface.h"
|
#include "EntityActionFactoryInterface.h"
|
||||||
|
@ -1063,6 +1064,34 @@ QStringList EntityScriptingInterface::getJointNames(const QUuid& entityID) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QVector<QUuid> EntityScriptingInterface::getChildrenIDsOfJoint(const QUuid& parentID, int jointIndex) {
|
||||||
|
QVector<QUuid> result;
|
||||||
|
if (!_entityTree) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
_entityTree->withReadLock([&] {
|
||||||
|
QSharedPointer<SpatialParentFinder> parentFinder = DependencyManager::get<SpatialParentFinder>();
|
||||||
|
if (!parentFinder) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
bool success;
|
||||||
|
SpatiallyNestableWeakPointer parentWP = parentFinder->find(parentID, success);
|
||||||
|
if (!success) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
SpatiallyNestablePointer parent = parentWP.lock();
|
||||||
|
if (!parent) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
parent->forEachChild([&](SpatiallyNestablePointer child) {
|
||||||
|
if (child->getParentJointIndex() == jointIndex) {
|
||||||
|
result.push_back(child->getID());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
float EntityScriptingInterface::calculateCost(float mass, float oldVelocity, float newVelocity) {
|
float EntityScriptingInterface::calculateCost(float mass, float oldVelocity, float newVelocity) {
|
||||||
return std::abs(mass * (newVelocity - oldVelocity));
|
return std::abs(mass * (newVelocity - oldVelocity));
|
||||||
}
|
}
|
||||||
|
|
|
@ -168,7 +168,7 @@ public slots:
|
||||||
|
|
||||||
Q_INVOKABLE int getJointIndex(const QUuid& entityID, const QString& name);
|
Q_INVOKABLE int getJointIndex(const QUuid& entityID, const QString& name);
|
||||||
Q_INVOKABLE QStringList getJointNames(const QUuid& entityID);
|
Q_INVOKABLE QStringList getJointNames(const QUuid& entityID);
|
||||||
|
Q_INVOKABLE QVector<QUuid> getChildrenIDsOfJoint(const QUuid& parentID, int jointIndex);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void collisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, const Collision& collision);
|
void collisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, const Collision& collision);
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#include "SpatiallyNestable.h"
|
#include "SpatiallyNestable.h"
|
||||||
|
|
||||||
const float defaultAACubeSize = 1.0f;
|
const float defaultAACubeSize = 1.0f;
|
||||||
|
const int maxParentingChain = 30;
|
||||||
|
|
||||||
SpatiallyNestable::SpatiallyNestable(NestableType nestableType, QUuid id) :
|
SpatiallyNestable::SpatiallyNestable(NestableType nestableType, QUuid id) :
|
||||||
_nestableType(nestableType),
|
_nestableType(nestableType),
|
||||||
|
@ -56,14 +57,14 @@ void SpatiallyNestable::setParentID(const QUuid& parentID) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Transform SpatiallyNestable::getParentTransform(bool& success) const {
|
Transform SpatiallyNestable::getParentTransform(bool& success, int depth) const {
|
||||||
Transform result;
|
Transform result;
|
||||||
SpatiallyNestablePointer parent = getParentPointer(success);
|
SpatiallyNestablePointer parent = getParentPointer(success);
|
||||||
if (!success) {
|
if (!success) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
if (parent) {
|
if (parent) {
|
||||||
Transform parentTransform = parent->getTransform(_parentJointIndex, success);
|
Transform parentTransform = parent->getTransform(_parentJointIndex, success, depth + 1);
|
||||||
result = parentTransform.setScale(1.0f); // TODO: scaling
|
result = parentTransform.setScale(1.0f); // TODO: scaling
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
|
@ -393,11 +394,11 @@ void SpatiallyNestable::setOrientation(const glm::quat& orientation) {
|
||||||
|
|
||||||
glm::vec3 SpatiallyNestable::getVelocity(bool& success) const {
|
glm::vec3 SpatiallyNestable::getVelocity(bool& success) const {
|
||||||
glm::vec3 result;
|
glm::vec3 result;
|
||||||
glm::vec3 parentVelocity = getParentVelocity(success);
|
Transform parentTransform = getParentTransform(success);
|
||||||
if (!success) {
|
if (!success) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
Transform parentTransform = getParentTransform(success);
|
glm::vec3 parentVelocity = getParentVelocity(success);
|
||||||
if (!success) {
|
if (!success) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -448,11 +449,11 @@ glm::vec3 SpatiallyNestable::getParentVelocity(bool& success) const {
|
||||||
|
|
||||||
glm::vec3 SpatiallyNestable::getAngularVelocity(bool& success) const {
|
glm::vec3 SpatiallyNestable::getAngularVelocity(bool& success) const {
|
||||||
glm::vec3 result;
|
glm::vec3 result;
|
||||||
glm::vec3 parentAngularVelocity = getParentAngularVelocity(success);
|
Transform parentTransform = getParentTransform(success);
|
||||||
if (!success) {
|
if (!success) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
Transform parentTransform = getParentTransform(success);
|
glm::vec3 parentAngularVelocity = getParentAngularVelocity(success);
|
||||||
if (!success) {
|
if (!success) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -499,22 +500,36 @@ glm::vec3 SpatiallyNestable::getParentAngularVelocity(bool& success) const {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Transform SpatiallyNestable::getTransform(bool& success) const {
|
const Transform SpatiallyNestable::getTransform(bool& success, int depth) const {
|
||||||
// return a world-space transform for this object's location
|
|
||||||
Transform parentTransform = getParentTransform(success);
|
|
||||||
Transform result;
|
Transform result;
|
||||||
|
// return a world-space transform for this object's location
|
||||||
|
Transform parentTransform = getParentTransform(success, depth);
|
||||||
_transformLock.withReadLock([&] {
|
_transformLock.withReadLock([&] {
|
||||||
Transform::mult(result, parentTransform, _transform);
|
Transform::mult(result, parentTransform, _transform);
|
||||||
});
|
});
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Transform SpatiallyNestable::getTransform(int jointIndex, bool& success) const {
|
const Transform SpatiallyNestable::getTransform(int jointIndex, bool& success, int depth) const {
|
||||||
// this returns the world-space transform for this object. It finds its parent's transform (which may
|
// this returns the world-space transform for this object. It finds its parent's transform (which may
|
||||||
// cause this object's parent to query its parent, etc) and multiplies this object's local transform onto it.
|
// cause this object's parent to query its parent, etc) and multiplies this object's local transform onto it.
|
||||||
Transform jointInWorldFrame;
|
Transform jointInWorldFrame;
|
||||||
|
|
||||||
Transform worldTransform = getTransform(success);
|
if (depth > maxParentingChain) {
|
||||||
|
success = false;
|
||||||
|
// someone created a loop. break it...
|
||||||
|
qDebug() << "Parenting loop detected.";
|
||||||
|
SpatiallyNestablePointer _this = getThisPointer();
|
||||||
|
_this->setParentID(QUuid());
|
||||||
|
bool setPositionSuccess;
|
||||||
|
AACube aaCube = getQueryAACube(setPositionSuccess);
|
||||||
|
if (setPositionSuccess) {
|
||||||
|
_this->setPosition(aaCube.calcCenter());
|
||||||
|
}
|
||||||
|
return jointInWorldFrame;
|
||||||
|
}
|
||||||
|
|
||||||
|
Transform worldTransform = getTransform(success, depth);
|
||||||
worldTransform.setScale(1.0f); // TODO -- scale;
|
worldTransform.setScale(1.0f); // TODO -- scale;
|
||||||
if (!success) {
|
if (!success) {
|
||||||
return jointInWorldFrame;
|
return jointInWorldFrame;
|
||||||
|
@ -682,7 +697,7 @@ QList<SpatiallyNestablePointer> SpatiallyNestable::getChildren() const {
|
||||||
_childrenLock.withReadLock([&] {
|
_childrenLock.withReadLock([&] {
|
||||||
foreach(SpatiallyNestableWeakPointer childWP, _children.values()) {
|
foreach(SpatiallyNestableWeakPointer childWP, _children.values()) {
|
||||||
SpatiallyNestablePointer child = childWP.lock();
|
SpatiallyNestablePointer child = childWP.lock();
|
||||||
if (child) {
|
if (child && child->_parentKnowsMe && child->getParentID() == getID()) {
|
||||||
children << child;
|
children << child;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,10 +52,10 @@ public:
|
||||||
static glm::quat localToWorld(const glm::quat& orientation, const QUuid& parentID, int parentJointIndex, bool& success);
|
static glm::quat localToWorld(const glm::quat& orientation, const QUuid& parentID, int parentJointIndex, bool& success);
|
||||||
|
|
||||||
// world frame
|
// world frame
|
||||||
virtual const Transform getTransform(bool& success) const;
|
virtual const Transform getTransform(bool& success, int depth = 0) const;
|
||||||
virtual void setTransform(const Transform& transform, bool& success);
|
virtual void setTransform(const Transform& transform, bool& success);
|
||||||
|
|
||||||
virtual Transform getParentTransform(bool& success) const;
|
virtual Transform getParentTransform(bool& success, int depth = 0) const;
|
||||||
|
|
||||||
virtual glm::vec3 getPosition(bool& success) const;
|
virtual glm::vec3 getPosition(bool& success) const;
|
||||||
virtual glm::vec3 getPosition() const;
|
virtual glm::vec3 getPosition() const;
|
||||||
|
@ -92,7 +92,7 @@ public:
|
||||||
virtual void setScale(const glm::vec3& scale);
|
virtual void setScale(const glm::vec3& scale);
|
||||||
|
|
||||||
// get world-frame values for a specific joint
|
// get world-frame values for a specific joint
|
||||||
virtual const Transform getTransform(int jointIndex, bool& success) const;
|
virtual const Transform getTransform(int jointIndex, bool& success, int depth = 0) const;
|
||||||
virtual glm::vec3 getPosition(int jointIndex, bool& success) const;
|
virtual glm::vec3 getPosition(int jointIndex, bool& success) const;
|
||||||
virtual glm::vec3 getScale(int jointIndex) const;
|
virtual glm::vec3 getScale(int jointIndex) const;
|
||||||
|
|
||||||
|
|
|
@ -60,10 +60,10 @@ void ViveControllerManager::activate() {
|
||||||
[this] (bool clicked) { this->setRenderControllers(clicked); },
|
[this] (bool clicked) { this->setRenderControllers(clicked); },
|
||||||
true, true);
|
true, true);
|
||||||
|
|
||||||
if (!_hmd) {
|
if (!_system) {
|
||||||
_hmd = acquireOpenVrSystem();
|
_system = acquireOpenVrSystem();
|
||||||
}
|
}
|
||||||
Q_ASSERT(_hmd);
|
Q_ASSERT(_system);
|
||||||
|
|
||||||
// OpenVR provides 3d mesh representations of the controllers
|
// OpenVR provides 3d mesh representations of the controllers
|
||||||
// Disabled controller rendering code
|
// Disabled controller rendering code
|
||||||
|
@ -71,7 +71,7 @@ void ViveControllerManager::activate() {
|
||||||
auto renderModels = vr::VRRenderModels();
|
auto renderModels = vr::VRRenderModels();
|
||||||
|
|
||||||
vr::RenderModel_t model;
|
vr::RenderModel_t model;
|
||||||
if (!_hmd->LoadRenderModel(CONTROLLER_MODEL_STRING, &model)) {
|
if (!_system->LoadRenderModel(CONTROLLER_MODEL_STRING, &model)) {
|
||||||
qDebug() << QString("Unable to load render model %1\n").arg(CONTROLLER_MODEL_STRING);
|
qDebug() << QString("Unable to load render model %1\n").arg(CONTROLLER_MODEL_STRING);
|
||||||
} else {
|
} else {
|
||||||
model::Mesh* mesh = new model::Mesh();
|
model::Mesh* mesh = new model::Mesh();
|
||||||
|
@ -118,7 +118,7 @@ void ViveControllerManager::activate() {
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// unregister with UserInputMapper
|
// register with UserInputMapper
|
||||||
auto userInputMapper = DependencyManager::get<controller::UserInputMapper>();
|
auto userInputMapper = DependencyManager::get<controller::UserInputMapper>();
|
||||||
userInputMapper->registerDevice(_inputDevice);
|
userInputMapper->registerDevice(_inputDevice);
|
||||||
_registeredWithInputMapper = true;
|
_registeredWithInputMapper = true;
|
||||||
|
@ -130,9 +130,9 @@ void ViveControllerManager::deactivate() {
|
||||||
_container->removeMenuItem(MENU_NAME, RENDER_CONTROLLERS);
|
_container->removeMenuItem(MENU_NAME, RENDER_CONTROLLERS);
|
||||||
_container->removeMenu(MENU_PATH);
|
_container->removeMenu(MENU_PATH);
|
||||||
|
|
||||||
if (_hmd) {
|
if (_system) {
|
||||||
releaseOpenVrSystem();
|
releaseOpenVrSystem();
|
||||||
_hmd = nullptr;
|
_system = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
_inputDevice->_poseStateMap.clear();
|
_inputDevice->_poseStateMap.clear();
|
||||||
|
@ -226,56 +226,56 @@ void ViveControllerManager::pluginUpdate(float deltaTime, const controller::Inpu
|
||||||
|
|
||||||
void ViveControllerManager::InputDevice::update(float deltaTime, const controller::InputCalibrationData& inputCalibrationData, bool jointsCaptured) {
|
void ViveControllerManager::InputDevice::update(float deltaTime, const controller::InputCalibrationData& inputCalibrationData, bool jointsCaptured) {
|
||||||
_poseStateMap.clear();
|
_poseStateMap.clear();
|
||||||
|
|
||||||
_buttonPressedMap.clear();
|
_buttonPressedMap.clear();
|
||||||
|
|
||||||
PerformanceTimer perfTimer("ViveControllerManager::update");
|
PerformanceTimer perfTimer("ViveControllerManager::update");
|
||||||
|
|
||||||
|
auto leftHandDeviceIndex = _system->GetTrackedDeviceIndexForControllerRole(vr::TrackedControllerRole_LeftHand);
|
||||||
|
auto rightHandDeviceIndex = _system->GetTrackedDeviceIndexForControllerRole(vr::TrackedControllerRole_RightHand);
|
||||||
|
|
||||||
|
if (!jointsCaptured) {
|
||||||
|
handleHandController(deltaTime, leftHandDeviceIndex, inputCalibrationData, true);
|
||||||
|
handleHandController(deltaTime, rightHandDeviceIndex, inputCalibrationData, false);
|
||||||
|
}
|
||||||
|
|
||||||
int numTrackedControllers = 0;
|
int numTrackedControllers = 0;
|
||||||
|
if (leftHandDeviceIndex != vr::k_unTrackedDeviceIndexInvalid) {
|
||||||
for (vr::TrackedDeviceIndex_t device = vr::k_unTrackedDeviceIndex_Hmd + 1;
|
|
||||||
device < vr::k_unMaxTrackedDeviceCount && numTrackedControllers < 2; ++device) {
|
|
||||||
|
|
||||||
if (!_hmd->IsTrackedDeviceConnected(device)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_hmd->GetTrackedDeviceClass(device) != vr::TrackedDeviceClass_Controller) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!_trackedDevicePose[device].bPoseIsValid) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
numTrackedControllers++;
|
numTrackedControllers++;
|
||||||
bool left = numTrackedControllers == 2;
|
}
|
||||||
|
if (rightHandDeviceIndex != vr::k_unTrackedDeviceIndexInvalid) {
|
||||||
|
numTrackedControllers++;
|
||||||
|
}
|
||||||
|
_trackedControllers = numTrackedControllers;
|
||||||
|
}
|
||||||
|
|
||||||
if (!jointsCaptured) {
|
void ViveControllerManager::InputDevice::handleHandController(float deltaTime, uint32_t deviceIndex, const controller::InputCalibrationData& inputCalibrationData, bool isLeftHand) {
|
||||||
const mat4& mat = _trackedDevicePoseMat4[device];
|
|
||||||
const vec3 linearVelocity = _trackedDeviceLinearVelocities[device];
|
if (_system->IsTrackedDeviceConnected(deviceIndex) &&
|
||||||
const vec3 angularVelocity = _trackedDeviceAngularVelocities[device];
|
_system->GetTrackedDeviceClass(deviceIndex) == vr::TrackedDeviceClass_Controller &&
|
||||||
handlePoseEvent(inputCalibrationData, mat, linearVelocity, angularVelocity, numTrackedControllers - 1);
|
_trackedDevicePose[deviceIndex].bPoseIsValid) {
|
||||||
}
|
|
||||||
|
// process pose
|
||||||
|
const mat4& mat = _trackedDevicePoseMat4[deviceIndex];
|
||||||
|
const vec3 linearVelocity = _trackedDeviceLinearVelocities[deviceIndex];
|
||||||
|
const vec3 angularVelocity = _trackedDeviceAngularVelocities[deviceIndex];
|
||||||
|
handlePoseEvent(deltaTime, inputCalibrationData, mat, linearVelocity, angularVelocity, isLeftHand);
|
||||||
|
|
||||||
// handle inputs
|
|
||||||
vr::VRControllerState_t controllerState = vr::VRControllerState_t();
|
vr::VRControllerState_t controllerState = vr::VRControllerState_t();
|
||||||
if (_hmd->GetControllerState(device, &controllerState)) {
|
if (_system->GetControllerState(deviceIndex, &controllerState)) {
|
||||||
//qDebug() << (numTrackedControllers == 1 ? "Left: " : "Right: ");
|
|
||||||
//qDebug() << "Trackpad: " << controllerState.rAxis[0].x << " " << controllerState.rAxis[0].y;
|
// process each button
|
||||||
//qDebug() << "Trigger: " << controllerState.rAxis[1].x << " " << controllerState.rAxis[1].y;
|
|
||||||
for (uint32_t i = 0; i < vr::k_EButton_Max; ++i) {
|
for (uint32_t i = 0; i < vr::k_EButton_Max; ++i) {
|
||||||
auto mask = vr::ButtonMaskFromId((vr::EVRButtonId)i);
|
auto mask = vr::ButtonMaskFromId((vr::EVRButtonId)i);
|
||||||
bool pressed = 0 != (controllerState.ulButtonPressed & mask);
|
bool pressed = 0 != (controllerState.ulButtonPressed & mask);
|
||||||
handleButtonEvent(i, pressed, left);
|
handleButtonEvent(deltaTime, i, pressed, isLeftHand);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// process each axis
|
||||||
for (uint32_t i = 0; i < vr::k_unControllerStateAxisCount; i++) {
|
for (uint32_t i = 0; i < vr::k_unControllerStateAxisCount; i++) {
|
||||||
handleAxisEvent(i, controllerState.rAxis[i].x, controllerState.rAxis[i].y, left);
|
handleAxisEvent(deltaTime, i, controllerState.rAxis[i].x, controllerState.rAxis[i].y, isLeftHand);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_trackedControllers = numTrackedControllers;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ViveControllerManager::InputDevice::focusOutEvent() {
|
void ViveControllerManager::InputDevice::focusOutEvent() {
|
||||||
|
@ -284,42 +284,46 @@ void ViveControllerManager::InputDevice::focusOutEvent() {
|
||||||
};
|
};
|
||||||
|
|
||||||
// These functions do translation from the Steam IDs to the standard controller IDs
|
// These functions do translation from the Steam IDs to the standard controller IDs
|
||||||
void ViveControllerManager::InputDevice::handleAxisEvent(uint32_t axis, float x, float y, bool left) {
|
void ViveControllerManager::InputDevice::handleAxisEvent(float deltaTime, uint32_t axis, float x, float y, bool isLeftHand) {
|
||||||
//FIX ME? It enters here every frame: probably we want to enter only if an event occurs
|
//FIX ME? It enters here every frame: probably we want to enter only if an event occurs
|
||||||
axis += vr::k_EButton_Axis0;
|
axis += vr::k_EButton_Axis0;
|
||||||
using namespace controller;
|
using namespace controller;
|
||||||
|
|
||||||
if (axis == vr::k_EButton_SteamVR_Touchpad) {
|
if (axis == vr::k_EButton_SteamVR_Touchpad) {
|
||||||
_axisStateMap[left ? LX : RX] = x;
|
glm::vec2 stick(x, y);
|
||||||
_axisStateMap[left ? LY : RY] = y;
|
if (isLeftHand) {
|
||||||
|
stick = _filteredLeftStick.process(deltaTime, stick);
|
||||||
|
} else {
|
||||||
|
stick = _filteredRightStick.process(deltaTime, stick);
|
||||||
|
}
|
||||||
|
_axisStateMap[isLeftHand ? LX : RX] = stick.x;
|
||||||
|
_axisStateMap[isLeftHand ? LY : RY] = stick.y;
|
||||||
} else if (axis == vr::k_EButton_SteamVR_Trigger) {
|
} else if (axis == vr::k_EButton_SteamVR_Trigger) {
|
||||||
_axisStateMap[left ? LT : RT] = x;
|
_axisStateMap[isLeftHand ? LT : RT] = x;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// These functions do translation from the Steam IDs to the standard controller IDs
|
// These functions do translation from the Steam IDs to the standard controller IDs
|
||||||
void ViveControllerManager::InputDevice::handleButtonEvent(uint32_t button, bool pressed, bool left) {
|
void ViveControllerManager::InputDevice::handleButtonEvent(float deltaTime, uint32_t button, bool pressed, bool isLeftHand) {
|
||||||
if (!pressed) {
|
if (!pressed) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
using namespace controller;
|
||||||
if (button == vr::k_EButton_ApplicationMenu) {
|
if (button == vr::k_EButton_ApplicationMenu) {
|
||||||
_buttonPressedMap.insert(left ? controller::LEFT_PRIMARY_THUMB : controller::RIGHT_PRIMARY_THUMB);
|
_buttonPressedMap.insert(isLeftHand ? LEFT_PRIMARY_THUMB : RIGHT_PRIMARY_THUMB);
|
||||||
} else if (button == vr::k_EButton_Grip) {
|
} else if (button == vr::k_EButton_Grip) {
|
||||||
// Tony says these are harder to reach, so make them the meta buttons
|
_buttonPressedMap.insert(isLeftHand ? LB : RB);
|
||||||
_buttonPressedMap.insert(left ? controller::LB : controller::RB);
|
|
||||||
} else if (button == vr::k_EButton_SteamVR_Trigger) {
|
} else if (button == vr::k_EButton_SteamVR_Trigger) {
|
||||||
_buttonPressedMap.insert(left ? controller::LT : controller::RT);
|
_buttonPressedMap.insert(isLeftHand ? LT : RT);
|
||||||
} else if (button == vr::k_EButton_SteamVR_Touchpad) {
|
} else if (button == vr::k_EButton_SteamVR_Touchpad) {
|
||||||
_buttonPressedMap.insert(left ? controller::LS : controller::RS);
|
_buttonPressedMap.insert(isLeftHand ? LS : RS);
|
||||||
} else if (button == vr::k_EButton_System) {
|
|
||||||
//FIX ME: not able to ovrewrite the behaviour of this button
|
|
||||||
_buttonPressedMap.insert(left ? controller::LEFT_SECONDARY_THUMB : controller::RIGHT_SECONDARY_THUMB);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ViveControllerManager::InputDevice::handlePoseEvent(const controller::InputCalibrationData& inputCalibrationData,
|
void ViveControllerManager::InputDevice::handlePoseEvent(float deltaTime, const controller::InputCalibrationData& inputCalibrationData,
|
||||||
const mat4& mat, const vec3& linearVelocity,
|
const mat4& mat, const vec3& linearVelocity,
|
||||||
const vec3& angularVelocity, bool left) {
|
const vec3& angularVelocity, bool isLeftHand) {
|
||||||
// When the sensor-to-world rotation is identity the coordinate axes look like this:
|
// When the sensor-to-world rotation is identity the coordinate axes look like this:
|
||||||
//
|
//
|
||||||
// user
|
// user
|
||||||
|
@ -384,8 +388,8 @@ void ViveControllerManager::InputDevice::handlePoseEvent(const controller::Input
|
||||||
static const glm::vec3 leftTranslationOffset = glm::vec3(-1.0f, 1.0f, 1.0f) * CONTROLLER_OFFSET;
|
static const glm::vec3 leftTranslationOffset = glm::vec3(-1.0f, 1.0f, 1.0f) * CONTROLLER_OFFSET;
|
||||||
static const glm::vec3 rightTranslationOffset = CONTROLLER_OFFSET;
|
static const glm::vec3 rightTranslationOffset = CONTROLLER_OFFSET;
|
||||||
|
|
||||||
auto translationOffset = (left ? leftTranslationOffset : rightTranslationOffset);
|
auto translationOffset = (isLeftHand ? leftTranslationOffset : rightTranslationOffset);
|
||||||
auto rotationOffset = (left ? leftRotationOffset : rightRotationOffset);
|
auto rotationOffset = (isLeftHand ? leftRotationOffset : rightRotationOffset);
|
||||||
|
|
||||||
glm::vec3 position = extractTranslation(mat);
|
glm::vec3 position = extractTranslation(mat);
|
||||||
glm::quat rotation = glm::normalize(glm::quat_cast(mat));
|
glm::quat rotation = glm::normalize(glm::quat_cast(mat));
|
||||||
|
@ -399,7 +403,7 @@ void ViveControllerManager::InputDevice::handlePoseEvent(const controller::Input
|
||||||
// handle change in velocity due to translationOffset
|
// handle change in velocity due to translationOffset
|
||||||
avatarPose.velocity = linearVelocity + glm::cross(angularVelocity, position - extractTranslation(mat));
|
avatarPose.velocity = linearVelocity + glm::cross(angularVelocity, position - extractTranslation(mat));
|
||||||
avatarPose.angularVelocity = angularVelocity;
|
avatarPose.angularVelocity = angularVelocity;
|
||||||
_poseStateMap[left ? controller::LEFT_HAND : controller::RIGHT_HAND] = avatarPose.transform(controllerToAvatar);
|
_poseStateMap[isLeftHand ? controller::LEFT_HAND : controller::RIGHT_HAND] = avatarPose.transform(controllerToAvatar);
|
||||||
}
|
}
|
||||||
|
|
||||||
controller::Input::NamedVector ViveControllerManager::InputDevice::getAvailableInputs() const {
|
controller::Input::NamedVector ViveControllerManager::InputDevice::getAvailableInputs() const {
|
||||||
|
|
|
@ -50,7 +50,7 @@ public:
|
||||||
private:
|
private:
|
||||||
class InputDevice : public controller::InputDevice {
|
class InputDevice : public controller::InputDevice {
|
||||||
public:
|
public:
|
||||||
InputDevice(vr::IVRSystem*& hmd) : controller::InputDevice("Vive"), _hmd(hmd) {}
|
InputDevice(vr::IVRSystem*& system) : controller::InputDevice("Vive"), _system(system) {}
|
||||||
private:
|
private:
|
||||||
// Device functions
|
// Device functions
|
||||||
virtual controller::Input::NamedVector getAvailableInputs() const override;
|
virtual controller::Input::NamedVector getAvailableInputs() const override;
|
||||||
|
@ -58,20 +58,46 @@ private:
|
||||||
virtual void update(float deltaTime, const controller::InputCalibrationData& inputCalibrationData, bool jointsCaptured) override;
|
virtual void update(float deltaTime, const controller::InputCalibrationData& inputCalibrationData, bool jointsCaptured) override;
|
||||||
virtual void focusOutEvent() override;
|
virtual void focusOutEvent() override;
|
||||||
|
|
||||||
void handleButtonEvent(uint32_t button, bool pressed, bool left);
|
void handleHandController(float deltaTime, uint32_t deviceIndex, const controller::InputCalibrationData& inputCalibrationData, bool isLeftHand);
|
||||||
void handleAxisEvent(uint32_t axis, float x, float y, bool left);
|
void handleButtonEvent(float deltaTime, uint32_t button, bool pressed, bool isLeftHand);
|
||||||
void handlePoseEvent(const controller::InputCalibrationData& inputCalibrationData, const mat4& mat,
|
void handleAxisEvent(float deltaTime, uint32_t axis, float x, float y, bool isLeftHand);
|
||||||
const vec3& linearVelocity, const vec3& angularVelocity, bool left);
|
void handlePoseEvent(float deltaTime, const controller::InputCalibrationData& inputCalibrationData, const mat4& mat,
|
||||||
|
const vec3& linearVelocity, const vec3& angularVelocity, bool isLeftHand);
|
||||||
|
|
||||||
|
class FilteredStick {
|
||||||
|
public:
|
||||||
|
glm::vec2 process(float deltaTime, const glm::vec2& stick) {
|
||||||
|
// Use a timer to prevent the stick going to back to zero.
|
||||||
|
// This to work around the noisy touch pad that will flash back to zero breifly
|
||||||
|
const float ZERO_HYSTERESIS_PERIOD = 0.2f; // 200 ms
|
||||||
|
if (glm::length(stick) == 0.0f) {
|
||||||
|
if (_timer <= 0.0f) {
|
||||||
|
return glm::vec2(0.0f, 0.0f);
|
||||||
|
} else {
|
||||||
|
_timer -= deltaTime;
|
||||||
|
return _stick;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
_timer = ZERO_HYSTERESIS_PERIOD;
|
||||||
|
_stick = stick;
|
||||||
|
return stick;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
protected:
|
||||||
|
float _timer { 0.0f };
|
||||||
|
glm::vec2 _stick { 0.0f, 0.0f };
|
||||||
|
};
|
||||||
|
|
||||||
|
FilteredStick _filteredLeftStick;
|
||||||
|
FilteredStick _filteredRightStick;
|
||||||
|
|
||||||
int _trackedControllers { 0 };
|
int _trackedControllers { 0 };
|
||||||
vr::IVRSystem*& _hmd;
|
vr::IVRSystem*& _system;
|
||||||
friend class ViveControllerManager;
|
friend class ViveControllerManager;
|
||||||
};
|
};
|
||||||
|
|
||||||
void renderHand(const controller::Pose& pose, gpu::Batch& batch, int sign);
|
void renderHand(const controller::Pose& pose, gpu::Batch& batch, int sign);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool _registeredWithInputMapper { false };
|
bool _registeredWithInputMapper { false };
|
||||||
bool _modelLoaded { false };
|
bool _modelLoaded { false };
|
||||||
model::Geometry _modelGeometry;
|
model::Geometry _modelGeometry;
|
||||||
|
@ -81,8 +107,8 @@ private:
|
||||||
int _rightHandRenderID { 0 };
|
int _rightHandRenderID { 0 };
|
||||||
|
|
||||||
bool _renderControllers { false };
|
bool _renderControllers { false };
|
||||||
vr::IVRSystem* _hmd { nullptr };
|
vr::IVRSystem* _system { nullptr };
|
||||||
std::shared_ptr<InputDevice> _inputDevice { std::make_shared<InputDevice>(_hmd) };
|
std::shared_ptr<InputDevice> _inputDevice { std::make_shared<InputDevice>(_system) };
|
||||||
|
|
||||||
static const QString NAME;
|
static const QString NAME;
|
||||||
|
|
||||||
|
|
|
@ -96,6 +96,9 @@
|
||||||
if (this.ballLocked === true) {
|
if (this.ballLocked === true) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if(this.ball!==null){
|
||||||
|
Entities.deleteEntity(this.ball);
|
||||||
|
}
|
||||||
|
|
||||||
var properties = {
|
var properties = {
|
||||||
name: 'Hifi Tilt Maze Ball',
|
name: 'Hifi Tilt Maze Ball',
|
||||||
|
|
Loading…
Reference in a new issue