Add avatar joints filter to intersection calculation

This commit is contained in:
luiscuenca 2019-01-17 14:00:54 -07:00
parent 67cc5bd7f2
commit 2158e084d4
6 changed files with 94 additions and 51 deletions

View file

@ -640,23 +640,27 @@ AvatarSharedPointer AvatarManager::getAvatarBySessionID(const QUuid& sessionID)
RayToAvatarIntersectionResult AvatarManager::findRayIntersection(const PickRay& ray,
const QScriptValue& avatarIdsToInclude,
const QScriptValue& avatarIdsToDiscard) {
const QScriptValue& avatarIdsToDiscard,
const QScriptValue& jointIndicesToFilter) {
QVector<EntityItemID> avatarsToInclude = qVectorEntityItemIDFromScriptValue(avatarIdsToInclude);
QVector<EntityItemID> avatarsToDiscard = qVectorEntityItemIDFromScriptValue(avatarIdsToDiscard);
return findRayIntersectionVector(ray, avatarsToInclude, avatarsToDiscard);
QVector<uint> jointsToFilter;
qVectorIntFromScriptValue(jointIndicesToFilter, jointsToFilter);
return findRayIntersectionVector(ray, avatarsToInclude, avatarsToDiscard, jointsToFilter);
}
RayToAvatarIntersectionResult AvatarManager::findRayIntersectionVector(const PickRay& ray,
const QVector<EntityItemID>& avatarsToInclude,
const QVector<EntityItemID>& avatarsToDiscard) {
const QVector<EntityItemID>& avatarsToDiscard,
const QVector<uint>& jointIndicesToFilter) {
RayToAvatarIntersectionResult result;
if (QThread::currentThread() != thread()) {
BLOCKING_INVOKE_METHOD(const_cast<AvatarManager*>(this), "findRayIntersectionVector",
Q_RETURN_ARG(RayToAvatarIntersectionResult, result),
Q_ARG(const PickRay&, ray),
Q_ARG(const QVector<EntityItemID>&, avatarsToInclude),
Q_ARG(const QVector<EntityItemID>&, avatarsToDiscard));
Q_ARG(const QVector<EntityItemID>&, avatarsToDiscard),
Q_ARG(const QVector<uint>&, jointIndicesToFilter));
return result;
}
@ -672,55 +676,80 @@ RayToAvatarIntersectionResult AvatarManager::findRayIntersectionVector(const Pic
if (physicsResults.size() > 0) {
MyCharacterController::RayAvatarResult rayAvatarResult;
AvatarPointer avatar = nullptr;
for (auto &hit : physicsResults) {
if ((avatarsToInclude.size() > 0 && !avatarsToInclude.contains(hit._intersectWithAvatar)) ||
(avatarsToDiscard.size() > 0 && avatarsToDiscard.contains(hit._intersectWithAvatar))) {
auto avatarID = hit._intersectWithAvatar;
bool skipThisAvatar = (avatarsToInclude.size() > 0 && !avatarsToInclude.contains(avatarID)) ||
(avatarsToDiscard.size() > 0 && avatarsToDiscard.contains(avatarID)) && jointIndicesToFilter.size() == 0;
if (skipThisAvatar) {
continue;
}
if (!hit._isBound) {
rayAvatarResult = hit;
break;
} else {
if (!(_myAvatar->getSessionUUID() == avatarID)) {
auto avatarMap = getHashCopy();
auto avatarID = hit._intersectWithAvatar;
AvatarHash::iterator itr = avatarMap.find(avatarID);
if (itr != avatarMap.end()) {
const auto& avatar = std::static_pointer_cast<Avatar>(*itr);
auto &multiSpheres = avatar->getMultiSphereShapes();
if (multiSpheres.size() > 0) {
std::vector<MyCharacterController::RayAvatarResult> boxHits;
for (size_t i = 0; i < hit._boundJoints.size(); i++) {
assert(hit._boundJoints[i] < multiSpheres.size());
auto &mSphere = multiSpheres[hit._boundJoints[i]];
if (mSphere.isValid()) {
float boundDistance = FLT_MAX;
BoxFace face;
glm::vec3 surfaceNormal;
auto &bbox = mSphere.getBoundingBox();
if (bbox.findRayIntersection(ray.origin, ray.direction, rayDirectionInv, boundDistance, face, surfaceNormal)) {
MyCharacterController::RayAvatarResult boxHit;
boxHit._distance = boundDistance;
boxHit._intersect = true;
boxHit._intersectionNormal = surfaceNormal;
boxHit._intersectionPoint = ray.origin + boundDistance * glm::normalize(ray.direction);
boxHit._intersectWithAvatar = avatarID;
boxHit._intersectWithJoint = mSphere.getJointIndex();
boxHits.push_back(boxHit);
}
}
}
if (boxHits.size() > 0) {
if (boxHits.size() > 1) {
std::sort(boxHits.begin(), boxHits.end(), [](const MyCharacterController::RayAvatarResult& hitA,
const MyCharacterController::RayAvatarResult& hitB) {
return hitA._distance < hitB._distance;
});
}
rayAvatarResult = boxHits[0];
break;
avatar = std::static_pointer_cast<Avatar>(*itr);
}
} else {
avatar = _myAvatar;
}
QVector<int> jointsToDiscard;
if (avatar && jointIndicesToFilter.size() > 0) {
int jointCount = avatar->getJointCount();
if (avatarsToInclude.size() > 0 && avatarsToInclude.contains(avatarID)) {
for (int i = 0; i < jointCount; i++) {
if (!jointIndicesToFilter.contains(i)) {
jointsToDiscard.push_back(i);
}
}
}
} else if (avatarsToDiscard.size() > 0 && avatarsToDiscard.contains(avatarID)) {
for (int i = 0; i < jointCount; i++) {
if (jointIndicesToFilter.contains(i)) {
jointsToDiscard.push_back(i);
}
}
}
}
if (!hit._isBound) {
if (!jointsToDiscard.contains(hit._intersectWithJoint)) {
rayAvatarResult = hit;
break;
}
} else if (avatar) {
auto &multiSpheres = avatar->getMultiSphereShapes();
if (multiSpheres.size() > 0) {
std::vector<MyCharacterController::RayAvatarResult> boxHits;
for (size_t i = 0; i < hit._boundJoints.size(); i++) {
assert(hit._boundJoints[i] < multiSpheres.size());
auto &mSphere = multiSpheres[hit._boundJoints[i]];
if (mSphere.isValid() && !jointsToDiscard.contains(hit._boundJoints[i])) {
float boundDistance = FLT_MAX;
BoxFace face;
glm::vec3 surfaceNormal;
auto &bbox = mSphere.getBoundingBox();
if (bbox.findRayIntersection(ray.origin, ray.direction, rayDirectionInv, boundDistance, face, surfaceNormal)) {
MyCharacterController::RayAvatarResult boxHit;
boxHit._distance = boundDistance;
boxHit._intersect = true;
boxHit._intersectionNormal = surfaceNormal;
boxHit._intersectionPoint = ray.origin + boundDistance * glm::normalize(ray.direction);
boxHit._intersectWithAvatar = avatarID;
boxHit._intersectWithJoint = hit._intersectWithJoint;
boxHits.push_back(boxHit);
}
}
}
if (boxHits.size() > 0) {
if (boxHits.size() > 1) {
std::sort(boxHits.begin(), boxHits.end(), [](const MyCharacterController::RayAvatarResult& hitA,
const MyCharacterController::RayAvatarResult& hitB) {
return hitA._distance < hitB._distance;
});
}
rayAvatarResult = boxHits[0];
break;
}
}
}
}
if (rayAvatarResult._intersect) {

View file

@ -138,21 +138,25 @@ public:
* @param {PickRay} ray
* @param {Uuid[]} [avatarsToInclude=[]]
* @param {Uuid[]} [avatarsToDiscard=[]]
* @param {uint[]} [jointIndicesToFilter=[] - If included/discarded avatars are provided only this joints corresponding to those avatars would be included/discarded. ]
* @returns {RayToAvatarIntersectionResult}
*/
Q_INVOKABLE RayToAvatarIntersectionResult findRayIntersection(const PickRay& ray,
const QScriptValue& avatarIdsToInclude = QScriptValue(),
const QScriptValue& avatarIdsToDiscard = QScriptValue());
const QScriptValue& avatarIdsToDiscard = QScriptValue(),
const QScriptValue& jointIndicesToFilter = QScriptValue());
/**jsdoc
* @function AvatarManager.findRayIntersectionVector
* @param {PickRay} ray
* @param {Uuid[]} avatarsToInclude
* @param {Uuid[]} avatarsToDiscard
* @param {uint[]} [jointIndicesToFilter=[] - If included/discarded avatars are provided only this joints corresponding to those avatars would be included/discarded. ]
* @returns {RayToAvatarIntersectionResult}
*/
Q_INVOKABLE RayToAvatarIntersectionResult findRayIntersectionVector(const PickRay& ray,
const QVector<EntityItemID>& avatarsToInclude,
const QVector<EntityItemID>& avatarsToDiscard);
const QVector<EntityItemID>& avatarsToDiscard,
const QVector<uint>& jointIndicesToFilter);
/**jsdoc
* @function AvatarManager.findParabolaIntersectionVector

View file

@ -182,7 +182,7 @@ void DetailedMotionState::setShape(const btCollisionShape* shape) {
}
void DetailedMotionState::forceActive() {
if (_body) {
if (_body && !_body->isActive()) {
_body->setActivationState(ACTIVE_TAG);
}
}

View file

@ -360,6 +360,9 @@ btCollisionShape* MyCharacterController::createDetailedCollisionShapeForJoint(in
_avatar->computeDetailedShapeInfo(shapeInfo, jointIndex);
if (shapeInfo.getType() != SHAPE_TYPE_NONE) {
btCollisionShape* shape = const_cast<btCollisionShape*>(ObjectMotionState::getShapeManager()->getShape(shapeInfo));
if (shape) {
shape->setMargin(0.001f);
}
return shape;
}
return nullptr;

View file

@ -114,6 +114,9 @@ void OtherAvatar::updateSpaceProxy(workload::Transaction& transaction) const {
int OtherAvatar::parseDataFromBuffer(const QByteArray& buffer) {
int32_t bytesRead = Avatar::parseDataFromBuffer(buffer);
for (size_t i = 0; i < _detailedMotionStates.size(); i++) {
_detailedMotionStates[i]->forceActive();
}
if (_moving && _motionState) {
_motionState->addDirtyFlags(Simulation::DIRTY_POSITION);
}
@ -166,7 +169,11 @@ btCollisionShape* OtherAvatar::createCollisionShape(int jointIndex, bool& isBoun
break;
}
if (shapeInfo.getType() != SHAPE_TYPE_NONE) {
return const_cast<btCollisionShape*>(ObjectMotionState::getShapeManager()->getShape(shapeInfo));
auto shape = const_cast<btCollisionShape*>(ObjectMotionState::getShapeManager()->getShape(shapeInfo));
if (shape) {
shape->setMargin(0.001f);
}
return shape;
}
return nullptr;
}

View file

@ -56,7 +56,7 @@ PickResultPointer RayPick::getOverlayIntersection(const PickRay& pick) {
}
PickResultPointer RayPick::getAvatarIntersection(const PickRay& pick) {
RayToAvatarIntersectionResult avatarRes = DependencyManager::get<AvatarManager>()->findRayIntersectionVector(pick, getIncludeItemsAs<EntityItemID>(), getIgnoreItemsAs<EntityItemID>());
RayToAvatarIntersectionResult avatarRes = DependencyManager::get<AvatarManager>()->findRayIntersectionVector(pick, getIncludeItemsAs<EntityItemID>(), getIgnoreItemsAs<EntityItemID>(), QVector<uint>());
if (avatarRes.intersects) {
return std::make_shared<RayPickResult>(IntersectionType::AVATAR, avatarRes.avatarID, avatarRes.distance, avatarRes.intersection, pick, avatarRes.surfaceNormal, avatarRes.extraInfo);
} else {