From 50216ca4ade1e04cb22ceb5855c6b72bf4f8bc49 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 16 Oct 2013 15:37:59 -0700 Subject: [PATCH] Base the number of people we include in the circle on whether we would actually fall in its radius (plus an expansion factor). --- interface/src/avatar/MyAvatar.cpp | 92 +++++++++++++++++++------------ 1 file changed, 58 insertions(+), 34 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index d4664168a7..149aa504f5 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1094,27 +1094,60 @@ void MyAvatar::applyCollisionWithOtherAvatar(Avatar * otherAvatar, float deltaTi _velocity += bodyPushForce; } +class SortedAvatar { +public: + Avatar* avatar; + float distance; + glm::vec3 accumulatedCenter; +}; + +bool operator<(const SortedAvatar& s1, const SortedAvatar& s2) { + return s1.distance < s2.distance; +} + void MyAvatar::updateChatCircle(float deltaTime) { - // find the number of members, their center of mass, and the average up vector - glm::vec3 center = _position; - glm::vec3 up = getWorldAlignedOrientation() * IDENTITY_UP; - int memberCount = 1; + // find all members and sort by distance + QVector sortedAvatars; NodeList* nodeList = NodeList::getInstance(); - const float MAX_CHAT_DISTANCE = 10.0f; for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) { if (node->getLinkedData() && node->getType() == NODE_TYPE_AGENT) { - Avatar* otherAvatar = (Avatar*)node->getLinkedData(); - if (glm::distance(_position, otherAvatar->getPosition()) < MAX_CHAT_DISTANCE) { - center += otherAvatar->getPosition(); - up += otherAvatar->getWorldAlignedOrientation() * IDENTITY_UP; - memberCount++; - } + SortedAvatar sortedAvatar; + sortedAvatar.avatar = (Avatar*)node->getLinkedData(); + sortedAvatar.distance = glm::distance(_position, sortedAvatar.avatar->getPosition()); + sortedAvatars.append(sortedAvatar); } } - if (memberCount == 1) { + qSort(sortedAvatars.begin(), sortedAvatars.end()); + + // compute the accumulated centers + glm::vec3 center = _position; + for (int i = 0; i < sortedAvatars.size(); i++) { + SortedAvatar& sortedAvatar = sortedAvatars[i]; + sortedAvatar.accumulatedCenter = (center += sortedAvatar.avatar->getPosition()) / (i + 2.0f); + } + + // remove members whose accumulated circles are too far away to influence us + const float CIRCUMFERENCE_PER_MEMBER = 2.0f; + const float CIRCLE_INFLUENCE_SCALE = 1.1f; + for (int i = sortedAvatars.size() - 1; i >= 0; i--) { + float radius = (CIRCUMFERENCE_PER_MEMBER * (i + 2)) / PI_TIMES_TWO; + if (glm::distance(_position, sortedAvatars[i].accumulatedCenter) > radius * CIRCLE_INFLUENCE_SCALE) { + sortedAvatars.remove(i); + } else { + break; + } + } + if (sortedAvatars.isEmpty()) { return; } - center /= memberCount; + center = sortedAvatars.last().accumulatedCenter; + float radius = (CIRCUMFERENCE_PER_MEMBER * (sortedAvatars.size() + 1)) / PI_TIMES_TWO; + + // compute the average up vector + glm::vec3 up = getWorldAlignedOrientation() * IDENTITY_UP; + foreach (const SortedAvatar& sortedAvatar, sortedAvatars) { + up += sortedAvatar.avatar->getWorldAlignedOrientation() * IDENTITY_UP; + } up = glm::normalize(up); // find reasonable corresponding right/front vectors @@ -1131,29 +1164,20 @@ void MyAvatar::updateChatCircle(float deltaTime) { float myAngle = glm::length(projected) > EPSILON ? atan2f(projected.y, projected.x) : 0.0f; float leftDistance = PIf; float rightDistance = PIf; - for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) { - if (node->getLinkedData() && node->getType() == NODE_TYPE_AGENT) { - Avatar* otherAvatar = (Avatar*)node->getLinkedData(); - if (glm::distance(_position, otherAvatar->getPosition()) < MAX_CHAT_DISTANCE) { - delta = otherAvatar->getPosition() - center; - projected = glm::vec3(glm::dot(right, delta), glm::dot(front, delta), 0.0f); - float angle = glm::length(projected) > EPSILON ? atan2f(projected.y, projected.x) : 0.0f; - if (angle < myAngle) { - leftDistance = min(myAngle - angle, leftDistance); - rightDistance = min(PI_TIMES_TWO - (myAngle - angle), rightDistance); - - } else { - leftDistance = min(PI_TIMES_TWO - (angle - myAngle), leftDistance); - rightDistance = min(angle - myAngle, rightDistance); - } - } + foreach (const SortedAvatar& sortedAvatar, sortedAvatars) { + delta = sortedAvatar.avatar->getPosition() - center; + projected = glm::vec3(glm::dot(right, delta), glm::dot(front, delta), 0.0f); + float angle = glm::length(projected) > EPSILON ? atan2f(projected.y, projected.x) : 0.0f; + if (angle < myAngle) { + leftDistance = min(myAngle - angle, leftDistance); + rightDistance = min(PI_TIMES_TWO - (myAngle - angle), rightDistance); + + } else { + leftDistance = min(PI_TIMES_TWO - (angle - myAngle), leftDistance); + rightDistance = min(angle - myAngle, rightDistance); } } - // determine the chat circle radius - const float CIRCUMFERENCE_PER_MEMBER = 2.0f; - float radius = (CIRCUMFERENCE_PER_MEMBER * memberCount) / PI_TIMES_TWO; - // split the difference between our neighbors float targetAngle = myAngle + (rightDistance - leftDistance) / 2.0f; glm::vec3 targetPosition = center + (front * sinf(targetAngle) + right * cosf(targetAngle)) * radius; @@ -1164,7 +1188,7 @@ void MyAvatar::updateChatCircle(float deltaTime) { targetOrientation = rotationBetween(targetOrientation * IDENTITY_UP, up) * targetOrientation; // approach the target position/orientation - const float APPROACH_RATE = 0.1f; + const float APPROACH_RATE = 0.05f; _position = glm::mix(_position, targetPosition, APPROACH_RATE); setOrientation(safeMix(orientation, targetOrientation, APPROACH_RATE)); }