Merge branch 'master' of github.com:highfidelity/hifi into feat/avatarTools/avatarPackager

This commit is contained in:
Thijs Wenker 2019-01-04 21:13:29 +01:00
commit b105607cb2
6 changed files with 120 additions and 70 deletions
interface/src/avatar
libraries
avatars-renderer/src/avatars-renderer
networking/src

View file

@ -28,7 +28,6 @@
#pragma GCC diagnostic pop
#endif
#include <shared/QtHelpers.h>
#include <AvatarData.h>
#include <PerfStat.h>
@ -529,6 +528,7 @@ void AvatarManager::handleChangedMotionStates(const VectorOfMotionStates& motion
}
void AvatarManager::handleCollisionEvents(const CollisionEvents& collisionEvents) {
bool playedCollisionSound { false };
for (Collision collision : collisionEvents) {
// TODO: The plan is to handle MOTIONSTATE_TYPE_AVATAR, and then MOTIONSTATE_TYPE_MYAVATAR. As it is, other
// people's avatars will have an id that doesn't match any entities, and one's own avatar will have
@ -536,43 +536,47 @@ void AvatarManager::handleCollisionEvents(const CollisionEvents& collisionEvents
// my avatar. (Other user machines will make a similar analysis and inject sound for their collisions.)
if (collision.idA.isNull() || collision.idB.isNull()) {
auto myAvatar = getMyAvatar();
auto collisionSound = myAvatar->getCollisionSound();
if (collisionSound) {
const auto characterController = myAvatar->getCharacterController();
const float avatarVelocityChange = (characterController ? glm::length(characterController->getVelocityChange()) : 0.0f);
const float velocityChange = glm::length(collision.velocityChange) + avatarVelocityChange;
const float MIN_AVATAR_COLLISION_ACCELERATION = 2.4f; // walking speed
const bool isSound = (collision.type == CONTACT_EVENT_TYPE_START) && (velocityChange > MIN_AVATAR_COLLISION_ACCELERATION);
myAvatar->collisionWithEntity(collision);
if (!isSound) {
return; // No sense iterating for others. We only have one avatar.
if (!playedCollisionSound) {
playedCollisionSound = true;
auto collisionSound = myAvatar->getCollisionSound();
if (collisionSound) {
const auto characterController = myAvatar->getCharacterController();
const float avatarVelocityChange =
(characterController ? glm::length(characterController->getVelocityChange()) : 0.0f);
const float velocityChange = glm::length(collision.velocityChange) + avatarVelocityChange;
const float MIN_AVATAR_COLLISION_ACCELERATION = 2.4f; // walking speed
const bool isSound =
(collision.type == CONTACT_EVENT_TYPE_START) && (velocityChange > MIN_AVATAR_COLLISION_ACCELERATION);
if (!isSound) {
return; // No sense iterating for others. We only have one avatar.
}
// Your avatar sound is personal to you, so let's say the "mass" part of the kinetic energy is already accounted for.
const float energy = velocityChange * velocityChange;
const float COLLISION_ENERGY_AT_FULL_VOLUME = 10.0f;
const float energyFactorOfFull = fmin(1.0f, energy / COLLISION_ENERGY_AT_FULL_VOLUME);
// For general entity collisionSoundURL, playSound supports changing the pitch for the sound based on the size of the object,
// but most avatars are roughly the same size, so let's not be so fancy yet.
const float AVATAR_STRETCH_FACTOR = 1.0f;
_collisionInjectors.remove_if(
[](const AudioInjectorPointer& injector) { return !injector || injector->isFinished(); });
static const int MAX_INJECTOR_COUNT = 3;
if (_collisionInjectors.size() < MAX_INJECTOR_COUNT) {
AudioInjectorOptions options;
options.stereo = collisionSound->isStereo();
options.position = myAvatar->getWorldPosition();
options.volume = energyFactorOfFull;
options.pitch = 1.0f / AVATAR_STRETCH_FACTOR;
auto injector = AudioInjector::playSoundAndDelete(collisionSound, options);
_collisionInjectors.emplace_back(injector);
}
}
// Your avatar sound is personal to you, so let's say the "mass" part of the kinetic energy is already accounted for.
const float energy = velocityChange * velocityChange;
const float COLLISION_ENERGY_AT_FULL_VOLUME = 10.0f;
const float energyFactorOfFull = fmin(1.0f, energy / COLLISION_ENERGY_AT_FULL_VOLUME);
// For general entity collisionSoundURL, playSound supports changing the pitch for the sound based on the size of the object,
// but most avatars are roughly the same size, so let's not be so fancy yet.
const float AVATAR_STRETCH_FACTOR = 1.0f;
_collisionInjectors.remove_if([](const AudioInjectorPointer& injector) {
return !injector || injector->isFinished();
});
static const int MAX_INJECTOR_COUNT = 3;
if (_collisionInjectors.size() < MAX_INJECTOR_COUNT) {
AudioInjectorOptions options;
options.stereo = collisionSound->isStereo();
options.position = myAvatar->getWorldPosition();
options.volume = energyFactorOfFull;
options.pitch = 1.0f / AVATAR_STRETCH_FACTOR;
auto injector = AudioInjector::playSoundAndDelete(collisionSound, options);
_collisionInjectors.emplace_back(injector);
}
myAvatar->collisionWithEntity(collision);
return;
}
}
}

View file

@ -1531,35 +1531,74 @@ ScriptAvatarData* MyAvatar::getTargetAvatar() const {
}
}
void MyAvatar::updateLookAtTargetAvatar() {
//
// Look at the avatar whose eyes are closest to the ray in direction of my avatar's head
// And set the correctedLookAt for all (nearby) avatars that are looking at me.
_lookAtTargetAvatar.reset();
_targetAvatarPosition = glm::vec3(0.0f);
static float lookAtCostFunction(const glm::vec3& myForward, const glm::vec3& myPosition, const glm::vec3& otherForward, const glm::vec3& otherPosition,
bool otherIsTalking, bool lookingAtOtherAlready) {
const float DISTANCE_FACTOR = 3.14f;
const float MY_ANGLE_FACTOR = 1.0f;
const float OTHER_ANGLE_FACTOR = 1.0f;
const float OTHER_IS_TALKING_TERM = otherIsTalking ? 1.0f : 0.0f;
const float LOOKING_AT_OTHER_ALREADY_TERM = lookingAtOtherAlready ? -0.2f : 0.0f;
glm::vec3 lookForward = getHead()->getFinalOrientationInWorldFrame() * IDENTITY_FORWARD;
glm::vec3 cameraPosition = qApp->getCamera().getPosition();
const float GREATEST_LOOKING_AT_DISTANCE = 10.0f; // meters
const float MAX_MY_ANGLE = PI / 8.0f; // 22.5 degrees, Don't look too far away from the head facing.
const float MAX_OTHER_ANGLE = (3.0f * PI) / 4.0f; // 135 degrees, Don't stare at the back of another avatars head.
float smallestAngleTo = glm::radians(DEFAULT_FIELD_OF_VIEW_DEGREES) / 2.0f;
const float KEEP_LOOKING_AT_CURRENT_ANGLE_FACTOR = 1.3f;
const float GREATEST_LOOKING_AT_DISTANCE = 10.0f;
glm::vec3 d = otherPosition - myPosition;
float distance = glm::length(d);
glm::vec3 dUnit = d / distance;
float myAngle = acosf(glm::dot(myForward, dUnit));
float otherAngle = acosf(glm::dot(otherForward, -dUnit));
AvatarHash hash = DependencyManager::get<AvatarManager>()->getHashCopy();
if (distance > GREATEST_LOOKING_AT_DISTANCE || myAngle > MAX_MY_ANGLE || otherAngle > MAX_OTHER_ANGLE) {
return FLT_MAX;
} else {
return (DISTANCE_FACTOR * distance +
MY_ANGLE_FACTOR * myAngle +
OTHER_ANGLE_FACTOR * otherAngle +
OTHER_IS_TALKING_TERM +
LOOKING_AT_OTHER_ALREADY_TERM);
}
}
foreach (const AvatarSharedPointer& avatarPointer, hash) {
auto avatar = static_pointer_cast<Avatar>(avatarPointer);
bool isCurrentTarget = avatar->getIsLookAtTarget();
float distanceTo = glm::length(avatar->getHead()->getEyePosition() - cameraPosition);
avatar->setIsLookAtTarget(false);
if (!avatar->isMyAvatar() && avatar->isInitialized() &&
(distanceTo < GREATEST_LOOKING_AT_DISTANCE * getModelScale())) {
float radius = glm::length(avatar->getHead()->getEyePosition() - avatar->getHead()->getRightEyePosition());
float angleTo = coneSphereAngle(getHead()->getEyePosition(), lookForward, avatar->getHead()->getEyePosition(), radius);
if (angleTo < (smallestAngleTo * (isCurrentTarget ? KEEP_LOOKING_AT_CURRENT_ANGLE_FACTOR : 1.0f))) {
_lookAtTargetAvatar = avatarPointer;
_targetAvatarPosition = avatarPointer->getWorldPosition();
void MyAvatar::computeMyLookAtTarget(const AvatarHash& hash) {
glm::vec3 myForward = getHead()->getFinalOrientationInWorldFrame() * IDENTITY_FORWARD;
glm::vec3 myPosition = getHead()->getEyePosition();
CameraMode mode = qApp->getCamera().getMode();
if (mode == CAMERA_MODE_FIRST_PERSON) {
myPosition = qApp->getCamera().getPosition();
}
float bestCost = FLT_MAX;
std::shared_ptr<Avatar> bestAvatar;
foreach (const AvatarSharedPointer& avatarData, hash) {
std::shared_ptr<Avatar> avatar = std::static_pointer_cast<Avatar>(avatarData);
if (!avatar->isMyAvatar() && avatar->isInitialized()) {
glm::vec3 otherForward = avatar->getHead()->getForwardDirection();
glm::vec3 otherPosition = avatar->getHead()->getEyePosition();
const float TIME_WITHOUT_TALKING_THRESHOLD = 1.0f;
bool otherIsTalking = avatar->getHead()->getTimeWithoutTalking() <= TIME_WITHOUT_TALKING_THRESHOLD;
bool lookingAtOtherAlready = _lookAtTargetAvatar.lock().get() == avatar.get();
float cost = lookAtCostFunction(myForward, myPosition, otherForward, otherPosition, otherIsTalking, lookingAtOtherAlready);
if (cost < bestCost) {
bestCost = cost;
bestAvatar = avatar;
}
}
}
if (bestAvatar) {
_lookAtTargetAvatar = bestAvatar;
_targetAvatarPosition = bestAvatar->getWorldPosition();
} else {
_lookAtTargetAvatar.reset();
}
}
void MyAvatar::snapOtherAvatarLookAtTargetsToMe(const AvatarHash& hash) {
foreach (const AvatarSharedPointer& avatarData, hash) {
std::shared_ptr<Avatar> avatar = std::static_pointer_cast<Avatar>(avatarData);
if (!avatar->isMyAvatar() && avatar->isInitialized()) {
if (_lookAtSnappingEnabled && avatar->getLookAtSnappingEnabled() && isLookingAtMe(avatar)) {
// Alter their gaze to look directly at my camera; this looks more natural than looking at my avatar's face.
@ -1614,10 +1653,19 @@ void MyAvatar::updateLookAtTargetAvatar() {
avatar->getHead()->clearCorrectedLookAtPosition();
}
}
auto avatarPointer = _lookAtTargetAvatar.lock();
if (avatarPointer) {
static_pointer_cast<Avatar>(avatarPointer)->setIsLookAtTarget(true);
}
}
void MyAvatar::updateLookAtTargetAvatar() {
// The AvatarManager is a mutable class shared by many threads. We make a thread-safe deep copy of it,
// to avoid having to hold a lock while we iterate over all the avatars within.
AvatarHash hash = DependencyManager::get<AvatarManager>()->getHashCopy();
// determine what the best look at target for my avatar should be.
computeMyLookAtTarget(hash);
// snap look at position for avatars that are looking at me.
snapOtherAvatarLookAtTargetsToMe(hash);
}
void MyAvatar::clearLookAtTargetAvatar() {

View file

@ -832,6 +832,8 @@ public:
AvatarWeakPointer getLookAtTargetAvatar() const { return _lookAtTargetAvatar; }
void updateLookAtTargetAvatar();
void computeMyLookAtTarget(const AvatarHash& hash);
void snapOtherAvatarLookAtTargetsToMe(const AvatarHash& hash);
void clearLookAtTargetAvatar();
virtual void setJointRotations(const QVector<glm::quat>& jointRotations) override;

View file

@ -296,6 +296,7 @@ void Avatar::setTargetScale(float targetScale) {
if (_targetScale != newValue) {
_targetScale = newValue;
_scaleChanged = usecTimestampNow();
_avatarScaleChanged = _scaleChanged;
_isAnimatingScale = true;
emit targetScaleChanged(targetScale);

View file

@ -156,9 +156,6 @@ public:
virtual void postUpdate(float deltaTime, const render::ScenePointer& scene);
//setters
void setIsLookAtTarget(const bool isLookAtTarget) { _isLookAtTarget = isLookAtTarget; }
bool getIsLookAtTarget() const { return _isLookAtTarget; }
//getters
bool isInitialized() const { return _initialized; }
SkeletonModelPointer getSkeletonModel() { return _skeletonModel; }
@ -595,7 +592,6 @@ protected:
int _rightPointerGeometryID { 0 };
int _nameRectGeometryID { 0 };
bool _initialized { false };
bool _isLookAtTarget { false };
bool _isAnimatingScale { false };
bool _mustFadeIn { false };
bool _isFading { false };

View file

@ -139,11 +139,10 @@ void UserActivityLogger::connectedDevice(QString typeOfDevice, QString deviceNam
"NullDisplayPlugin",
"3D TV - Side by Side Stereo",
"3D TV - Interleaved",
"Keyboard/Mouse"
};
if (DEVICE_BLACKLIST.contains(deviceName)) {
if (DEVICE_BLACKLIST.contains(deviceName) || deviceName.isEmpty()) {
return;
}