Example #1
0
void Head::simulate(float deltaTime, bool isMine) {
    
    //  Update audio trailing average for rendering facial animations
    Faceshift* faceshift = Application::getInstance()->getFaceshift();
    if (isMine) {
        _isFaceshiftConnected = faceshift->isActive();
    }
    
    if (isMine && faceshift->isActive()) {
        const float EYE_OPEN_SCALE = 0.5f;
        _leftEyeBlink = faceshift->getLeftBlink() - EYE_OPEN_SCALE * faceshift->getLeftEyeOpen();
        _rightEyeBlink = faceshift->getRightBlink() - EYE_OPEN_SCALE * faceshift->getRightEyeOpen();
        
        // set these values based on how they'll be used.  if we use faceshift in the long term, we'll want a complete
        // mapping between their blendshape coefficients and our avatar features
        const float MOUTH_SIZE_SCALE = 2500.0f;
        _averageLoudness = faceshift->getMouthSize() * faceshift->getMouthSize() * MOUTH_SIZE_SCALE;
        const float BROW_HEIGHT_SCALE = 0.005f;
        _browAudioLift = faceshift->getBrowUpCenter() * BROW_HEIGHT_SCALE;
        _blendshapeCoefficients = faceshift->getBlendshapeCoefficients();
        
    } else if (!_isFaceshiftConnected) {
        // Update eye saccades
        const float AVERAGE_MICROSACCADE_INTERVAL = 0.50f;
        const float AVERAGE_SACCADE_INTERVAL = 4.0f;
        const float MICROSACCADE_MAGNITUDE = 0.002f;
        const float SACCADE_MAGNITUDE = 0.04f;
        
        if (randFloat() < deltaTime / AVERAGE_MICROSACCADE_INTERVAL) {
            _saccadeTarget = MICROSACCADE_MAGNITUDE * randVector();
        } else if (randFloat() < deltaTime / AVERAGE_SACCADE_INTERVAL) {
            _saccadeTarget = SACCADE_MAGNITUDE * randVector();
        }
        _saccade += (_saccadeTarget - _saccade) * 0.50f;
    
        const float AUDIO_AVERAGING_SECS = 0.05f;
        _averageLoudness = (1.f - deltaTime / AUDIO_AVERAGING_SECS) * _averageLoudness +
                                 (deltaTime / AUDIO_AVERAGING_SECS) * _audioLoudness;
        
        //  Detect transition from talking to not; force blink after that and a delay
        bool forceBlink = false;
        const float TALKING_LOUDNESS = 100.0f;
        const float BLINK_AFTER_TALKING = 0.25f;
        if (_averageLoudness > TALKING_LOUDNESS) {
            _timeWithoutTalking = 0.0f;
        
        } else if (_timeWithoutTalking < BLINK_AFTER_TALKING && (_timeWithoutTalking += deltaTime) >= BLINK_AFTER_TALKING) {
            forceBlink = true;
        }
                                 
        //  Update audio attack data for facial animation (eyebrows and mouth)
        _audioAttack = 0.9f * _audioAttack + 0.1f * fabs(_audioLoudness - _lastLoudness);
        _lastLoudness = _audioLoudness;
        
        const float BROW_LIFT_THRESHOLD = 100.0f;
        if (_audioAttack > BROW_LIFT_THRESHOLD) {
            _browAudioLift += sqrtf(_audioAttack) * 0.00005f;
        }
        
        const float CLAMP = 0.01f;
        if (_browAudioLift > CLAMP) {
            _browAudioLift = CLAMP;
        }
        
        _browAudioLift *= 0.7f;      

        const float BLINK_SPEED = 10.0f;
        const float FULLY_OPEN = 0.0f;
        const float FULLY_CLOSED = 1.0f;
        if (_leftEyeBlinkVelocity == 0.0f && _rightEyeBlinkVelocity == 0.0f) {
            // no blinking when brows are raised; blink less with increasing loudness
            const float BASE_BLINK_RATE = 15.0f / 60.0f;
            const float ROOT_LOUDNESS_TO_BLINK_INTERVAL = 0.25f;
            if (forceBlink || (_browAudioLift < EPSILON && shouldDo(glm::max(1.0f, sqrt(_averageLoudness) *
                    ROOT_LOUDNESS_TO_BLINK_INTERVAL) / BASE_BLINK_RATE, deltaTime))) {
                _leftEyeBlinkVelocity = BLINK_SPEED;
                _rightEyeBlinkVelocity = BLINK_SPEED;
            }
        } else {
            _leftEyeBlink = glm::clamp(_leftEyeBlink + _leftEyeBlinkVelocity * deltaTime, FULLY_OPEN, FULLY_CLOSED);
            _rightEyeBlink = glm::clamp(_rightEyeBlink + _rightEyeBlinkVelocity * deltaTime, FULLY_OPEN, FULLY_CLOSED);
            
            if (_leftEyeBlink == FULLY_CLOSED) {
                _leftEyeBlinkVelocity = -BLINK_SPEED;
            
            } else if (_leftEyeBlink == FULLY_OPEN) {
                _leftEyeBlinkVelocity = 0.0f;
            }
            if (_rightEyeBlink == FULLY_CLOSED) {
                _rightEyeBlinkVelocity = -BLINK_SPEED;
            
            } else if (_rightEyeBlink == FULLY_OPEN) {
                _rightEyeBlinkVelocity = 0.0f;
            }
        }
        
        // use data to update fake Faceshift blendshape coefficients
        const float BROW_LIFT_SCALE = 500.0f;
        const float JAW_OPEN_SCALE = 0.01f;
        const float JAW_OPEN_DEAD_ZONE = 0.75f;
        faceshift->updateFakeCoefficients(_leftEyeBlink, _rightEyeBlink, min(1.0f, _browAudioLift * BROW_LIFT_SCALE),
            glm::clamp(sqrt(_averageLoudness * JAW_OPEN_SCALE) - JAW_OPEN_DEAD_ZONE, 0.0f, 1.0f), _blendshapeCoefficients);
    }
    
    _faceModel.simulate(deltaTime);
    
    // the blend face may have custom eye meshes
    if (!_faceModel.getEyePositions(_leftEyePosition, _rightEyePosition)) {
        _leftEyePosition = _rightEyePosition = getPosition();
    }
    _eyePosition = calculateAverageEyePosition();
}
Example #2
0
void PerlinFace::updatePositions() {
    const float BROWS_UP_MAX = 3;
    const float BROWS_DOWN_MAX = 1;
    const float BROWS_UP_CENTER_MAX = 1;

    Faceshift* faceshift = Application::getInstance()->getFaceshift();
    if (faceshift->isActive()) {
        _browsD_L = faceshift->getBrowDownLeft();
        _browsD_R = faceshift->getBrowDownRight();
        _browsU_C = faceshift->getBrowUpCenter();
        _browsU_L = faceshift->getBrowUpLeft();
        _browsU_R = faceshift->getBrowUpRight();
        _mouthSize = faceshift->getMouthSize();
        _mouthSmileLeft = faceshift->getMouthSmileLeft();
        _mouthSmileRight = faceshift->getMouthSmileRight();
        _eyeBlink_L = faceshift->getLeftBlink();
        _eyeBlink_R = faceshift->getRightBlink();
        _eyeOpen_L = faceshift->getLeftEyeOpen();
        _eyeOpen_R = faceshift->getRightEyeOpen();
    }


    // Update left brow
    _vertices[BROW_LEFT].y = getVec3(BROW_LEFT).y
                             + _browsU_L * BROWS_UP_MAX
                             - _browsD_L * BROWS_DOWN_MAX
                             - _browsU_C * BROWS_UP_CENTER_MAX;
    _vertices[BROW_MID_TOP].y = getVec3(BROW_MID_TOP).y
                                + _browsU_L * BROWS_UP_MAX
                                - _browsD_L * BROWS_DOWN_MAX;
    _vertices[BROW_MID_BOTTOM].y = getVec3(BROW_MID_BOTTOM).y
                                   + _browsU_L * BROWS_UP_MAX
                                   - _browsD_L * BROWS_DOWN_MAX;
    _vertices[BROW_RIGHT_TOP].y = getVec3(BROW_RIGHT_TOP).y
                                  + _browsU_L * BROWS_UP_MAX
                                  - _browsD_L * BROWS_DOWN_MAX
                                  + _browsU_C * BROWS_UP_CENTER_MAX;
    _vertices[BROW_RIGHT_BOTTOM].y = getVec3(BROW_RIGHT_BOTTOM).y
                                     + _browsU_L * BROWS_UP_MAX
                                     - _browsD_L * BROWS_DOWN_MAX
                                     + _browsU_C * BROWS_UP_CENTER_MAX;

    // Update right brow
    _vertices[NUM_VERTICES + BROW_LEFT].y = getVec3(NUM_VERTICES + BROW_LEFT).y
                                            + _browsU_R * BROWS_UP_MAX
                                            - _browsD_R * BROWS_DOWN_MAX
                                            - _browsU_C * BROWS_UP_CENTER_MAX;
    _vertices[NUM_VERTICES + BROW_MID_TOP].y = getVec3(NUM_VERTICES + BROW_MID_TOP).y
            + _browsU_R * BROWS_UP_MAX
            - _browsD_R * BROWS_DOWN_MAX;
    _vertices[NUM_VERTICES + BROW_MID_BOTTOM].y = getVec3(NUM_VERTICES + BROW_MID_BOTTOM).y
            + _browsU_R * BROWS_UP_MAX
            - _browsD_R * BROWS_DOWN_MAX;
    _vertices[NUM_VERTICES + BROW_RIGHT_TOP].y = getVec3(NUM_VERTICES + BROW_RIGHT_TOP).y
            + _browsU_R * BROWS_UP_MAX
            - _browsD_R * BROWS_DOWN_MAX
            + _browsU_C * BROWS_UP_CENTER_MAX;
    _vertices[NUM_VERTICES + BROW_RIGHT_BOTTOM].y = getVec3(NUM_VERTICES + BROW_RIGHT_BOTTOM).y
            + _browsU_R * BROWS_UP_MAX
            - _browsD_R * BROWS_DOWN_MAX
            + _browsU_C * BROWS_UP_CENTER_MAX;

    const float MOUTH_UP_MAX = 6.5f;
    const float MOUTH_SIDE_UP_MAX = 4.0f;
    const float SMILE_FACTOR = 1.0f / 3.0f;  // 0 = No smile, 1 = The Jocker.

    // Mouth
    _vertices[MOUTH_BOTTOM_IN].y = getVec3(MOUTH_BOTTOM_IN).y
                                   + (1.0 - _mouthSize) * MOUTH_UP_MAX;
    _vertices[MOUTH_BOTTOM_OUT].y = getVec3(MOUTH_BOTTOM_OUT).y
                                    + (1.0 - _mouthSize) * MOUTH_UP_MAX;
    _vertices[MOUTH_MID_IN] = (1.0f - (_mouthSmileLeft * SMILE_FACTOR)) * (getVec3(MOUTH_MID_IN)
                              + glm::vec3(0, (1.0 - _mouthSize) * MOUTH_SIDE_UP_MAX, 0))
                              + (_mouthSmileLeft * SMILE_FACTOR) * getVec3(CHICK_MID);
    _vertices[MOUTH_MID_OUT] = (1.0f - (_mouthSmileLeft * SMILE_FACTOR)) * (getVec3(MOUTH_MID_OUT)
                               + glm::vec3(0, (1.0 - _mouthSize) * MOUTH_SIDE_UP_MAX, 0))
                               + (_mouthSmileLeft * SMILE_FACTOR) * getVec3(CHICK_MID);


    _vertices[NUM_VERTICES + MOUTH_BOTTOM_IN].y = getVec3(NUM_VERTICES + MOUTH_BOTTOM_IN).y
            + (1.0 - _mouthSize) * MOUTH_UP_MAX;
    _vertices[NUM_VERTICES + MOUTH_BOTTOM_OUT].y = getVec3(NUM_VERTICES + MOUTH_BOTTOM_OUT).y
            + (1.0 - _mouthSize) * MOUTH_UP_MAX;
    _vertices[NUM_VERTICES + MOUTH_MID_IN] = (1.0f - (_mouthSmileLeft * SMILE_FACTOR)) * (getVec3(NUM_VERTICES + MOUTH_MID_IN)
            + glm::vec3(0, (1.0 - _mouthSize) * MOUTH_SIDE_UP_MAX, 0))
            + (_mouthSmileLeft * SMILE_FACTOR) * getVec3(NUM_VERTICES + CHICK_MID);
    _vertices[NUM_VERTICES + MOUTH_MID_OUT] = (1.0f - (_mouthSmileLeft * SMILE_FACTOR)) * (getVec3(NUM_VERTICES + MOUTH_MID_OUT)
            + glm::vec3(0, (1.0 - _mouthSize) * MOUTH_SIDE_UP_MAX, 0))
            + (_mouthSmileLeft * SMILE_FACTOR) * getVec3(NUM_VERTICES + CHICK_MID);



    // Jaw
    _vertices[CHIN_IN].y = getVec3(CHIN_IN).y
                           + (1.0 - _mouthSize) * MOUTH_UP_MAX;
    _vertices[CHIN_TIP].y = getVec3(CHIN_TIP).y
                            + (1.0 - _mouthSize) * MOUTH_UP_MAX;
    _vertices[CHIN_BOTTOM].y = getVec3(CHIN_BOTTOM).y
                               + (1.0 - _mouthSize) * MOUTH_UP_MAX;

    _vertices[NUM_VERTICES +CHIN_IN].y = getVec3(NUM_VERTICES + CHIN_IN).y
                                         + (1.0 - _mouthSize) * MOUTH_UP_MAX;
    _vertices[NUM_VERTICES +CHIN_TIP].y = getVec3(NUM_VERTICES + CHIN_TIP).y
                                          + (1.0 - _mouthSize) * MOUTH_UP_MAX;
    _vertices[NUM_VERTICES +CHIN_BOTTOM].y = getVec3(NUM_VERTICES + CHIN_BOTTOM).y
            + (1.0 - _mouthSize) * MOUTH_UP_MAX;


    // Eyelids
    glm::vec3 topLeftEyelid = getVec3(EYE_MID_TOP);
    glm::vec3 bottomLeftEyelid = getVec3(EYE_MID_BOTTOM);
    glm::vec3 topRightEyelid = getVec3(NUM_VERTICES + EYE_MID_TOP);
    glm::vec3 bottomRightEyelid = getVec3(NUM_VERTICES + EYE_MID_BOTTOM);

    _vertices[EYE_MID_TOP] = (1.0f - (_eyeBlink_L - _eyeOpen_L / 2.0f)) * topLeftEyelid
                             + (_eyeBlink_L - _eyeOpen_L / 2.0f) * (topLeftEyelid + bottomLeftEyelid) / 2.0f;
    _vertices[EYE_MID_BOTTOM] = (1.0f - (_eyeBlink_L - _eyeOpen_L / 2.0f)) * bottomLeftEyelid
                                + (_eyeBlink_L - _eyeOpen_L / 2.0f) * (topLeftEyelid + bottomLeftEyelid) / 2.0f;

    _vertices[NUM_VERTICES + EYE_MID_TOP] = (1.0f - (_eyeBlink_R - _eyeOpen_R / 2.0f)) * topRightEyelid
                                            + (_eyeBlink_R - _eyeOpen_R / 2.0f) * (topRightEyelid + bottomRightEyelid) / 2.0f;
    _vertices[NUM_VERTICES + EYE_MID_BOTTOM] = (1.0f - (_eyeBlink_R - _eyeOpen_R / 2.0f)) * bottomRightEyelid
            + (_eyeBlink_R - _eyeOpen_R / 2.0f) * (topRightEyelid + bottomRightEyelid) / 2.0f;
}
Example #3
0
File: Head.cpp Project: Chris7/hifi
void Head::simulate(float deltaTime, bool isMine, bool billboard) {
    
    //  Update audio trailing average for rendering facial animations
    Faceshift* faceshift = Application::getInstance()->getFaceshift();
    Visage* visage = Application::getInstance()->getVisage();
    if (isMine) {
        _isFaceshiftConnected = false;
        if (faceshift->isActive()) {
            _blendshapeCoefficients = faceshift->getBlendshapeCoefficients();
            _isFaceshiftConnected = true;
            
        } else if (visage->isActive()) {
            _blendshapeCoefficients = visage->getBlendshapeCoefficients();
            _isFaceshiftConnected = true;
        }
    }
    
    if (!(_isFaceshiftConnected || billboard)) {
        // Update eye saccades
        const float AVERAGE_MICROSACCADE_INTERVAL = 0.50f;
        const float AVERAGE_SACCADE_INTERVAL = 4.0f;
        const float MICROSACCADE_MAGNITUDE = 0.002f;
        const float SACCADE_MAGNITUDE = 0.04f;
        
        if (randFloat() < deltaTime / AVERAGE_MICROSACCADE_INTERVAL) {
            _saccadeTarget = MICROSACCADE_MAGNITUDE * randVector();
        } else if (randFloat() < deltaTime / AVERAGE_SACCADE_INTERVAL) {
            _saccadeTarget = SACCADE_MAGNITUDE * randVector();
        }
        _saccade += (_saccadeTarget - _saccade) * 0.50f;
    
        const float AUDIO_AVERAGING_SECS = 0.05f;
        _averageLoudness = (1.f - deltaTime / AUDIO_AVERAGING_SECS) * _averageLoudness +
                                 (deltaTime / AUDIO_AVERAGING_SECS) * _audioLoudness;
        
        //  Detect transition from talking to not; force blink after that and a delay
        bool forceBlink = false;
        const float TALKING_LOUDNESS = 100.0f;
        const float BLINK_AFTER_TALKING = 0.25f;
        if (_averageLoudness > TALKING_LOUDNESS) {
            _timeWithoutTalking = 0.0f;
        
        } else if (_timeWithoutTalking < BLINK_AFTER_TALKING && (_timeWithoutTalking += deltaTime) >= BLINK_AFTER_TALKING) {
            forceBlink = true;
        }
                                 
        //  Update audio attack data for facial animation (eyebrows and mouth)
        _audioAttack = 0.9f * _audioAttack + 0.1f * fabs(_audioLoudness - _lastLoudness);
        _lastLoudness = _audioLoudness;
        
        const float BROW_LIFT_THRESHOLD = 100.0f;
        if (_audioAttack > BROW_LIFT_THRESHOLD) {
            _browAudioLift += sqrtf(_audioAttack) * 0.00005f;
        }
        
        const float CLAMP = 0.01f;
        if (_browAudioLift > CLAMP) {
            _browAudioLift = CLAMP;
        }
        
        _browAudioLift *= 0.7f;      

        const float BLINK_SPEED = 10.0f;
        const float FULLY_OPEN = 0.0f;
        const float FULLY_CLOSED = 1.0f;
        if (_leftEyeBlinkVelocity == 0.0f && _rightEyeBlinkVelocity == 0.0f) {
            // no blinking when brows are raised; blink less with increasing loudness
            const float BASE_BLINK_RATE = 15.0f / 60.0f;
            const float ROOT_LOUDNESS_TO_BLINK_INTERVAL = 0.25f;
            if (forceBlink || (_browAudioLift < EPSILON && shouldDo(glm::max(1.0f, sqrt(_averageLoudness) *
                    ROOT_LOUDNESS_TO_BLINK_INTERVAL) / BASE_BLINK_RATE, deltaTime))) {
                _leftEyeBlinkVelocity = BLINK_SPEED;
                _rightEyeBlinkVelocity = BLINK_SPEED;
            }
        } else {
            _leftEyeBlink = glm::clamp(_leftEyeBlink + _leftEyeBlinkVelocity * deltaTime, FULLY_OPEN, FULLY_CLOSED);
            _rightEyeBlink = glm::clamp(_rightEyeBlink + _rightEyeBlinkVelocity * deltaTime, FULLY_OPEN, FULLY_CLOSED);
            
            if (_leftEyeBlink == FULLY_CLOSED) {
                _leftEyeBlinkVelocity = -BLINK_SPEED;
            
            } else if (_leftEyeBlink == FULLY_OPEN) {
                _leftEyeBlinkVelocity = 0.0f;
            }
            if (_rightEyeBlink == FULLY_CLOSED) {
                _rightEyeBlinkVelocity = -BLINK_SPEED;
            
            } else if (_rightEyeBlink == FULLY_OPEN) {
                _rightEyeBlinkVelocity = 0.0f;
            }
        }
        
        // use data to update fake Faceshift blendshape coefficients
        const float BROW_LIFT_SCALE = 500.0f;
        const float JAW_OPEN_SCALE = 0.01f;
        const float JAW_OPEN_DEAD_ZONE = 0.75f;
        faceshift->updateFakeCoefficients(_leftEyeBlink, _rightEyeBlink, min(1.0f, _browAudioLift * BROW_LIFT_SCALE),
            glm::clamp(sqrt(_averageLoudness * JAW_OPEN_SCALE) - JAW_OPEN_DEAD_ZONE, 0.0f, 1.0f), _blendshapeCoefficients);
    }
    
    if (!isMine) {
        _faceModel.setLODDistance(static_cast<Avatar*>(_owningAvatar)->getLODDistance());
    }
    _leftEyePosition = _rightEyePosition = getPosition();
    if (!billboard) {
        _faceModel.simulate(deltaTime);
        _faceModel.getEyePositions(_leftEyePosition, _rightEyePosition);
    }
    _eyePosition = calculateAverageEyePosition();
}