Merge pull request #13619 from luiscuenca/handTouchDisabler

Allow creators to disable hand touch from javascript
This commit is contained in:
Qliemillar 2018-07-18 08:16:37 -06:00 committed by GitHub
commit 080d664341
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 351 additions and 270 deletions

View file

@ -262,6 +262,26 @@ void MyAvatar::setDominantHand(const QString& hand) {
}
}
void MyAvatar::requestDisableHandTouch() {
std::lock_guard<std::mutex> guard(_disableHandTouchMutex);
_disableHandTouchCount++;
emit shouldDisableHandTouchChanged(_disableHandTouchCount > 0);
}
void MyAvatar::requestEnableHandTouch() {
std::lock_guard<std::mutex> guard(_disableHandTouchMutex);
_disableHandTouchCount = std::max(_disableHandTouchCount - 1, 0);
emit shouldDisableHandTouchChanged(_disableHandTouchCount > 0);
}
void MyAvatar::disableHandTouchForID(const QUuid& entityID) {
emit disableHandTouchForIDChanged(entityID, true);
}
void MyAvatar::enableHandTouchForID(const QUuid& entityID) {
emit disableHandTouchForIDChanged(entityID, false);
}
void MyAvatar::registerMetaTypes(ScriptEnginePointer engine) {
QScriptValue value = engine->newQObject(this, QScriptEngine::QtOwnership, QScriptEngine::ExcludeDeleteLater | QScriptEngine::ExcludeChildObjects);
engine->globalObject().setProperty("MyAvatar", value);

View file

@ -505,6 +505,28 @@ public:
* @returns {boolean}
*/
Q_INVOKABLE bool getHMDLeanRecenterEnabled() const { return _hmdLeanRecenterEnabled; }
/**jsdoc
* Request to enable hand touch effect globally
* @function MyAvatar.requestEnableHandTouch
*/
Q_INVOKABLE void requestEnableHandTouch();
/**jsdoc
* Request to disable hand touch effect globally
* @function MyAvatar.requestDisableHandTouch
*/
Q_INVOKABLE void requestDisableHandTouch();
/**jsdoc
* Disables hand touch effect on a specific entity
* @function MyAvatar.disableHandTouchForID
* @param {Uuid} entityID - ID of the entity that will disable hand touch effect
*/
Q_INVOKABLE void disableHandTouchForID(const QUuid& entityID);
/**jsdoc
* Enables hand touch effect on a specific entity
* @function MyAvatar.enableHandTouchForID
* @param {Uuid} entityID - ID of the entity that will enable hand touch effect
*/
Q_INVOKABLE void enableHandTouchForID(const QUuid& entityID);
bool useAdvancedMovementControls() const { return _useAdvancedMovementControls.get(); }
void setUseAdvancedMovementControls(bool useAdvancedMovementControls)
@ -1392,6 +1414,23 @@ signals:
*/
void scaleChanged();
/**jsdoc
* Triggered when hand touch is globally enabled or disabled
* @function MyAvatar.shouldDisableHandTouchChanged
* @param {boolean} shouldDisable
* @returns {Signal}
*/
void shouldDisableHandTouchChanged(bool shouldDisable);
/**jsdoc
* Triggered when hand touch is enabled or disabled for an specific entity
* @function MyAvatar.disableHandTouchForIDChanged
* @param {Uuid} entityID - ID of the entity that will enable hand touch effect
* @param {boolean} disable
* @returns {Signal}
*/
void disableHandTouchForIDChanged(const QUuid& entityID, bool disable);
private slots:
void leaveDomain();
@ -1628,6 +1667,7 @@ private:
// all poses are in sensor-frame
std::map<controller::Action, controller::Pose> _controllerPoseMap;
mutable std::mutex _controllerPoseMapMutex;
mutable std::mutex _disableHandTouchMutex;
bool _centerOfGravityModelEnabled { true };
bool _hmdLeanRecenterEnabled { true };
@ -1668,6 +1708,7 @@ private:
bool _shouldLoadScripts { false };
bool _haveReceivedHeightLimitsFromDomain { false };
int _disableHandTouchCount { 0 };
};
QScriptValue audioListenModeToScriptValue(QScriptEngine* engine, const AudioListenerMode& audioListenerMode);

View file

