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

View file

@ -138,21 +138,25 @@ public:
* @param {PickRay} ray * @param {PickRay} ray
* @param {Uuid[]} [avatarsToInclude=[]] * @param {Uuid[]} [avatarsToInclude=[]]
* @param {Uuid[]} [avatarsToDiscard=[]] * @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} * @returns {RayToAvatarIntersectionResult}
*/ */
Q_INVOKABLE RayToAvatarIntersectionResult findRayIntersection(const PickRay& ray, Q_INVOKABLE RayToAvatarIntersectionResult findRayIntersection(const PickRay& ray,
const QScriptValue& avatarIdsToInclude = QScriptValue(), const QScriptValue& avatarIdsToInclude = QScriptValue(),
const QScriptValue& avatarIdsToDiscard = QScriptValue()); const QScriptValue& avatarIdsToDiscard = QScriptValue(),
const QScriptValue& jointIndicesToFilter = QScriptValue());
/**jsdoc /**jsdoc
* @function AvatarManager.findRayIntersectionVector * @function AvatarManager.findRayIntersectionVector
* @param {PickRay} ray * @param {PickRay} ray
* @param {Uuid[]} avatarsToInclude * @param {Uuid[]} avatarsToInclude
* @param {Uuid[]} avatarsToDiscard * @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} * @returns {RayToAvatarIntersectionResult}
*/ */
Q_INVOKABLE RayToAvatarIntersectionResult findRayIntersectionVector(const PickRay& ray, Q_INVOKABLE RayToAvatarIntersectionResult findRayIntersectionVector(const PickRay& ray,
const QVector<EntityItemID>& avatarsToInclude, const QVector<EntityItemID>& avatarsToInclude,
const QVector<EntityItemID>& avatarsToDiscard); const QVector<EntityItemID>& avatarsToDiscard,
const QVector<uint>& jointIndicesToFilter);
/**jsdoc /**jsdoc
* @function AvatarManager.findParabolaIntersectionVector * @function AvatarManager.findParabolaIntersectionVector

View file

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

View file

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

View file

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

View file

@ -56,7 +56,7 @@ PickResultPointer RayPick::getOverlayIntersection(const PickRay& pick) {
} }
PickResultPointer RayPick::getAvatarIntersection(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) { if (avatarRes.intersects) {
return std::make_shared<RayPickResult>(IntersectionType::AVATAR, avatarRes.avatarID, avatarRes.distance, avatarRes.intersection, pick, avatarRes.surfaceNormal, avatarRes.extraInfo); return std::make_shared<RayPickResult>(IntersectionType::AVATAR, avatarRes.avatarID, avatarRes.distance, avatarRes.intersection, pick, avatarRes.surfaceNormal, avatarRes.extraInfo);
} else { } else {