mirror of
https://github.com/overte-org/overte.git
synced 2025-04-22 21:13:31 +02:00
Merge pull request #14647 from hyperlogic/feature/improve-eye-look-at-interest-calculation
Update eye look at interest calculation
This commit is contained in:
commit
bdac7fe298
3 changed files with 78 additions and 32 deletions
|
@ -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() {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 };
|
||||
|
|
Loading…
Reference in a new issue