@ -14,12 +14,12 @@
/* global Script, Overlays, Controller, Vec3, MyAvatar, Entities
*/
(function() {
(function () {
var handTouchEnabled = true;
var MSECONDS_AFTER_LOAD = 2000;
var updateFingerWithIndex = 0;
var untouchableEntities = [];
// Keys to access finger data
var fingerKeys = ["pinky", "ring", "middle", "index", "thumb"];
@ -305,7 +305,6 @@
avatarLoaded: false
};
// Add/Subtract the joint data - per finger joint
function addVals(val1, val2, sign) {
var val = [];
@ -351,7 +350,6 @@
}
function dataRelativeToWorld(side, dataIn, dataOut) {
var handJoint = handJointNames[side];
var jointIndex = MyAvatar.getJointIndex(handJoint);
var worldPosHand = MyAvatar.jointToWorldPoint({x: 0, y: 0, z: 0}, jointIndex);
@ -369,7 +367,6 @@
}
function dataRelativeToHandJoint(side, dataIn, dataOut) {
var handJoint = handJointNames[side];
var jointIndex = MyAvatar.getJointIndex(handJoint);
var worldPosHand = MyAvatar.jointToWorldPoint({x: 0, y: 0, z: 0}, jointIndex);
@ -385,7 +382,6 @@
// Calculate touch field; Sphere at the center of the palm,
// perpendicular vector from the palm plane and origin of the the finger rays
function estimatePalmData(side) {
// Return data object
var data = new Palm();
@ -407,7 +403,6 @@
var weightCount = 0;
// Calculate palm center
var handJointWeight = 1;
var fingerJointWeight = 2;
@ -459,7 +454,6 @@
// return getDataRelativeToHandJoint(side, data);
dataRelativeToHandJoint(side, data, palmData[side]);
palmData[side].set = true;
// return palmData[side];
}
// Register GlobalDebugger for API Debugger
@ -484,11 +478,9 @@
};
// Create debug overlays - finger rays + palm rays + spheres
var palmRay, sphereHand;
function createDebugLines() {
for (var i = 0; i < fingerKeys.length; i++) {
fingerRays.left[fingerKeys[i]] = Overlays.addOverlay("line3d", {
color: { red: 0, green: 0, blue: 255 },
@ -522,7 +514,6 @@
}
function createDebugSphere() {
sphereHand = {
right: Overlays.addOverlay("sphere", {
position: MyAvatar.position,
@ -633,6 +624,7 @@
RayPick.setPrecisionPicking(rayPicks[side][finger], true);
}
}
function activateNextRay(side, index) {
var nextIndex = (index < fingerKeys.length-1) ? index + 1 : 0;
for (var i = 0; i < fingerKeys.length; i++) {
@ -646,7 +638,6 @@
}
function updateSphereHand(side) {
var data = new Palm();
dataRelativeToWorld(side, palmData[side], data);
varsToDebug.palmData[side] = palmData[side];
@ -656,7 +647,6 @@
var dist = LOOKUP_DISTANCE_MULTIPLIER*data.distance;
// Situate the debugging overlays
var checkOffset = {
x: data.perpendicular.x * dist,
y: data.perpendicular.y * dist,
@ -694,12 +684,12 @@
}
// Update the intersection of only one finger at a time
var finger = fingerKeys[updateFingerWithIndex];
var grabbables = Entities.findEntities(spherePos, dist);
var nearbyEntities = Entities.findEntities(spherePos, dist);
// Filter the entities that are allowed to be touched
var touchableEntities = nearbyEntities.filter(function (id) {
return untouchableEntities.indexOf(id) == -1;
});
var intersection;
if (rayPicks[side][finger] !== undefined) {
intersection = RayPick.getPrevRayPickResult(rayPicks[side][finger]);
@ -708,9 +698,8 @@
var animationSteps = defaultAnimationSteps;
var newFingerData = dataDefault[side][finger];
var isAbleToGrab = false;
if (grabbables.length > 0) {
RayPick.setIncludeItems(rayPicks[side][finger], grabbables);
if (touchableEntities.length > 0) {
RayPick.setIncludeItems(rayPicks[side][finger], touchableEntities);
if (intersection === undefined) {
return;
@ -726,7 +715,6 @@
isTouching[side][finger] = isAbleToGrab;
if (isAbleToGrab) {
// update the open/close percentage for this finger
var FINGER_REACT_MULTIPLIER = 2.8;
percent = intersection.distance/(FINGER_REACT_MULTIPLIER*dist);
@ -761,7 +749,6 @@
}
// Recreate the finger joint names
function getJointNames(side, finger, count) {
var names = [];
for (var i = 1; i < count+1; i++) {
@ -772,26 +759,30 @@
}
// Capture the controller values
var leftTriggerPress = function (value) {
varsToDebug.triggerValues.leftTriggerValue = value;
// the value for the trigger increments the hand-close percentage
grabPercent.left = value;
};
var leftTriggerClick = function (value) {
varsToDebug.triggerValues.leftTriggerClicked = value;
};
var rightTriggerPress = function (value) {
varsToDebug.triggerValues.rightTriggerValue = value;
// the value for the trigger increments the hand-close percentage
grabPercent.right = value;
};
var rightTriggerClick = function (value) {
varsToDebug.triggerValues.rightTriggerClicked = value;
};
var leftSecondaryPress = function (value) {
varsToDebug.triggerValues.leftSecondaryValue = value;
};
var rightSecondaryPress = function (value) {
varsToDebug.triggerValues.rightSecondaryValue = value;
};
@ -814,6 +805,7 @@
createDebugLines();
linesCreated = true;
}
if (showSphere && !sphereCreated) {
createDebugSphere();
sphereCreated = true;
@ -840,6 +832,57 @@
});
}
function cleanUp() {
["right", "left"].forEach(function (side) {
if (linesCreated) {
Overlays.deleteOverlay(palmRay[side]);
}
if (sphereCreated) {
Overlays.deleteOverlay(sphereHand[side]);
}
clearRayPicks(side);
for (var i = 0; i < fingerKeys.length; i++) {
var finger = fingerKeys[i];
var jointSuffixes = 3; // We need to clear the joints 0, 1 and 2 joints
var names = getJointNames(side, finger, jointSuffixes);
for (var j = 0; j < names.length; j++) {
var index = MyAvatar.getJointIndex(names[j]);
MyAvatar.clearJointData(index);
}
if (linesCreated) {
Overlays.deleteOverlay(fingerRays[side][finger]);
}
}
});
}
MyAvatar.shouldDisableHandTouchChanged.connect(function (shouldDisable) {
if (shouldDisable) {
if (handTouchEnabled) {
cleanUp();
}
} else {
if (!handTouchEnabled) {
reEstimatePalmData();
recreateRayPicks();
}
}
handTouchEnabled = !shouldDisable;
});
MyAvatar.disableHandTouchForIDChanged.connect(function (entityID, disable) {
var entityIndex = untouchableEntities.indexOf(entityID);
if (disable) {
if (entityIndex == -1) {
untouchableEntities.push(entityID);
}
} else {
if (entityIndex != -1) {
untouchableEntities.splice(entityIndex, 1);
}
}
});
MyAvatar.onLoadComplete.connect(function () {
// Sometimes the rig is not ready when this signal is trigger
console.log("avatar loaded");
@ -854,36 +897,16 @@
});
Script.scriptEnding.connect(function () {
["right", "left"].forEach(function(side) {
if (linesCreated) {
Overlays.deleteOverlay(palmRay[side]);
}
if (sphereCreated) {
Overlays.deleteOverlay(sphereHand[side]);
}
clearRayPicks(side);
for (var i = 0; i < fingerKeys.length; i++) {
var finger = fingerKeys[i];
var jointSuffixes = 3; // We need to clear the joints 0, 1 and 2 joints
var names = getJointNames(side, finger, jointSuffixes);
for (var j = 0; j < names.length; j++) {
var index = MyAvatar.getJointIndex(names[j]);
MyAvatar.clearJointData(index);
}
if (linesCreated) {
Overlays.deleteOverlay(fingerRays[side][finger]);
}
}
});
cleanUp();
});
Script.update.connect(function() {
Script.update.connect(function () {
if (!handTouchEnabled) {
return;
}
// index of the finger that needs to be updated this frame
updateFingerWithIndex = (updateFingerWithIndex < fingerKeys.length-1) ? updateFingerWithIndex + 1 : 0;
["right", "left"].forEach(function(side) {
@ -901,18 +924,15 @@
var isHandTouching = getTouching(side);
countToDefault[side] = isHandTouching ? 0 : countToDefault[side] + 1;
for (var i = 0; i < fingerKeys.length; i++) {
var finger = fingerKeys[i];
var jointSuffixes = 3; // We need to update rotation of the 0, 1 and 2 joints
var names = getJointNames(side, finger, jointSuffixes);
// Add the animation increments
dataCurrent[side][finger] = addVals(dataCurrent[side][finger], dataDelta[side][finger], 1);
// update every finger joint
for (var j = 0; j < names.length; j++) {
var index = MyAvatar.getJointIndex(names[j]);
// if no finger is touching restate the default poses