2139 lines · 83.3 KB · C++
RawDownload
////  MyAvatar.cpp//  interface/src/avatar////  Created by Mark Peng on 8/16/13.//  Copyright 2012 High Fidelity, Inc.////  Distributed under the Apache License, Version 2.0.//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html// #include <algorithm>#include <vector> #include <QBuffer> #include <glm/gtx/norm.hpp>#include <glm/gtx/vector_angle.hpp> #include <QtCore/QTimer> #include <scripting/HMDScriptingInterface.h>#include <AccountManager.h>#include <AddressManager.h>#include <AudioClient.h>#include <display-plugins/DisplayPlugin.h>#include <FSTReader.h>#include <GeometryUtil.h>#include <NodeList.h>#include <udt/PacketHeaders.h>#include <PathUtils.h>#include <PerfStat.h>#include <SharedUtil.h>#include <SoundCache.h>#include <TextRenderer3D.h>#include <UserActivityLogger.h>#include <AnimDebugDraw.h>#include <AnimClip.h>#include <recording/Deck.h>#include <recording/Recorder.h>#include <recording/Clip.h>#include <recording/Frame.h>#include <RecordingScriptingInterface.h> #include "Application.h"#include "devices/Faceshift.h"#include "AvatarManager.h"#include "Menu.h"#include "MyAvatar.h"#include "Physics.h"#include "Util.h"#include "InterfaceLogging.h"#include "DebugDraw.h"#include "EntityEditPacketSender.h"#include "MovingEntitiesOperator.h" using namespace std; const glm::vec3 DEFAULT_UP_DIRECTION(0.0f, 1.0f, 0.0f);const float DEFAULT_REAL_WORLD_FIELD_OF_VIEW_DEGREES = 30.0f; const float MAX_WALKING_SPEED = 2.6f; // human walking speedconst float MAX_BOOST_SPEED = 0.5f * MAX_WALKING_SPEED; // action motor gets additive boost below this speedconst float MIN_AVATAR_SPEED = 0.05f;const float MIN_AVATAR_SPEED_SQUARED = MIN_AVATAR_SPEED * MIN_AVATAR_SPEED; // speed is set to zero below this const float YAW_SPEED_DEFAULT = 120.0f;   // degrees/secconst float PITCH_SPEED_DEFAULT = 90.0f; // degrees/sec // TODO: normalize avatar speed for standard avatar size, then scale all motion logic// to properly follow avatar size.float MAX_AVATAR_SPEED = 30.0f;float MAX_ACTION_MOTOR_SPEED = MAX_AVATAR_SPEED;float MIN_SCRIPTED_MOTOR_TIMESCALE = 0.005f;float DEFAULT_SCRIPTED_MOTOR_TIMESCALE = 1.0e6f;const int SCRIPTED_MOTOR_CAMERA_FRAME = 0;const int SCRIPTED_MOTOR_AVATAR_FRAME = 1;const int SCRIPTED_MOTOR_WORLD_FRAME = 2;const QString& DEFAULT_AVATAR_COLLISION_SOUND_URL = "https://hifi-public.s3.amazonaws.com/sounds/Collisions-otherorganic/Body_Hits_Impact.wav"; const float MyAvatar::ZOOM_MIN = 0.5f;const float MyAvatar::ZOOM_MAX = 25.0f;const float MyAvatar::ZOOM_DEFAULT = 1.5f; MyAvatar::MyAvatar(RigPointer rig) :    Avatar(rig),    _wasPushing(false),    _isPushing(false),    _isBeingPushed(false),    _isBraking(false),    _boomLength(ZOOM_DEFAULT),    _yawSpeed(YAW_SPEED_DEFAULT),    _pitchSpeed(PITCH_SPEED_DEFAULT),    _thrust(0.0f),    _actionMotorVelocity(0.0f),    _scriptedMotorVelocity(0.0f),    _scriptedMotorTimescale(DEFAULT_SCRIPTED_MOTOR_TIMESCALE),    _scriptedMotorFrame(SCRIPTED_MOTOR_CAMERA_FRAME),    _motionBehaviors(AVATAR_MOTION_DEFAULTS),    _characterController(this),    _lookAtTargetAvatar(),    _shouldRender(true),    _eyeContactTarget(LEFT_EYE),    _realWorldFieldOfView("realWorldFieldOfView",                          DEFAULT_REAL_WORLD_FIELD_OF_VIEW_DEGREES),    _hmdSensorMatrix(),    _hmdSensorOrientation(),    _hmdSensorPosition(),    _bodySensorMatrix(),    _sensorToWorldMatrix(),    _goToPending(false),    _goToPosition(),    _goToOrientation(),    _rig(rig),    _prevShouldDrawHead(true),    _audioListenerMode(FROM_HEAD),    _hmdAtRestDetector(glm::vec3(0), glm::quat()){    using namespace recording;     for (int i = 0; i < MAX_DRIVE_KEYS; i++) {        _driveKeys[i] = 0.0f;    }     // connect to AddressManager signal for location jumps    connect(DependencyManager::get<AddressManager>().data(), &AddressManager::locationChangeRequired,         [=](const glm::vec3& newPosition, bool hasOrientation, const glm::quat& newOrientation, bool shouldFaceLocation){        goToLocation(newPosition, hasOrientation, newOrientation, shouldFaceLocation);    });     _characterController.setEnabled(true);     _bodySensorMatrix = deriveBodyFromHMDSensor();     using namespace recording;     auto player = DependencyManager::get<Deck>();    auto recorder = DependencyManager::get<Recorder>();    connect(player.data(), &Deck::playbackStateChanged, [=] {        if (player->isPlaying()) {            auto recordingInterface = DependencyManager::get<RecordingScriptingInterface>();            if (recordingInterface->getPlayFromCurrentLocation()) {                setRecordingBasis();            }        } else {            clearRecordingBasis();        }    });     connect(recorder.data(), &Recorder::recordingStateChanged, [=] {        if (recorder->isRecording()) {            setRecordingBasis();        } else {            clearRecordingBasis();        }    });     static const recording::FrameType AVATAR_FRAME_TYPE = recording::Frame::registerFrameType(AvatarData::FRAME_NAME);    Frame::registerFrameHandler(AVATAR_FRAME_TYPE, [=](Frame::ConstPointer frame) {        static AvatarData dummyAvatar;        AvatarData::fromFrame(frame->data, dummyAvatar);        if (getRecordingBasis()) {            dummyAvatar.setRecordingBasis(getRecordingBasis());        } else {            dummyAvatar.clearRecordingBasis();        }         auto recordingInterface = DependencyManager::get<RecordingScriptingInterface>();         if (recordingInterface->getPlayerUseSkeletonModel() && dummyAvatar.getSkeletonModelURL().isValid() &&            (dummyAvatar.getSkeletonModelURL() != getSkeletonModelURL())) {            // FIXME            //myAvatar->useFullAvatarURL()        }         if (recordingInterface->getPlayerUseDisplayName() && dummyAvatar.getDisplayName() != getDisplayName()) {            setDisplayName(dummyAvatar.getDisplayName());        }         setPosition(dummyAvatar.getPosition());        setOrientation(dummyAvatar.getOrientation());         if (!dummyAvatar.getAttachmentData().isEmpty()) {            setAttachmentData(dummyAvatar.getAttachmentData());        }         auto headData = dummyAvatar.getHeadData();        if (headData && _headData) {            // blendshapes            if (!headData->getBlendshapeCoefficients().isEmpty()) {                _headData->setBlendshapeCoefficients(headData->getBlendshapeCoefficients());            }            // head orientation            _headData->setLookAtPosition(headData->getLookAtPosition());        }    });     connect(rig.get(), SIGNAL(onLoadComplete()), this, SIGNAL(onLoadComplete()));} MyAvatar::~MyAvatar() {    _lookAtTargetAvatar.reset();} void MyAvatar::setOrientationVar(const QVariant& newOrientationVar) {    Avatar::setOrientation(quatFromVariant(newOrientationVar));} QVariant MyAvatar::getOrientationVar() const {    return quatToVariant(Avatar::getOrientation());}  // virtualvoid MyAvatar::simulateAttachments(float deltaTime) {    // don't update attachments here, do it in harvestResultsFromPhysicsSimulation()} QByteArray MyAvatar::toByteArray(bool cullSmallChanges, bool sendAll) {    CameraMode mode = qApp->getCamera()->getMode();    _globalPosition = getPosition();    if (mode == CAMERA_MODE_THIRD_PERSON || mode == CAMERA_MODE_INDEPENDENT) {        // fake the avatar position that is sent up to the AvatarMixer        glm::vec3 oldPosition = getPosition();        setPosition(getSkeletonPosition());        QByteArray array = AvatarData::toByteArray(cullSmallChanges, sendAll);        // copy the correct position back        setPosition(oldPosition);        return array;    }    return AvatarData::toByteArray(cullSmallChanges, sendAll);} void MyAvatar::reset(bool andRecenter, bool andReload, bool andHead) {     if (QThread::currentThread() != thread()) {        QMetaObject::invokeMethod(this, "reset", Q_ARG(bool, andRecenter), Q_ARG(bool, andReload), Q_ARG(bool, andHead));        return;    }     // Reset dynamic state.    _wasPushing = _isPushing = _isBraking = false;    _follow.deactivate();    if (andReload) {        _skeletonModel->reset();    }    if (andHead) { // which drives camera in desktop        getHead()->reset();    }    setThrust(glm::vec3(0.0f));     if (andRecenter) {        // derive the desired body orientation from the *old* hmd orientation, before the sensor reset.        auto newBodySensorMatrix = deriveBodyFromHMDSensor(); // Based on current cached HMD position/rotation..         // transform this body into world space        auto worldBodyMatrix = _sensorToWorldMatrix * newBodySensorMatrix;        auto worldBodyPos = extractTranslation(worldBodyMatrix);        auto worldBodyRot = glm::normalize(glm::quat_cast(worldBodyMatrix));         // this will become our new position.        setPosition(worldBodyPos);        setOrientation(worldBodyRot);         // now sample the new hmd orientation AFTER sensor reset, which should be identity.        glm::mat4 identity;        updateFromHMDSensorMatrix(identity);         // update the body in sensor space using the new hmd sensor sample        _bodySensorMatrix = deriveBodyFromHMDSensor();         // rebuild the sensor to world matrix such that, the HMD will point in the desired orientation.        // i.e. the along avatar's current position and orientation.        updateSensorToWorldMatrix();    }} void MyAvatar::update(float deltaTime) {     // update moving average of HMD facing in xz plane.    const float HMD_FACING_TIMESCALE = 4.0f; // very slow average    float tau = deltaTime / HMD_FACING_TIMESCALE;    _hmdSensorFacingMovingAverage = lerp(_hmdSensorFacingMovingAverage, _hmdSensorFacing, tau); #ifdef DEBUG_DRAW_HMD_MOVING_AVERAGE    glm::vec3 p = transformPoint(getSensorToWorldMatrix(), _hmdSensorPosition + glm::vec3(_hmdSensorFacingMovingAverage.x, 0.0f, _hmdSensorFacingMovingAverage.y));    DebugDraw::getInstance().addMarker("facing-avg", getOrientation(), p, glm::vec4(1.0f));    p = transformPoint(getSensorToWorldMatrix(), _hmdSensorPosition + glm::vec3(_hmdSensorFacing.x, 0.0f, _hmdSensorFacing.y));    DebugDraw::getInstance().addMarker("facing", getOrientation(), p, glm::vec4(1.0f));#endif     if (_goToPending) {        setPosition(_goToPosition);        setOrientation(_goToOrientation);        _hmdSensorFacingMovingAverage = _hmdSensorFacing;  // reset moving average        _goToPending = false;        // updateFromHMDSensorMatrix (called from paintGL) expects that the sensorToWorldMatrix is updated for any position changes        // that happen between render and Application::update (which calls updateSensorToWorldMatrix to do so).        // However, render/MyAvatar::update/Application::update don't always match (e.g., when using the separate avatar update thread),        // so we update now. It's ok if it updates again in the normal way.        updateSensorToWorldMatrix();        emit positionGoneTo();    }     Head* head = getHead();    head->relax(deltaTime);    updateFromTrackers(deltaTime);     //  Get audio loudness data from audio input device    auto audio = DependencyManager::get<AudioClient>();    head->setAudioLoudness(audio->getLastInputLoudness());    head->setAudioAverageLoudness(audio->getAudioAverageInputLoudness());     if (_avatarEntityDataLocallyEdited) {        sendIdentityPacket();    }     simulate(deltaTime);     currentEnergy += energyChargeRate;    currentEnergy -= getAccelerationEnergy();    currentEnergy -= getAudioEnergy();     if(didTeleport()) {        currentEnergy = 0.0f;    }    currentEnergy = max(0.0f, min(currentEnergy,1.0f));    emit energyChanged(currentEnergy);     updateEyeContactTarget(deltaTime);} void MyAvatar::updateEyeContactTarget(float deltaTime) {     _eyeContactTargetTimer -= deltaTime;    if (_eyeContactTargetTimer < 0.0f) {         const float CHANCE_OF_CHANGING_TARGET = 0.01f;        if (randFloat() < CHANCE_OF_CHANGING_TARGET) {             float const FIFTY_FIFTY_CHANCE = 0.5f;            float const EYE_TO_MOUTH_CHANCE = 0.25f;            switch (_eyeContactTarget) {                case LEFT_EYE:                    _eyeContactTarget = (randFloat() < EYE_TO_MOUTH_CHANCE) ? MOUTH : RIGHT_EYE;                    break;                case RIGHT_EYE:                    _eyeContactTarget = (randFloat() < EYE_TO_MOUTH_CHANCE) ? MOUTH : LEFT_EYE;                    break;                case MOUTH:                default:                    _eyeContactTarget = (randFloat() < FIFTY_FIFTY_CHANCE) ? RIGHT_EYE : LEFT_EYE;                    break;            }             const float EYE_TARGET_DELAY_TIME = 0.33f;            _eyeContactTargetTimer = EYE_TARGET_DELAY_TIME;        }    }} extern QByteArray avatarStateToFrame(const AvatarData* _avatar);extern void avatarStateFromFrame(const QByteArray& frameData, AvatarData* _avatar); void MyAvatar::simulate(float deltaTime) {    PerformanceTimer perfTimer("simulate");     animateScaleChanges(deltaTime);     {        PerformanceTimer perfTimer("transform");        bool stepAction = false;        // When there are no step values, we zero out the last step pulse.        // This allows a user to do faster snapping by tapping a control        for (int i = STEP_TRANSLATE_X; !stepAction && i <= STEP_YAW; ++i) {            if (_driveKeys[i] != 0.0f) {                stepAction = true;            }        }         updateOrientation(deltaTime);        updatePosition(deltaTime);    }     // update sensorToWorldMatrix for camera and hand controllers    // before we perform rig animations and IK.    updateSensorToWorldMatrix();     {        PerformanceTimer perfTimer("skeleton");        _skeletonModel->simulate(deltaTime);    }     // we've achived our final adjusted position and rotation for the avatar    // and all of its joints, now update our attachements.    Avatar::simulateAttachments(deltaTime);     if (!_skeletonModel->hasSkeleton()) {        // All the simulation that can be done has been done        return;    }     {        PerformanceTimer perfTimer("joints");        // copy out the skeleton joints from the model        _rig->copyJointsIntoJointData(_jointData);    }     {        PerformanceTimer perfTimer("head");        Head* head = getHead();        glm::vec3 headPosition;        if (!_skeletonModel->getHeadPosition(headPosition)) {            headPosition = getPosition();        }        head->setPosition(headPosition);        head->setScale(getUniformScale());        head->simulate(deltaTime, true);    }     // Record avatars movements.    auto recorder = DependencyManager::get<recording::Recorder>();    if (recorder->isRecording()) {        static const recording::FrameType FRAME_TYPE = recording::Frame::registerFrameType(AvatarData::FRAME_NAME);        recorder->recordFrame(FRAME_TYPE, toFrame(*this));    }     locationChanged();    // if a entity-child of this avatar has moved outside of its queryAACube, update the cube and tell the entity server.    EntityTreeRenderer* entityTreeRenderer = qApp->getEntities();    EntityTreePointer entityTree = entityTreeRenderer ? entityTreeRenderer->getTree() : nullptr;    if (entityTree) {        bool flyingAllowed = true;        bool ghostingAllowed = true;        entityTree->withWriteLock([&] {            std::shared_ptr<ZoneEntityItem> zone = entityTreeRenderer->myAvatarZone();            if (zone) {                flyingAllowed = zone->getFlyingAllowed();                ghostingAllowed = zone->getGhostingAllowed();            }            auto now = usecTimestampNow();            EntityEditPacketSender* packetSender = qApp->getEntityEditPacketSender();            MovingEntitiesOperator moveOperator(entityTree);            forEachDescendant([&](SpatiallyNestablePointer object) {                // if the queryBox has changed, tell the entity-server                if (object->computePuffedQueryAACube() && object->getNestableType() == NestableType::Entity) {                    EntityItemPointer entity = std::static_pointer_cast<EntityItem>(object);                    bool success;                    AACube newCube = entity->getQueryAACube(success);                    if (success) {                        moveOperator.addEntityToMoveList(entity, newCube);                    }                    if (packetSender) {                        EntityItemProperties properties = entity->getProperties();                        properties.setQueryAACubeDirty();                        properties.setLastEdited(now);                         packetSender->queueEditEntityMessage(PacketType::EntityEdit, entityTree, entity->getID(), properties);                        entity->setLastBroadcast(usecTimestampNow());                    }                }            });            // also update the position of children in our local octree            if (moveOperator.hasMovingEntities()) {                PerformanceTimer perfTimer("recurseTreeWithOperator");                entityTree->recurseTreeWithOperator(&moveOperator);            }        });        _characterController.setFlyingAllowed(flyingAllowed);        if (!_characterController.isEnabled() && !ghostingAllowed) {            _characterController.setEnabled(true);        }    }     updateAvatarEntities();} // thread-safeglm::mat4 MyAvatar::getSensorToWorldMatrix() const {    return _sensorToWorldMatrixCache.get();} // Pass a recent sample of the HMD to the avatar.// This can also update the avatar's position to follow the HMD// as it moves through the world.void MyAvatar::updateFromHMDSensorMatrix(const glm::mat4& hmdSensorMatrix) {    // update the sensorMatrices based on the new hmd pose    _hmdSensorMatrix = hmdSensorMatrix;    _hmdSensorPosition = extractTranslation(hmdSensorMatrix);    _hmdSensorOrientation = glm::quat_cast(hmdSensorMatrix);    _hmdSensorFacing = getFacingDir2D(_hmdSensorOrientation);} // best called at end of main loop, after physics.// update sensor to world matrix from current body position and hmd sensor.// This is so the correct camera can be used for rendering.void MyAvatar::updateSensorToWorldMatrix() {     // update the sensor mat so that the body position will end up in the desired    // position when driven from the head.

Lines 1–500 of 2139.