mirror of
https://thingvellir.net/git/overte
synced 2025-03-27 23:52:03 +01:00
Merge pull request #13502 from luiscuenca/eyelidFix
Fix closed eyelids when head is tilted down
This commit is contained in:
commit
f56c0a3a3f
6 changed files with 81 additions and 39 deletions
|
@ -1440,9 +1440,9 @@ void Rig::updateEyeJoint(int index, const glm::vec3& modelTranslation, const glm
|
|||
|
||||
glm::quat deltaQuat = desiredQuat * glm::inverse(headQuat);
|
||||
|
||||
// limit swing rotation of the deltaQuat by a 30 degree cone.
|
||||
// limit swing rotation of the deltaQuat by a 25 degree cone.
|
||||
// TODO: use swing twist decomposition constraint instead, for off axis rotation clamping.
|
||||
const float MAX_ANGLE = 30.0f * RADIANS_PER_DEGREE;
|
||||
const float MAX_ANGLE = 25.0f * RADIANS_PER_DEGREE;
|
||||
if (fabsf(glm::angle(deltaQuat)) > MAX_ANGLE) {
|
||||
deltaQuat = glm::angleAxis(glm::clamp(glm::angle(deltaQuat), -MAX_ANGLE, MAX_ANGLE), glm::axis(deltaQuat));
|
||||
}
|
||||
|
|
|
@ -220,30 +220,44 @@ 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;
|
||||
}
|
||||
|
||||
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;
|
||||
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;
|
||||
|
||||
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);
|
||||
glm::vec3 lookAt = glm::normalize(getLookAtPosition() - _eyePosition);
|
||||
glm::vec3 headUp = headOrientation * Vectors::UNIT_Y;
|
||||
float eyePitch = (PI / 2.0f) - acos(glm::dot(lookAt, headUp));
|
||||
float eyelidOffset = glm::clamp(abs(eyePitch * EYE_PITCH_TO_COEFFICIENT), 0.0f, MAX_EYELID_OFFSET);
|
||||
|
||||
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;
|
||||
float blinkUpCoefficient = -eyelidOffset;
|
||||
float blinkDownCoefficient = BLINK_DOWN_MULTIPLIER * eyelidOffset;
|
||||
|
||||
float openUpCoefficient = eyelidOffset;
|
||||
float openDownCoefficient = OPEN_DOWN_MULTIPLIER * eyelidOffset;
|
||||
|
||||
float browsUpCoefficient = BROW_UP_MULTIPLIER * eyelidOffset;
|
||||
float browsDownCoefficient = 0.0f;
|
||||
|
||||
} else {
|
||||
_transientBlendshapeCoefficients[i] = 0.0f;
|
||||
_transientBlendshapeCoefficients[LEFT_EYE + i] = -eyeCoefficient;
|
||||
bool isLookingUp = (eyePitch > 0);
|
||||
|
||||
if (isLookingUp) {
|
||||
for (int i = 0; i < 2; i++) {
|
||||
_transientBlendshapeCoefficients[EYE_BLINK_INDICES[i]] = blinkUpCoefficient;
|
||||
_transientBlendshapeCoefficients[EYE_OPEN_INDICES[i]] = openUpCoefficient;
|
||||
_transientBlendshapeCoefficients[BROWS_U_INDICES[i]] = browsUpCoefficient;
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < 2; i++) {
|
||||
_transientBlendshapeCoefficients[EYE_BLINK_INDICES[i]] = blinkDownCoefficient;
|
||||
_transientBlendshapeCoefficients[EYE_OPEN_INDICES[i]] = openDownCoefficient;
|
||||
_transientBlendshapeCoefficients[BROWS_U_INDICES[i]] = browsDownCoefficient;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
#include <QtCore/QJsonArray>
|
||||
#include <QVector>
|
||||
|
||||
#include <FaceshiftConstants.h>
|
||||
#include <GLMHelpers.h>
|
||||
#include <shared/JSONHelpers.h>
|
||||
|
||||
|
@ -33,7 +32,7 @@ HeadData::HeadData(AvatarData* owningAvatar) :
|
|||
_summedBlendshapeCoefficients(QVector<float>(0, 0.0f)),
|
||||
_owningAvatar(owningAvatar)
|
||||
{
|
||||
|
||||
computeBlendshapesLookupMap();
|
||||
}
|
||||
|
||||
glm::quat HeadData::getRawOrientation() const {
|
||||
|
@ -71,16 +70,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 +101,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 +115,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 +135,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];
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include <glm/gtc/quaternion.hpp>
|
||||
|
||||
#include <SharedUtil.h>
|
||||
#include <FaceshiftConstants.h>
|
||||
|
||||
// degrees
|
||||
const float MIN_HEAD_YAW = -180.0f;
|
||||
|
@ -55,6 +56,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 +117,7 @@ protected:
|
|||
QVector<float> _blendshapeCoefficients;
|
||||
QVector<float> _transientBlendshapeCoefficients;
|
||||
QVector<float> _summedBlendshapeCoefficients;
|
||||
QMap<QString, int> _blendshapeLookupMap;
|
||||
AvatarData* _owningAvatar;
|
||||
|
||||
private:
|
||||
|
@ -122,6 +126,7 @@ private:
|
|||
HeadData& operator= (const HeadData&);
|
||||
|
||||
void setHeadOrientation(const glm::quat& orientation);
|
||||
void computeBlendshapesLookupMap();
|
||||
};
|
||||
|
||||
#endif // hifi_HeadData_h
|
||||
|
|
|
@ -64,3 +64,18 @@ const char* FACESHIFT_BLENDSHAPES[] = {
|
|||
};
|
||||
|
||||
const int NUM_FACESHIFT_BLENDSHAPES = sizeof(FACESHIFT_BLENDSHAPES) / sizeof(char*);
|
||||
|
||||
const int EYE_BLINK_L_INDEX = 0;
|
||||
const int EYE_BLINK_R_INDEX = 1;
|
||||
const int EYE_SQUINT_L_INDEX = 2;
|
||||
const int EYE_SQUINT_R_INDEX = 3;
|
||||
const int EYE_OPEN_L_INDEX = 8;
|
||||
const int EYE_OPEN_R_INDEX = 9;
|
||||
const int BROWS_U_L_INDEX = 17;
|
||||
const int BROWS_U_R_INDEX = 18;
|
||||
|
||||
|
||||
const int EYE_BLINK_INDICES[] = { EYE_BLINK_L_INDEX, EYE_BLINK_R_INDEX };
|
||||
const int EYE_SQUINT_INDICES[] = { EYE_SQUINT_L_INDEX, EYE_SQUINT_R_INDEX };
|
||||
const int EYE_OPEN_INDICES[] = { EYE_OPEN_L_INDEX, EYE_OPEN_R_INDEX };
|
||||
const int BROWS_U_INDICES[] = { BROWS_U_L_INDEX, BROWS_U_R_INDEX };
|
||||
|
|
|
@ -16,5 +16,10 @@
|
|||
extern const char* FACESHIFT_BLENDSHAPES[];
|
||||
/// The size of FACESHIFT_BLENDSHAPES
|
||||
extern const int NUM_FACESHIFT_BLENDSHAPES;
|
||||
// Eyes and Brows indices
|
||||
extern const int EYE_BLINK_INDICES[];
|
||||
extern const int EYE_OPEN_INDICES[];
|
||||
extern const int BROWS_U_INDICES[];
|
||||
extern const int EYE_SQUINT_INDICES[];
|
||||
|
||||
#endif // hifi_FaceshiftConstants_h
|
||||
#endif // hifi_FaceshiftConstants_h
|
||||
|
|
Loading…
Reference in a new issue