From 512034fd7cb5f10ef3123218210a3f873b43d82a Mon Sep 17 00:00:00 2001 From: barnold1953 Date: Wed, 23 Jul 2014 15:23:27 -0700 Subject: [PATCH] Ability to modify AC avatar blendshapes from JS --- assignment-client/src/Agent.cpp | 7 ++- examples/bot.js | 15 ++++-- interface/src/avatar/Head.cpp | 2 +- .../animation/src/FacialAnimationData.cpp | 10 +++- libraries/animation/src/FacialAnimationData.h | 18 +++++++ libraries/avatars/src/AvatarData.cpp | 5 ++ libraries/avatars/src/AvatarData.h | 18 +++++-- libraries/avatars/src/HeadData.cpp | 49 +++++++++++++++++++ libraries/avatars/src/HeadData.h | 15 +++++- 9 files changed, 125 insertions(+), 14 deletions(-) diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index 0449e0d682..0f485dec14 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -229,11 +229,13 @@ void Agent::run() { // setup an Avatar for the script to use AvatarData scriptedAvatar; - + // Pretend faceshift is active so we can modify facial data + scriptedAvatar.setIsFaceshiftConnected(true); + // call model URL setters with empty URLs so our avatar, if user, will have the default models scriptedAvatar.setFaceModelURL(QUrl()); scriptedAvatar.setSkeletonModelURL(QUrl()); - + // give this AvatarData object to the script engine _scriptEngine.setAvatarData(&scriptedAvatar, "Avatar"); _scriptEngine.setAvatarHashMap(&_avatarHashMap, "AvatarList"); @@ -263,6 +265,7 @@ void Agent::run() { _scriptEngine.getModelsScriptingInterface()->setModelTree(_modelViewer.getTree()); _scriptEngine.setScriptContents(scriptContents); + _scriptEngine.run(); setFinished(true); } diff --git a/examples/bot.js b/examples/bot.js index edef280e21..1c8fd218d9 100644 --- a/examples/bot.js +++ b/examples/bot.js @@ -24,11 +24,11 @@ function printVector(string, vector) { print(string + " " + vector.x + ", " + vector.y + ", " + vector.z); } -var CHANCE_OF_MOVING = 0.005; -var CHANCE_OF_SOUND = 0.005; +var CHANCE_OF_MOVING = 0.0; +var CHANCE_OF_SOUND = 0.0; var CHANCE_OF_HEAD_TURNING = 0.05; -var CHANCE_OF_BIG_MOVE = 0.1; -var CHANCE_OF_WAVING = 0.009; +var CHANCE_OF_BIG_MOVE = 0.0; +var CHANCE_OF_WAVING = 0.0; var shouldReceiveVoxels = true; var VOXEL_FPS = 60.0; @@ -147,6 +147,13 @@ function updateBehavior(deltaTime) { if (CHANCE_OF_MOVING == 0.000) { Avatar.position = firstPosition; } + //print("hi"); + Avatar.setLeftBlink(1.0); + Avatar.setRightBlink(0.5); + Avatar.setBrowDownLeft(1.0); + Avatar.setMouthSize(1.0); + Avatar.setMouthSmileRight(1.0); + //print("ho"); if (shouldReceiveVoxels && ((cumulativeTime - lastVoxelQueryTime) > (1.0 / VOXEL_FPS))) { VoxelViewer.setPosition(Avatar.position); diff --git a/interface/src/avatar/Head.cpp b/interface/src/avatar/Head.cpp index 814377b3d2..244eaab8ab 100644 --- a/interface/src/avatar/Head.cpp +++ b/interface/src/avatar/Head.cpp @@ -146,7 +146,7 @@ void Head::simulate(float deltaTime, bool isMine, bool billboard) { _browAudioLift, glm::clamp(log(_averageLoudness) / JAW_OPEN_SCALE, 0.0f, 1.0f)); } - + if (!isMine) { _faceModel.setLODDistance(static_cast(_owningAvatar)->getLODDistance()); } diff --git a/libraries/animation/src/FacialAnimationData.cpp b/libraries/animation/src/FacialAnimationData.cpp index 974cdec66f..68e61bbe72 100644 --- a/libraries/animation/src/FacialAnimationData.cpp +++ b/libraries/animation/src/FacialAnimationData.cpp @@ -29,12 +29,18 @@ _mouthSmileRightIndex(29), _jawOpenIndex(21) { } +void FacialAnimationData::setBlendshapeCoefficient(int index, float val) { + _blendshapeCoefficients.resize(max((int)_blendshapeCoefficients.size(), _jawOpenIndex + 1)); + if (index >= 0 && index < (int)_blendshapeCoefficients.size()) { + _blendshapeCoefficients[index] = val; + } +} + float FacialAnimationData::getBlendshapeCoefficient(int index) const { return (index >= 0 && index < (int)_blendshapeCoefficients.size()) ? _blendshapeCoefficients[index] : 0.0f; } -void FacialAnimationData::updateFakeCoefficients(float leftBlink, float rightBlink, float browUp, - float jawOpen) { +void FacialAnimationData::updateFakeCoefficients(float leftBlink, float rightBlink, float browUp, float jawOpen) { _blendshapeCoefficients.resize(max((int)_blendshapeCoefficients.size(), _jawOpenIndex + 1)); qFill(_blendshapeCoefficients.begin(), _blendshapeCoefficients.end(), 0.0f); _blendshapeCoefficients[_leftBlinkIndex] = leftBlink; diff --git a/libraries/animation/src/FacialAnimationData.h b/libraries/animation/src/FacialAnimationData.h index 514fd5a55f..f87f3a9748 100644 --- a/libraries/animation/src/FacialAnimationData.h +++ b/libraries/animation/src/FacialAnimationData.h @@ -26,6 +26,23 @@ public: FacialAnimationData(); + // Setters + void setLeftBlink(float val) { setBlendshapeCoefficient(_leftBlinkIndex, val); } + void setRightBlink(float val) { setBlendshapeCoefficient(_rightBlinkIndex, val); } + void setLeftEyeOpen(float val) { setBlendshapeCoefficient(_leftBlinkIndex, val); } + void setRightEyeOpen(float val) { setBlendshapeCoefficient(_rightBlinkIndex, val); } + + void setBrowDownLeft(float val) { setBlendshapeCoefficient(_browDownLeftIndex, val); } + void setBrowDownRight(float val) { setBlendshapeCoefficient(_browDownRightIndex, val); } + void setBrowUpCenter(float val) { setBlendshapeCoefficient(_browUpCenterIndex, val); } + void setBrowUpLeft(float val) { setBlendshapeCoefficient(_browUpLeftIndex, val); } + void setBrowUpRight(float val) { setBlendshapeCoefficient(_browUpRightIndex, val); } + + void setMouthSize(float val) { setBlendshapeCoefficient(_jawOpenIndex, val); } + void setMouthSmileLeft(float val) { setBlendshapeCoefficient(_mouthSmileLeftIndex, val); } + void setMouthSmileRight(float val) { setBlendshapeCoefficient(_mouthSmileRightIndex, val); } + + // Getters float getLeftBlink() const { return getBlendshapeCoefficient(_leftBlinkIndex); } float getRightBlink() const { return getBlendshapeCoefficient(_rightBlinkIndex); } float getLeftEyeOpen() const { return getBlendshapeCoefficient(_leftEyeOpenIndex); } @@ -47,6 +64,7 @@ public: const QVector& getBlendshapeCoefficients() const { return _blendshapeCoefficients; } private: + void setBlendshapeCoefficient(int index, float val); float getBlendshapeCoefficient(int index) const; int _leftBlinkIndex; diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index fc5b762a0f..93186eb78a 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -45,6 +45,7 @@ AvatarData::AvatarData() : _handState(0), _keyState(NO_KEY_DOWN), _isChatCirclingEnabled(false), + _forceFaceshiftIsConnected(false), _hasNewJointRotations(true), _headData(NULL), _handData(NULL), @@ -82,6 +83,10 @@ QByteArray AvatarData::toByteArray() { // lazily allocate memory for HeadData in case we're not an Avatar instance if (!_headData) { _headData = new HeadData(this); + // In some cases, for instance for AC avatars, we might want to force faceshift to appear connected + if (_forceFaceshiftIsConnected) { + _headData->setIsFaceshiftConnected(true); + } } QByteArray avatarDataByteArray; diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index b1b48e3941..33fbd39616 100755 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -207,9 +207,20 @@ public: Q_INVOKABLE virtual QStringList getJointNames() const { return _jointNames; } // Facial Animation - Q_INVOKABLE void setLeftEyebrow(float f) { - _headData->setLeftEyebrow(f); - } + Q_INVOKABLE void setLeftBlink(float val) { _headData->setLeftBlink(val); } + Q_INVOKABLE void setRightBlink(float val) { _headData->setRightBlink(val); } + Q_INVOKABLE void setLeftEyeOpen(float val) { _headData->setLeftEyeOpen(val); } + Q_INVOKABLE void setRightEyeOpen(float val) { _headData->setRightEyeOpen(val); } + Q_INVOKABLE void setBrowDownLeft(float val) { _headData->setBrowDownLeft(val); } + Q_INVOKABLE void setBrowDownRight(float val) { _headData->setBrowDownRight(val); } + Q_INVOKABLE void setBrowUpCenter(float val) { _headData->setBrowUpCenter(val); } + Q_INVOKABLE void setBrowUpLeft(float val) { _headData->setBrowUpLeft(val); } + Q_INVOKABLE void setBrowUpRight(float val) { _headData->setBrowUpRight(val); } + Q_INVOKABLE void setMouthSize(float val) { _headData->setMouthSize(val); } + Q_INVOKABLE void setMouthSmileLeft(float val) { _headData->setMouthSmileLeft(val); } + Q_INVOKABLE void setMouthSmileRight(float val) { _headData->setMouthSmileRight(val); } + + void setIsFaceshiftConnected(bool isFaceshift) { _forceFaceshiftIsConnected = isFaceshift; } // key state void setKeyState(KeyState s) { _keyState = s; } @@ -305,6 +316,7 @@ protected: std::string _chatMessage; bool _isChatCirclingEnabled; + bool _forceFaceshiftIsConnected; bool _hasNewJointRotations; // set in AvatarData, cleared in Avatar diff --git a/libraries/avatars/src/HeadData.cpp b/libraries/avatars/src/HeadData.cpp index 1f2bb73834..919adcd642 100644 --- a/libraries/avatars/src/HeadData.cpp +++ b/libraries/avatars/src/HeadData.cpp @@ -55,6 +55,55 @@ void HeadData::setOrientation(const glm::quat& orientation) { _baseRoll = eulers.z; } +void HeadData::setLeftBlink(float val) { + _facialAnimationData->setLeftBlink(val); +} + +void HeadData::setRightBlink(float val) { + _facialAnimationData->setRightBlink(val); +} + +void HeadData::setLeftEyeOpen(float val) { + _facialAnimationData->setLeftEyeOpen(val); +} + +void HeadData::setRightEyeOpen(float val) { + _facialAnimationData->setRightEyeOpen(val); +} + +void HeadData::setBrowDownLeft(float val) { + _facialAnimationData->setBrowDownLeft(val); +} + +void HeadData::setBrowDownRight(float val) { + _facialAnimationData->setBrowDownRight(val); +} + +void HeadData::setBrowUpCenter(float val) { + _facialAnimationData->setBrowUpCenter(val); +} + +void HeadData::setBrowUpLeft(float val) { + _facialAnimationData->setBrowUpLeft(val); +} + +void HeadData::setBrowUpRight(float val) { + _facialAnimationData->setBrowUpRight(val); +} + +void HeadData::setMouthSize(float val) { + _facialAnimationData->setMouthSize(val); +} + +void HeadData::setMouthSmileLeft(float val) { + _facialAnimationData->setLeftBlink(val); +} + +void HeadData::setMouthSmileRight(float val) { + _facialAnimationData->setMouthSmileRight(val); +} + + void HeadData::addYaw(float yaw) { setBaseYaw(_baseYaw + yaw); } diff --git a/libraries/avatars/src/HeadData.h b/libraries/avatars/src/HeadData.h index 9920776b2a..b6e877564a 100644 --- a/libraries/avatars/src/HeadData.h +++ b/libraries/avatars/src/HeadData.h @@ -61,9 +61,20 @@ public: void setPupilDilation(float pupilDilation) { _pupilDilation = pupilDilation; } // Facial animation - void setLeftEyebrow(float f) { + void setLeftBlink(float val); + void setRightBlink(float val); + void setLeftEyeOpen(float val); + void setRightEyeOpen(float val); + void setBrowDownLeft(float val); + void setBrowDownRight(float val); + void setBrowUpCenter(float val); + void setBrowUpLeft(float val); + void setBrowUpRight(float val); + void setMouthSize(float val); + void setMouthSmileLeft(float val); + void setMouthSmileRight(float val); - } + void setIsFaceshiftConnected(bool isFaceshiftConnected) { _isFaceshiftConnected = isFaceshiftConnected; } // degrees void addYaw(float yaw);