// // Faceplus.cpp // interface // // Created by Andrzej Kapolka on 4/8/14. // Copyright (c) 2014 High Fidelity, Inc. All rights reserved. // #ifdef HAVE_FACEPLUS #include #endif #include "Application.h" #include "Faceplus.h" #include "renderer/FBXReader.h" Faceplus::Faceplus() : _enabled(false), _active(false) { #ifdef HAVE_FACEPLUS // these are ignored--any values will do faceplus_log_in("username", "password"); #endif } Faceplus::~Faceplus() { setEnabled(false); } void Faceplus::init() { connect(Application::getInstance()->getFaceshift(), SIGNAL(connectionStateChanged()), SLOT(updateEnabled())); updateEnabled(); } #ifdef HAVE_FACEPLUS static QMultiHash > createChannelNameMap() { QMultiHash > blendshapeMap; blendshapeMap.insert("EyeBlink_L", QPair("Mix::Blink_Left", 1.0f)); blendshapeMap.insert("EyeBlink_R", QPair("Mix::Blink_Right", 1.0f)); blendshapeMap.insert("BrowsD_L", QPair("Mix::BrowsDown_Left", 1.0f)); blendshapeMap.insert("BrowsD_R", QPair("Mix::BrowsDown_Right", 1.0f)); blendshapeMap.insert("...", QPair("Mix::BrowsIn_Left", 1.0f)); blendshapeMap.insert("...", QPair("Mix::BrowsIn_Right", 1.0f)); blendshapeMap.insert("...", QPair("Mix::BrowsOuterLower_Left", 1.0f)); blendshapeMap.insert("...", QPair("Mix::BrowsOuterLower_Right", 1.0f)); blendshapeMap.insert("BrowsU_L", QPair("Mix::BrowsUp_Left", 5.0f)); blendshapeMap.insert("BrowsU_R", QPair("Mix::BrowsUp_Right", 5.0f)); blendshapeMap.insert("EyeOpen_L", QPair("Mix::EyesWide_Left", 1.0f)); blendshapeMap.insert("EyeOpen_R", QPair("Mix::EyesWide_Right", 1.0f)); blendshapeMap.insert("MouthFrown_L", QPair("Mix::Frown_Left", 1.0f)); blendshapeMap.insert("MouthFrown_R", QPair("Mix::Frown_Right", 1.0f)); blendshapeMap.insert("JawLeft", QPair("Mix::Jaw_RotateY_Left", 1.0f)); blendshapeMap.insert("JawRight", QPair("Mix::Jaw_RotateY_Right", 1.0f)); blendshapeMap.insert("LipsLowerDown", QPair("Mix::LowerLipDown_Left", 0.5f)); blendshapeMap.insert("LipsLowerDown", QPair("Mix::LowerLipDown_Right", 0.5f)); blendshapeMap.insert("...", QPair("Mix::LowerLipIn", 1.0f)); blendshapeMap.insert("...", QPair("Mix::LowerLipOut", 1.0f)); blendshapeMap.insert("MouthLeft", QPair("Mix::Midmouth_Left", 1.0f)); blendshapeMap.insert("MouthRight", QPair("Mix::Midmouth_Right", 1.0f)); blendshapeMap.insert("...", QPair("Mix::MouthDown", 1.0f)); blendshapeMap.insert("...", QPair("Mix::MouthNarrow_Left", 1.0f)); blendshapeMap.insert("...", QPair("Mix::MouthNarrow_Right", 1.0f)); blendshapeMap.insert("JawOpen", QPair("Mix::MouthOpen", 1.0f)); blendshapeMap.insert("...", QPair("Mix::MouthUp", 1.0f)); blendshapeMap.insert("LipsPucker", QPair("Mix::MouthWhistle_NarrowAdjust_Left", 0.5f)); blendshapeMap.insert("LipsPucker", QPair("Mix::MouthWhistle_NarrowAdjust_Right", 0.5f)); blendshapeMap.insert("Sneer", QPair("Mix::NoseScrunch_Left", 0.5f)); blendshapeMap.insert("Sneer", QPair("Mix::NoseScrunch_Right", 0.5f)); blendshapeMap.insert("MouthSmile_L", QPair("Mix::Smile_Left", 1.0f)); blendshapeMap.insert("MouthSmile_R", QPair("Mix::Smile_Right", 1.0f)); blendshapeMap.insert("EyeSquint_L", QPair("Mix::Squint_Left", 1.0f)); blendshapeMap.insert("EyeSquint_R", QPair("Mix::Squint_Right", 1.0f)); blendshapeMap.insert("...", QPair("Mix::UpperLipIn", 1.0f)); blendshapeMap.insert("...", QPair("Mix::UpperLipOut", 1.0f)); blendshapeMap.insert("LipsUpperUp", QPair("Mix::UpperLipUp_Left", 0.5f)); blendshapeMap.insert("LipsUpperUp", QPair("Mix::UpperLipUp_Right", 0.5f)); QMultiHash > channelNameMap; for (int i = 0;; i++) { QByteArray blendshape = FACESHIFT_BLENDSHAPES[i]; if (blendshape.isEmpty()) { break; } for (QMultiHash >::const_iterator it = blendshapeMap.constFind(blendshape); it != blendshapeMap.constEnd() && it.key() == blendshape; it++) { channelNameMap.insert(it.value().first, QPair(i, it.value().second)); } } return channelNameMap; } static const QMultiHash >& getChannelNameMap() { static QMultiHash > channelNameMap = createChannelNameMap(); return channelNameMap; } #endif void Faceplus::update() { #ifdef HAVE_FACEPLUS if (!_active) { return; } if (!(_active = faceplus_synchronous_track() && faceplus_current_output_vector(_outputVector.data()))) { return; } _headRotation = glm::quat(glm::radians(glm::vec3(-_outputVector.at(_headRotationIndices[0]), _outputVector.at(_headRotationIndices[1]), -_outputVector.at(_headRotationIndices[2])))); _estimatedEyePitch = (_outputVector.at(_leftEyeRotationIndices[0]) + _outputVector.at(_rightEyeRotationIndices[0])) * -0.5f; _estimatedEyeYaw = (_outputVector.at(_leftEyeRotationIndices[1]) + _outputVector.at(_rightEyeRotationIndices[1])) * 0.5f; qFill(_blendshapeCoefficients.begin(), _blendshapeCoefficients.end(), 0.0f); for (int i = 0; i < _outputVector.size(); i++) { for (QMultiHash >::const_iterator it = _channelIndexMap.constFind(i); it != _channelIndexMap.constEnd() && it.key() == i; it++) { _blendshapeCoefficients[it.value().first] += _outputVector.at(i) * it.value().second; } } #endif } void Faceplus::reset() { } void Faceplus::updateEnabled() { setEnabled(Menu::getInstance()->isOptionChecked(MenuOption::Faceplus) && !(Menu::getInstance()->isOptionChecked(MenuOption::Faceshift) && Application::getInstance()->getFaceshift()->isConnectedOrConnecting())); } void Faceplus::setEnabled(bool enabled) { #ifdef HAVE_FACEPLUS if (_enabled == enabled) { return; } if ((_enabled = enabled)) { if (faceplus_init("VGA")) { qDebug() << "Faceplus initialized."; _active = true; int channelCount = faceplus_output_channels_count(); _outputVector.resize(channelCount); int maxIndex = -1; _channelIndexMap.clear(); for (int i = 0; i < channelCount; i++) { QByteArray name = faceplus_output_channel_name(i); if (name == "Head_Joint::Rotation_X") { _headRotationIndices[0] = i; } else if (name == "Head_Joint::Rotation_Y") { _headRotationIndices[1] = i; } else if (name == "Head_Joint::Rotation_Z") { _headRotationIndices[2] = i; } else if (name == "Left_Eye_Joint::Rotation_X") { _leftEyeRotationIndices[0] = i; } else if (name == "Left_Eye_Joint::Rotation_Y") { _leftEyeRotationIndices[1] = i; } else if (name == "Right_Eye_Joint::Rotation_X") { _rightEyeRotationIndices[0] = i; } else if (name == "Right_Eye_Joint::Rotation_Y") { _rightEyeRotationIndices[1] = i; } for (QMultiHash >::const_iterator it = getChannelNameMap().constFind(name); it != getChannelNameMap().constEnd() && it.key() == name; it++) { _channelIndexMap.insert(i, it.value()); maxIndex = qMax(maxIndex, it.value().first); } } _blendshapeCoefficients.resize(maxIndex + 1); } } else if (faceplus_teardown()) { qDebug() << "Faceplus torn down."; _active = false; } #endif }