Fix eyelid behaviour

This commit is contained in:
luiscuenca 2018-06-28 16:41:39 -07:00
parent e7d5ea561b
commit 2264425f9f
3 changed files with 66 additions and 32 deletions

View file

@ -220,30 +220,56 @@ void Head::calculateMouthShapes(float deltaTime) {
void Head::applyEyelidOffset(glm::quat headOrientation) {
// Adjusts the eyelid blendshape coefficients so that the eyelid follows the iris as the head pitches.
if (disableEyelidAdjustment) {
bool isBlinking = (_rightEyeBlinkVelocity != 0.0f && _rightEyeBlinkVelocity != 0.0f);
if (disableEyelidAdjustment || isBlinking) {
return;
}
const std::vector<QString> eyeBlinkBlendShapes = { "EyeBlink_L", "EyeBlink_R" };
const std::vector<QString> eyeOpenBlendShapes = { "EyeOpen_L", "EyeOpen_R" };
const std::vector<QString> browsBlendShapes = { "BrowsU_L", "BrowsU_R" };
const float EYE_PITCH_TO_COEFFICIENT = 3.5f; // Empirically determined
const float MAX_EYELID_OFFSET = 1.5f;
const float BLINK_DOWN_MULTIPLIER = 0.25f;
const float OPEN_DOWN_MULTIPLIER = 0.3f;
const float BROW_UP_MULTIPLIER = 0.5f;
glm::quat eyeRotation = rotationBetween(headOrientation * IDENTITY_FORWARD, getLookAtPosition() - _eyePosition);
eyeRotation = eyeRotation * glm::angleAxis(safeEulerAngles(headOrientation).y, IDENTITY_UP); // Rotation w.r.t. head
float eyePitch = safeEulerAngles(eyeRotation).x;
float eyelidOffset = glm::clamp(abs(eyePitch * EYE_PITCH_TO_COEFFICIENT), 0.0f, MAX_EYELID_OFFSET);
const float EYE_PITCH_TO_COEFFICIENT = 1.6f; // Empirically determined
const float MAX_EYELID_OFFSET = 0.8f; // So that don't fully close eyes when looking way down
float eyelidOffset = glm::clamp(-eyePitch * EYE_PITCH_TO_COEFFICIENT, -1.0f, MAX_EYELID_OFFSET);
std::vector<int> eyeBlinkIndices, eyeOpenIndices, browsIndices;
for (int i = 0; i < 2; i++) {
const int LEFT_EYE = 8;
float eyeCoefficient = _transientBlendshapeCoefficients[i] - _transientBlendshapeCoefficients[LEFT_EYE + i];
eyeCoefficient = glm::clamp(eyelidOffset + eyeCoefficient * (1.0f - eyelidOffset), -1.0f, 1.0f);
if (eyeCoefficient > 0.0f) {
_transientBlendshapeCoefficients[i] = eyeCoefficient;
_transientBlendshapeCoefficients[LEFT_EYE + i] = 0.0f;
getBlendshapeIndices(eyeBlinkBlendShapes, eyeBlinkIndices);
getBlendshapeIndices(eyeOpenBlendShapes, eyeOpenIndices);
getBlendshapeIndices(browsBlendShapes, browsIndices);
} else {
_transientBlendshapeCoefficients[i] = 0.0f;
_transientBlendshapeCoefficients[LEFT_EYE + i] = -eyeCoefficient;
bool isLookingUp = (eyePitch > 0);
for (auto& blinkIndex : eyeBlinkIndices) {
float lookingUpCoefficient = -eyelidOffset;
float lookingDownCoefficient = BLINK_DOWN_MULTIPLIER * eyelidOffset;
if (blinkIndex >= 0 && blinkIndex < _transientBlendshapeCoefficients.size()) {
_transientBlendshapeCoefficients[blinkIndex] = isLookingUp ? lookingUpCoefficient : lookingDownCoefficient;
}
}
for (auto& openIndex : eyeOpenIndices) {
float lookingUpCoefficient = eyelidOffset;
float lookingDownCoefficient = OPEN_DOWN_MULTIPLIER * eyelidOffset;
if (openIndex >= 0 && openIndex < _transientBlendshapeCoefficients.size()) {
_transientBlendshapeCoefficients[openIndex] = isLookingUp ? lookingUpCoefficient : lookingDownCoefficient;
}
}
for (auto& browIndex : browsIndices) {
float lookingUpCoefficient = BROW_UP_MULTIPLIER * eyelidOffset;
float lookingDownCoefficient = 0.0f;
if (browIndex >= 0 && browIndex < _transientBlendshapeCoefficients.size()) {
_transientBlendshapeCoefficients[browIndex] = isLookingUp ? lookingUpCoefficient : lookingDownCoefficient;
}
}
}

View file

@ -33,7 +33,7 @@ HeadData::HeadData(AvatarData* owningAvatar) :
_summedBlendshapeCoefficients(QVector<float>(0, 0.0f)),
_owningAvatar(owningAvatar)
{
computeBlendshapesLookupMap();
}
glm::quat HeadData::getRawOrientation() const {
@ -71,16 +71,10 @@ void HeadData::setOrientation(const glm::quat& orientation) {
setHeadOrientation(orientation);
}
//Lazily construct a lookup map from the blendshapes
static const QMap<QString, int>& getBlendshapesLookupMap() {
static std::once_flag once;
static QMap<QString, int> blendshapeLookupMap;
std::call_once(once, [&] {
for (int i = 0; i < NUM_FACESHIFT_BLENDSHAPES; i++) {
blendshapeLookupMap[FACESHIFT_BLENDSHAPES[i]] = i;
}
});
return blendshapeLookupMap;
void HeadData::computeBlendshapesLookupMap(){
for (int i = 0; i < NUM_FACESHIFT_BLENDSHAPES; i++) {
_blendshapeLookupMap[FACESHIFT_BLENDSHAPES[i]] = i;
}
}
int HeadData::getNumSummedBlendshapeCoefficients() const {
@ -108,11 +102,10 @@ const QVector<float>& HeadData::getSummedBlendshapeCoefficients() {
}
void HeadData::setBlendshape(QString name, float val) {
const auto& blendshapeLookupMap = getBlendshapesLookupMap();
//Check to see if the named blendshape exists, and then set its value if it does
auto it = blendshapeLookupMap.find(name);
if (it != blendshapeLookupMap.end()) {
auto it = _blendshapeLookupMap.find(name);
if (it != _blendshapeLookupMap.end()) {
if (_blendshapeCoefficients.size() <= it.value()) {
_blendshapeCoefficients.resize(it.value() + 1);
}
@ -123,6 +116,18 @@ void HeadData::setBlendshape(QString name, float val) {
}
}
int HeadData::getBlendshapeIndex(const QString& name) {
auto it = _blendshapeLookupMap.find(name);
int index = it != _blendshapeLookupMap.end() ? it.value() : -1;
return index;
}
void HeadData::getBlendshapeIndices(const std::vector<QString>& blendShapeNames, std::vector<int>& indexes) {
for (auto& name : blendShapeNames) {
indexes.push_back(getBlendshapeIndex(name));
}
}
static const QString JSON_AVATAR_HEAD_ROTATION = QStringLiteral("rotation");
static const QString JSON_AVATAR_HEAD_BLENDSHAPE_COEFFICIENTS = QStringLiteral("blendShapes");
static const QString JSON_AVATAR_HEAD_LEAN_FORWARD = QStringLiteral("leanForward");
@ -131,10 +136,9 @@ static const QString JSON_AVATAR_HEAD_LOOKAT = QStringLiteral("lookAt");
QJsonObject HeadData::toJson() const {
QJsonObject headJson;
const auto& blendshapeLookupMap = getBlendshapesLookupMap();
QJsonObject blendshapesJson;
for (auto name : blendshapeLookupMap.keys()) {
auto index = blendshapeLookupMap[name];
for (auto name : _blendshapeLookupMap.keys()) {
auto index = _blendshapeLookupMap[name];
float value = 0.0f;
if (index < _blendshapeCoefficients.size()) {
value += _blendshapeCoefficients[index];

View file

@ -55,6 +55,8 @@ public:
void setOrientation(const glm::quat& orientation);
void setBlendshape(QString name, float val);
int getBlendshapeIndex(const QString& name);
void getBlendshapeIndices(const std::vector<QString>& blendShapeNames, std::vector<int>& indexes);
const QVector<float>& getBlendshapeCoefficients() const { return _blendshapeCoefficients; }
const QVector<float>& getSummedBlendshapeCoefficients();
int getNumSummedBlendshapeCoefficients() const;
@ -114,6 +116,7 @@ protected:
QVector<float> _blendshapeCoefficients;
QVector<float> _transientBlendshapeCoefficients;
QVector<float> _summedBlendshapeCoefficients;
QMap<QString, int> _blendshapeLookupMap;
AvatarData* _owningAvatar;
private:
@ -122,6 +125,7 @@ private:
HeadData& operator= (const HeadData&);
void setHeadOrientation(const glm::quat& orientation);
void computeBlendshapesLookupMap();
};
#endif // hifi_HeadData_h