{"action":"created","comment":{"url":"https://api.github.com/repos/highfidelity/hifi/pulls/comments/50495539","id":50495539,"diff_hunk":"@@ -1832,3 +1762,80 @@ void audioListenModeFromScriptValue(const QScriptValue& object, AudioListenerMod\n void MyAvatar::lateUpdatePalms() {\n     Avatar::updatePalms();\n }\n+\n+\n+static const float FOLLOW_TIME = 0.5f;\n+\n+void MyAvatar::FollowHelper::deactivate() {\n+    _timeTotal = FOLLOW_TIME;\n+    _timeRemaining = 0.0f;\n+}\n+\n+void MyAvatar::FollowHelper::activate() {\n+    // TODO: the follow time should be proportional to the displacement.\n+    _timeRemaining = FOLLOW_TIME;\n+    _timeTotal = FOLLOW_TIME;\n+}\n+\n+bool MyAvatar::FollowHelper::isActive() const {\n+    return _timeRemaining > 0.0f;\n+}\n+\n+bool MyAvatar::FollowHelper::shouldActivate(const MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix) const {\n+\n+    const float FOLLOW_ROTATION_THRESHOLD = cosf(PI / 4.0f);\n+\n+    glm::vec2 bodyFacing = getFacingDir2D(currentBodyMatrix);\n+    if (glm::dot(myAvatar.getHMDSensorFacingMovingAverage(), bodyFacing) < FOLLOW_ROTATION_THRESHOLD) {\n+        return true;\n+    }\n+\n+    const float CYLINDER_TOP = 0.1f;\n+    const float CYLINDER_BOTTOM = -0.5f;\n+    const float CYLINDER_RADIUS = 0.15f;\n+\n+    glm::vec3 offset = extractTranslation(desiredBodyMatrix) - extractTranslation(currentBodyMatrix);\n+    glm::vec3 truncatedOffset(offset.x, 0.0f, offset.y);\n+    float truncatedDistance = glm::length(truncatedOffset);\n+\n+    return (offset.y > CYLINDER_TOP) || (offset.y < CYLINDER_BOTTOM) || (truncatedDistance > CYLINDER_RADIUS);\n+}\n+\n+void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix) {\n+    _desiredBodyMatrix = desiredBodyMatrix;\n+    if (!isActive() && shouldActivate(myAvatar, desiredBodyMatrix, currentBodyMatrix)) {\n+        activate();\n+    }\n+\n+    if (isActive()) {\n+        glm::mat4 desiredWorldMatrix = myAvatar.getSensorToWorldMatrix() * _desiredBodyMatrix;\n+        myAvatar.getCharacterController()->setFollowParameters(desiredWorldMatrix, _timeRemaining);\n+    } else {\n+        glm::mat4 currentWorldMatrix = myAvatar.getSensorToWorldMatrix() * currentBodyMatrix;\n+        myAvatar.getCharacterController()->setFollowParameters(currentWorldMatrix, 0.0f);\n+    }\n+}\n+\n+glm::mat4 MyAvatar::FollowHelper::postPhysicsUpdate(const MyAvatar& myAvatar, const glm::mat4& currentBodyMatrix) {\n+    if (isActive()) {\n+        float dt = myAvatar.getCharacterController()->getFollowTime();\n+        _timeRemaining -= dt;\n+\n+        // apply follow displacement to the body matrix.\n+        glm::vec3 worldLinearDisplacement = myAvatar.getCharacterController()->getFollowLinearDisplacement();\n+        glm::quat worldAngularDisplacement = myAvatar.getCharacterController()->getFollowAngularDisplacement();\n+        glm::quat sensorToWorld = glmExtractRotation(myAvatar.getSensorToWorldMatrix());\n+        glm::quat worldToSensor = glm::inverse(sensorToWorld);\n+\n+        glm::vec3 sensorLinearDisplacement = worldToSensor * worldLinearDisplacement;\n+        glm::quat sensorAngularDisplacement = worldToSensor * worldAngularDisplacement * sensorToWorld;\n+\n+        glm::mat4 newBodyMat = createMatFromQuatAndPos(sensorAngularDisplacement * glmExtractRotation(currentBodyMatrix),\n+                                                       sensorLinearDisplacement + extractTranslation(currentBodyMatrix));\n+        return newBodyMat;","path":"interface/src/avatar/MyAvatar.cpp","position":232,"original_position":232,"commit_id":"ca8a832818231f8bc3ae004953ef4cd357bf782d","original_commit_id":"ca8a832818231f8bc3ae004953ef4cd357bf782d","user":{"login":"hyperlogic","id":20499,"avatar_url":"https://avatars.githubusercontent.com/u/20499?v=3","gravatar_id":"","url":"https://api.github.com/users/hyperlogic","html_url":"https://github.com/hyperlogic","followers_url":"https://api.github.com/users/hyperlogic/followers","following_url":"https://api.github.com/users/hyperlogic/following{/other_user}","gists_url":"https://api.github.com/users/hyperlogic/gists{/gist_id}","starred_url":"https://api.github.com/users/hyperlogic/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/hyperlogic/subscriptions","organizations_url":"https://api.github.com/users/hyperlogic/orgs","repos_url":"https://api.github.com/users/hyperlogic/repos","events_url":"https://api.github.com/users/hyperlogic/events{/privacy}","received_events_url":"https://api.github.com/users/hyperlogic/received_events","type":"User","site_admin":false},"body":"After physics simulation, we get the angular and linear displacements it used internally, and apply them to the bodySensorMatrix.  This will keep these two motions in sync, which will come in handy if we decide to make the following non-linear.","created_at":"2016-01-22T02:23:14Z","updated_at":"2016-01-22T02:23:14Z","html_url":"https://github.com/highfidelity/hifi/pull/6895#discussion_r50495539","pull_request_url":"https://api.github.com/repos/highfidelity/hifi/pulls/6895","_links":{"self":{"href":"https://api.github.com/repos/highfidelity/hifi/pulls/comments/50495539"},"html":{"href":"https://github.com/highfidelity/hifi/pull/6895#discussion_r50495539"},"pull_request":{"href":"https://api.github.com/repos/highfidelity/hifi/pulls/6895"}}},"pull_request":{"url":"https://api.github.com/repos/highfidelity/hifi/pulls/6895","id":56835768,"html_url":"https://github.com/highfidelity/hifi/pull/6895","diff_url":"https://github.com/highfidelity/hifi/pull/6895.diff","patch_url":"https://github.com/highfidelity/hifi/pull/6895.patch","issue_url":"https://api.github.com/repos/highfidelity/hifi/issues/6895","number":6895,"state":"open","locked":false,"title":"MyAvatar: Recenter when the head turns away from the hips","user":{"login":"hyperlogic","id":20499,"avatar_url":"https://avatars.githubusercontent.com/u/20499?v=3","gravatar_id":"","url":"https://api.github.com/users/hyperlogic","html_url":"https://github.com/hyperlogic","followers_url":"https://api.github.com/users/hyperlogic/followers","following_url":"https://api.github.com/users/hyperlogic/following{/other_user}","gists_url":"https://api.github.com/users/hyperlogic/gists{/gist_id}","starred_url":"https://api.github.com/users/hyperlogic/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/hyperlogic/subscriptions","organizations_url":"https://api.github.com/users/hyperlogic/orgs","repos_url":"https://api.github.com/users/hyperlogic/repos","events_url":"https://api.github.com/users/hyperlogic/events{/privacy}","received_events_url":"https://api.github.com/users/hyperlogic/received_events","type":"User","site_admin":false},"body":"Compute the HMD facing moving average.  When the moving average diverges from the hips by more than 45 degrees, recenter the body.\r\n\r\nAlso, the follow code has been changed, instead of a follow velocity being passed to the CharacterController a desired target is passed.  The CharacterController homes toward it's target based on the time remaining.  Any follow deltas applied to move the avatar's position closer to it's target is stored and re-applied to the bodySensorMatrix.  This centralizes the moving/homing code to one place, the CharacterContoller.  The displacement each timestep is clamped, to avoid tunneling.\r\n\r\nA new FollowHelper class was also introduced, it groups together the data and logic necessary to perform the re-centering/follow procedure.  This \"hopefully\" makes it easier to maintain.\r\n\r\nAlso, unit tests were added for new helper functions introduced to physics/BulletUtils.h\r\n\r\nTo test you must be wearing an HMD:\r\n\r\nOnce you are wearing an HMD, perform the following steps.\r\n\r\n1. reset sensors using the \"single quote\" key.\r\n2. look down and your avatar's toes/body should be pointing forward.\r\n3. look to the right 90 degrees.  \r\n4. Wait 3-4 seconds.\r\n5. look down while maintaining your current head facing direction.  Your avatar toes should be aligned to your head facing. ","created_at":"2016-01-22T01:34:19Z","updated_at":"2016-01-22T02:23:15Z","closed_at":null,"merged_at":null,"merge_commit_sha":"6cbb3e764088254b4f2febf12a61408b12b3b54c","assignee":{"login":"AndrewMeadows","id":2186405,"avatar_url":"https://avatars.githubusercontent.com/u/2186405?v=3","gravatar_id":"","url":"https://api.github.com/users/AndrewMeadows","html_url":"https://github.com/AndrewMeadows","followers_url":"https://api.github.com/users/AndrewMeadows/followers","following_url":"https://api.github.com/users/AndrewMeadows/following{/other_user}","gists_url":"https://api.github.com/users/AndrewMeadows/gists{/gist_id}","starred_url":"https://api.github.com/users/AndrewMeadows/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/AndrewMeadows/subscriptions","organizations_url":"https://api.github.com/users/AndrewMeadows/orgs","repos_url":"https://api.github.com/users/AndrewMeadows/repos","events_url":"https://api.github.com/users/AndrewMeadows/events{/privacy}","received_events_url":"https://api.github.com/users/AndrewMeadows/received_events","type":"User","site_admin":false},"milestone":null,"commits_url":"https://api.github.com/repos/highfidelity/hifi/pulls/6895/commits","review_comments_url":"https://api.github.com/repos/highfidelity/hifi/pulls/6895/comments","review_comment_url":"https://api.github.com/repos/highfidelity/hifi/pulls/comments{/number}","comments_url":"https://api.github.com/repos/highfidelity/hifi/issues/6895/comments","statuses_url":"https://api.github.com/repos/highfidelity/hifi/statuses/ca8a832818231f8bc3ae004953ef4cd357bf782d","head":{"label":"hyperlogic:tony/hmd-recenter-on-rotation","ref":"tony/hmd-recenter-on-rotation","sha":"ca8a832818231f8bc3ae004953ef4cd357bf782d","user":{"login":"hyperlogic","id":20499,"avatar_url":"https://avatars.githubusercontent.com/u/20499?v=3","gravatar_id":"","url":"https://api.github.com/users/hyperlogic","html_url":"https://github.com/hyperlogic","followers_url":"https://api.github.com/users/hyperlogic/followers","following_url":"https://api.github.com/users/hyperlogic/following{/other_user}","gists_url":"https://api.github.com/users/hyperlogic/gists{/gist_id}","starred_url":"https://api.github.com/users/hyperlogic/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/hyperlogic/subscriptions","organizations_url":"https://api.github.com/users/hyperlogic/orgs","repos_url":"https://api.github.com/users/hyperlogic/repos","events_url":"https://api.github.com/users/hyperlogic/events{/privacy}","received_events_url":"https://api.github.com/users/hyperlogic/received_events","type":"User","site_admin":false},"repo":{"id":34955357,"name":"hifi","full_name":"hyperlogic/hifi","owner":{"login":"hyperlogic","id":20499,"avatar_url":"https://avatars.githubusercontent.com/u/20499?v=3","gravatar_id":"","url":"https://api.github.com/users/hyperlogic","html_url":"https://github.com/hyperlogic","followers_url":"https://api.github.com/users/hyperlogic/followers","following_url":"https://api.github.com/users/hyperlogic/following{/other_user}","gists_url":"https://api.github.com/users/hyperlogic/gists{/gist_id}","starred_url":"https://api.github.com/users/hyperlogic/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/hyperlogic/subscriptions","organizations_url":"https://api.github.com/users/hyperlogic/orgs","repos_url":"https://api.github.com/users/hyperlogic/repos","events_url":"https://api.github.com/users/hyperlogic/events{/privacy}","received_events_url":"https://api.github.com/users/hyperlogic/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/hyperlogic/hifi","description":"Open source software for shared virtual worlds using HMDs and dynamically assigned devices as servers.  San Francisco based startup, we are hiring: http://highfidelity.com/jobs  Documentation at http://docs.highfidelity.com  Contribute by reporting bugs & doing jobs on http://worklist.net","fork":true,"url":"https://api.github.com/repos/hyperlogic/hifi","forks_url":"https://api.github.com/repos/hyperlogic/hifi/forks","keys_url":"https://api.github.com/repos/hyperlogic/hifi/keys{/key_id}","collaborators_url":"https://api.github.com/repos/hyperlogic/hifi/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/hyperlogic/hifi/teams","hooks_url":"https://api.github.com/repos/hyperlogic/hifi/hooks","issue_events_url":"https://api.github.com/repos/hyperlogic/hifi/issues/events{/number}","events_url":"https://api.github.com/repos/hyperlogic/hifi/events","assignees_url":"https://api.github.com/repos/hyperlogic/hifi/assignees{/user}","branches_url":"https://api.github.com/repos/hyperlogic/hifi/branches{/branch}","tags_url":"https://api.github.com/repos/hyperlogic/hifi/tags","blobs_url":"https://api.github.com/repos/hyperlogic/hifi/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/hyperlogic/hifi/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/hyperlogic/hifi/git/refs{/sha}","trees_url":"https://api.github.com/repos/hyperlogic/hifi/git/trees{/sha}","statuses_url":"https://api.github.com/repos/hyperlogic/hifi/statuses/{sha}","languages_url":"https://api.github.com/repos/hyperlogic/hifi/languages","stargazers_url":"https://api.github.com/repos/hyperlogic/hifi/stargazers","contributors_url":"https://api.github.com/repos/hyperlogic/hifi/contributors","subscribers_url":"https://api.github.com/repos/hyperlogic/hifi/subscribers","subscription_url":"https://api.github.com/repos/hyperlogic/hifi/subscription","commits_url":"https://api.github.com/repos/hyperlogic/hifi/commits{/sha}","git_commits_url":"https://api.github.com/repos/hyperlogic/hifi/git/commits{/sha}","comments_url":"https://api.github.com/repos/hyperlogic/hifi/comments{/number}","issue_comment_url":"https://api.github.com/repos/hyperlogic/hifi/issues/comments{/number}","contents_url":"https://api.github.com/repos/hyperlogic/hifi/contents/{+path}","compare_url":"https://api.github.com/repos/hyperlogic/hifi/compare/{base}...{head}","merges_url":"https://api.github.com/repos/hyperlogic/hifi/merges","archive_url":"https://api.github.com/repos/hyperlogic/hifi/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/hyperlogic/hifi/downloads","issues_url":"https://api.github.com/repos/hyperlogic/hifi/issues{/number}","pulls_url":"https://api.github.com/repos/hyperlogic/hifi/pulls{/number}","milestones_url":"https://api.github.com/repos/hyperlogic/hifi/milestones{/number}","notifications_url":"https://api.github.com/repos/hyperlogic/hifi/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/hyperlogic/hifi/labels{/name}","releases_url":"https://api.github.com/repos/hyperlogic/hifi/releases{/id}","deployments_url":"https://api.github.com/repos/hyperlogic/hifi/deployments","created_at":"2015-05-02T16:40:40Z","updated_at":"2016-01-11T18:16:17Z","pushed_at":"2016-01-22T01:29:54Z","git_url":"git://github.com/hyperlogic/hifi.git","ssh_url":"git@github.com:hyperlogic/hifi.git","clone_url":"https://github.com/hyperlogic/hifi.git","svn_url":"https://github.com/hyperlogic/hifi","homepage":"","size":182625,"stargazers_count":0,"watchers_count":0,"language":"C++","has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"highfidelity:master","ref":"master","sha":"9127edc968693573db275ade881508a59044a743","user":{"login":"highfidelity","id":1565370,"avatar_url":"https://avatars.githubusercontent.com/u/1565370?v=3","gravatar_id":"","url":"https://api.github.com/users/highfidelity","html_url":"https://github.com/highfidelity","followers_url":"https://api.github.com/users/highfidelity/followers","following_url":"https://api.github.com/users/highfidelity/following{/other_user}","gists_url":"https://api.github.com/users/highfidelity/gists{/gist_id}","starred_url":"https://api.github.com/users/highfidelity/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/highfidelity/subscriptions","organizations_url":"https://api.github.com/users/highfidelity/orgs","repos_url":"https://api.github.com/users/highfidelity/repos","events_url":"https://api.github.com/users/highfidelity/events{/privacy}","received_events_url":"https://api.github.com/users/highfidelity/received_events","type":"Organization","site_admin":false},"repo":{"id":5372872,"name":"hifi","full_name":"highfidelity/hifi","owner":{"login":"highfidelity","id":1565370,"avatar_url":"https://avatars.githubusercontent.com/u/1565370?v=3","gravatar_id":"","url":"https://api.github.com/users/highfidelity","html_url":"https://github.com/highfidelity","followers_url":"https://api.github.com/users/highfidelity/followers","following_url":"https://api.github.com/users/highfidelity/following{/other_user}","gists_url":"https://api.github.com/users/highfidelity/gists{/gist_id}","starred_url":"https://api.github.com/users/highfidelity/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/highfidelity/subscriptions","organizations_url":"https://api.github.com/users/highfidelity/orgs","repos_url":"https://api.github.com/users/highfidelity/repos","events_url":"https://api.github.com/users/highfidelity/events{/privacy}","received_events_url":"https://api.github.com/users/highfidelity/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/highfidelity/hifi","description":"Open source software for shared virtual worlds using HMDs and dynamically assigned devices as servers.  San Francisco based startup, we are hiring: http://highfidelity.com/jobs  Documentation at http://docs.highfidelity.com  Contribute by reporting bugs & doing jobs on http://worklist.net","fork":false,"url":"https://api.github.com/repos/highfidelity/hifi","forks_url":"https://api.github.com/repos/highfidelity/hifi/forks","keys_url":"https://api.github.com/repos/highfidelity/hifi/keys{/key_id}","collaborators_url":"https://api.github.com/repos/highfidelity/hifi/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/highfidelity/hifi/teams","hooks_url":"https://api.github.com/repos/highfidelity/hifi/hooks","issue_events_url":"https://api.github.com/repos/highfidelity/hifi/issues/events{/number}","events_url":"https://api.github.com/repos/highfidelity/hifi/events","assignees_url":"https://api.github.com/repos/highfidelity/hifi/assignees{/user}","branches_url":"https://api.github.com/repos/highfidelity/hifi/branches{/branch}","tags_url":"https://api.github.com/repos/highfidelity/hifi/tags","blobs_url":"https://api.github.com/repos/highfidelity/hifi/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/highfidelity/hifi/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/highfidelity/hifi/git/refs{/sha}","trees_url":"https://api.github.com/repos/highfidelity/hifi/git/trees{/sha}","statuses_url":"https://api.github.com/repos/highfidelity/hifi/statuses/{sha}","languages_url":"https://api.github.com/repos/highfidelity/hifi/languages","stargazers_url":"https://api.github.com/repos/highfidelity/hifi/stargazers","contributors_url":"https://api.github.com/repos/highfidelity/hifi/contributors","subscribers_url":"https://api.github.com/repos/highfidelity/hifi/subscribers","subscription_url":"https://api.github.com/repos/highfidelity/hifi/subscription","commits_url":"https://api.github.com/repos/highfidelity/hifi/commits{/sha}","git_commits_url":"https://api.github.com/repos/highfidelity/hifi/git/commits{/sha}","comments_url":"https://api.github.com/repos/highfidelity/hifi/comments{/number}","issue_comment_url":"https://api.github.com/repos/highfidelity/hifi/issues/comments{/number}","contents_url":"https://api.github.com/repos/highfidelity/hifi/contents/{+path}","compare_url":"https://api.github.com/repos/highfidelity/hifi/compare/{base}...{head}","merges_url":"https://api.github.com/repos/highfidelity/hifi/merges","archive_url":"https://api.github.com/repos/highfidelity/hifi/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/highfidelity/hifi/downloads","issues_url":"https://api.github.com/repos/highfidelity/hifi/issues{/number}","pulls_url":"https://api.github.com/repos/highfidelity/hifi/pulls{/number}","milestones_url":"https://api.github.com/repos/highfidelity/hifi/milestones{/number}","notifications_url":"https://api.github.com/repos/highfidelity/hifi/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/highfidelity/hifi/labels{/name}","releases_url":"https://api.github.com/repos/highfidelity/hifi/releases{/id}","deployments_url":"https://api.github.com/repos/highfidelity/hifi/deployments","created_at":"2012-08-10T18:26:22Z","updated_at":"2016-01-18T01:29:50Z","pushed_at":"2016-01-22T02:10:52Z","git_url":"git://github.com/highfidelity/hifi.git","ssh_url":"git@github.com:highfidelity/hifi.git","clone_url":"https://github.com/highfidelity/hifi.git","svn_url":"https://github.com/highfidelity/hifi","homepage":"","size":225467,"stargazers_count":345,"watchers_count":345,"language":"C++","has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":204,"mirror_url":null,"open_issues_count":64,"forks":204,"open_issues":64,"watchers":345,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/highfidelity/hifi/pulls/6895"},"html":{"href":"https://github.com/highfidelity/hifi/pull/6895"},"issue":{"href":"https://api.github.com/repos/highfidelity/hifi/issues/6895"},"comments":{"href":"https://api.github.com/repos/highfidelity/hifi/issues/6895/comments"},"review_comments":{"href":"https://api.github.com/repos/highfidelity/hifi/pulls/6895/comments"},"review_comment":{"href":"https://api.github.com/repos/highfidelity/hifi/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/highfidelity/hifi/pulls/6895/commits"},"statuses":{"href":"https://api.github.com/repos/highfidelity/hifi/statuses/ca8a832818231f8bc3ae004953ef4cd357bf782d"}}}}