From c2612af7a8550e301a4861302cb6a9ae0cd9fc46 Mon Sep 17 00:00:00 2001 From: amantley Date: Fri, 10 Aug 2018 17:10:33 -0700 Subject: [PATCH 01/24] changed the spine stretch limit, will check the scale implications next --- interface/src/avatar/MyAvatar.cpp | 1 + libraries/shared/src/AvatarConstants.h | 2 +- scripts/developer/objectOrientedStep.js | 683 ++++++++++++++++++++++++ 3 files changed, 685 insertions(+), 1 deletion(-) create mode 100644 scripts/developer/objectOrientedStep.js diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 0d7b00da78..db0c683632 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -3692,6 +3692,7 @@ void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat setForceActivateRotation(false); } if (!isActive(Horizontal) && getForceActivateHorizontal()) { + qCDebug(interfaceapp) << "called the recentering from script"; activate(Horizontal); setForceActivateHorizontal(false); } diff --git a/libraries/shared/src/AvatarConstants.h b/libraries/shared/src/AvatarConstants.h index d9b26927e2..6b35a45f4c 100644 --- a/libraries/shared/src/AvatarConstants.h +++ b/libraries/shared/src/AvatarConstants.h @@ -34,7 +34,7 @@ const float DEFAULT_HANDS_ANGULAR_VELOCITY_STEPPING_THRESHOLD = 3.3f; const float DEFAULT_HEAD_VELOCITY_STEPPING_THRESHOLD = 0.18f; const float DEFAULT_HEAD_PITCH_STEPPING_TOLERANCE = 7.0f; const float DEFAULT_HEAD_ROLL_STEPPING_TOLERANCE = 7.0f; -const float DEFAULT_AVATAR_SPINE_STRETCH_LIMIT = 0.07f; +const float DEFAULT_AVATAR_SPINE_STRETCH_LIMIT = 0.03f; const float DEFAULT_AVATAR_FORWARD_DAMPENING_FACTOR = 0.5f; const float DEFAULT_AVATAR_LATERAL_DAMPENING_FACTOR = 2.0f; const float DEFAULT_AVATAR_HIPS_MASS = 40.0f; diff --git a/scripts/developer/objectOrientedStep.js b/scripts/developer/objectOrientedStep.js new file mode 100644 index 0000000000..4eca1fb115 --- /dev/null +++ b/scripts/developer/objectOrientedStep.js @@ -0,0 +1,683 @@ +/* jslint bitwise: true */ + +/* global Script, Vec3, MyAvatar, Tablet, Messages, Quat, +DebugDraw, Mat4, Entities, Xform, Controller, Camera, console, document*/ + +Script.registerValue("STEPAPP", true); +var CENTIMETERSPERMETER = 100.0; +var LEFT = 0; +var RIGHT = 1; +var INCREASING = 1.0; +var DECREASING = -1.0; +var DEFAULT_AVATAR_HEIGHT = 1.64; +var TABLET_BUTTON_NAME = "STEP"; +var CHANGE_OF_BASIS_ROTATION = { x: 0, y: 1, z: 0, w: 0 }; +// in meters (mostly) +var DEFAULT_ANTERIOR = 0.04; +var DEFAULT_POSTERIOR = 0.06; +var DEFAULT_LATERAL = 0.10; +var DEFAULT_HEIGHT_DIFFERENCE = 0.02; +var DEFAULT_ANGULAR_VELOCITY = 0.3; +var DEFAULT_HAND_VELOCITY = 0.4; +var DEFAULT_ANGULAR_HAND_VELOCITY = 3.3; +var DEFAULT_HEAD_VELOCITY = 0.14; +var DEFAULT_LEVEL_PITCH = 7; +var DEFAULT_LEVEL_ROLL = 7; +var DEFAULT_DIFF = 0.0; +var DEFAULT_DIFF_EULERS = { x: 0.0, y: 0.0, z: 0.0 }; +var DEFAULT_HIPS_POSITION; +var DEFAULT_HEAD_POSITION; +var DEFAULT_TORSO_LENGTH; +var SPINE_STRETCH_LIMIT = 0.02; + +var VELOCITY_EPSILON = 0.02; +var AVERAGING_RATE = 0.03; +var HEIGHT_AVERAGING_RATE = 0.01; +var STEP_TIME_SECS = 0.2; +var MODE_SAMPLE_LENGTH = 100; +var RESET_MODE = false; +var HEAD_TURN_THRESHOLD = 25.0; +var NO_SHARED_DIRECTION = -0.98; +var LOADING_DELAY = 500; +var FAILSAFE_TIMEOUT = 2.5; + +var debugDrawBase = true; +var activated = false; +var documentLoaded = false; +var failsafeFlag = false; +var failsafeSignalTimer = -1.0; +var stepTimer = -1.0; + + +var modeArray = new Array(MODE_SAMPLE_LENGTH); +var modeHeight = -10.0; + +var handPosition; +var handOrientation; +var hands = []; +var hipToHandAverage = []; +var handDotHead = []; +var headAverageOrientation = MyAvatar.orientation; +var headPoseAverageOrientation = { x: 0, y: 0, z: 0, w: 1 }; +var averageHeight = 1.0; +var headEulers = { x: 0.0, y: 0.0, z: 0.0 }; +var headAverageEulers = { x: 0.0, y: 0.0, z: 0.0 }; +var headAveragePosition = { x: 0, y: 0.4, z: 0 }; +var frontLeft = { x: -DEFAULT_LATERAL, y: 0, z: -DEFAULT_ANTERIOR }; +var frontRight = { x: DEFAULT_LATERAL, y: 0, z: -DEFAULT_ANTERIOR }; +var backLeft = { x: -DEFAULT_LATERAL, y: 0, z: DEFAULT_POSTERIOR }; +var backRight = { x: DEFAULT_LATERAL, y: 0, z: DEFAULT_POSTERIOR }; + + +// define state readings constructor +function StateReading(headPose, rhandPose, lhandPose, backLength, diffFromMode, diffFromAverageHeight, diffFromAveragePosition, + diffFromAverageEulers) { + this.headPose = headPose; + this.rhandPose = rhandPose; + this.lhandPose = lhandPose; + this.backLength = backLength; + this.diffFromMode = diffFromMode; + this.diffFromAverageHeight = diffFromAverageHeight; + this.diffFromAveragePosition = diffFromAveragePosition; + this.diffFromAverageEulers = diffFromAverageEulers; +} + +// define current state readings object for holding tracker readings and current differences from averages +var currentStateReadings = new StateReading(Controller.getPoseValue(Controller.Standard.Head), + Controller.getPoseValue(Controller.Standard.RightHand), Controller.getPoseValue(Controller.Standard.LeftHand), + DEFAULT_TORSO_LENGTH, DEFAULT_DIFF, DEFAULT_DIFF, DEFAULT_DIFF, DEFAULT_DIFF_EULERS); + +// declare the checkbox constructor +function AppCheckbox(type,id,eventType,isChecked) { + this.type = type; + this.id = id; + this.eventType = eventType; + this.data = {value: isChecked}; +} + +// define the checkboxes in the html file +var usingAverageHeight = new AppCheckbox("checkboxtick", "runningAverageHeightCheck", "onRunningAverageHeightCheckBox", + false); +var usingModeHeight = new AppCheckbox("checkboxtick","modeCheck","onModeCheckBox",true); +var usingBaseOfSupport = new AppCheckbox("checkboxtick","baseOfSupportCheck","onBaseOfSupportCheckBox",true); +var usingAverageHeadPosition = new AppCheckbox("checkboxtick", "headAveragePositionCheck", "onHeadAveragePositionCheckBox", + false); + +var checkBoxArray = new Array(usingAverageHeight,usingModeHeight,usingBaseOfSupport,usingAverageHeadPosition); + +// declare the html slider constructor +function AppProperty(name, type, eventType, signalType, setFunction, initValue, convertToThreshold, convertToSlider, signalOn) { + this.name = name; + this.type = type; + this.eventType = eventType; + this.signalType = signalType; + this.setValue = setFunction; + this.value = initValue; + this.get = function () { + return this.value; + }; + this.convertToThreshold = convertToThreshold; + this.convertToSlider = convertToSlider; + this.signalOn = signalOn; +} + +// define the sliders +var frontBaseProperty = new AppProperty("#anteriorBase-slider", "slider", "onAnteriorBaseSlider", "frontSignal", + setAnteriorDistance, DEFAULT_ANTERIOR, function (num) { + return convertToMeters(num); + }, function (num) { + return convertToCentimeters(num); + },true); +var backBaseProperty = new AppProperty("#posteriorBase-slider", "slider", "onPosteriorBaseSlider", "backSignal", + setPosteriorDistance, DEFAULT_POSTERIOR, function (num) { + return convertToMeters(num); + }, function (num) { + return convertToCentimeters(num); + }, true); +var lateralBaseProperty = new AppProperty("#lateralBase-slider", "slider", "onLateralBaseSlider", "lateralSignal", + setLateralDistance, DEFAULT_LATERAL, function (num) { + return convertToMeters(num); + }, function (num) { + return convertToCentimeters(num); + }, true); +var headAngularVelocityProperty = new AppProperty("#angularVelocityHead-slider", "slider", "onAngularVelocitySlider", + "angularHeadSignal", setAngularThreshold, DEFAULT_ANGULAR_VELOCITY, function (num) { + var base = 4; + var shift = 2; + return convertExponential(base, num, DECREASING, shift); + }, function (num) { + var base = 4; + var shift = 2; + return convertLog(base, num, DECREASING, shift); + }, true); +var heightDifferenceProperty = new AppProperty("#heightDifference-slider", "slider", "onHeightDifferenceSlider", "heightSignal", + setHeightThreshold, DEFAULT_HEIGHT_DIFFERENCE, function (num) { + return convertToMeters(-num); + }, function (num) { + return convertToCentimeters(-num); + }, true); +var handsVelocityProperty = new AppProperty("#handsVelocity-slider", "slider", "onHandsVelocitySlider", "handVelocitySignal", + setHandVelocityThreshold, DEFAULT_HAND_VELOCITY, function (num) { + return num; + }, function (num) { + return num; + }, true); +var handsAngularVelocityProperty = new AppProperty("#handsAngularVelocity-slider", "slider", "onHandsAngularVelocitySlider", + "handAngularSignal", setHandAngularVelocityThreshold, DEFAULT_ANGULAR_HAND_VELOCITY, function (num) { + var base = 7; + var shift = 2; + return convertExponential(base, num, DECREASING, shift); + }, function (num) { + var base = 7; + var shift = 2; + return convertLog(base, num, DECREASING, shift); + }, true); +var headVelocityProperty = new AppProperty("#headVelocity-slider", "slider", "onHeadVelocitySlider", "headVelocitySignal", + setHeadVelocityThreshold, DEFAULT_HEAD_VELOCITY, function (num) { + var base = 2; + var shift = 0; + return convertExponential(base, num, INCREASING, shift); + }, function (num) { + var base = 2; + var shift = 0; + return convertLog(base, num, INCREASING, shift); + }, true); +var headPitchProperty = new AppProperty("#headPitch-slider", "slider", "onHeadPitchSlider", "headPitchSignal", + setHeadPitchThreshold, DEFAULT_LEVEL_PITCH, function (num) { + var base = 2.5; + var shift = 5; + return convertExponential(base, num, DECREASING, shift); + }, function (num) { + var base = 2.5; + var shift = 5; + return convertLog(base, num, DECREASING, shift); + }, true); +var headRollProperty = new AppProperty("#headRoll-slider", "slider", "onHeadRollSlider", "headRollSignal", setHeadRollThreshold, + DEFAULT_LEVEL_ROLL, function (num) { + var base = 2.5; + var shift = 5; + return convertExponential(base, num, DECREASING, shift); + }, function (num) { + var base = 2.5; + var shift = 5; + return convertLog(base, num, DECREASING, shift); + }, true); + +var propArray = new Array(frontBaseProperty, backBaseProperty, lateralBaseProperty, headAngularVelocityProperty, + heightDifferenceProperty, handsVelocityProperty, handsAngularVelocityProperty, headVelocityProperty, headPitchProperty, + headRollProperty); + +// var HTML_URL = Script.resolvePath("http://hifi-content.s3.amazonaws.com/angus/stepApp/stepApp.html"); +var HTML_URL = Script.resolvePath("http://hifi-content.s3.amazonaws.com/angus/stepApp/stepAppExtra.html"); +var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); + +function manageClick() { + if (activated) { + tablet.gotoHomeScreen(); + } else { + tablet.gotoWebScreen(HTML_URL); + } +} + +var tabletButton = tablet.addButton({ + text: TABLET_BUTTON_NAME, + icon: Script.resolvePath("http://hifi-content.s3.amazonaws.com/angus/stepApp/foot.svg"), + activeIcon: Script.resolvePath("http://hifi-content.s3.amazonaws.com/angus/stepApp/foot.svg") +}); + +function drawBase() { + // transform corners into world space, for rendering. + var worldPointLf = Vec3.sum(MyAvatar.position,Vec3.multiplyQbyV(MyAvatar.orientation, frontLeft)); + var worldPointRf = Vec3.sum(MyAvatar.position,Vec3.multiplyQbyV(MyAvatar.orientation, frontRight)); + var worldPointLb = Vec3.sum(MyAvatar.position,Vec3.multiplyQbyV(MyAvatar.orientation, backLeft)); + var worldPointRb = Vec3.sum(MyAvatar.position,Vec3.multiplyQbyV(MyAvatar.orientation, backRight)); + + var GREEN = { r: 0, g: 1, b: 0, a: 1 }; + // draw border + DebugDraw.drawRay(worldPointLf, worldPointRf, GREEN); + DebugDraw.drawRay(worldPointRf, worldPointRb, GREEN); + DebugDraw.drawRay(worldPointRb, worldPointLb, GREEN); + DebugDraw.drawRay(worldPointLb, worldPointLf, GREEN); +} + +function onKeyPress(event) { + if (event.text === "'") { + // when the sensors are reset, then reset the mode. + RESET_MODE = false; + } +} + +function onWebEventReceived(msg) { + var message = JSON.parse(msg); + print(" we have a message from html dialog " + message.type); + propArray.forEach(function (prop) { + if (prop.eventType === message.type) { + prop.setValue(prop.convertToThreshold(message.data.value)); + print("message from " + prop.name); + // break; + } + }); + checkBoxArray.forEach(function(cbox) { + if (cbox.eventType === message.type) { + cbox.data.value = message.data.value; + // break; + } + }); + if (message.type === "onCreateStepApp") { + print("document loaded"); + documentLoaded = true; + Script.setTimeout(initAppForm, LOADING_DELAY); + } +} + +function initAppForm() { + print("step app is loaded: " + documentLoaded); + if (documentLoaded === true) { + propArray.forEach(function (prop) { + tablet.emitScriptEvent(JSON.stringify({ + "type": "trigger", + "id": prop.signalType, + "data": { "value": "green" } + })); + tablet.emitScriptEvent(JSON.stringify({ + "type": "slider", + "id": prop.name, + "data": { "value": prop.convertToSlider(prop.value) } + })); + }); + checkBoxArray.forEach(function (cbox) { + tablet.emitScriptEvent(JSON.stringify({ + "type": "checkboxtick", + "id": cbox.id, + "data": { "value": cbox.data.value } + })); + }); + } +} + +function updateSignalColors() { + + // force the updates by running the threshold comparisons + withinBaseOfSupport(currentStateReadings.headPose.translation); + withinThresholdOfStandingHeightMode(currentStateReadings.diffFromMode); + headAngularVelocityBelowThreshold(currentStateReadings.headPose.angularVelocity); + handDirectionMatchesHeadDirection(currentStateReadings.lhandPose, currentStateReadings.rhandPose); + handAngularVelocityBelowThreshold(currentStateReadings.lhandPose, currentStateReadings.rhandPose); + headVelocityGreaterThanThreshold(Vec3.length(currentStateReadings.headPose.velocity)); + headMovedAwayFromAveragePosition(currentStateReadings.diffFromAveragePosition); + headLowerThanHeightAverage(currentStateReadings.diffFromAverageHeight); + isHeadLevel(currentStateReadings.diffFromAverageEulers); + + propArray.forEach(function (prop) { + if (prop.signalOn) { + tablet.emitScriptEvent(JSON.stringify({ "type": "trigger", "id": prop.signalType, "data": { "value": "green" } })); + } else { + tablet.emitScriptEvent(JSON.stringify({ "type": "trigger", "id": prop.signalType, "data": { "value": "red" } })); + } + }); +} + +function onScreenChanged(type, url) { + print("Screen changed"); + if (type === "Web" && url === HTML_URL) { + if (!activated) { + // hook up to event bridge + tablet.webEventReceived.connect(onWebEventReceived); + print("after connect web event"); + MyAvatar.hmdLeanRecenterEnabled = false; + + } + activated = true; + } else { + if (activated) { + // disconnect from event bridge + tablet.webEventReceived.disconnect(onWebEventReceived); + documentLoaded = false; + } + activated = false; + } +} + +function getLog(x, y) { + return Math.log(y) / Math.log(x); +} + +function noConversion(num) { + return num; +} + +function convertLog(base, num, direction, shift) { + return direction * getLog(base, (num + 1.0)) + shift; +} + +function convertExponential(base, num, direction, shift) { + return Math.pow(base, (direction*num + shift)) - 1.0; +} + +function convertToCentimeters(num) { + return num * CENTIMETERSPERMETER; +} + +function convertToMeters(num) { + print("convert to meters " + num); + return num / CENTIMETERSPERMETER; +} + +function isInsideLine(a, b, c) { + return (((b.x - a.x)*(c.z - a.z) - (b.z - a.z)*(c.x - a.x)) > 0); +} + +function setAngularThreshold(num) { + headAngularVelocityProperty.value = num; + print("angular threshold " + headAngularVelocityProperty.get()); +} + +function setHeadRollThreshold(num) { + headRollProperty.value = num; + print("head roll threshold " + headRollProperty.get()); +} + +function setHeadPitchThreshold(num) { + headPitchProperty.value = num; + print("head pitch threshold " + headPitchProperty.get()); +} + +function setHeightThreshold(num) { + heightDifferenceProperty.value = num; + print("height threshold " + heightDifferenceProperty.get()); +} + +function setLateralDistance(num) { + lateralBaseProperty.value = num; + frontLeft.x = -lateralBaseProperty.get(); + frontRight.x = lateralBaseProperty.get(); + backLeft.x = -lateralBaseProperty.get(); + backRight.x = lateralBaseProperty.get(); + print("lateral distance " + lateralBaseProperty.get()); +} + +function setAnteriorDistance(num) { + frontBaseProperty.value = num; + frontLeft.z = -frontBaseProperty.get(); + frontRight.z = -frontBaseProperty.get(); + print("anterior distance " + frontBaseProperty.get()); +} + +function setPosteriorDistance(num) { + backBaseProperty.value = num; + backLeft.z = backBaseProperty.get(); + backRight.z = backBaseProperty.get(); + print("posterior distance " + backBaseProperty.get()); +} + +function setHandAngularVelocityThreshold(num) { + handsAngularVelocityProperty.value = num; + print("hand angular velocity threshold " + handsAngularVelocityProperty.get()); +} + +function setHandVelocityThreshold(num) { + handsVelocityProperty.value = num; + print("hand velocity threshold " + handsVelocityProperty.get()); +} + +function setHeadVelocityThreshold(num) { + headVelocityProperty.value = num; + print("headvelocity threshold " + headVelocityProperty.get()); +} + +function withinBaseOfSupport(pos) { + var userScale = 1.0; + frontBaseProperty.signalOn = !(isInsideLine(Vec3.multiply(userScale, frontLeft), Vec3.multiply(userScale, frontRight), pos)); + backBaseProperty.signalOn = !(isInsideLine(Vec3.multiply(userScale, backRight), Vec3.multiply(userScale, backLeft), pos)); + lateralBaseProperty.signalOn = !(isInsideLine(Vec3.multiply(userScale, frontRight), Vec3.multiply(userScale, backRight), pos) + && isInsideLine(Vec3.multiply(userScale, backLeft), Vec3.multiply(userScale, frontLeft), pos)); + return (!frontBaseProperty.signalOn && !backBaseProperty.signalOn && !lateralBaseProperty.signalOn); +} + +function withinThresholdOfStandingHeightMode(heightDiff) { + if (usingModeHeight.data.value) { + heightDifferenceProperty.signalOn = heightDiff < heightDifferenceProperty.get(); + return heightDifferenceProperty.signalOn; + } else { + return true; + } +} + +function headAngularVelocityBelowThreshold(headAngularVelocity) { + var angVel = Vec3.length({ x: headAngularVelocity.x, y: 0, z: headAngularVelocity.z }); + headAngularVelocityProperty.signalOn = angVel < headAngularVelocityProperty.get(); + return headAngularVelocityProperty.signalOn; +} + +function handDirectionMatchesHeadDirection(lhPose, rhPose) { + handsVelocityProperty.signalOn = ((handsVelocityProperty.get() < NO_SHARED_DIRECTION) || + ((!lhPose.valid || ((handDotHead[LEFT] > handsVelocityProperty.get()) && + (Vec3.length(lhPose.velocity) > VELOCITY_EPSILON))) && + (!rhPose.valid || ((handDotHead[RIGHT] > handsVelocityProperty.get()) && + (Vec3.length(rhPose.velocity) > VELOCITY_EPSILON))))); + return handsVelocityProperty.signalOn; +} + +function handAngularVelocityBelowThreshold(lhPose, rhPose) { + var xzRHandAngularVelocity = Vec3.length({ x: rhPose.angularVelocity.x, y: 0.0, z: rhPose.angularVelocity.z }); + var xzLHandAngularVelocity = Vec3.length({ x: lhPose.angularVelocity.x, y: 0.0, z: lhPose.angularVelocity.z }); + handsAngularVelocityProperty.signalOn = ((!rhPose.valid ||(xzRHandAngularVelocity < handsAngularVelocityProperty.get())) + && (!lhPose.valid || (xzLHandAngularVelocity < handsAngularVelocityProperty.get()))); + return handsAngularVelocityProperty.signalOn; +} + +function headVelocityGreaterThanThreshold(headVel) { + headVelocityProperty.signalOn = (headVel > headVelocityProperty.get()) || (headVelocityProperty.get() < VELOCITY_EPSILON); + return headVelocityProperty.signalOn; +} + +function headMovedAwayFromAveragePosition(headDelta) { + return !withinBaseOfSupport(headDelta) || !usingAverageHeadPosition.data.value; +} + +function headLowerThanHeightAverage(heightDiff) { + if (usingAverageHeight.data.value) { + print("head lower than height average"); + heightDifferenceProperty.signalOn = heightDiff < heightDifferenceProperty.get(); + return heightDifferenceProperty.signalOn; + } else { + return true; + } +} + +function isHeadLevel(diffEulers) { + headRollProperty.signalOn = Math.abs(diffEulers.z) < headRollProperty.get(); + headPitchProperty.signalOn = Math.abs(diffEulers.x) < headPitchProperty.get(); + return (headRollProperty.signalOn && headPitchProperty.signalOn); +} + +function findAverage(arr) { + var sum = arr.reduce(function (acc, val) { + return acc + val; + },0); + return sum / arr.length; +} + +function addToModeArray(arr,num) { + for (var i = 0 ;i < (arr.length - 1); i++) { + arr[i] = arr[i+1]; + } + arr[arr.length - 1] = (Math.floor(num*CENTIMETERSPERMETER))/CENTIMETERSPERMETER; +} + +function findMode(ary, currentMode, backLength, defaultBack, currentHeight) { + var numMapping = {}; + var greatestFreq = 0; + var mode; + ary.forEach(function (number) { + numMapping[number] = (numMapping[number] || 0) + 1; + if ((greatestFreq < numMapping[number]) || ((numMapping[number] === MODE_SAMPLE_LENGTH) && (number > currentMode) )) { + greatestFreq = numMapping[number]; + mode = number; + } + }); + if (mode > currentMode) { + return Number(mode); + } else { + if (!RESET_MODE && HMD.active) { + print("resetting the mode............................................. "); + print("resetting the mode............................................. "); + RESET_MODE = true; + var correction = 0.02; + return currentHeight - correction; + } else { + return currentMode; + } + } +} + +function update(dt) { + if (debugDrawBase) { + drawBase(); + } + // Update current state information + currentStateReadings.headPose = Controller.getPoseValue(Controller.Standard.Head); + currentStateReadings.rhandPose = Controller.getPoseValue(Controller.Standard.RightHand); + currentStateReadings.lhandPose = Controller.getPoseValue(Controller.Standard.LeftHand); + + // back length + var headMinusHipLean = Vec3.subtract(currentStateReadings.headPose.translation, DEFAULT_HIPS_POSITION); + currentStateReadings.backLength = Vec3.length(headMinusHipLean); + // print("back length and default " + currentStateReadings.backLength + " " + DEFAULT_TORSO_LENGTH); + + // mode height + addToModeArray(modeArray, currentStateReadings.headPose.translation.y); + modeHeight = findMode(modeArray, modeHeight, currentStateReadings.backLength, DEFAULT_TORSO_LENGTH, + currentStateReadings.headPose.translation.y); + currentStateReadings.diffFromMode = modeHeight - currentStateReadings.headPose.translation.y; + + // hand direction + var leftHandLateralPoseVelocity = currentStateReadings.lhandPose.velocity; + leftHandLateralPoseVelocity.y = 0.0; + var rightHandLateralPoseVelocity = currentStateReadings.rhandPose.velocity; + rightHandLateralPoseVelocity.y = 0.0; + var headLateralPoseVelocity = currentStateReadings.headPose.velocity; + headLateralPoseVelocity.y = 0.0; + handDotHead[LEFT] = Vec3.dot(Vec3.normalize(leftHandLateralPoseVelocity), Vec3.normalize(headLateralPoseVelocity)); + handDotHead[RIGHT] = Vec3.dot(Vec3.normalize(rightHandLateralPoseVelocity), Vec3.normalize(headLateralPoseVelocity)); + + // average head position + headAveragePosition = Vec3.mix(headAveragePosition, currentStateReadings.headPose.translation, AVERAGING_RATE); + currentStateReadings.diffFromAveragePosition = Vec3.subtract(currentStateReadings.headPose.translation, + headAveragePosition); + + // average height + averageHeight = currentStateReadings.headPose.translation.y * HEIGHT_AVERAGING_RATE + + averageHeight * (1.0 - HEIGHT_AVERAGING_RATE); + currentStateReadings.diffFromAverageHeight = Math.abs(currentStateReadings.headPose.translation.y - averageHeight); + + // eulers diff + headEulers = Quat.safeEulerAngles(currentStateReadings.headPose.rotation); + headAverageOrientation = Quat.slerp(headAverageOrientation, currentStateReadings.headPose.rotation, AVERAGING_RATE); + headAverageEulers = Quat.safeEulerAngles(headAverageOrientation); + currentStateReadings.diffFromAverageEulers = Vec3.subtract(headAverageEulers, headEulers); + + // headpose rig space is for determining when to recenter rotation. + var headPoseRigSpace = Quat.multiply(CHANGE_OF_BASIS_ROTATION, currentStateReadings.headPose.rotation); + headPoseAverageOrientation = Quat.slerp(headPoseAverageOrientation, headPoseRigSpace, AVERAGING_RATE); + var headPoseAverageEulers = Quat.safeEulerAngles(headPoseAverageOrientation); + + // make the signal colors reflect the current thresholds that have been crossed + updateSignalColors(); + print("the current back length is " + currentStateReadings.backLength + " " + DEFAULT_TORSO_LENGTH); + // Conditions for taking a step. + // 1. off the base of support. front, lateral, back edges. + // 2. head is not lower than the height mode value by more than the maxHeightChange tolerance + // 3. the angular velocity of the head is not greater than the threshold value + // ie this reflects the speed the head is rotating away from having up = (0,1,0) in Avatar frame.. + // 4. the hands velocity vector has the same direction as the head, within the given tolerance + // the tolerance is an acos value, -1 means the hands going in any direction will not block translating + // up to 1 where the hands velocity direction must exactly match that of the head. -1 threshold disables this condition. + // 5. the angular velocity xz magnitude for each hand is below the threshold value + // ie here this reflects the speed that each hand is rotating away from having up = (0,1,0) in Avatar frame. + // 6. head velocity is below step threshold + // 7. head has moved further than the threshold from the running average position of the head. + // 8. head height is not lower than the running average head height with a difference of maxHeightChange. + // 9. head's rotation in avatar space is not pitching or rolling greater than the pitch or roll thresholds + if (!withinBaseOfSupport(currentStateReadings.headPose.translation) && + withinThresholdOfStandingHeightMode(currentStateReadings.diffFromMode) && + headAngularVelocityBelowThreshold(currentStateReadings.headPose.angularVelocity) && + handDirectionMatchesHeadDirection(currentStateReadings.lhandPose, currentStateReadings.rhandPose) && + handAngularVelocityBelowThreshold(currentStateReadings.lhandPose, currentStateReadings.rhandPose) && + headVelocityGreaterThanThreshold(Vec3.length(currentStateReadings.headPose.velocity)) && + headMovedAwayFromAveragePosition(currentStateReadings.diffFromAveragePosition) && + headLowerThanHeightAverage(currentStateReadings.diffFromAverageHeight) && + isHeadLevel(currentStateReadings.diffFromAverageEulers)) { + + if (stepTimer < 0.0) { //!MyAvatar.isRecenteringHorizontally() + print("trigger recenter========================================================"); + MyAvatar.triggerHorizontalRecenter(); + stepTimer = STEP_TIME_SECS; + } + } else if ((currentStateReadings.backLength > (DEFAULT_TORSO_LENGTH + SPINE_STRETCH_LIMIT)) && + (failsafeSignalTimer < 0.0) && HMD.active) { + // do the failsafe recenter. + // failsafeFlag stops repeated setting of failsafe button color. + // RESET_MODE false forces a reset of the height + RESET_MODE = false; + failsafeFlag = true; + failsafeSignalTimer = FAILSAFE_TIMEOUT; + MyAvatar.triggerHorizontalRecenter(); + tablet.emitScriptEvent(JSON.stringify({ "type": "failsafe", "id": "failsafeSignal", "data": { "value": "green" } })); + // in fail safe we debug print the values that were blocking us. + print("failsafe debug---------------------------------------------------------------"); + propArray.forEach(function (prop) { + print(prop.name); + if (!prop.signalOn) { + print(prop.signalType + " contributed to failsafe call"); + } + }); + print("end failsafe debug---------------------------------------------------------------"); + + } + + if ((failsafeSignalTimer < 0.0) && failsafeFlag) { + failsafeFlag = false; + tablet.emitScriptEvent(JSON.stringify({ "type": "failsafe", "id": "failsafeSignal", "data": { "value": "orange" } })); + } + + stepTimer -= dt; + failsafeSignalTimer -= dt; + + if (!HMD.active) { + RESET_MODE = false; + } + + if (Math.abs(headPoseAverageEulers.y) > HEAD_TURN_THRESHOLD) { + // Turn feet + // MyAvatar.triggerRotationRecenter(); + // headPoseAverageOrientation = { x: 0, y: 0, z: 0, w: 1 }; + } +} + +function shutdownTabletApp() { + // GlobalDebugger.stop(); + tablet.removeButton(tabletButton); + if (activated) { + tablet.webEventReceived.disconnect(onWebEventReceived); + tablet.gotoHomeScreen(); + } + tablet.screenChanged.disconnect(onScreenChanged); +} + +tabletButton.clicked.connect(manageClick); +tablet.screenChanged.connect(onScreenChanged); + +Script.setTimeout(function() { + DEFAULT_HIPS_POSITION = MyAvatar.getAbsoluteDefaultJointTranslationInObjectFrame(MyAvatar.getJointIndex("Hips")); + DEFAULT_HEAD_POSITION = MyAvatar.getAbsoluteDefaultJointTranslationInObjectFrame(MyAvatar.getJointIndex("Head")); + DEFAULT_TORSO_LENGTH = Vec3.length(Vec3.subtract(DEFAULT_HEAD_POSITION, DEFAULT_HIPS_POSITION)); +},(4*LOADING_DELAY)); + +Script.update.connect(update); +Controller.keyPressEvent.connect(onKeyPress); +Script.scriptEnding.connect(function () { + MyAvatar.hmdLeanRecenterEnabled = true; + Script.update.disconnect(update); + shutdownTabletApp(); +}); From 9f289711cee9a850b643278b2c23da76a6c36665 Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Fri, 17 Aug 2018 14:33:21 -0700 Subject: [PATCH 02/24] fixing scripting window visiblity and size issues --- scripts/developer/debugging/debugWindow.js | 25 ++++++++++++++-------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/scripts/developer/debugging/debugWindow.js b/scripts/developer/debugging/debugWindow.js index 9522676007..993ca49a40 100644 --- a/scripts/developer/debugging/debugWindow.js +++ b/scripts/developer/debugging/debugWindow.js @@ -23,7 +23,7 @@ if (scripts.length >= 2) { var qml = Script.resolvePath('debugWindow.qml'); var HMD_DEBUG_WINDOW_GEOMETRY_KEY = 'hmdDebugWindowGeometry'; -var hmdDebugWindowGeometryValue = Settings.getValue(HMD_DEBUG_WINDOW_GEOMETRY_KEY) +var hmdDebugWindowGeometryValue = Settings.getValue(HMD_DEBUG_WINDOW_GEOMETRY_KEY); var windowWidth = 400; var windowHeight = 900; @@ -34,12 +34,13 @@ var windowY = 0; if (hmdDebugWindowGeometryValue !== '') { var geometry = JSON.parse(hmdDebugWindowGeometryValue); - - windowWidth = geometry.width - windowHeight = geometry.height - windowX = geometry.x - windowY = geometry.y - hasPosition = true; + if ((geometry.x !== 0) && (geometry.y !== 0)) { + windowWidth = geometry.width; + windowHeight = geometry.height; + windowX = geometry.x; + windowY = geometry.y; + hasPosition = true; + } } var window = new OverlayWindow({ @@ -52,6 +53,12 @@ if (hasPosition) { window.setPosition(windowX, windowY); } +window.visibleChanged.connect(function() { + if (!window.visible) { + window.setVisible(true); + } +}); + window.closed.connect(function () { Script.stop(); }); var getFormattedDate = function() { @@ -93,10 +100,10 @@ Script.scriptEnding.connect(function () { y: window.position.y, width: window.size.x, height: window.size.y - }) + }); Settings.setValue(HMD_DEBUG_WINDOW_GEOMETRY_KEY, geometry); window.close(); -}) +}); }()); From 2dcdd607508eaa9dd98799915102913701a54cb3 Mon Sep 17 00:00:00 2001 From: amantley Date: Mon, 20 Aug 2018 17:32:52 -0700 Subject: [PATCH 03/24] added new AvatarConstants and more frequent horizontal recentering to deal with lurching walk in large tracked volumes --- interface/src/avatar/MyAvatar.cpp | 19 +++++++++++-------- libraries/shared/src/AvatarConstants.h | 2 +- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index d69ba21f6d..d1147cc796 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -3557,10 +3557,10 @@ static bool headAngularVelocityBelowThreshold(const controller::Pose& head) { return isBelowThreshold; } -static bool isWithinThresholdHeightMode(const controller::Pose& head,const float& newMode) { +static bool isWithinThresholdHeightMode(const controller::Pose& head, const float& newMode, const float& scale) { bool isWithinThreshold = true; if (head.isValid()) { - isWithinThreshold = (head.getTranslation().y - newMode) > DEFAULT_AVATAR_MODE_HEIGHT_STEPPING_THRESHOLD; + isWithinThreshold = (head.getTranslation().y - newMode) > DEFAULT_AVATAR_MODE_HEIGHT_STEPPING_THRESHOLD * scale; } return isWithinThreshold; } @@ -3791,8 +3791,7 @@ void MyAvatar::lateUpdatePalms() { Avatar::updatePalms(); } - -static const float FOLLOW_TIME = 0.5f; +static const float FOLLOW_TIME = 0.1f; MyAvatar::FollowHelper::FollowHelper() { deactivate(); @@ -3883,9 +3882,10 @@ bool MyAvatar::FollowHelper::shouldActivateHorizontalCG(MyAvatar& myAvatar) cons controller::Pose currentRightHandPose = myAvatar.getControllerPoseInAvatarFrame(controller::Action::RIGHT_HAND); bool stepDetected = false; + float myScale = myAvatar.getAvatarScale(); if (!withinBaseOfSupport(currentHeadPose) && headAngularVelocityBelowThreshold(currentHeadPose) && - isWithinThresholdHeightMode(currentHeadPose, myAvatar.getCurrentStandingHeight()) && + isWithinThresholdHeightMode(currentHeadPose, myAvatar.getCurrentStandingHeight(), myScale) && handDirectionMatchesHeadDirection(currentLeftHandPose, currentRightHandPose, currentHeadPose) && handAngularVelocityBelowThreshold(currentLeftHandPose, currentRightHandPose) && headVelocityGreaterThanThreshold(currentHeadPose) && @@ -3897,8 +3897,8 @@ bool MyAvatar::FollowHelper::shouldActivateHorizontalCG(MyAvatar& myAvatar) cons glm::vec3 defaultHeadPosition = myAvatar.getAbsoluteDefaultJointTranslationInObjectFrame(myAvatar.getJointIndex("Head")); glm::vec3 currentHeadPosition = currentHeadPose.getTranslation(); float anatomicalHeadToHipsDistance = glm::length(defaultHeadPosition - defaultHipsPosition); - if (!isActive(Horizontal) && - (glm::length(currentHeadPosition - defaultHipsPosition) > (anatomicalHeadToHipsDistance + DEFAULT_AVATAR_SPINE_STRETCH_LIMIT))) { + if (!isActive(Horizontal) && + (glm::length(currentHeadPosition - defaultHipsPosition) > (anatomicalHeadToHipsDistance + (DEFAULT_AVATAR_SPINE_STRETCH_LIMIT * anatomicalHeadToHipsDistance * myAvatar.getAvatarScale())))) { myAvatar.setResetMode(true); stepDetected = true; } @@ -3918,6 +3918,9 @@ bool MyAvatar::FollowHelper::shouldActivateVertical(const MyAvatar& myAvatar, co void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix, bool hasDriveInput) { + const float VELOCITY_THRESHHOLD = 0.5f; + float currentVelocity = glm::length(myAvatar.getLocalVelocity() / myAvatar.getSensorToWorldScale()); + if (myAvatar.getHMDLeanRecenterEnabled() && qApp->getCamera().getMode() != CAMERA_MODE_MIRROR) { if (!isActive(Rotation) && (shouldActivateRotation(myAvatar, desiredBodyMatrix, currentBodyMatrix) || hasDriveInput)) { @@ -3925,7 +3928,7 @@ void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat myAvatar.setHeadControllerFacingMovingAverage(myAvatar._headControllerFacing); } if (myAvatar.getCenterOfGravityModelEnabled()) { - if (!isActive(Horizontal) && (shouldActivateHorizontalCG(myAvatar) || hasDriveInput)) { + if ((!isActive(Horizontal) && (shouldActivateHorizontalCG(myAvatar) || hasDriveInput)) || ( isActive(Horizontal) && (currentVelocity > VELOCITY_THRESHHOLD))) { activate(Horizontal); } } else { diff --git a/libraries/shared/src/AvatarConstants.h b/libraries/shared/src/AvatarConstants.h index cdc571d1aa..c3e8a3f173 100644 --- a/libraries/shared/src/AvatarConstants.h +++ b/libraries/shared/src/AvatarConstants.h @@ -34,7 +34,7 @@ const float DEFAULT_HANDS_ANGULAR_VELOCITY_STEPPING_THRESHOLD = 3.3f; const float DEFAULT_HEAD_VELOCITY_STEPPING_THRESHOLD = 0.18f; const float DEFAULT_HEAD_PITCH_STEPPING_TOLERANCE = 7.0f; const float DEFAULT_HEAD_ROLL_STEPPING_TOLERANCE = 7.0f; -const float DEFAULT_AVATAR_SPINE_STRETCH_LIMIT = 0.03f; +const float DEFAULT_AVATAR_SPINE_STRETCH_LIMIT = 0.04f; const float DEFAULT_AVATAR_FORWARD_DAMPENING_FACTOR = 0.5f; const float DEFAULT_AVATAR_LATERAL_DAMPENING_FACTOR = 2.0f; const float DEFAULT_AVATAR_HIPS_MASS = 40.0f; From 1e2ca579c776287652c60399ab0703539cc4a85e Mon Sep 17 00:00:00 2001 From: amantley Date: Mon, 20 Aug 2018 18:06:34 -0700 Subject: [PATCH 04/24] widened base of support and put head angular and hand angular back to normal --- libraries/shared/src/AvatarConstants.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libraries/shared/src/AvatarConstants.h b/libraries/shared/src/AvatarConstants.h index c3e8a3f173..4e6fa67c9f 100644 --- a/libraries/shared/src/AvatarConstants.h +++ b/libraries/shared/src/AvatarConstants.h @@ -24,10 +24,10 @@ const float DEFAULT_AVATAR_SUPPORT_BASE_LEFT = -0.25f; const float DEFAULT_AVATAR_SUPPORT_BASE_RIGHT = 0.25f; const float DEFAULT_AVATAR_SUPPORT_BASE_FRONT = -0.20f; const float DEFAULT_AVATAR_SUPPORT_BASE_BACK = 0.12f; -const float DEFAULT_AVATAR_LATERAL_STEPPING_THRESHOLD = 0.10f; -const float DEFAULT_AVATAR_ANTERIOR_STEPPING_THRESHOLD = 0.04f; -const float DEFAULT_AVATAR_POSTERIOR_STEPPING_THRESHOLD = 0.05f; -const float DEFAULT_AVATAR_HEAD_ANGULAR_VELOCITY_STEPPING_THRESHOLD = 0.3f; +const float DEFAULT_AVATAR_LATERAL_STEPPING_THRESHOLD = 0.15f; +const float DEFAULT_AVATAR_ANTERIOR_STEPPING_THRESHOLD = 0.07f; +const float DEFAULT_AVATAR_POSTERIOR_STEPPING_THRESHOLD = 0.08f; +const float DEFAULT_AVATAR_HEAD_ANGULAR_VELOCITY_STEPPING_THRESHOLD = 0.6f; const float DEFAULT_AVATAR_MODE_HEIGHT_STEPPING_THRESHOLD = -0.02f; const float DEFAULT_HANDS_VELOCITY_DIRECTION_STEPPING_THRESHOLD = 0.4f; const float DEFAULT_HANDS_ANGULAR_VELOCITY_STEPPING_THRESHOLD = 3.3f; From 1fabc77244d2546979e0ed5d95979714b89fc481 Mon Sep 17 00:00:00 2001 From: amantley Date: Tue, 21 Aug 2018 12:34:05 -0700 Subject: [PATCH 05/24] latest update to stop lurching, and allow leaning, and stop perma leans --- interface/src/avatar/MyAvatar.cpp | 9 ++++++--- libraries/shared/src/AvatarConstants.h | 8 ++++---- scripts/developer/objectOrientedStep.js | 7 ++++++- 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index d1147cc796..ba4636bfa6 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -3560,7 +3560,7 @@ static bool headAngularVelocityBelowThreshold(const controller::Pose& head) { static bool isWithinThresholdHeightMode(const controller::Pose& head, const float& newMode, const float& scale) { bool isWithinThreshold = true; if (head.isValid()) { - isWithinThreshold = (head.getTranslation().y - newMode) > DEFAULT_AVATAR_MODE_HEIGHT_STEPPING_THRESHOLD * scale; + isWithinThreshold = (head.getTranslation().y - newMode) > (DEFAULT_AVATAR_MODE_HEIGHT_STEPPING_THRESHOLD * scale); } return isWithinThreshold; } @@ -3881,6 +3881,7 @@ bool MyAvatar::FollowHelper::shouldActivateHorizontalCG(MyAvatar& myAvatar) cons controller::Pose currentLeftHandPose = myAvatar.getControllerPoseInAvatarFrame(controller::Action::LEFT_HAND); controller::Pose currentRightHandPose = myAvatar.getControllerPoseInAvatarFrame(controller::Action::RIGHT_HAND); + bool stepDetected = false; float myScale = myAvatar.getAvatarScale(); if (!withinBaseOfSupport(currentHeadPose) && @@ -3898,10 +3899,12 @@ bool MyAvatar::FollowHelper::shouldActivateHorizontalCG(MyAvatar& myAvatar) cons glm::vec3 currentHeadPosition = currentHeadPose.getTranslation(); float anatomicalHeadToHipsDistance = glm::length(defaultHeadPosition - defaultHipsPosition); if (!isActive(Horizontal) && - (glm::length(currentHeadPosition - defaultHipsPosition) > (anatomicalHeadToHipsDistance + (DEFAULT_AVATAR_SPINE_STRETCH_LIMIT * anatomicalHeadToHipsDistance * myAvatar.getAvatarScale())))) { + (glm::length(currentHeadPosition - defaultHipsPosition) > (anatomicalHeadToHipsDistance + (DEFAULT_AVATAR_SPINE_STRETCH_LIMIT * anatomicalHeadToHipsDistance)))) { myAvatar.setResetMode(true); + qCDebug(interfaceapp) << "failsafe called, default back " << anatomicalHeadToHipsDistance << " scale " << myAvatar.getAvatarScale() << " current length " << glm::length(currentHeadPosition - defaultHipsPosition); stepDetected = true; } + qCDebug(interfaceapp) << "current head height " << currentHeadPose.getTranslation().y << " scale " << myAvatar.getAvatarScale() << " anatomical " << anatomicalHeadToHipsDistance; } return stepDetected; } @@ -3918,7 +3921,7 @@ bool MyAvatar::FollowHelper::shouldActivateVertical(const MyAvatar& myAvatar, co void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix, bool hasDriveInput) { - const float VELOCITY_THRESHHOLD = 0.5f; + const float VELOCITY_THRESHHOLD = 1.0f; float currentVelocity = glm::length(myAvatar.getLocalVelocity() / myAvatar.getSensorToWorldScale()); if (myAvatar.getHMDLeanRecenterEnabled() && diff --git a/libraries/shared/src/AvatarConstants.h b/libraries/shared/src/AvatarConstants.h index 4e6fa67c9f..6f807a4115 100644 --- a/libraries/shared/src/AvatarConstants.h +++ b/libraries/shared/src/AvatarConstants.h @@ -24,17 +24,17 @@ const float DEFAULT_AVATAR_SUPPORT_BASE_LEFT = -0.25f; const float DEFAULT_AVATAR_SUPPORT_BASE_RIGHT = 0.25f; const float DEFAULT_AVATAR_SUPPORT_BASE_FRONT = -0.20f; const float DEFAULT_AVATAR_SUPPORT_BASE_BACK = 0.12f; -const float DEFAULT_AVATAR_LATERAL_STEPPING_THRESHOLD = 0.15f; +const float DEFAULT_AVATAR_LATERAL_STEPPING_THRESHOLD = 0.10f; const float DEFAULT_AVATAR_ANTERIOR_STEPPING_THRESHOLD = 0.07f; -const float DEFAULT_AVATAR_POSTERIOR_STEPPING_THRESHOLD = 0.08f; -const float DEFAULT_AVATAR_HEAD_ANGULAR_VELOCITY_STEPPING_THRESHOLD = 0.6f; +const float DEFAULT_AVATAR_POSTERIOR_STEPPING_THRESHOLD = 0.06f; +const float DEFAULT_AVATAR_HEAD_ANGULAR_VELOCITY_STEPPING_THRESHOLD = 0.4f; const float DEFAULT_AVATAR_MODE_HEIGHT_STEPPING_THRESHOLD = -0.02f; const float DEFAULT_HANDS_VELOCITY_DIRECTION_STEPPING_THRESHOLD = 0.4f; const float DEFAULT_HANDS_ANGULAR_VELOCITY_STEPPING_THRESHOLD = 3.3f; const float DEFAULT_HEAD_VELOCITY_STEPPING_THRESHOLD = 0.18f; const float DEFAULT_HEAD_PITCH_STEPPING_TOLERANCE = 7.0f; const float DEFAULT_HEAD_ROLL_STEPPING_TOLERANCE = 7.0f; -const float DEFAULT_AVATAR_SPINE_STRETCH_LIMIT = 0.04f; +const float DEFAULT_AVATAR_SPINE_STRETCH_LIMIT = 0.05f; const float DEFAULT_AVATAR_FORWARD_DAMPENING_FACTOR = 0.5f; const float DEFAULT_AVATAR_LATERAL_DAMPENING_FACTOR = 2.0f; const float DEFAULT_AVATAR_HIPS_MASS = 40.0f; diff --git a/scripts/developer/objectOrientedStep.js b/scripts/developer/objectOrientedStep.js index 4eca1fb115..a5c27e36b9 100644 --- a/scripts/developer/objectOrientedStep.js +++ b/scripts/developer/objectOrientedStep.js @@ -584,7 +584,11 @@ function update(dt) { // make the signal colors reflect the current thresholds that have been crossed updateSignalColors(); - print("the current back length is " + currentStateReadings.backLength + " " + DEFAULT_TORSO_LENGTH); + + SPINE_STRETCH_LIMIT = (0.04) * DEFAULT_TORSO_LENGTH * MyAvatar.scale; + + //print("the spine stretch limit is " + SPINE_STRETCH_LIMIT + " head avatar space is " + currentStateReadings.headPose.translation.y); + //print("the current back length is " + currentStateReadings.backLength + " " + DEFAULT_TORSO_LENGTH); // Conditions for taking a step. // 1. off the base of support. front, lateral, back edges. // 2. head is not lower than the height mode value by more than the maxHeightChange tolerance @@ -672,6 +676,7 @@ Script.setTimeout(function() { DEFAULT_HIPS_POSITION = MyAvatar.getAbsoluteDefaultJointTranslationInObjectFrame(MyAvatar.getJointIndex("Hips")); DEFAULT_HEAD_POSITION = MyAvatar.getAbsoluteDefaultJointTranslationInObjectFrame(MyAvatar.getJointIndex("Head")); DEFAULT_TORSO_LENGTH = Vec3.length(Vec3.subtract(DEFAULT_HEAD_POSITION, DEFAULT_HIPS_POSITION)); + SPINE_STRETCH_LIMIT = (0.04) * DEFAULT_TORSO_LENGTH * MyAvatar.scale; },(4*LOADING_DELAY)); Script.update.connect(update); From e8ce1526876cfbba3c883891e9aa1165ea24adb6 Mon Sep 17 00:00:00 2001 From: sabrina-shanman Date: Wed, 5 Sep 2018 14:46:07 -0700 Subject: [PATCH 06/24] Scale collision picks relative to parent by adding and using more specialized transform nodes. --- .../src/raypick/PickScriptingInterface.cpp | 16 ++++++++-- .../src/ui/overlays/OverlayTransformNode.cpp | 30 +++++++++++++++++++ .../src/ui/overlays/OverlayTransformNode.h | 26 ++++++++++++++++ .../avatars-renderer/AvatarTransformNode.cpp | 30 +++++++++++++++++++ .../avatars-renderer/AvatarTransformNode.h | 25 ++++++++++++++++ .../entities/src/EntityTransformNode.cpp | 30 +++++++++++++++++++ libraries/entities/src/EntityTransformNode.h | 25 ++++++++++++++++ 7 files changed, 180 insertions(+), 2 deletions(-) create mode 100644 interface/src/ui/overlays/OverlayTransformNode.cpp create mode 100644 interface/src/ui/overlays/OverlayTransformNode.h create mode 100644 libraries/avatars-renderer/src/avatars-renderer/AvatarTransformNode.cpp create mode 100644 libraries/avatars-renderer/src/avatars-renderer/AvatarTransformNode.h create mode 100644 libraries/entities/src/EntityTransformNode.cpp create mode 100644 libraries/entities/src/EntityTransformNode.h diff --git a/interface/src/raypick/PickScriptingInterface.cpp b/interface/src/raypick/PickScriptingInterface.cpp index 6dedf3fca1..c3a783a72b 100644 --- a/interface/src/raypick/PickScriptingInterface.cpp +++ b/interface/src/raypick/PickScriptingInterface.cpp @@ -24,11 +24,13 @@ #include "CollisionPick.h" #include "SpatialParentFinder.h" -#include "NestableTransformNode.h" #include "PickTransformNode.h" #include "MouseTransformNode.h" #include "avatar/MyAvatarHeadTransformNode.h" #include "avatar/AvatarManager.h" +#include "avatars-renderer/AvatarTransformNode.h" +#include "ui/overlays/OverlayTransformNode.h" +#include "EntityTransformNode.h" #include @@ -375,6 +377,16 @@ std::shared_ptr PickScriptingInterface::createTransformNode(const } auto sharedNestablePointer = nestablePointer.lock(); if (success && sharedNestablePointer) { + NestableType nestableType = sharedNestablePointer->getNestableType(); + if (nestableType == NestableType::Avatar) { + return std::make_shared(std::static_pointer_cast(sharedNestablePointer), parentJointIndex); + } + if (nestableType == NestableType::Overlay) { + return std::make_shared(std::static_pointer_cast(sharedNestablePointer), parentJointIndex); + } + if (nestableType == NestableType::Entity) { + return std::make_shared(std::static_pointer_cast(sharedNestablePointer), parentJointIndex); + } return std::make_shared(nestablePointer, parentJointIndex); } } @@ -394,7 +406,7 @@ std::shared_ptr PickScriptingInterface::createTransformNode(const } else if (!joint.isNull()) { auto myAvatar = DependencyManager::get()->getMyAvatar(); int jointIndex = myAvatar->getJointIndex(joint); - return std::make_shared(myAvatar, jointIndex); + return std::make_shared(myAvatar, jointIndex); } } diff --git a/interface/src/ui/overlays/OverlayTransformNode.cpp b/interface/src/ui/overlays/OverlayTransformNode.cpp new file mode 100644 index 0000000000..64f5be932c --- /dev/null +++ b/interface/src/ui/overlays/OverlayTransformNode.cpp @@ -0,0 +1,30 @@ +// +// Created by Sabrina Shanman 9/5/2018 +// Copyright 2018 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#include "OverlayTransformNode.h" + +OverlayTransformNode::OverlayTransformNode(std::weak_ptr overlay, int jointIndex) : + _overlay(overlay), + _jointIndex(jointIndex) +{} + +Transform OverlayTransformNode::getTransform() { + auto overlay = _overlay.lock(); + if (!overlay) { + return Transform(); + } + + bool success; + Transform jointWorldTransform = overlay->getTransform(_jointIndex, success); + if (!success) { + jointWorldTransform = Transform(); + } + + jointWorldTransform.setScale(overlay->getBounds().getScale()); + + return jointWorldTransform; +} \ No newline at end of file diff --git a/interface/src/ui/overlays/OverlayTransformNode.h b/interface/src/ui/overlays/OverlayTransformNode.h new file mode 100644 index 0000000000..79e6a37f45 --- /dev/null +++ b/interface/src/ui/overlays/OverlayTransformNode.h @@ -0,0 +1,26 @@ +// +// Created by Sabrina Shanman 9/5/2018 +// Copyright 2018 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#ifndef hifi_OverlayTransformNode_h +#define hifi_OverlayTransformNode_h + +#include "NestableTransformNode.h" + +#include "Base3DOverlay.h" + +// For 3D overlays only +class OverlayTransformNode : public TransformNode { +public: + OverlayTransformNode(std::weak_ptr overlay, int jointIndex); + Transform getTransform() override; + +protected: + std::weak_ptr _overlay; + int _jointIndex; +}; + +#endif // hifi_OverlayTransformNode_h \ No newline at end of file diff --git a/libraries/avatars-renderer/src/avatars-renderer/AvatarTransformNode.cpp b/libraries/avatars-renderer/src/avatars-renderer/AvatarTransformNode.cpp new file mode 100644 index 0000000000..2f198e8917 --- /dev/null +++ b/libraries/avatars-renderer/src/avatars-renderer/AvatarTransformNode.cpp @@ -0,0 +1,30 @@ +// +// Created by Sabrina Shanman 9/5/2018 +// Copyright 2018 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#include "AvatarTransformNode.h" + +AvatarTransformNode::AvatarTransformNode(AvatarWeakPointer avatar, int jointIndex) : + _avatar(avatar), + _jointIndex(jointIndex) +{} + +Transform AvatarTransformNode::getTransform() { + auto avatar = _avatar.lock(); + if (!avatar) { + return Transform(); + } + + bool success; + Transform jointWorldTransform = avatar->getTransform(_jointIndex, success); + if (!success) { + jointWorldTransform = Transform(); + } + + jointWorldTransform.setScale(avatar->scaleForChildren()); + + return jointWorldTransform; +} \ No newline at end of file diff --git a/libraries/avatars-renderer/src/avatars-renderer/AvatarTransformNode.h b/libraries/avatars-renderer/src/avatars-renderer/AvatarTransformNode.h new file mode 100644 index 0000000000..9036d42639 --- /dev/null +++ b/libraries/avatars-renderer/src/avatars-renderer/AvatarTransformNode.h @@ -0,0 +1,25 @@ +// +// Created by Sabrina Shanman 9/5/2018 +// Copyright 2018 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#ifndef hifi_AvatarTransformNode_h +#define hifi_AvatarTransformNode_h + +#include "NestableTransformNode.h" + +#include "Avatar.h" + +class AvatarTransformNode : public TransformNode { +public: + AvatarTransformNode(AvatarWeakPointer avatar, int jointIndex); + Transform getTransform() override; + +protected: + AvatarWeakPointer _avatar; + int _jointIndex; +}; + +#endif // hifi_AvatarTransformNode_h \ No newline at end of file diff --git a/libraries/entities/src/EntityTransformNode.cpp b/libraries/entities/src/EntityTransformNode.cpp new file mode 100644 index 0000000000..42b60759db --- /dev/null +++ b/libraries/entities/src/EntityTransformNode.cpp @@ -0,0 +1,30 @@ +// +// Created by Sabrina Shanman 9/5/2018 +// Copyright 2018 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#include "EntityTransformNode.h" + +EntityTransformNode::EntityTransformNode(EntityItemWeakPointer entity, int jointIndex) : + _entity(entity), + _jointIndex(jointIndex) +{} + +Transform EntityTransformNode::getTransform() { + auto entity = _entity.lock(); + if (!entity) { + return Transform(); + } + + bool success; + Transform jointWorldTransform = entity->getTransform(_jointIndex, success); + if (!success) { + jointWorldTransform = Transform(); + } + + jointWorldTransform.setScale(entity->getScaledDimensions()); + + return jointWorldTransform; +} \ No newline at end of file diff --git a/libraries/entities/src/EntityTransformNode.h b/libraries/entities/src/EntityTransformNode.h new file mode 100644 index 0000000000..fc5eeff652 --- /dev/null +++ b/libraries/entities/src/EntityTransformNode.h @@ -0,0 +1,25 @@ +// +// Created by Sabrina Shanman 9/5/2018 +// Copyright 2018 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#ifndef hifi_EntityTransformNode_h +#define hifi_EntityTransformNode_h + +#include "NestableTransformNode.h" + +#include "EntityItem.h" + +class EntityTransformNode : public TransformNode { +public: + EntityTransformNode(EntityItemWeakPointer entity, int jointIndex); + Transform getTransform() override; + +protected: + EntityItemWeakPointer _entity; + int _jointIndex; +}; + +#endif // hifi_EntityTransformNode_h \ No newline at end of file From 84a2512f315d581edd54400ecb2cf457b69fc5b7 Mon Sep 17 00:00:00 2001 From: sabrina-shanman Date: Wed, 5 Sep 2018 16:50:39 -0700 Subject: [PATCH 07/24] Fix collision pick scale not being used --- interface/src/raypick/CollisionPick.cpp | 18 +++++++++--------- interface/src/raypick/CollisionPick.h | 6 +++--- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/interface/src/raypick/CollisionPick.cpp b/interface/src/raypick/CollisionPick.cpp index 7d0276875b..d183aecfeb 100644 --- a/interface/src/raypick/CollisionPick.cpp +++ b/interface/src/raypick/CollisionPick.cpp @@ -86,23 +86,23 @@ bool CollisionPick::isLoaded() const { return !_mathPick.shouldComputeShapeInfo() || (_cachedResource && _cachedResource->isLoaded()); } -bool CollisionPick::getShapeInfoReady() { +bool CollisionPick::getShapeInfoReady(const CollisionRegion& pick) { if (_mathPick.shouldComputeShapeInfo()) { if (_cachedResource && _cachedResource->isLoaded()) { - computeShapeInfo(_mathPick, *_mathPick.shapeInfo, _cachedResource); + computeShapeInfo(pick, *_mathPick.shapeInfo, _cachedResource); _mathPick.loaded = true; } else { _mathPick.loaded = false; } } else { - computeShapeInfoDimensionsOnly(_mathPick, *_mathPick.shapeInfo, _cachedResource); + computeShapeInfoDimensionsOnly(pick, *_mathPick.shapeInfo, _cachedResource); _mathPick.loaded = true; } return _mathPick.loaded; } -void CollisionPick::computeShapeInfoDimensionsOnly(CollisionRegion& pick, ShapeInfo& shapeInfo, QSharedPointer resource) { +void CollisionPick::computeShapeInfoDimensionsOnly(const CollisionRegion& pick, ShapeInfo& shapeInfo, QSharedPointer resource) { ShapeType type = shapeInfo.getType(); glm::vec3 dimensions = pick.transform.getScale(); QString modelURL = (resource ? resource->getURL().toString() : ""); @@ -115,7 +115,7 @@ void CollisionPick::computeShapeInfoDimensionsOnly(CollisionRegion& pick, ShapeI } } -void CollisionPick::computeShapeInfo(CollisionRegion& pick, ShapeInfo& shapeInfo, QSharedPointer resource) { +void CollisionPick::computeShapeInfo(const CollisionRegion& pick, ShapeInfo& shapeInfo, QSharedPointer resource) { // This code was copied and modified from RenderableModelEntityItem::computeShapeInfo // TODO: Move to some shared code area (in entities-renderer? model-networking?) // after we verify this is working and do a diff comparison with RenderableModelEntityItem::computeShapeInfo @@ -393,9 +393,9 @@ PickResultPointer CollisionPick::getEntityIntersection(const CollisionRegion& pi // Cannot compute result return std::make_shared(pick.toVariantMap(), std::vector(), std::vector()); } - getShapeInfoReady(); + getShapeInfoReady(pick); - auto entityIntersections = _physicsEngine->contactTest(USER_COLLISION_MASK_ENTITIES, *pick.shapeInfo, pick.transform, USER_COLLISION_GROUP_DYNAMIC, pick.threshold); + auto entityIntersections = _physicsEngine->contactTest(USER_COLLISION_MASK_ENTITIES, *_mathPick.shapeInfo, pick.transform, USER_COLLISION_GROUP_DYNAMIC, pick.threshold); filterIntersections(entityIntersections); return std::make_shared(pick, entityIntersections, std::vector()); } @@ -409,9 +409,9 @@ PickResultPointer CollisionPick::getAvatarIntersection(const CollisionRegion& pi // Cannot compute result return std::make_shared(pick, std::vector(), std::vector()); } - getShapeInfoReady(); + getShapeInfoReady(pick); - auto avatarIntersections = _physicsEngine->contactTest(USER_COLLISION_MASK_AVATARS, *pick.shapeInfo, pick.transform, USER_COLLISION_GROUP_DYNAMIC, pick.threshold); + auto avatarIntersections = _physicsEngine->contactTest(USER_COLLISION_MASK_AVATARS, *_mathPick.shapeInfo, pick.transform, USER_COLLISION_GROUP_DYNAMIC, pick.threshold); filterIntersections(avatarIntersections); return std::make_shared(pick, std::vector(), avatarIntersections); } diff --git a/interface/src/raypick/CollisionPick.h b/interface/src/raypick/CollisionPick.h index ce8b3bd199..fe0e5a6337 100644 --- a/interface/src/raypick/CollisionPick.h +++ b/interface/src/raypick/CollisionPick.h @@ -62,9 +62,9 @@ protected: // Returns true if the resource for _mathPick.shapeInfo is loaded or if a resource is not needed. bool isLoaded() const; // Returns true if _mathPick.shapeInfo is valid. Otherwise, attempts to get the _mathPick ready for use. - bool getShapeInfoReady(); - void computeShapeInfo(CollisionRegion& pick, ShapeInfo& shapeInfo, QSharedPointer resource); - void computeShapeInfoDimensionsOnly(CollisionRegion& pick, ShapeInfo& shapeInfo, QSharedPointer resource); + bool getShapeInfoReady(const CollisionRegion& pick); + void computeShapeInfo(const CollisionRegion& pick, ShapeInfo& shapeInfo, QSharedPointer resource); + void computeShapeInfoDimensionsOnly(const CollisionRegion& pick, ShapeInfo& shapeInfo, QSharedPointer resource); void filterIntersections(std::vector& intersections) const; CollisionRegion _mathPick; From 6fb335429de5b9db88c76d5d825e5d4dfb8530c6 Mon Sep 17 00:00:00 2001 From: amantley Date: Wed, 5 Sep 2018 17:55:27 -0700 Subject: [PATCH 08/24] starting to re-implement the walking state detection for smoothwalking --- interface/src/avatar/MyAvatar.cpp | 15 +++++++++++++-- interface/src/avatar/MyAvatar.h | 1 + 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 4fa41809d0..8a29d3f9c7 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -516,6 +516,10 @@ void MyAvatar::update(float deltaTime) { head->relax(deltaTime); updateFromTrackers(deltaTime); + if (_isInWalkingState && glm::length(getControllerPoseInAvatarFrame(controller::Action::HEAD).getVelocity()) < 0.15f) { + _isInWalkingState = false; + } + // Get audio loudness data from audio input device // Also get the AudioClient so we can update the avatar bounding box data // on the AudioClient side. @@ -3912,7 +3916,7 @@ void MyAvatar::lateUpdatePalms() { Avatar::updatePalms(); } -static const float FOLLOW_TIME = 0.1f; +static const float FOLLOW_TIME = 0.5f; MyAvatar::FollowHelper::FollowHelper() { deactivate(); @@ -4002,7 +4006,8 @@ bool MyAvatar::FollowHelper::shouldActivateHorizontalCG(MyAvatar& myAvatar) cons controller::Pose currentLeftHandPose = myAvatar.getControllerPoseInAvatarFrame(controller::Action::LEFT_HAND); controller::Pose currentRightHandPose = myAvatar.getControllerPoseInAvatarFrame(controller::Action::RIGHT_HAND); - + qCDebug(interfaceapp) << "currentVelocity is " < 0.15f) { + myAvatar._isInWalkingState = true; + } } else { glm::vec3 defaultHipsPosition = myAvatar.getAbsoluteDefaultJointTranslationInObjectFrame(myAvatar.getJointIndex("Hips")); glm::vec3 defaultHeadPosition = myAvatar.getAbsoluteDefaultJointTranslationInObjectFrame(myAvatar.getJointIndex("Head")); @@ -4024,6 +4032,9 @@ bool MyAvatar::FollowHelper::shouldActivateHorizontalCG(MyAvatar& myAvatar) cons myAvatar.setResetMode(true); qCDebug(interfaceapp) << "failsafe called, default back " << anatomicalHeadToHipsDistance << " scale " << myAvatar.getAvatarScale() << " current length " << glm::length(currentHeadPosition - defaultHipsPosition); stepDetected = true; + if (glm::length(currentHeadPose.velocity) > 0.15f) { + myAvatar._isInWalkingState = true; + } } qCDebug(interfaceapp) << "current head height " << currentHeadPose.getTranslation().y << " scale " << myAvatar.getAvatarScale() << " anatomical " << anatomicalHeadToHipsDistance; } diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 06267b3819..aa76e29b14 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -1788,6 +1788,7 @@ private: ThreadSafeValueCache _walkBackwardSpeed { DEFAULT_AVATAR_MAX_WALKING_BACKWARD_SPEED }; ThreadSafeValueCache _sprintSpeed { AVATAR_SPRINT_SPEED_SCALAR }; float _walkSpeedScalar { AVATAR_WALK_SPEED_SCALAR }; + bool _isInWalkingState { false }; // load avatar scripts once when rig is ready bool _shouldLoadScripts { false }; From f7226757ad0d901adf02859e20025b616dd4b058 Mon Sep 17 00:00:00 2001 From: sabrina-shanman Date: Thu, 6 Sep 2018 10:03:05 -0700 Subject: [PATCH 09/24] Just import TransformNode in AvatarTransformNode.h and similar --- interface/src/ui/overlays/OverlayTransformNode.h | 2 +- .../avatars-renderer/src/avatars-renderer/AvatarTransformNode.h | 2 +- libraries/entities/src/EntityTransformNode.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/interface/src/ui/overlays/OverlayTransformNode.h b/interface/src/ui/overlays/OverlayTransformNode.h index 79e6a37f45..b9ea9f72c4 100644 --- a/interface/src/ui/overlays/OverlayTransformNode.h +++ b/interface/src/ui/overlays/OverlayTransformNode.h @@ -8,7 +8,7 @@ #ifndef hifi_OverlayTransformNode_h #define hifi_OverlayTransformNode_h -#include "NestableTransformNode.h" +#include "TransformNode.h" #include "Base3DOverlay.h" diff --git a/libraries/avatars-renderer/src/avatars-renderer/AvatarTransformNode.h b/libraries/avatars-renderer/src/avatars-renderer/AvatarTransformNode.h index 9036d42639..03191b8dbe 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/AvatarTransformNode.h +++ b/libraries/avatars-renderer/src/avatars-renderer/AvatarTransformNode.h @@ -8,7 +8,7 @@ #ifndef hifi_AvatarTransformNode_h #define hifi_AvatarTransformNode_h -#include "NestableTransformNode.h" +#include "TransformNode.h" #include "Avatar.h" diff --git a/libraries/entities/src/EntityTransformNode.h b/libraries/entities/src/EntityTransformNode.h index fc5eeff652..b7388600df 100644 --- a/libraries/entities/src/EntityTransformNode.h +++ b/libraries/entities/src/EntityTransformNode.h @@ -8,7 +8,7 @@ #ifndef hifi_EntityTransformNode_h #define hifi_EntityTransformNode_h -#include "NestableTransformNode.h" +#include "TransformNode.h" #include "EntityItem.h" From 390e89a64ddfa8cecead7f1b2e3403d80e63939b Mon Sep 17 00:00:00 2001 From: sabrina-shanman Date: Thu, 6 Sep 2018 10:20:26 -0700 Subject: [PATCH 10/24] Fix missing NestableTransformNode import --- interface/src/raypick/PickScriptingInterface.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/interface/src/raypick/PickScriptingInterface.cpp b/interface/src/raypick/PickScriptingInterface.cpp index c3a783a72b..41dd3bb6de 100644 --- a/interface/src/raypick/PickScriptingInterface.cpp +++ b/interface/src/raypick/PickScriptingInterface.cpp @@ -28,6 +28,7 @@ #include "MouseTransformNode.h" #include "avatar/MyAvatarHeadTransformNode.h" #include "avatar/AvatarManager.h" +#include "NestableTransformNode.h" #include "avatars-renderer/AvatarTransformNode.h" #include "ui/overlays/OverlayTransformNode.h" #include "EntityTransformNode.h" From e8ea95e3758ec5893100d49eae30549d94dbb6c5 Mon Sep 17 00:00:00 2001 From: sabrina-shanman Date: Thu, 6 Sep 2018 10:21:48 -0700 Subject: [PATCH 11/24] Use elseifs in PickScriptingInterface::createTransformNode --- interface/src/raypick/PickScriptingInterface.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/interface/src/raypick/PickScriptingInterface.cpp b/interface/src/raypick/PickScriptingInterface.cpp index 41dd3bb6de..6b8a2d0d7a 100644 --- a/interface/src/raypick/PickScriptingInterface.cpp +++ b/interface/src/raypick/PickScriptingInterface.cpp @@ -381,14 +381,13 @@ std::shared_ptr PickScriptingInterface::createTransformNode(const NestableType nestableType = sharedNestablePointer->getNestableType(); if (nestableType == NestableType::Avatar) { return std::make_shared(std::static_pointer_cast(sharedNestablePointer), parentJointIndex); - } - if (nestableType == NestableType::Overlay) { + } else if (nestableType == NestableType::Overlay) { return std::make_shared(std::static_pointer_cast(sharedNestablePointer), parentJointIndex); - } - if (nestableType == NestableType::Entity) { + } else if (nestableType == NestableType::Entity) { return std::make_shared(std::static_pointer_cast(sharedNestablePointer), parentJointIndex); + } else { + return std::make_shared(nestablePointer, parentJointIndex); } - return std::make_shared(nestablePointer, parentJointIndex); } } From 3f7a7fb11ab1bf4877f59e93381a3df8bbf0dc56 Mon Sep 17 00:00:00 2001 From: sabrina-shanman Date: Thu, 6 Sep 2018 10:29:01 -0700 Subject: [PATCH 12/24] Return early from AvatarTransformNode and similar when getTransform fails --- interface/src/ui/overlays/OverlayTransformNode.cpp | 2 +- .../src/avatars-renderer/AvatarTransformNode.cpp | 2 +- libraries/entities/src/EntityTransformNode.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/interface/src/ui/overlays/OverlayTransformNode.cpp b/interface/src/ui/overlays/OverlayTransformNode.cpp index 64f5be932c..d0a6618e37 100644 --- a/interface/src/ui/overlays/OverlayTransformNode.cpp +++ b/interface/src/ui/overlays/OverlayTransformNode.cpp @@ -21,7 +21,7 @@ Transform OverlayTransformNode::getTransform() { bool success; Transform jointWorldTransform = overlay->getTransform(_jointIndex, success); if (!success) { - jointWorldTransform = Transform(); + return Transform(); } jointWorldTransform.setScale(overlay->getBounds().getScale()); diff --git a/libraries/avatars-renderer/src/avatars-renderer/AvatarTransformNode.cpp b/libraries/avatars-renderer/src/avatars-renderer/AvatarTransformNode.cpp index 2f198e8917..fc5ba5bc1a 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/AvatarTransformNode.cpp +++ b/libraries/avatars-renderer/src/avatars-renderer/AvatarTransformNode.cpp @@ -21,7 +21,7 @@ Transform AvatarTransformNode::getTransform() { bool success; Transform jointWorldTransform = avatar->getTransform(_jointIndex, success); if (!success) { - jointWorldTransform = Transform(); + return Transform(); } jointWorldTransform.setScale(avatar->scaleForChildren()); diff --git a/libraries/entities/src/EntityTransformNode.cpp b/libraries/entities/src/EntityTransformNode.cpp index 42b60759db..5b0a690619 100644 --- a/libraries/entities/src/EntityTransformNode.cpp +++ b/libraries/entities/src/EntityTransformNode.cpp @@ -21,7 +21,7 @@ Transform EntityTransformNode::getTransform() { bool success; Transform jointWorldTransform = entity->getTransform(_jointIndex, success); if (!success) { - jointWorldTransform = Transform(); + return Transform(); } jointWorldTransform.setScale(entity->getScaledDimensions()); From 7839ba42db01d7b5b755a961830530f731602148 Mon Sep 17 00:00:00 2001 From: sabrina-shanman Date: Thu, 6 Sep 2018 10:37:48 -0700 Subject: [PATCH 13/24] Make the Collision Pick threshold scale with the largest dimension of the parent --- interface/src/raypick/CollisionPick.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/interface/src/raypick/CollisionPick.cpp b/interface/src/raypick/CollisionPick.cpp index d183aecfeb..c21ee69b74 100644 --- a/interface/src/raypick/CollisionPick.cpp +++ b/interface/src/raypick/CollisionPick.cpp @@ -357,12 +357,14 @@ CollisionPick::CollisionPick(const PickFilter& filter, float maxDistance, bool e CollisionRegion CollisionPick::getMathematicalPick() const { CollisionRegion mathPick = _mathPick; mathPick.loaded = isLoaded(); - if (!parentTransform) { - return mathPick; - } else { - mathPick.transform = parentTransform->getTransform().worldTransform(mathPick.transform); - return mathPick; + if (parentTransform) { + Transform parentTransformValue = parentTransform->getTransform(); + mathPick.transform = parentTransformValue.worldTransform(mathPick.transform); + glm::vec3 scale = parentTransformValue.getScale(); + float largestDimension = glm::max(glm::max(scale.x, scale.y), scale.z); + mathPick.threshold *= largestDimension; } + return mathPick; } void CollisionPick::filterIntersections(std::vector& intersections) const { From 727b62144fb939501af03a4034850f4474f9a222 Mon Sep 17 00:00:00 2001 From: sabrina-shanman Date: Thu, 6 Sep 2018 12:03:13 -0700 Subject: [PATCH 14/24] Fix MyAvatarHeadTransformNode not using avatar scale --- interface/src/avatar/MyAvatarHeadTransformNode.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/interface/src/avatar/MyAvatarHeadTransformNode.cpp b/interface/src/avatar/MyAvatarHeadTransformNode.cpp index 9c202ba94a..1e83a17dd3 100644 --- a/interface/src/avatar/MyAvatarHeadTransformNode.cpp +++ b/interface/src/avatar/MyAvatarHeadTransformNode.cpp @@ -16,8 +16,9 @@ Transform MyAvatarHeadTransformNode::getTransform() { auto myAvatar = DependencyManager::get()->getMyAvatar(); glm::vec3 pos = myAvatar->getHeadPosition(); + glm::vec3 scale = glm::vec3(myAvatar->scaleForChildren()); glm::quat headOri = myAvatar->getHeadOrientation(); glm::quat ori = headOri * glm::angleAxis(-PI / 2.0f, Vectors::RIGHT); - return Transform(ori, glm::vec3(1.0f), pos); + return Transform(ori, scale, pos); } \ No newline at end of file From 714cfc5ef12f0cac1966306f0ec047edcf800f4b Mon Sep 17 00:00:00 2001 From: sabrina-shanman Date: Thu, 6 Sep 2018 12:08:27 -0700 Subject: [PATCH 15/24] Add scaling information to CollisionRegion jsdoc and missing info to CollisionPickProperties jsdoc --- interface/src/raypick/PickScriptingInterface.cpp | 13 ++++++++++--- libraries/shared/src/RegisteredMetaTypes.h | 5 +++-- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/interface/src/raypick/PickScriptingInterface.cpp b/interface/src/raypick/PickScriptingInterface.cpp index 6b8a2d0d7a..b892c6da8e 100644 --- a/interface/src/raypick/PickScriptingInterface.cpp +++ b/interface/src/raypick/PickScriptingInterface.cpp @@ -263,9 +263,16 @@ unsigned int PickScriptingInterface::createParabolaPick(const QVariant& properti * A set of properties that can be passed to {@link Picks.createPick} to create a new Collision Pick. * @typedef {object} Picks.CollisionPickProperties -* @property {Shape} shape - The information about the collision region's size and shape. -* @property {Vec3} position - The position of the collision region. -* @property {Quat} orientation - The orientation of the collision region. +* @property {boolean} [enabled=false] If this Pick should start enabled or not. Disabled Picks do not updated their pick results. +* @property {number} [filter=Picks.PICK_NOTHING] The filter for this Pick to use, constructed using filter flags combined using bitwise OR. +* @property {Shape} shape - The information about the collision region's size and shape. Dimensions are relative to a parent if defined. +* @property {Vec3} position - The position of the collision region, relative to a parent if defined. +* @property {Quat} orientation - The orientation of the collision region, relative to a parent if defined. +* @property {float} threshold - The approximate minimum penetration depth for a test object to be considered in contact with the collision region, relative to a parent if defined. +* For overlay and entity parents, this is relative to the parent's largest dimension. +* @property {Uuid} parentID - The ID of the parent, either an avatar, an entity, or an overlay. +* @property {number} parentJointIndex - The joint of the parent to parent to, for example, the joints on the model of an avatar. (default = 0, no joint) +* @property {string} joint - If "Mouse," parents the pick to the mouse. If "Avatar," parents the pick to MyAvatar's head. Otherwise, parents to the joint of the given name on MyAvatar. */ unsigned int PickScriptingInterface::createCollisionPick(const QVariant& properties) { QVariantMap propMap = properties.toMap(); diff --git a/libraries/shared/src/RegisteredMetaTypes.h b/libraries/shared/src/RegisteredMetaTypes.h index 02f5fa570c..79adce0a39 100644 --- a/libraries/shared/src/RegisteredMetaTypes.h +++ b/libraries/shared/src/RegisteredMetaTypes.h @@ -259,10 +259,11 @@ public: * A CollisionRegion defines a volume for checking collisions in the physics simulation. * @typedef {object} CollisionRegion -* @property {Shape} shape - The information about the collision region's size and shape. +* @property {Shape} shape - The information about the collision region's size and shape. Dimensions are relative to a parent if defined. * @property {Vec3} position - The position of the collision region, relative to a parent if defined. * @property {Quat} orientation - The orientation of the collision region, relative to a parent if defined. -* @property {float} threshold - The approximate minimum penetration depth for a test object to be considered in contact with the collision region. +* @property {float} threshold - The approximate minimum penetration depth for a test object to be considered in contact with the collision region, relative to a parent if defined. +* For overlay and entity parents, this is relative to the parent's largest dimension. * @property {Uuid} parentID - The ID of the parent, either an avatar, an entity, or an overlay. * @property {number} parentJointIndex - The joint of the parent to parent to, for example, the joints on the model of an avatar. (default = 0, no joint) * @property {string} joint - If "Mouse," parents the pick to the mouse. If "Avatar," parents the pick to MyAvatar's head. Otherwise, parents to the joint of the given name on MyAvatar. From 90a51e618134faf605074afb2785d0962dfa4121 Mon Sep 17 00:00:00 2001 From: amantley Date: Thu, 6 Sep 2018 13:12:48 -0700 Subject: [PATCH 16/24] added walk velocity threshold, this determines if we are in the walk state. when we are then we don't do cg leaning calculation. this will smooth out the walking in a large tracked area --- interface/src/avatar/MyAvatar.cpp | 59 +++++++++++++----------- interface/src/avatar/MyAvatar.h | 2 + interface/src/avatar/MySkeletonModel.cpp | 2 +- libraries/shared/src/AvatarConstants.h | 7 +-- 4 files changed, 39 insertions(+), 31 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 8a29d3f9c7..c8af792d8f 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -516,8 +516,8 @@ void MyAvatar::update(float deltaTime) { head->relax(deltaTime); updateFromTrackers(deltaTime); - if (_isInWalkingState && glm::length(getControllerPoseInAvatarFrame(controller::Action::HEAD).getVelocity()) < 0.15f) { - _isInWalkingState = false; + if (getIsInWalkingState() && glm::length(getControllerPoseInAvatarFrame(controller::Action::HEAD).getVelocity()) < DEFAULT_AVATAR_WALK_SPEED_THRESHOLD) { + setIsInWalkingState(false); } // Get audio loudness data from audio input device @@ -3806,6 +3806,10 @@ float MyAvatar::getUserEyeHeight() const { return userHeight - userHeight * ratio; } +bool MyAvatar::getIsInWalkingState() const { + return _isInWalkingState; +} + float MyAvatar::getWalkSpeed() const { return _walkSpeed.get() * _walkSpeedScalar; } @@ -3822,6 +3826,10 @@ void MyAvatar::setSprintMode(bool sprint) { _walkSpeedScalar = sprint ? _sprintSpeed.get() : AVATAR_WALK_SPEED_SCALAR; } +void MyAvatar::setIsInWalkingState(bool isWalking) { + _isInWalkingState = isWalking; +} + void MyAvatar::setWalkSpeed(float value) { _walkSpeed.set(value); } @@ -4006,37 +4014,38 @@ bool MyAvatar::FollowHelper::shouldActivateHorizontalCG(MyAvatar& myAvatar) cons controller::Pose currentLeftHandPose = myAvatar.getControllerPoseInAvatarFrame(controller::Action::LEFT_HAND); controller::Pose currentRightHandPose = myAvatar.getControllerPoseInAvatarFrame(controller::Action::RIGHT_HAND); - qCDebug(interfaceapp) << "currentVelocity is " < 0.15f) { - myAvatar._isInWalkingState = true; - } - } else { - glm::vec3 defaultHipsPosition = myAvatar.getAbsoluteDefaultJointTranslationInObjectFrame(myAvatar.getJointIndex("Hips")); - glm::vec3 defaultHeadPosition = myAvatar.getAbsoluteDefaultJointTranslationInObjectFrame(myAvatar.getJointIndex("Head")); - glm::vec3 currentHeadPosition = currentHeadPose.getTranslation(); - float anatomicalHeadToHipsDistance = glm::length(defaultHeadPosition - defaultHipsPosition); - if (!isActive(Horizontal) && - (glm::length(currentHeadPosition - defaultHipsPosition) > (anatomicalHeadToHipsDistance + (DEFAULT_AVATAR_SPINE_STRETCH_LIMIT * anatomicalHeadToHipsDistance)))) { - myAvatar.setResetMode(true); - qCDebug(interfaceapp) << "failsafe called, default back " << anatomicalHeadToHipsDistance << " scale " << myAvatar.getAvatarScale() << " current length " << glm::length(currentHeadPosition - defaultHipsPosition); + // a step is detected stepDetected = true; - if (glm::length(currentHeadPose.velocity) > 0.15f) { - myAvatar._isInWalkingState = true; + if (glm::length(currentHeadPose.velocity) > DEFAULT_AVATAR_WALK_SPEED_THRESHOLD) { + myAvatar.setIsInWalkingState(true); + } + } else { + glm::vec3 defaultHipsPosition = myAvatar.getAbsoluteDefaultJointTranslationInObjectFrame(myAvatar.getJointIndex("Hips")); + glm::vec3 defaultHeadPosition = myAvatar.getAbsoluteDefaultJointTranslationInObjectFrame(myAvatar.getJointIndex("Head")); + glm::vec3 currentHeadPosition = currentHeadPose.getTranslation(); + float anatomicalHeadToHipsDistance = glm::length(defaultHeadPosition - defaultHipsPosition); + if (!isActive(Horizontal) && + (glm::length(currentHeadPosition - defaultHipsPosition) > (anatomicalHeadToHipsDistance + (DEFAULT_AVATAR_SPINE_STRETCH_LIMIT * anatomicalHeadToHipsDistance)))) { + myAvatar.setResetMode(true); + stepDetected = true; + if (glm::length(currentHeadPose.velocity) > DEFAULT_AVATAR_WALK_SPEED_THRESHOLD) { + myAvatar.setIsInWalkingState(true); + } } } - qCDebug(interfaceapp) << "current head height " << currentHeadPose.getTranslation().y << " scale " << myAvatar.getAvatarScale() << " anatomical " << anatomicalHeadToHipsDistance; } return stepDetected; } @@ -4053,9 +4062,6 @@ bool MyAvatar::FollowHelper::shouldActivateVertical(const MyAvatar& myAvatar, co void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix, bool hasDriveInput) { - const float VELOCITY_THRESHHOLD = 1.0f; - float currentVelocity = glm::length(myAvatar.getLocalVelocity() / myAvatar.getSensorToWorldScale()); - if (myAvatar.getHMDLeanRecenterEnabled() && qApp->getCamera().getMode() != CAMERA_MODE_MIRROR) { if (!isActive(Rotation) && (shouldActivateRotation(myAvatar, desiredBodyMatrix, currentBodyMatrix) || hasDriveInput)) { @@ -4063,7 +4069,7 @@ void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat myAvatar.setHeadControllerFacingMovingAverage(myAvatar.getHeadControllerFacing()); } if (myAvatar.getCenterOfGravityModelEnabled()) { - if ((!isActive(Horizontal) && (shouldActivateHorizontalCG(myAvatar) || hasDriveInput)) || ( isActive(Horizontal) && (currentVelocity > VELOCITY_THRESHHOLD))) { + if (!isActive(Horizontal) && (shouldActivateHorizontalCG(myAvatar) || hasDriveInput)) { activate(Horizontal); if (myAvatar.getEnableStepResetRotation()) { activate(Rotation); @@ -4089,7 +4095,6 @@ void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat setForceActivateRotation(false); } if (!isActive(Horizontal) && getForceActivateHorizontal()) { - qCDebug(interfaceapp) << "called the recentering from script"; activate(Horizontal); setForceActivateHorizontal(false); } diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index aa76e29b14..5008190c33 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -1086,6 +1086,8 @@ public: const QUuid& getSelfID() const { return AVATAR_SELF_ID; } + void setIsInWalkingState(bool isWalking); + bool getIsInWalkingState() const; void setWalkSpeed(float value); float getWalkSpeed() const; void setWalkBackwardSpeed(float value); diff --git a/interface/src/avatar/MySkeletonModel.cpp b/interface/src/avatar/MySkeletonModel.cpp index 77d1a87195..3084542472 100644 --- a/interface/src/avatar/MySkeletonModel.cpp +++ b/interface/src/avatar/MySkeletonModel.cpp @@ -46,7 +46,7 @@ static AnimPose computeHipsInSensorFrame(MyAvatar* myAvatar, bool isFlying) { } glm::mat4 hipsMat; - if (myAvatar->getCenterOfGravityModelEnabled() && !isFlying) { + if (myAvatar->getCenterOfGravityModelEnabled() && !isFlying && !(myAvatar->getIsInWalkingState())) { // then we use center of gravity model hipsMat = myAvatar->deriveBodyUsingCgModel(); } else { diff --git a/libraries/shared/src/AvatarConstants.h b/libraries/shared/src/AvatarConstants.h index 80676b6a51..6c38d08c96 100644 --- a/libraries/shared/src/AvatarConstants.h +++ b/libraries/shared/src/AvatarConstants.h @@ -25,9 +25,9 @@ const float DEFAULT_AVATAR_SUPPORT_BASE_RIGHT = 0.25f; const float DEFAULT_AVATAR_SUPPORT_BASE_FRONT = -0.20f; const float DEFAULT_AVATAR_SUPPORT_BASE_BACK = 0.12f; const float DEFAULT_AVATAR_LATERAL_STEPPING_THRESHOLD = 0.10f; -const float DEFAULT_AVATAR_ANTERIOR_STEPPING_THRESHOLD = 0.07f; -const float DEFAULT_AVATAR_POSTERIOR_STEPPING_THRESHOLD = 0.06f; -const float DEFAULT_AVATAR_HEAD_ANGULAR_VELOCITY_STEPPING_THRESHOLD = 0.4f; +const float DEFAULT_AVATAR_ANTERIOR_STEPPING_THRESHOLD = 0.04f; +const float DEFAULT_AVATAR_POSTERIOR_STEPPING_THRESHOLD = 0.05f; +const float DEFAULT_AVATAR_HEAD_ANGULAR_VELOCITY_STEPPING_THRESHOLD = 0.3f; const float DEFAULT_AVATAR_MODE_HEIGHT_STEPPING_THRESHOLD = -0.02f; const float DEFAULT_HANDS_VELOCITY_DIRECTION_STEPPING_THRESHOLD = 0.4f; const float DEFAULT_HANDS_ANGULAR_VELOCITY_STEPPING_THRESHOLD = 3.3f; @@ -68,6 +68,7 @@ const glm::quat DEFAULT_AVATAR_RIGHTFOOT_ROT { -0.4016716778278351f, 0.915461599 const float DEFAULT_AVATAR_MAX_WALKING_SPEED = 2.6f; // meters / second const float DEFAULT_AVATAR_MAX_WALKING_BACKWARD_SPEED = 2.2f; // meters / second const float DEFAULT_AVATAR_MAX_FLYING_SPEED = 30.0f; // meters / second +const float DEFAULT_AVATAR_WALK_SPEED_THRESHOLD = 0.15f; const float DEFAULT_AVATAR_GRAVITY = -5.0f; // meters / second^2 const float DEFAULT_AVATAR_JUMP_SPEED = 3.5f; // meters / second From c986d55d8b9050eda0c1a48031ccd62d5f3ac5e1 Mon Sep 17 00:00:00 2001 From: amantley Date: Thu, 6 Sep 2018 13:18:54 -0700 Subject: [PATCH 17/24] removed step script from repo --- scripts/developer/objectOrientedStep.js | 688 ------------------------ 1 file changed, 688 deletions(-) delete mode 100644 scripts/developer/objectOrientedStep.js diff --git a/scripts/developer/objectOrientedStep.js b/scripts/developer/objectOrientedStep.js deleted file mode 100644 index a5c27e36b9..0000000000 --- a/scripts/developer/objectOrientedStep.js +++ /dev/null @@ -1,688 +0,0 @@ -/* jslint bitwise: true */ - -/* global Script, Vec3, MyAvatar, Tablet, Messages, Quat, -DebugDraw, Mat4, Entities, Xform, Controller, Camera, console, document*/ - -Script.registerValue("STEPAPP", true); -var CENTIMETERSPERMETER = 100.0; -var LEFT = 0; -var RIGHT = 1; -var INCREASING = 1.0; -var DECREASING = -1.0; -var DEFAULT_AVATAR_HEIGHT = 1.64; -var TABLET_BUTTON_NAME = "STEP"; -var CHANGE_OF_BASIS_ROTATION = { x: 0, y: 1, z: 0, w: 0 }; -// in meters (mostly) -var DEFAULT_ANTERIOR = 0.04; -var DEFAULT_POSTERIOR = 0.06; -var DEFAULT_LATERAL = 0.10; -var DEFAULT_HEIGHT_DIFFERENCE = 0.02; -var DEFAULT_ANGULAR_VELOCITY = 0.3; -var DEFAULT_HAND_VELOCITY = 0.4; -var DEFAULT_ANGULAR_HAND_VELOCITY = 3.3; -var DEFAULT_HEAD_VELOCITY = 0.14; -var DEFAULT_LEVEL_PITCH = 7; -var DEFAULT_LEVEL_ROLL = 7; -var DEFAULT_DIFF = 0.0; -var DEFAULT_DIFF_EULERS = { x: 0.0, y: 0.0, z: 0.0 }; -var DEFAULT_HIPS_POSITION; -var DEFAULT_HEAD_POSITION; -var DEFAULT_TORSO_LENGTH; -var SPINE_STRETCH_LIMIT = 0.02; - -var VELOCITY_EPSILON = 0.02; -var AVERAGING_RATE = 0.03; -var HEIGHT_AVERAGING_RATE = 0.01; -var STEP_TIME_SECS = 0.2; -var MODE_SAMPLE_LENGTH = 100; -var RESET_MODE = false; -var HEAD_TURN_THRESHOLD = 25.0; -var NO_SHARED_DIRECTION = -0.98; -var LOADING_DELAY = 500; -var FAILSAFE_TIMEOUT = 2.5; - -var debugDrawBase = true; -var activated = false; -var documentLoaded = false; -var failsafeFlag = false; -var failsafeSignalTimer = -1.0; -var stepTimer = -1.0; - - -var modeArray = new Array(MODE_SAMPLE_LENGTH); -var modeHeight = -10.0; - -var handPosition; -var handOrientation; -var hands = []; -var hipToHandAverage = []; -var handDotHead = []; -var headAverageOrientation = MyAvatar.orientation; -var headPoseAverageOrientation = { x: 0, y: 0, z: 0, w: 1 }; -var averageHeight = 1.0; -var headEulers = { x: 0.0, y: 0.0, z: 0.0 }; -var headAverageEulers = { x: 0.0, y: 0.0, z: 0.0 }; -var headAveragePosition = { x: 0, y: 0.4, z: 0 }; -var frontLeft = { x: -DEFAULT_LATERAL, y: 0, z: -DEFAULT_ANTERIOR }; -var frontRight = { x: DEFAULT_LATERAL, y: 0, z: -DEFAULT_ANTERIOR }; -var backLeft = { x: -DEFAULT_LATERAL, y: 0, z: DEFAULT_POSTERIOR }; -var backRight = { x: DEFAULT_LATERAL, y: 0, z: DEFAULT_POSTERIOR }; - - -// define state readings constructor -function StateReading(headPose, rhandPose, lhandPose, backLength, diffFromMode, diffFromAverageHeight, diffFromAveragePosition, - diffFromAverageEulers) { - this.headPose = headPose; - this.rhandPose = rhandPose; - this.lhandPose = lhandPose; - this.backLength = backLength; - this.diffFromMode = diffFromMode; - this.diffFromAverageHeight = diffFromAverageHeight; - this.diffFromAveragePosition = diffFromAveragePosition; - this.diffFromAverageEulers = diffFromAverageEulers; -} - -// define current state readings object for holding tracker readings and current differences from averages -var currentStateReadings = new StateReading(Controller.getPoseValue(Controller.Standard.Head), - Controller.getPoseValue(Controller.Standard.RightHand), Controller.getPoseValue(Controller.Standard.LeftHand), - DEFAULT_TORSO_LENGTH, DEFAULT_DIFF, DEFAULT_DIFF, DEFAULT_DIFF, DEFAULT_DIFF_EULERS); - -// declare the checkbox constructor -function AppCheckbox(type,id,eventType,isChecked) { - this.type = type; - this.id = id; - this.eventType = eventType; - this.data = {value: isChecked}; -} - -// define the checkboxes in the html file -var usingAverageHeight = new AppCheckbox("checkboxtick", "runningAverageHeightCheck", "onRunningAverageHeightCheckBox", - false); -var usingModeHeight = new AppCheckbox("checkboxtick","modeCheck","onModeCheckBox",true); -var usingBaseOfSupport = new AppCheckbox("checkboxtick","baseOfSupportCheck","onBaseOfSupportCheckBox",true); -var usingAverageHeadPosition = new AppCheckbox("checkboxtick", "headAveragePositionCheck", "onHeadAveragePositionCheckBox", - false); - -var checkBoxArray = new Array(usingAverageHeight,usingModeHeight,usingBaseOfSupport,usingAverageHeadPosition); - -// declare the html slider constructor -function AppProperty(name, type, eventType, signalType, setFunction, initValue, convertToThreshold, convertToSlider, signalOn) { - this.name = name; - this.type = type; - this.eventType = eventType; - this.signalType = signalType; - this.setValue = setFunction; - this.value = initValue; - this.get = function () { - return this.value; - }; - this.convertToThreshold = convertToThreshold; - this.convertToSlider = convertToSlider; - this.signalOn = signalOn; -} - -// define the sliders -var frontBaseProperty = new AppProperty("#anteriorBase-slider", "slider", "onAnteriorBaseSlider", "frontSignal", - setAnteriorDistance, DEFAULT_ANTERIOR, function (num) { - return convertToMeters(num); - }, function (num) { - return convertToCentimeters(num); - },true); -var backBaseProperty = new AppProperty("#posteriorBase-slider", "slider", "onPosteriorBaseSlider", "backSignal", - setPosteriorDistance, DEFAULT_POSTERIOR, function (num) { - return convertToMeters(num); - }, function (num) { - return convertToCentimeters(num); - }, true); -var lateralBaseProperty = new AppProperty("#lateralBase-slider", "slider", "onLateralBaseSlider", "lateralSignal", - setLateralDistance, DEFAULT_LATERAL, function (num) { - return convertToMeters(num); - }, function (num) { - return convertToCentimeters(num); - }, true); -var headAngularVelocityProperty = new AppProperty("#angularVelocityHead-slider", "slider", "onAngularVelocitySlider", - "angularHeadSignal", setAngularThreshold, DEFAULT_ANGULAR_VELOCITY, function (num) { - var base = 4; - var shift = 2; - return convertExponential(base, num, DECREASING, shift); - }, function (num) { - var base = 4; - var shift = 2; - return convertLog(base, num, DECREASING, shift); - }, true); -var heightDifferenceProperty = new AppProperty("#heightDifference-slider", "slider", "onHeightDifferenceSlider", "heightSignal", - setHeightThreshold, DEFAULT_HEIGHT_DIFFERENCE, function (num) { - return convertToMeters(-num); - }, function (num) { - return convertToCentimeters(-num); - }, true); -var handsVelocityProperty = new AppProperty("#handsVelocity-slider", "slider", "onHandsVelocitySlider", "handVelocitySignal", - setHandVelocityThreshold, DEFAULT_HAND_VELOCITY, function (num) { - return num; - }, function (num) { - return num; - }, true); -var handsAngularVelocityProperty = new AppProperty("#handsAngularVelocity-slider", "slider", "onHandsAngularVelocitySlider", - "handAngularSignal", setHandAngularVelocityThreshold, DEFAULT_ANGULAR_HAND_VELOCITY, function (num) { - var base = 7; - var shift = 2; - return convertExponential(base, num, DECREASING, shift); - }, function (num) { - var base = 7; - var shift = 2; - return convertLog(base, num, DECREASING, shift); - }, true); -var headVelocityProperty = new AppProperty("#headVelocity-slider", "slider", "onHeadVelocitySlider", "headVelocitySignal", - setHeadVelocityThreshold, DEFAULT_HEAD_VELOCITY, function (num) { - var base = 2; - var shift = 0; - return convertExponential(base, num, INCREASING, shift); - }, function (num) { - var base = 2; - var shift = 0; - return convertLog(base, num, INCREASING, shift); - }, true); -var headPitchProperty = new AppProperty("#headPitch-slider", "slider", "onHeadPitchSlider", "headPitchSignal", - setHeadPitchThreshold, DEFAULT_LEVEL_PITCH, function (num) { - var base = 2.5; - var shift = 5; - return convertExponential(base, num, DECREASING, shift); - }, function (num) { - var base = 2.5; - var shift = 5; - return convertLog(base, num, DECREASING, shift); - }, true); -var headRollProperty = new AppProperty("#headRoll-slider", "slider", "onHeadRollSlider", "headRollSignal", setHeadRollThreshold, - DEFAULT_LEVEL_ROLL, function (num) { - var base = 2.5; - var shift = 5; - return convertExponential(base, num, DECREASING, shift); - }, function (num) { - var base = 2.5; - var shift = 5; - return convertLog(base, num, DECREASING, shift); - }, true); - -var propArray = new Array(frontBaseProperty, backBaseProperty, lateralBaseProperty, headAngularVelocityProperty, - heightDifferenceProperty, handsVelocityProperty, handsAngularVelocityProperty, headVelocityProperty, headPitchProperty, - headRollProperty); - -// var HTML_URL = Script.resolvePath("http://hifi-content.s3.amazonaws.com/angus/stepApp/stepApp.html"); -var HTML_URL = Script.resolvePath("http://hifi-content.s3.amazonaws.com/angus/stepApp/stepAppExtra.html"); -var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); - -function manageClick() { - if (activated) { - tablet.gotoHomeScreen(); - } else { - tablet.gotoWebScreen(HTML_URL); - } -} - -var tabletButton = tablet.addButton({ - text: TABLET_BUTTON_NAME, - icon: Script.resolvePath("http://hifi-content.s3.amazonaws.com/angus/stepApp/foot.svg"), - activeIcon: Script.resolvePath("http://hifi-content.s3.amazonaws.com/angus/stepApp/foot.svg") -}); - -function drawBase() { - // transform corners into world space, for rendering. - var worldPointLf = Vec3.sum(MyAvatar.position,Vec3.multiplyQbyV(MyAvatar.orientation, frontLeft)); - var worldPointRf = Vec3.sum(MyAvatar.position,Vec3.multiplyQbyV(MyAvatar.orientation, frontRight)); - var worldPointLb = Vec3.sum(MyAvatar.position,Vec3.multiplyQbyV(MyAvatar.orientation, backLeft)); - var worldPointRb = Vec3.sum(MyAvatar.position,Vec3.multiplyQbyV(MyAvatar.orientation, backRight)); - - var GREEN = { r: 0, g: 1, b: 0, a: 1 }; - // draw border - DebugDraw.drawRay(worldPointLf, worldPointRf, GREEN); - DebugDraw.drawRay(worldPointRf, worldPointRb, GREEN); - DebugDraw.drawRay(worldPointRb, worldPointLb, GREEN); - DebugDraw.drawRay(worldPointLb, worldPointLf, GREEN); -} - -function onKeyPress(event) { - if (event.text === "'") { - // when the sensors are reset, then reset the mode. - RESET_MODE = false; - } -} - -function onWebEventReceived(msg) { - var message = JSON.parse(msg); - print(" we have a message from html dialog " + message.type); - propArray.forEach(function (prop) { - if (prop.eventType === message.type) { - prop.setValue(prop.convertToThreshold(message.data.value)); - print("message from " + prop.name); - // break; - } - }); - checkBoxArray.forEach(function(cbox) { - if (cbox.eventType === message.type) { - cbox.data.value = message.data.value; - // break; - } - }); - if (message.type === "onCreateStepApp") { - print("document loaded"); - documentLoaded = true; - Script.setTimeout(initAppForm, LOADING_DELAY); - } -} - -function initAppForm() { - print("step app is loaded: " + documentLoaded); - if (documentLoaded === true) { - propArray.forEach(function (prop) { - tablet.emitScriptEvent(JSON.stringify({ - "type": "trigger", - "id": prop.signalType, - "data": { "value": "green" } - })); - tablet.emitScriptEvent(JSON.stringify({ - "type": "slider", - "id": prop.name, - "data": { "value": prop.convertToSlider(prop.value) } - })); - }); - checkBoxArray.forEach(function (cbox) { - tablet.emitScriptEvent(JSON.stringify({ - "type": "checkboxtick", - "id": cbox.id, - "data": { "value": cbox.data.value } - })); - }); - } -} - -function updateSignalColors() { - - // force the updates by running the threshold comparisons - withinBaseOfSupport(currentStateReadings.headPose.translation); - withinThresholdOfStandingHeightMode(currentStateReadings.diffFromMode); - headAngularVelocityBelowThreshold(currentStateReadings.headPose.angularVelocity); - handDirectionMatchesHeadDirection(currentStateReadings.lhandPose, currentStateReadings.rhandPose); - handAngularVelocityBelowThreshold(currentStateReadings.lhandPose, currentStateReadings.rhandPose); - headVelocityGreaterThanThreshold(Vec3.length(currentStateReadings.headPose.velocity)); - headMovedAwayFromAveragePosition(currentStateReadings.diffFromAveragePosition); - headLowerThanHeightAverage(currentStateReadings.diffFromAverageHeight); - isHeadLevel(currentStateReadings.diffFromAverageEulers); - - propArray.forEach(function (prop) { - if (prop.signalOn) { - tablet.emitScriptEvent(JSON.stringify({ "type": "trigger", "id": prop.signalType, "data": { "value": "green" } })); - } else { - tablet.emitScriptEvent(JSON.stringify({ "type": "trigger", "id": prop.signalType, "data": { "value": "red" } })); - } - }); -} - -function onScreenChanged(type, url) { - print("Screen changed"); - if (type === "Web" && url === HTML_URL) { - if (!activated) { - // hook up to event bridge - tablet.webEventReceived.connect(onWebEventReceived); - print("after connect web event"); - MyAvatar.hmdLeanRecenterEnabled = false; - - } - activated = true; - } else { - if (activated) { - // disconnect from event bridge - tablet.webEventReceived.disconnect(onWebEventReceived); - documentLoaded = false; - } - activated = false; - } -} - -function getLog(x, y) { - return Math.log(y) / Math.log(x); -} - -function noConversion(num) { - return num; -} - -function convertLog(base, num, direction, shift) { - return direction * getLog(base, (num + 1.0)) + shift; -} - -function convertExponential(base, num, direction, shift) { - return Math.pow(base, (direction*num + shift)) - 1.0; -} - -function convertToCentimeters(num) { - return num * CENTIMETERSPERMETER; -} - -function convertToMeters(num) { - print("convert to meters " + num); - return num / CENTIMETERSPERMETER; -} - -function isInsideLine(a, b, c) { - return (((b.x - a.x)*(c.z - a.z) - (b.z - a.z)*(c.x - a.x)) > 0); -} - -function setAngularThreshold(num) { - headAngularVelocityProperty.value = num; - print("angular threshold " + headAngularVelocityProperty.get()); -} - -function setHeadRollThreshold(num) { - headRollProperty.value = num; - print("head roll threshold " + headRollProperty.get()); -} - -function setHeadPitchThreshold(num) { - headPitchProperty.value = num; - print("head pitch threshold " + headPitchProperty.get()); -} - -function setHeightThreshold(num) { - heightDifferenceProperty.value = num; - print("height threshold " + heightDifferenceProperty.get()); -} - -function setLateralDistance(num) { - lateralBaseProperty.value = num; - frontLeft.x = -lateralBaseProperty.get(); - frontRight.x = lateralBaseProperty.get(); - backLeft.x = -lateralBaseProperty.get(); - backRight.x = lateralBaseProperty.get(); - print("lateral distance " + lateralBaseProperty.get()); -} - -function setAnteriorDistance(num) { - frontBaseProperty.value = num; - frontLeft.z = -frontBaseProperty.get(); - frontRight.z = -frontBaseProperty.get(); - print("anterior distance " + frontBaseProperty.get()); -} - -function setPosteriorDistance(num) { - backBaseProperty.value = num; - backLeft.z = backBaseProperty.get(); - backRight.z = backBaseProperty.get(); - print("posterior distance " + backBaseProperty.get()); -} - -function setHandAngularVelocityThreshold(num) { - handsAngularVelocityProperty.value = num; - print("hand angular velocity threshold " + handsAngularVelocityProperty.get()); -} - -function setHandVelocityThreshold(num) { - handsVelocityProperty.value = num; - print("hand velocity threshold " + handsVelocityProperty.get()); -} - -function setHeadVelocityThreshold(num) { - headVelocityProperty.value = num; - print("headvelocity threshold " + headVelocityProperty.get()); -} - -function withinBaseOfSupport(pos) { - var userScale = 1.0; - frontBaseProperty.signalOn = !(isInsideLine(Vec3.multiply(userScale, frontLeft), Vec3.multiply(userScale, frontRight), pos)); - backBaseProperty.signalOn = !(isInsideLine(Vec3.multiply(userScale, backRight), Vec3.multiply(userScale, backLeft), pos)); - lateralBaseProperty.signalOn = !(isInsideLine(Vec3.multiply(userScale, frontRight), Vec3.multiply(userScale, backRight), pos) - && isInsideLine(Vec3.multiply(userScale, backLeft), Vec3.multiply(userScale, frontLeft), pos)); - return (!frontBaseProperty.signalOn && !backBaseProperty.signalOn && !lateralBaseProperty.signalOn); -} - -function withinThresholdOfStandingHeightMode(heightDiff) { - if (usingModeHeight.data.value) { - heightDifferenceProperty.signalOn = heightDiff < heightDifferenceProperty.get(); - return heightDifferenceProperty.signalOn; - } else { - return true; - } -} - -function headAngularVelocityBelowThreshold(headAngularVelocity) { - var angVel = Vec3.length({ x: headAngularVelocity.x, y: 0, z: headAngularVelocity.z }); - headAngularVelocityProperty.signalOn = angVel < headAngularVelocityProperty.get(); - return headAngularVelocityProperty.signalOn; -} - -function handDirectionMatchesHeadDirection(lhPose, rhPose) { - handsVelocityProperty.signalOn = ((handsVelocityProperty.get() < NO_SHARED_DIRECTION) || - ((!lhPose.valid || ((handDotHead[LEFT] > handsVelocityProperty.get()) && - (Vec3.length(lhPose.velocity) > VELOCITY_EPSILON))) && - (!rhPose.valid || ((handDotHead[RIGHT] > handsVelocityProperty.get()) && - (Vec3.length(rhPose.velocity) > VELOCITY_EPSILON))))); - return handsVelocityProperty.signalOn; -} - -function handAngularVelocityBelowThreshold(lhPose, rhPose) { - var xzRHandAngularVelocity = Vec3.length({ x: rhPose.angularVelocity.x, y: 0.0, z: rhPose.angularVelocity.z }); - var xzLHandAngularVelocity = Vec3.length({ x: lhPose.angularVelocity.x, y: 0.0, z: lhPose.angularVelocity.z }); - handsAngularVelocityProperty.signalOn = ((!rhPose.valid ||(xzRHandAngularVelocity < handsAngularVelocityProperty.get())) - && (!lhPose.valid || (xzLHandAngularVelocity < handsAngularVelocityProperty.get()))); - return handsAngularVelocityProperty.signalOn; -} - -function headVelocityGreaterThanThreshold(headVel) { - headVelocityProperty.signalOn = (headVel > headVelocityProperty.get()) || (headVelocityProperty.get() < VELOCITY_EPSILON); - return headVelocityProperty.signalOn; -} - -function headMovedAwayFromAveragePosition(headDelta) { - return !withinBaseOfSupport(headDelta) || !usingAverageHeadPosition.data.value; -} - -function headLowerThanHeightAverage(heightDiff) { - if (usingAverageHeight.data.value) { - print("head lower than height average"); - heightDifferenceProperty.signalOn = heightDiff < heightDifferenceProperty.get(); - return heightDifferenceProperty.signalOn; - } else { - return true; - } -} - -function isHeadLevel(diffEulers) { - headRollProperty.signalOn = Math.abs(diffEulers.z) < headRollProperty.get(); - headPitchProperty.signalOn = Math.abs(diffEulers.x) < headPitchProperty.get(); - return (headRollProperty.signalOn && headPitchProperty.signalOn); -} - -function findAverage(arr) { - var sum = arr.reduce(function (acc, val) { - return acc + val; - },0); - return sum / arr.length; -} - -function addToModeArray(arr,num) { - for (var i = 0 ;i < (arr.length - 1); i++) { - arr[i] = arr[i+1]; - } - arr[arr.length - 1] = (Math.floor(num*CENTIMETERSPERMETER))/CENTIMETERSPERMETER; -} - -function findMode(ary, currentMode, backLength, defaultBack, currentHeight) { - var numMapping = {}; - var greatestFreq = 0; - var mode; - ary.forEach(function (number) { - numMapping[number] = (numMapping[number] || 0) + 1; - if ((greatestFreq < numMapping[number]) || ((numMapping[number] === MODE_SAMPLE_LENGTH) && (number > currentMode) )) { - greatestFreq = numMapping[number]; - mode = number; - } - }); - if (mode > currentMode) { - return Number(mode); - } else { - if (!RESET_MODE && HMD.active) { - print("resetting the mode............................................. "); - print("resetting the mode............................................. "); - RESET_MODE = true; - var correction = 0.02; - return currentHeight - correction; - } else { - return currentMode; - } - } -} - -function update(dt) { - if (debugDrawBase) { - drawBase(); - } - // Update current state information - currentStateReadings.headPose = Controller.getPoseValue(Controller.Standard.Head); - currentStateReadings.rhandPose = Controller.getPoseValue(Controller.Standard.RightHand); - currentStateReadings.lhandPose = Controller.getPoseValue(Controller.Standard.LeftHand); - - // back length - var headMinusHipLean = Vec3.subtract(currentStateReadings.headPose.translation, DEFAULT_HIPS_POSITION); - currentStateReadings.backLength = Vec3.length(headMinusHipLean); - // print("back length and default " + currentStateReadings.backLength + " " + DEFAULT_TORSO_LENGTH); - - // mode height - addToModeArray(modeArray, currentStateReadings.headPose.translation.y); - modeHeight = findMode(modeArray, modeHeight, currentStateReadings.backLength, DEFAULT_TORSO_LENGTH, - currentStateReadings.headPose.translation.y); - currentStateReadings.diffFromMode = modeHeight - currentStateReadings.headPose.translation.y; - - // hand direction - var leftHandLateralPoseVelocity = currentStateReadings.lhandPose.velocity; - leftHandLateralPoseVelocity.y = 0.0; - var rightHandLateralPoseVelocity = currentStateReadings.rhandPose.velocity; - rightHandLateralPoseVelocity.y = 0.0; - var headLateralPoseVelocity = currentStateReadings.headPose.velocity; - headLateralPoseVelocity.y = 0.0; - handDotHead[LEFT] = Vec3.dot(Vec3.normalize(leftHandLateralPoseVelocity), Vec3.normalize(headLateralPoseVelocity)); - handDotHead[RIGHT] = Vec3.dot(Vec3.normalize(rightHandLateralPoseVelocity), Vec3.normalize(headLateralPoseVelocity)); - - // average head position - headAveragePosition = Vec3.mix(headAveragePosition, currentStateReadings.headPose.translation, AVERAGING_RATE); - currentStateReadings.diffFromAveragePosition = Vec3.subtract(currentStateReadings.headPose.translation, - headAveragePosition); - - // average height - averageHeight = currentStateReadings.headPose.translation.y * HEIGHT_AVERAGING_RATE + - averageHeight * (1.0 - HEIGHT_AVERAGING_RATE); - currentStateReadings.diffFromAverageHeight = Math.abs(currentStateReadings.headPose.translation.y - averageHeight); - - // eulers diff - headEulers = Quat.safeEulerAngles(currentStateReadings.headPose.rotation); - headAverageOrientation = Quat.slerp(headAverageOrientation, currentStateReadings.headPose.rotation, AVERAGING_RATE); - headAverageEulers = Quat.safeEulerAngles(headAverageOrientation); - currentStateReadings.diffFromAverageEulers = Vec3.subtract(headAverageEulers, headEulers); - - // headpose rig space is for determining when to recenter rotation. - var headPoseRigSpace = Quat.multiply(CHANGE_OF_BASIS_ROTATION, currentStateReadings.headPose.rotation); - headPoseAverageOrientation = Quat.slerp(headPoseAverageOrientation, headPoseRigSpace, AVERAGING_RATE); - var headPoseAverageEulers = Quat.safeEulerAngles(headPoseAverageOrientation); - - // make the signal colors reflect the current thresholds that have been crossed - updateSignalColors(); - - SPINE_STRETCH_LIMIT = (0.04) * DEFAULT_TORSO_LENGTH * MyAvatar.scale; - - //print("the spine stretch limit is " + SPINE_STRETCH_LIMIT + " head avatar space is " + currentStateReadings.headPose.translation.y); - //print("the current back length is " + currentStateReadings.backLength + " " + DEFAULT_TORSO_LENGTH); - // Conditions for taking a step. - // 1. off the base of support. front, lateral, back edges. - // 2. head is not lower than the height mode value by more than the maxHeightChange tolerance - // 3. the angular velocity of the head is not greater than the threshold value - // ie this reflects the speed the head is rotating away from having up = (0,1,0) in Avatar frame.. - // 4. the hands velocity vector has the same direction as the head, within the given tolerance - // the tolerance is an acos value, -1 means the hands going in any direction will not block translating - // up to 1 where the hands velocity direction must exactly match that of the head. -1 threshold disables this condition. - // 5. the angular velocity xz magnitude for each hand is below the threshold value - // ie here this reflects the speed that each hand is rotating away from having up = (0,1,0) in Avatar frame. - // 6. head velocity is below step threshold - // 7. head has moved further than the threshold from the running average position of the head. - // 8. head height is not lower than the running average head height with a difference of maxHeightChange. - // 9. head's rotation in avatar space is not pitching or rolling greater than the pitch or roll thresholds - if (!withinBaseOfSupport(currentStateReadings.headPose.translation) && - withinThresholdOfStandingHeightMode(currentStateReadings.diffFromMode) && - headAngularVelocityBelowThreshold(currentStateReadings.headPose.angularVelocity) && - handDirectionMatchesHeadDirection(currentStateReadings.lhandPose, currentStateReadings.rhandPose) && - handAngularVelocityBelowThreshold(currentStateReadings.lhandPose, currentStateReadings.rhandPose) && - headVelocityGreaterThanThreshold(Vec3.length(currentStateReadings.headPose.velocity)) && - headMovedAwayFromAveragePosition(currentStateReadings.diffFromAveragePosition) && - headLowerThanHeightAverage(currentStateReadings.diffFromAverageHeight) && - isHeadLevel(currentStateReadings.diffFromAverageEulers)) { - - if (stepTimer < 0.0) { //!MyAvatar.isRecenteringHorizontally() - print("trigger recenter========================================================"); - MyAvatar.triggerHorizontalRecenter(); - stepTimer = STEP_TIME_SECS; - } - } else if ((currentStateReadings.backLength > (DEFAULT_TORSO_LENGTH + SPINE_STRETCH_LIMIT)) && - (failsafeSignalTimer < 0.0) && HMD.active) { - // do the failsafe recenter. - // failsafeFlag stops repeated setting of failsafe button color. - // RESET_MODE false forces a reset of the height - RESET_MODE = false; - failsafeFlag = true; - failsafeSignalTimer = FAILSAFE_TIMEOUT; - MyAvatar.triggerHorizontalRecenter(); - tablet.emitScriptEvent(JSON.stringify({ "type": "failsafe", "id": "failsafeSignal", "data": { "value": "green" } })); - // in fail safe we debug print the values that were blocking us. - print("failsafe debug---------------------------------------------------------------"); - propArray.forEach(function (prop) { - print(prop.name); - if (!prop.signalOn) { - print(prop.signalType + " contributed to failsafe call"); - } - }); - print("end failsafe debug---------------------------------------------------------------"); - - } - - if ((failsafeSignalTimer < 0.0) && failsafeFlag) { - failsafeFlag = false; - tablet.emitScriptEvent(JSON.stringify({ "type": "failsafe", "id": "failsafeSignal", "data": { "value": "orange" } })); - } - - stepTimer -= dt; - failsafeSignalTimer -= dt; - - if (!HMD.active) { - RESET_MODE = false; - } - - if (Math.abs(headPoseAverageEulers.y) > HEAD_TURN_THRESHOLD) { - // Turn feet - // MyAvatar.triggerRotationRecenter(); - // headPoseAverageOrientation = { x: 0, y: 0, z: 0, w: 1 }; - } -} - -function shutdownTabletApp() { - // GlobalDebugger.stop(); - tablet.removeButton(tabletButton); - if (activated) { - tablet.webEventReceived.disconnect(onWebEventReceived); - tablet.gotoHomeScreen(); - } - tablet.screenChanged.disconnect(onScreenChanged); -} - -tabletButton.clicked.connect(manageClick); -tablet.screenChanged.connect(onScreenChanged); - -Script.setTimeout(function() { - DEFAULT_HIPS_POSITION = MyAvatar.getAbsoluteDefaultJointTranslationInObjectFrame(MyAvatar.getJointIndex("Hips")); - DEFAULT_HEAD_POSITION = MyAvatar.getAbsoluteDefaultJointTranslationInObjectFrame(MyAvatar.getJointIndex("Head")); - DEFAULT_TORSO_LENGTH = Vec3.length(Vec3.subtract(DEFAULT_HEAD_POSITION, DEFAULT_HIPS_POSITION)); - SPINE_STRETCH_LIMIT = (0.04) * DEFAULT_TORSO_LENGTH * MyAvatar.scale; -},(4*LOADING_DELAY)); - -Script.update.connect(update); -Controller.keyPressEvent.connect(onKeyPress); -Script.scriptEnding.connect(function () { - MyAvatar.hmdLeanRecenterEnabled = true; - Script.update.disconnect(update); - shutdownTabletApp(); -}); From 0e785f9bdb0746888209a8826bd48a1fb6915198 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Thu, 6 Sep 2018 15:35:26 -0700 Subject: [PATCH 18/24] Fix MS17877: Persist Connections table sort choice --- interface/resources/qml/hifi/Pal.qml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/interface/resources/qml/hifi/Pal.qml b/interface/resources/qml/hifi/Pal.qml index cbab83ea28..35a0078d32 100644 --- a/interface/resources/qml/hifi/Pal.qml +++ b/interface/resources/qml/hifi/Pal.qml @@ -780,6 +780,12 @@ Rectangle { headerVisible: true; sortIndicatorColumn: settings.connectionsSortIndicatorColumn; sortIndicatorOrder: settings.connectionsSortIndicatorOrder; + onSortIndicatorColumnChanged: { + settings.connectionsSortIndicatorColumn = sortIndicatorColumn; + } + onSortIndicatorOrderChanged: { + settings.connectionsSortIndicatorOrder = sortIndicatorOrder; + } TableViewColumn { id: connectionsUserNameHeader; From 836f810c419b1981da284aead6df1187910a7bc0 Mon Sep 17 00:00:00 2001 From: sabrina-shanman Date: Thu, 6 Sep 2018 14:11:42 -0700 Subject: [PATCH 19/24] Have OverlayTransformNode and similar define scale relative to nestable scale on creation time, and refactor code --- .../src/raypick/PickScriptingInterface.cpp | 4 ++ .../src/ui/overlays/OverlayTransformNode.cpp | 22 +--------- .../src/ui/overlays/OverlayTransformNode.h | 11 ++--- .../avatars-renderer/AvatarTransformNode.cpp | 22 +--------- .../avatars-renderer/AvatarTransformNode.h | 11 ++--- .../entities/src/EntityTransformNode.cpp | 22 +--------- libraries/entities/src/EntityTransformNode.h | 11 ++--- .../shared/src/NestableTransformNode.cpp | 22 +--------- libraries/shared/src/NestableTransformNode.h | 44 +++++++++++++++++-- 9 files changed, 61 insertions(+), 108 deletions(-) diff --git a/interface/src/raypick/PickScriptingInterface.cpp b/interface/src/raypick/PickScriptingInterface.cpp index b892c6da8e..247df2b11e 100644 --- a/interface/src/raypick/PickScriptingInterface.cpp +++ b/interface/src/raypick/PickScriptingInterface.cpp @@ -383,6 +383,10 @@ std::shared_ptr PickScriptingInterface::createTransformNode(const if (propMap["parentJointIndex"].isValid()) { parentJointIndex = propMap["parentJointIndex"].toInt(); } + glm::vec3 baseScale = glm::vec3(1); + if (propMap["baseScale"].isValid()) { + baseScale = vec3FromVariant(propMap["baseScale"]); + } auto sharedNestablePointer = nestablePointer.lock(); if (success && sharedNestablePointer) { NestableType nestableType = sharedNestablePointer->getNestableType(); diff --git a/interface/src/ui/overlays/OverlayTransformNode.cpp b/interface/src/ui/overlays/OverlayTransformNode.cpp index d0a6618e37..fa499b3ce3 100644 --- a/interface/src/ui/overlays/OverlayTransformNode.cpp +++ b/interface/src/ui/overlays/OverlayTransformNode.cpp @@ -7,24 +7,6 @@ // #include "OverlayTransformNode.h" -OverlayTransformNode::OverlayTransformNode(std::weak_ptr overlay, int jointIndex) : - _overlay(overlay), - _jointIndex(jointIndex) -{} - -Transform OverlayTransformNode::getTransform() { - auto overlay = _overlay.lock(); - if (!overlay) { - return Transform(); - } - - bool success; - Transform jointWorldTransform = overlay->getTransform(_jointIndex, success); - if (!success) { - return Transform(); - } - - jointWorldTransform.setScale(overlay->getBounds().getScale()); - - return jointWorldTransform; +glm::vec3 BaseNestableTransformNode::getActualScale(const std::shared_ptr& nestablePointer) const { + return nestablePointer->getBounds().getScale(); } \ No newline at end of file diff --git a/interface/src/ui/overlays/OverlayTransformNode.h b/interface/src/ui/overlays/OverlayTransformNode.h index b9ea9f72c4..11c3415828 100644 --- a/interface/src/ui/overlays/OverlayTransformNode.h +++ b/interface/src/ui/overlays/OverlayTransformNode.h @@ -8,19 +8,14 @@ #ifndef hifi_OverlayTransformNode_h #define hifi_OverlayTransformNode_h -#include "TransformNode.h" +#include "NestableTransformNode.h" #include "Base3DOverlay.h" // For 3D overlays only -class OverlayTransformNode : public TransformNode { +class OverlayTransformNode : public BaseNestableTransformNode { public: - OverlayTransformNode(std::weak_ptr overlay, int jointIndex); - Transform getTransform() override; - -protected: - std::weak_ptr _overlay; - int _jointIndex; + OverlayTransformNode(std::weak_ptr spatiallyNestable, int jointIndex) : BaseNestableTransformNode(spatiallyNestable, jointIndex) {}; }; #endif // hifi_OverlayTransformNode_h \ No newline at end of file diff --git a/libraries/avatars-renderer/src/avatars-renderer/AvatarTransformNode.cpp b/libraries/avatars-renderer/src/avatars-renderer/AvatarTransformNode.cpp index fc5ba5bc1a..bc24b8a570 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/AvatarTransformNode.cpp +++ b/libraries/avatars-renderer/src/avatars-renderer/AvatarTransformNode.cpp @@ -7,24 +7,6 @@ // #include "AvatarTransformNode.h" -AvatarTransformNode::AvatarTransformNode(AvatarWeakPointer avatar, int jointIndex) : - _avatar(avatar), - _jointIndex(jointIndex) -{} - -Transform AvatarTransformNode::getTransform() { - auto avatar = _avatar.lock(); - if (!avatar) { - return Transform(); - } - - bool success; - Transform jointWorldTransform = avatar->getTransform(_jointIndex, success); - if (!success) { - return Transform(); - } - - jointWorldTransform.setScale(avatar->scaleForChildren()); - - return jointWorldTransform; +glm::vec3 BaseNestableTransformNode::getActualScale(const std::shared_ptr& nestablePointer) const { + return nestablePointer->scaleForChildren(); } \ No newline at end of file diff --git a/libraries/avatars-renderer/src/avatars-renderer/AvatarTransformNode.h b/libraries/avatars-renderer/src/avatars-renderer/AvatarTransformNode.h index 03191b8dbe..183e4ab05c 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/AvatarTransformNode.h +++ b/libraries/avatars-renderer/src/avatars-renderer/AvatarTransformNode.h @@ -8,18 +8,13 @@ #ifndef hifi_AvatarTransformNode_h #define hifi_AvatarTransformNode_h -#include "TransformNode.h" +#include "NestableTransformNode.h" #include "Avatar.h" -class AvatarTransformNode : public TransformNode { +class AvatarTransformNode : public BaseNestableTransformNode { public: - AvatarTransformNode(AvatarWeakPointer avatar, int jointIndex); - Transform getTransform() override; - -protected: - AvatarWeakPointer _avatar; - int _jointIndex; + AvatarTransformNode(std::weak_ptr spatiallyNestable, int jointIndex) : BaseNestableTransformNode(spatiallyNestable, jointIndex) {}; }; #endif // hifi_AvatarTransformNode_h \ No newline at end of file diff --git a/libraries/entities/src/EntityTransformNode.cpp b/libraries/entities/src/EntityTransformNode.cpp index 5b0a690619..35f4d8e52f 100644 --- a/libraries/entities/src/EntityTransformNode.cpp +++ b/libraries/entities/src/EntityTransformNode.cpp @@ -7,24 +7,6 @@ // #include "EntityTransformNode.h" -EntityTransformNode::EntityTransformNode(EntityItemWeakPointer entity, int jointIndex) : - _entity(entity), - _jointIndex(jointIndex) -{} - -Transform EntityTransformNode::getTransform() { - auto entity = _entity.lock(); - if (!entity) { - return Transform(); - } - - bool success; - Transform jointWorldTransform = entity->getTransform(_jointIndex, success); - if (!success) { - return Transform(); - } - - jointWorldTransform.setScale(entity->getScaledDimensions()); - - return jointWorldTransform; +glm::vec3 BaseNestableTransformNode::getActualScale(const std::shared_ptr& nestablePointer) const { + return nestablePointer->getScaledDimensions(); } \ No newline at end of file diff --git a/libraries/entities/src/EntityTransformNode.h b/libraries/entities/src/EntityTransformNode.h index b7388600df..07818f99f3 100644 --- a/libraries/entities/src/EntityTransformNode.h +++ b/libraries/entities/src/EntityTransformNode.h @@ -8,18 +8,13 @@ #ifndef hifi_EntityTransformNode_h #define hifi_EntityTransformNode_h -#include "TransformNode.h" +#include "NestableTransformNode.h" #include "EntityItem.h" -class EntityTransformNode : public TransformNode { +class EntityTransformNode : public BaseNestableTransformNode { public: - EntityTransformNode(EntityItemWeakPointer entity, int jointIndex); - Transform getTransform() override; - -protected: - EntityItemWeakPointer _entity; - int _jointIndex; + EntityTransformNode(std::weak_ptr spatiallyNestable, int jointIndex) : BaseNestableTransformNode(spatiallyNestable, jointIndex) {}; }; #endif // hifi_EntityTransformNode_h \ No newline at end of file diff --git a/libraries/shared/src/NestableTransformNode.cpp b/libraries/shared/src/NestableTransformNode.cpp index 17456d69ce..9da2c85aa3 100644 --- a/libraries/shared/src/NestableTransformNode.cpp +++ b/libraries/shared/src/NestableTransformNode.cpp @@ -8,24 +8,6 @@ #include "NestableTransformNode.h" -NestableTransformNode::NestableTransformNode(SpatiallyNestableWeakPointer spatiallyNestable, int jointIndex) : - _spatiallyNestable(spatiallyNestable), - _jointIndex(jointIndex) -{ -} - -Transform NestableTransformNode::getTransform() { - auto nestable = _spatiallyNestable.lock(); - if (!nestable) { - return Transform(); - } - - bool success; - Transform jointWorldTransform = nestable->getTransform(_jointIndex, success); - - if (success) { - return jointWorldTransform; - } else { - return Transform(); - } +glm::vec3 BaseNestableTransformNode::getActualScale(const std::shared_ptr& nestablePointer) const { + return nestablePointer->getAbsoluteJointScaleInObjectFrame(_jointIndex); } \ No newline at end of file diff --git a/libraries/shared/src/NestableTransformNode.h b/libraries/shared/src/NestableTransformNode.h index 131de9e786..21efd1c690 100644 --- a/libraries/shared/src/NestableTransformNode.h +++ b/libraries/shared/src/NestableTransformNode.h @@ -12,14 +12,50 @@ #include "SpatiallyNestable.h" -class NestableTransformNode : public TransformNode { +template +class BaseNestableTransformNode : public TransformNode { public: - NestableTransformNode(SpatiallyNestableWeakPointer spatiallyNestable, int jointIndex); - Transform getTransform() override; + BaseNestableTransformNode(std::weak_ptr spatiallyNestable, int jointIndex) : + _spatiallyNestable(spatiallyNestable), + _jointIndex(jointIndex) { + auto nestablePointer = _spatiallyNestable.lock(); + if (nestablePointer) { + glm::vec3 nestableDimensions = getActualScale(nestablePointer); + if (!glm::any(glm::equal(nestableDimensions, glm::vec3(0.0f)))) { + _baseScale = nestableDimensions; + } + } + } + + Transform getTransform() { + std::shared_ptr nestable = _spatiallyNestable.lock(); + if (!nestable) { + return Transform(); + } + + bool success; + Transform jointWorldTransform = nestable->getTransform(_jointIndex, success); + + if (!success) { + return Transform(); + } + + jointWorldTransform.setScale(getActualScale(nestable) / _baseScale); + + return jointWorldTransform; + } + + glm::vec3 getActualScale(const std::shared_ptr& nestablePointer) const; protected: - SpatiallyNestableWeakPointer _spatiallyNestable; + std::weak_ptr _spatiallyNestable; int _jointIndex; + glm::vec3 _baseScale { 1.0f }; +}; + +class NestableTransformNode : public BaseNestableTransformNode { +public: + NestableTransformNode(std::weak_ptr spatiallyNestable, int jointIndex) : BaseNestableTransformNode(spatiallyNestable, jointIndex) {}; }; #endif // hifi_NestableTransformNode_h \ No newline at end of file From 23a6abbaca6f36726d81c3072a74bc0b9f79ce6b Mon Sep 17 00:00:00 2001 From: sabrina-shanman Date: Thu, 6 Sep 2018 16:47:09 -0700 Subject: [PATCH 20/24] Update jsdocs to reflect new collision pick scaling behavior --- interface/src/raypick/PickScriptingInterface.cpp | 6 +++--- libraries/shared/src/RegisteredMetaTypes.h | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/interface/src/raypick/PickScriptingInterface.cpp b/interface/src/raypick/PickScriptingInterface.cpp index 247df2b11e..41669c9f0c 100644 --- a/interface/src/raypick/PickScriptingInterface.cpp +++ b/interface/src/raypick/PickScriptingInterface.cpp @@ -265,11 +265,11 @@ unsigned int PickScriptingInterface::createParabolaPick(const QVariant& properti * @typedef {object} Picks.CollisionPickProperties * @property {boolean} [enabled=false] If this Pick should start enabled or not. Disabled Picks do not updated their pick results. * @property {number} [filter=Picks.PICK_NOTHING] The filter for this Pick to use, constructed using filter flags combined using bitwise OR. -* @property {Shape} shape - The information about the collision region's size and shape. Dimensions are relative to a parent if defined. +* @property {Shape} shape - The information about the collision region's size and shape. Dimensions are in world space, but will scale with the parent if defined. * @property {Vec3} position - The position of the collision region, relative to a parent if defined. * @property {Quat} orientation - The orientation of the collision region, relative to a parent if defined. -* @property {float} threshold - The approximate minimum penetration depth for a test object to be considered in contact with the collision region, relative to a parent if defined. -* For overlay and entity parents, this is relative to the parent's largest dimension. +* @property {float} threshold - The approximate minimum penetration depth for a test object to be considered in contact with the collision region. +* The depth is measured in world space, but will scale with the parent if defined. * @property {Uuid} parentID - The ID of the parent, either an avatar, an entity, or an overlay. * @property {number} parentJointIndex - The joint of the parent to parent to, for example, the joints on the model of an avatar. (default = 0, no joint) * @property {string} joint - If "Mouse," parents the pick to the mouse. If "Avatar," parents the pick to MyAvatar's head. Otherwise, parents to the joint of the given name on MyAvatar. diff --git a/libraries/shared/src/RegisteredMetaTypes.h b/libraries/shared/src/RegisteredMetaTypes.h index 79adce0a39..d59c58def8 100644 --- a/libraries/shared/src/RegisteredMetaTypes.h +++ b/libraries/shared/src/RegisteredMetaTypes.h @@ -259,11 +259,11 @@ public: * A CollisionRegion defines a volume for checking collisions in the physics simulation. * @typedef {object} CollisionRegion -* @property {Shape} shape - The information about the collision region's size and shape. Dimensions are relative to a parent if defined. +* @property {Shape} shape - The information about the collision region's size and shape. Dimensions are in world space, but will scale with the parent if defined. * @property {Vec3} position - The position of the collision region, relative to a parent if defined. * @property {Quat} orientation - The orientation of the collision region, relative to a parent if defined. -* @property {float} threshold - The approximate minimum penetration depth for a test object to be considered in contact with the collision region, relative to a parent if defined. -* For overlay and entity parents, this is relative to the parent's largest dimension. +* @property {float} threshold - The approximate minimum penetration depth for a test object to be considered in contact with the collision region. +* The depth is measured in world space, but will scale with the parent if defined. * @property {Uuid} parentID - The ID of the parent, either an avatar, an entity, or an overlay. * @property {number} parentJointIndex - The joint of the parent to parent to, for example, the joints on the model of an avatar. (default = 0, no joint) * @property {string} joint - If "Mouse," parents the pick to the mouse. If "Avatar," parents the pick to MyAvatar's head. Otherwise, parents to the joint of the given name on MyAvatar. From 7a9480723e61f58065acaeaaccdd72ec1b4ef393 Mon Sep 17 00:00:00 2001 From: sabrina-shanman Date: Thu, 6 Sep 2018 17:30:29 -0700 Subject: [PATCH 21/24] Remove unused variable in PickScriptingInterface::createTransformNode --- interface/src/raypick/PickScriptingInterface.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/interface/src/raypick/PickScriptingInterface.cpp b/interface/src/raypick/PickScriptingInterface.cpp index 41669c9f0c..0273b084b2 100644 --- a/interface/src/raypick/PickScriptingInterface.cpp +++ b/interface/src/raypick/PickScriptingInterface.cpp @@ -383,10 +383,6 @@ std::shared_ptr PickScriptingInterface::createTransformNode(const if (propMap["parentJointIndex"].isValid()) { parentJointIndex = propMap["parentJointIndex"].toInt(); } - glm::vec3 baseScale = glm::vec3(1); - if (propMap["baseScale"].isValid()) { - baseScale = vec3FromVariant(propMap["baseScale"]); - } auto sharedNestablePointer = nestablePointer.lock(); if (success && sharedNestablePointer) { NestableType nestableType = sharedNestablePointer->getNestableType(); From f40f40e135c8fbe205e9e7a8476304f94c086f30 Mon Sep 17 00:00:00 2001 From: sabrina-shanman Date: Thu, 6 Sep 2018 17:35:12 -0700 Subject: [PATCH 22/24] Use more reasonable value for BaseNestableTransformNode::_baseScale when given bad value --- libraries/shared/src/NestableTransformNode.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/libraries/shared/src/NestableTransformNode.h b/libraries/shared/src/NestableTransformNode.h index 21efd1c690..e73360d872 100644 --- a/libraries/shared/src/NestableTransformNode.h +++ b/libraries/shared/src/NestableTransformNode.h @@ -21,9 +21,7 @@ public: auto nestablePointer = _spatiallyNestable.lock(); if (nestablePointer) { glm::vec3 nestableDimensions = getActualScale(nestablePointer); - if (!glm::any(glm::equal(nestableDimensions, glm::vec3(0.0f)))) { - _baseScale = nestableDimensions; - } + _baseScale = glm::max(glm::vec3(0.001f), nestableDimensions); } } From 52bc09cd2aa29071d4fa56fb792fcc454be81d29 Mon Sep 17 00:00:00 2001 From: sabrina-shanman Date: Thu, 6 Sep 2018 17:44:06 -0700 Subject: [PATCH 23/24] Add override qualifier to BaseNestableTransformNode::getTransform --- libraries/shared/src/NestableTransformNode.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/shared/src/NestableTransformNode.h b/libraries/shared/src/NestableTransformNode.h index e73360d872..2f9bc2e985 100644 --- a/libraries/shared/src/NestableTransformNode.h +++ b/libraries/shared/src/NestableTransformNode.h @@ -25,7 +25,7 @@ public: } } - Transform getTransform() { + Transform getTransform() override { std::shared_ptr nestable = _spatiallyNestable.lock(); if (!nestable) { return Transform(); From 8d4c47cf8ed70e7ed8c8bd1955ecdbad93cd293d Mon Sep 17 00:00:00 2001 From: sabrina-shanman Date: Fri, 7 Sep 2018 08:49:44 -0700 Subject: [PATCH 24/24] Make template specialization of BaseNestableTransformNode explicit --- interface/src/ui/overlays/OverlayTransformNode.cpp | 1 + .../src/avatars-renderer/AvatarTransformNode.cpp | 1 + libraries/entities/src/EntityTransformNode.cpp | 1 + libraries/shared/src/NestableTransformNode.cpp | 1 + 4 files changed, 4 insertions(+) diff --git a/interface/src/ui/overlays/OverlayTransformNode.cpp b/interface/src/ui/overlays/OverlayTransformNode.cpp index fa499b3ce3..817b6af305 100644 --- a/interface/src/ui/overlays/OverlayTransformNode.cpp +++ b/interface/src/ui/overlays/OverlayTransformNode.cpp @@ -7,6 +7,7 @@ // #include "OverlayTransformNode.h" +template<> glm::vec3 BaseNestableTransformNode::getActualScale(const std::shared_ptr& nestablePointer) const { return nestablePointer->getBounds().getScale(); } \ No newline at end of file diff --git a/libraries/avatars-renderer/src/avatars-renderer/AvatarTransformNode.cpp b/libraries/avatars-renderer/src/avatars-renderer/AvatarTransformNode.cpp index bc24b8a570..ca3d4a6062 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/AvatarTransformNode.cpp +++ b/libraries/avatars-renderer/src/avatars-renderer/AvatarTransformNode.cpp @@ -7,6 +7,7 @@ // #include "AvatarTransformNode.h" +template<> glm::vec3 BaseNestableTransformNode::getActualScale(const std::shared_ptr& nestablePointer) const { return nestablePointer->scaleForChildren(); } \ No newline at end of file diff --git a/libraries/entities/src/EntityTransformNode.cpp b/libraries/entities/src/EntityTransformNode.cpp index 35f4d8e52f..438ece3840 100644 --- a/libraries/entities/src/EntityTransformNode.cpp +++ b/libraries/entities/src/EntityTransformNode.cpp @@ -7,6 +7,7 @@ // #include "EntityTransformNode.h" +template<> glm::vec3 BaseNestableTransformNode::getActualScale(const std::shared_ptr& nestablePointer) const { return nestablePointer->getScaledDimensions(); } \ No newline at end of file diff --git a/libraries/shared/src/NestableTransformNode.cpp b/libraries/shared/src/NestableTransformNode.cpp index 9da2c85aa3..9723f388f6 100644 --- a/libraries/shared/src/NestableTransformNode.cpp +++ b/libraries/shared/src/NestableTransformNode.cpp @@ -8,6 +8,7 @@ #include "NestableTransformNode.h" +template<> glm::vec3 BaseNestableTransformNode::getActualScale(const std::shared_ptr& nestablePointer) const { return nestablePointer->getAbsoluteJointScaleInObjectFrame(_jointIndex); } \ No newline at end of file