From dbcb778ea9d84d242640ab09a4ae0a79f8c04c77 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Thu, 18 Sep 2014 08:33:41 -0700 Subject: [PATCH 1/3] Drive mouth with loudness relative to long term average --- examples/headMove.js | 2 +- interface/src/avatar/Head.cpp | 22 ++++++++++++++++------ interface/src/avatar/Head.h | 1 + 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/examples/headMove.js b/examples/headMove.js index 0a7686c569..f8a1895a08 100644 --- a/examples/headMove.js +++ b/examples/headMove.js @@ -79,7 +79,7 @@ function moveWithHead(deltaTime) { if (Math.abs(headDelta.z) > HEAD_MOVE_DEAD_ZONE) { if (Math.abs(Vec3.dot(velocity, forward)) < maxVelocity) { thrust = Vec3.sum(thrust, Vec3.multiply(forward, -headDelta.z * HEAD_THRUST_FWD_SCALE * deltaTime)); - } + } } if (Math.abs(headDelta.x) > HEAD_STRAFE_DEAD_ZONE) { if (Math.abs(Vec3.dot(velocity, right)) < maxVelocity) { diff --git a/interface/src/avatar/Head.cpp b/interface/src/avatar/Head.cpp index b226b8ed31..d1fcc0f33f 100644 --- a/interface/src/avatar/Head.cpp +++ b/interface/src/avatar/Head.cpp @@ -32,6 +32,7 @@ Head::Head(Avatar* owningAvatar) : _eyePosition(0.0f, 0.0f, 0.0f), _scale(1.0f), _lastLoudness(0.0f), + _longTermAverageLoudness(-1.0f), _audioAttack(0.0f), _angularVelocity(0,0,0), _renderLookatVectors(false), @@ -62,7 +63,7 @@ void Head::reset() { } void Head::simulate(float deltaTime, bool isMine, bool billboard) { - // Update audio trailing average for rendering facial animations + if (isMine) { MyAvatar* myAvatar = static_cast(_owningAvatar); @@ -78,6 +79,18 @@ void Head::simulate(float deltaTime, bool isMine, bool billboard) { } } } + // Update audio trailing average for rendering facial animations + const float AUDIO_AVERAGING_SECS = 0.05f; + const float AUDIO_LONG_TERM_AVERAGING_SECS = 30.f; + _averageLoudness = glm::mix(_averageLoudness, _audioLoudness, glm::min(deltaTime / AUDIO_AVERAGING_SECS, 1.0f)); + + if (_longTermAverageLoudness == -1.0) { + _longTermAverageLoudness = _averageLoudness; + } else { + _longTermAverageLoudness = glm::mix(_longTermAverageLoudness, _averageLoudness, glm::min(deltaTime / AUDIO_LONG_TERM_AVERAGING_SECS, 1.0f)); + } + float deltaLoudness = glm::max(0.0f, _averageLoudness - _longTermAverageLoudness); + qDebug() << "deltaLoudness: " << deltaLoudness; if (!(_isFaceshiftConnected || billboard)) { // Update eye saccades @@ -92,9 +105,6 @@ void Head::simulate(float deltaTime, bool isMine, bool billboard) { _saccadeTarget = SACCADE_MAGNITUDE * randVector(); } _saccade += (_saccadeTarget - _saccade) * 0.50f; - - const float AUDIO_AVERAGING_SECS = 0.05f; - _averageLoudness = glm::mix(_averageLoudness, _audioLoudness, glm::min(deltaTime / AUDIO_AVERAGING_SECS, 1.0f)); // Detect transition from talking to not; force blink after that and a delay bool forceBlink = false; @@ -108,8 +118,8 @@ void Head::simulate(float deltaTime, bool isMine, bool billboard) { } // Update audio attack data for facial animation (eyebrows and mouth) - _audioAttack = 0.9f * _audioAttack + 0.1f * fabs(_audioLoudness - _lastLoudness); - _lastLoudness = _audioLoudness; + _audioAttack = 0.9f * _audioAttack + 0.1f * fabs((_audioLoudness - _longTermAverageLoudness) - _lastLoudness); + _lastLoudness = (_audioLoudness - _longTermAverageLoudness); const float BROW_LIFT_THRESHOLD = 100.0f; if (_audioAttack > BROW_LIFT_THRESHOLD) { diff --git a/interface/src/avatar/Head.h b/interface/src/avatar/Head.h index 1cdfdaf5a3..e99a7f5c7b 100644 --- a/interface/src/avatar/Head.h +++ b/interface/src/avatar/Head.h @@ -121,6 +121,7 @@ private: float _scale; float _lastLoudness; + float _longTermAverageLoudness; float _audioAttack; glm::vec3 _angularVelocity; bool _renderLookatVectors; From 8c71ed3f103b6106438d7633ff35e8cf5fa3eafa Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Thu, 18 Sep 2014 10:48:36 -0700 Subject: [PATCH 2/3] Improving headMove, added JS call for neckPosition --- examples/headMove.js | 29 +++++++++++++++++++++-------- interface/src/avatar/Avatar.cpp | 6 ++++++ interface/src/avatar/Avatar.h | 2 ++ interface/src/avatar/Head.cpp | 2 +- 4 files changed, 30 insertions(+), 9 deletions(-) diff --git a/examples/headMove.js b/examples/headMove.js index 359dfd8751..68a9a7833d 100644 --- a/examples/headMove.js +++ b/examples/headMove.js @@ -45,7 +45,7 @@ var maxVelocity = 1.25; var noFly = true; //var roomLimits = { xMin: 618, xMax: 635.5, zMin: 528, zMax: 552.5 }; -var roomLimits = { xMin: -1, xMax: 0, zMin: 0, zMax: 0 }; +var roomLimits = { xMin: 142.6, xMax: 153.7, zMin: 177.5, zMax: 192.0 }; function isInRoom(position) { var BUFFER = 2.0; @@ -71,19 +71,29 @@ function moveWithHead(deltaTime) { var deltaPitch = MyAvatar.getHeadDeltaPitch() - headStartDeltaPitch; var deltaRoll = MyAvatar.getHeadFinalRoll() - headStartRoll; var velocity = MyAvatar.getVelocity(); - var bodyLocalCurrentHeadVector = Vec3.subtract(MyAvatar.getHeadPosition(), MyAvatar.position); - bodyLocalCurrentHeadVector = Vec3.multiplyQbyV(Quat.angleAxis(-deltaYaw, {x:0, y: 1, z:0}), bodyLocalCurrentHeadVector); + var position = MyAvatar.position; + var neckPosition = MyAvatar.getNeckPosition(); + var bodyLocalCurrentHeadVector = Vec3.subtract(neckPosition, position); + //bodyLocalCurrentHeadVector = Vec3.multiplyQbyV(Quat.inverse(MyAvatar.orientation), bodyLocalCurrentHeadVector); var headDelta = Vec3.subtract(bodyLocalCurrentHeadVector, headStartPosition); - headDelta = Vec3.multiplyQbyV(Quat.inverse(Camera.getOrientation()), headDelta); + //headDelta = Vec3.multiplyQbyV(Quat.inverse(Camera.getOrientation()), headDelta); headDelta.y = 0.0; // Don't respond to any of the vertical component of head motion + if (Vec3.length(headDelta) > 0.005) { + Vec3.print("headDelta = ", headDelta); + Vec3.print("headStartPosition = ", headStartPosition); + Vec3.print("MyAvatar.position = ", position); + Vec3.print("MyAvatar.getNeckPosition() = ", neckPosition); + + } + // Thrust based on leaning forward and side-to-side var targetVelocity = {x:0.0, y:0.0, z:0.0}; if (Math.abs(headDelta.z) > HEAD_MOVE_DEAD_ZONE) { - targetVelocity = Vec3.multiply(zAxis, -headDelta.z * HEAD_VELOCITY_FWD_FACTOR); + targetVelocity = Vec3.multiply(zAxis, headDelta.z * HEAD_VELOCITY_FWD_FACTOR); } if (Math.abs(headDelta.x) > HEAD_STRAFE_DEAD_ZONE) { - var deltaVelocity = Vec3.multiply(xAxis, -headDelta.x * HEAD_VELOCITY_LEFT_FACTOR); + var deltaVelocity = Vec3.multiply(xAxis, headDelta.x * HEAD_VELOCITY_LEFT_FACTOR); targetVelocity = Vec3.sum(targetVelocity, deltaVelocity); } if (Math.abs(deltaYaw) > HEAD_ROTATE_DEAD_ZONE) { @@ -130,7 +140,10 @@ function moveWithHead(deltaTime) { Controller.keyPressEvent.connect(function(event) { if (event.text == "SPACE" && !movingWithHead) { movingWithHead = true; - headStartPosition = Vec3.subtract(MyAvatar.getHeadPosition(), MyAvatar.position); + Vec3.print("getNeckPosition() = ", MyAvatar.getNeckPosition()); + headStartPosition = Vec3.subtract(MyAvatar.getNeckPosition(), MyAvatar.position); + //headStartPosition = Vec3.multiplyQbyV(Quat.inverse(MyAvatar.orientation), headStartPosition); + Vec3.print("First HeadStartPosition = ", headStartPosition); headStartDeltaPitch = MyAvatar.getHeadDeltaPitch(); headStartFinalPitch = MyAvatar.getHeadFinalPitch(); headStartRoll = MyAvatar.getHeadFinalRoll(); @@ -138,7 +151,7 @@ Controller.keyPressEvent.connect(function(event) { // start with disabled motor -- it will be updated shortly MyAvatar.motorTimescale = VERY_LARGE_TIMESCALE; MyAvatar.motorVelocity = {x:0.0, y:0.0, z:0.0}; - MyAvatar.motorReferenceFrame = "camera"; // alternatives are: "avatar" and "world" + MyAvatar.motorReferenceFrame = "avatar"; // alternatives are: "avatar" and "world" } }); diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index b62c744fa2..bd05f7c4c0 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -97,6 +97,12 @@ glm::vec3 Avatar::getChestPosition() const { return _skeletonModel.getNeckPosition(neckPosition) ? (_position + neckPosition) * 0.5f : _position; } +glm::vec3 Avatar::getNeckPosition() const { + glm::vec3 neckPosition; + return _skeletonModel.getNeckPosition(neckPosition) ? neckPosition : _position; +} + + glm::quat Avatar::getWorldAlignedOrientation () const { return computeRotationFromBodyToWorldUp() * getOrientation(); } diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index 921722504d..c449a0d1b9 100755 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -154,6 +154,8 @@ public: Q_INVOKABLE void setJointModelPositionAndOrientation(int index, const glm::vec3 position, const glm::quat& rotation); Q_INVOKABLE void setJointModelPositionAndOrientation(const QString& name, const glm::vec3 position, const glm::quat& rotation); + + Q_INVOKABLE glm::vec3 getNeckPosition() const; Q_INVOKABLE glm::vec3 getVelocity() const { return _velocity; } Q_INVOKABLE glm::vec3 getAcceleration() const { return _acceleration; } diff --git a/interface/src/avatar/Head.cpp b/interface/src/avatar/Head.cpp index 3f0770428b..4c394377a3 100644 --- a/interface/src/avatar/Head.cpp +++ b/interface/src/avatar/Head.cpp @@ -90,7 +90,7 @@ void Head::simulate(float deltaTime, bool isMine, bool billboard) { _longTermAverageLoudness = glm::mix(_longTermAverageLoudness, _averageLoudness, glm::min(deltaTime / AUDIO_LONG_TERM_AVERAGING_SECS, 1.0f)); } float deltaLoudness = glm::max(0.0f, _averageLoudness - _longTermAverageLoudness); - qDebug() << "deltaLoudness: " << deltaLoudness; + //qDebug() << "deltaLoudness: " << deltaLoudness; if (!(_isFaceshiftConnected || billboard)) { // Update eye saccades From c6d6c347cd94f9fa38bb46c4c029bb40c2950167 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Fri, 19 Sep 2014 08:48:55 -0700 Subject: [PATCH 3/3] head move using neck measurement for movement rather than head. --- examples/headMove.js | 57 +++++++++++++++++++++++++------------------- 1 file changed, 32 insertions(+), 25 deletions(-) diff --git a/examples/headMove.js b/examples/headMove.js index 68a9a7833d..834c63c3ab 100644 --- a/examples/headMove.js +++ b/examples/headMove.js @@ -16,24 +16,21 @@ var debug = false; var movingWithHead = false; var headStartPosition, headStartDeltaPitch, headStartFinalPitch, headStartRoll, headStartYaw; -var HEAD_MOVE_DEAD_ZONE = 0.10; -var HEAD_STRAFE_DEAD_ZONE = 0.0; -var HEAD_ROTATE_DEAD_ZONE = 0.0; -//var HEAD_THRUST_FWD_SCALE = 12000.0; -//var HEAD_THRUST_STRAFE_SCALE = 0.0; -var HEAD_YAW_RATE = 1.0; +var HEAD_MOVE_DEAD_ZONE = 0.03; +var HEAD_STRAFE_DEAD_ZONE = 0.03; +var HEAD_ROTATE_DEAD_ZONE = 10.0; +var HEAD_YAW_RATE = 2.0; var HEAD_PITCH_RATE = 1.0; -//var HEAD_ROLL_THRUST_SCALE = 75.0; -//var HEAD_PITCH_LIFT_THRUST = 3.0; var WALL_BOUNCE = 4000.0; +var FIXED_WALK_VELOCITY = 1.5; // Modify these values to tweak the strength of the motion. // A larger *FACTOR increases the speed. // A lower SHORT_TIMESCALE makes the motor achieve full speed faster. var HEAD_VELOCITY_FWD_FACTOR = 20.0; -var HEAD_VELOCITY_LEFT_FACTOR = 20.0; +var HEAD_VELOCITY_LEFT_FACTOR = 0.0; var HEAD_VELOCITY_UP_FACTOR = 20.0; -var SHORT_TIMESCALE = 0.125; +var SHORT_TIMESCALE = 0.01; var VERY_LARGE_TIMESCALE = 1000000.0; var xAxis = {x:1.0, y:0.0, z:0.0 }; @@ -43,9 +40,10 @@ var zAxis = {x:0.0, y:0.0, z:1.0 }; // If these values are set to something var maxVelocity = 1.25; var noFly = true; +var fixedWalkVelocity = true; //var roomLimits = { xMin: 618, xMax: 635.5, zMin: 528, zMax: 552.5 }; -var roomLimits = { xMin: 142.6, xMax: 153.7, zMin: 177.5, zMax: 192.0 }; +var roomLimits = { xMin: 193.0, xMax: 206.5, zMin: 251.4, zMax: 269.5 }; function isInRoom(position) { var BUFFER = 2.0; @@ -74,32 +72,43 @@ function moveWithHead(deltaTime) { var position = MyAvatar.position; var neckPosition = MyAvatar.getNeckPosition(); var bodyLocalCurrentHeadVector = Vec3.subtract(neckPosition, position); - //bodyLocalCurrentHeadVector = Vec3.multiplyQbyV(Quat.inverse(MyAvatar.orientation), bodyLocalCurrentHeadVector); + bodyLocalCurrentHeadVector = Vec3.multiplyQbyV(Quat.inverse(MyAvatar.orientation), bodyLocalCurrentHeadVector); var headDelta = Vec3.subtract(bodyLocalCurrentHeadVector, headStartPosition); - //headDelta = Vec3.multiplyQbyV(Quat.inverse(Camera.getOrientation()), headDelta); headDelta.y = 0.0; // Don't respond to any of the vertical component of head motion - if (Vec3.length(headDelta) > 0.005) { - Vec3.print("headDelta = ", headDelta); - Vec3.print("headStartPosition = ", headStartPosition); - Vec3.print("MyAvatar.position = ", position); - Vec3.print("MyAvatar.getNeckPosition() = ", neckPosition); + headDelta = Vec3.multiplyQbyV(MyAvatar.orientation, headDelta); + headDelta = Vec3.multiplyQbyV(Quat.inverse(Camera.getOrientation()), headDelta); + + var length = Vec3.length(headDelta); + if (length > 1.0) { + // Needs fixed! Right now sometimes reported neck position jumps to a bad value + headDelta.x = headDelta.y = headDelta.z = 0.0; + length = 0.0; } - // Thrust based on leaning forward and side-to-side var targetVelocity = {x:0.0, y:0.0, z:0.0}; + if (length > HEAD_MOVE_DEAD_ZONE) { + targetVelocity = Vec3.multiply(headDelta, HEAD_VELOCITY_FWD_FACTOR); + } + /* if (Math.abs(headDelta.z) > HEAD_MOVE_DEAD_ZONE) { - targetVelocity = Vec3.multiply(zAxis, headDelta.z * HEAD_VELOCITY_FWD_FACTOR); + if (fixedWalkVelocity) { + targetVelocity = Vec3.multiply(zAxis, headDelta.z > 0 ? FIXED_WALK_VELOCITY : -FIXED_WALK_VELOCITY); + } else { + targetVelocity = Vec3.multiply(zAxis, headDelta.z * HEAD_VELOCITY_FWD_FACTOR); + } } if (Math.abs(headDelta.x) > HEAD_STRAFE_DEAD_ZONE) { var deltaVelocity = Vec3.multiply(xAxis, headDelta.x * HEAD_VELOCITY_LEFT_FACTOR); targetVelocity = Vec3.sum(targetVelocity, deltaVelocity); } + */ if (Math.abs(deltaYaw) > HEAD_ROTATE_DEAD_ZONE) { var orientation = Quat.multiply(Quat.angleAxis((deltaYaw + deltaRoll) * HEAD_YAW_RATE * deltaTime, yAxis), MyAvatar.orientation); MyAvatar.orientation = orientation; } + // Thrust Up/Down based on head pitch if (!noFly) { var deltaVelocity = Vec3.multiply(yAxis, headDelta.y * HEAD_VELOCITY_UP_FACTOR); @@ -140,10 +149,8 @@ function moveWithHead(deltaTime) { Controller.keyPressEvent.connect(function(event) { if (event.text == "SPACE" && !movingWithHead) { movingWithHead = true; - Vec3.print("getNeckPosition() = ", MyAvatar.getNeckPosition()); - headStartPosition = Vec3.subtract(MyAvatar.getNeckPosition(), MyAvatar.position); - //headStartPosition = Vec3.multiplyQbyV(Quat.inverse(MyAvatar.orientation), headStartPosition); - Vec3.print("First HeadStartPosition = ", headStartPosition); + headStartPosition = Vec3.subtract(MyAvatar.getNeckPosition(), MyAvatar.position); + headStartPosition = Vec3.multiplyQbyV(Quat.inverse(MyAvatar.orientation), headStartPosition); headStartDeltaPitch = MyAvatar.getHeadDeltaPitch(); headStartFinalPitch = MyAvatar.getHeadFinalPitch(); headStartRoll = MyAvatar.getHeadFinalRoll(); @@ -151,7 +158,7 @@ Controller.keyPressEvent.connect(function(event) { // start with disabled motor -- it will be updated shortly MyAvatar.motorTimescale = VERY_LARGE_TIMESCALE; MyAvatar.motorVelocity = {x:0.0, y:0.0, z:0.0}; - MyAvatar.motorReferenceFrame = "avatar"; // alternatives are: "avatar" and "world" + MyAvatar.motorReferenceFrame = "camera"; // alternatives are: "avatar" and "world" } });