From 11542aeca2b9b01b6e2d6fb9ec58abd8c41d1dcb Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 7 Jul 2016 16:36:25 -0700 Subject: [PATCH] pick against avatar's capsule and then against the T-pose mesh --- interface/src/avatar/Avatar.cpp | 9 ++ interface/src/avatar/Avatar.h | 1 + interface/src/avatar/AvatarManager.cpp | 32 ++++-- libraries/render-utils/src/Model.cpp | 137 ++++--------------------- libraries/render-utils/src/Model.h | 5 - 5 files changed, 52 insertions(+), 132 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 39bb7eac17..4d9481f002 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -1085,6 +1085,15 @@ void Avatar::computeShapeInfo(ShapeInfo& shapeInfo) { shapeInfo.setOffset(uniformScale * _skeletonModel->getBoundingCapsuleOffset()); } +void Avatar::getCapsule(glm::vec3& start, glm::vec3& end, float& radius) { + ShapeInfo shapeInfo; + computeShapeInfo(shapeInfo); + glm::vec3 halfExtents = shapeInfo.getHalfExtents(); // x = radius, y = halfHeight + start = getPosition() - glm::vec3(0, halfExtents.y, 0) + shapeInfo.getOffset(); + end = getPosition() + glm::vec3(0, halfExtents.y, 0) + shapeInfo.getOffset(); + radius = halfExtents.x; +} + void Avatar::setMotionState(AvatarMotionState* motionState) { _motionState = motionState; } diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index 064f0a9533..b9f44613c7 100644 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -154,6 +154,7 @@ public: virtual void rebuildCollisionShape(); virtual void computeShapeInfo(ShapeInfo& shapeInfo); + void getCapsule(glm::vec3& start, glm::vec3& end, float& radius); AvatarMotionState* getMotionState() { return _motionState; } diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index a5a02bdaff..31a77df0cf 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -429,18 +429,34 @@ RayToAvatarIntersectionResult AvatarManager::findRayIntersection(const PickRay& glm::vec3 surfaceNormal; SkeletonModelPointer avatarModel = avatar->getSkeletonModel(); - AABox avatarBounds = avatarModel->getRenderableMeshBound(); - if (!avatarBounds.findRayIntersection(ray.origin, normDirection, distance, face, surfaceNormal)) { - // ray doesn't intersect avatar's bounding-box + + // It's better to intersect the ray against the avatar's actual mesh, but this is currently difficult to + // do, because the transformed mesh data only exists over in GPU-land. As a compromise, this code + // intersects against the avatars capsule and then against the (T-pose) mesh. The end effect is that picking + // against the avatar is sort-of right, but you likely wont be able to pick against the arms. + + // TODO -- find a way to extract transformed avatar mesh data from the rendering engine. + + // if we weren't picking against the capsule, we would want to pick against the avatarBounds... + // AABox avatarBounds = avatarModel->getRenderableMeshBound(); + // if (!avatarBounds.findRayIntersection(ray.origin, normDirection, distance, face, surfaceNormal)) { + // // ray doesn't intersect avatar's bounding-box + // continue; + // } + + glm::vec3 start; + glm::vec3 end; + float radius; + avatar->getCapsule(start, end, radius); + bool intersects = findRayCapsuleIntersection(ray.origin, normDirection, start, end, radius, distance); + if (!intersects) { + // ray doesn't intersect avatar's capsule continue; } - avatarModel->invalidCalculatedMeshBoxes(); - avatarModel->recalculateMeshBoxes(true); - QString extraInfo; - bool intersects = avatarModel->findRayIntersectionAgainstSubMeshes(ray.origin, normDirection, - distance, face, surfaceNormal, extraInfo, true); + intersects = avatarModel->findRayIntersectionAgainstSubMeshes(ray.origin, normDirection, + distance, face, surfaceNormal, extraInfo, true); if (intersects && (!result.intersects || distance < result.distance)) { result.intersects = true; diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 4969585af4..43eced3107 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -442,31 +442,23 @@ void Model::recalculateMeshBoxes(bool pickAgainstTriangles) { PROFILE_RANGE(__FUNCTION__); bool calculatedMeshTrianglesNeeded = pickAgainstTriangles && !_calculatedMeshTrianglesValid; - if (!_calculatedMeshBoxesValid || calculatedMeshTrianglesNeeded || - (!_calculatedMeshPartBoxesValid && pickAgainstTriangles) ) { + if (!_calculatedMeshBoxesValid || calculatedMeshTrianglesNeeded || (!_calculatedMeshPartBoxesValid && pickAgainstTriangles) ) { const FBXGeometry& geometry = getFBXGeometry(); int numberOfMeshes = geometry.meshes.size(); _calculatedMeshBoxes.resize(numberOfMeshes); _calculatedMeshTriangles.clear(); _calculatedMeshTriangles.resize(numberOfMeshes); _calculatedMeshPartBoxes.clear(); - - - - int okCount = 0; - int notOkCount = 0; - - - for (int meshIndex = 0; meshIndex < numberOfMeshes; meshIndex++) { - const FBXMesh& mesh = geometry.meshes.at(meshIndex); + for (int i = 0; i < numberOfMeshes; i++) { + const FBXMesh& mesh = geometry.meshes.at(i); Extents scaledMeshExtents = calculateScaledOffsetExtents(mesh.meshExtents, _translation, _rotation); - _calculatedMeshBoxes[meshIndex] = AABox(scaledMeshExtents); + _calculatedMeshBoxes[i] = AABox(scaledMeshExtents); if (pickAgainstTriangles) { QVector thisMeshTriangles; - for (int partIndex = 0; partIndex < mesh.parts.size(); partIndex++) { - const FBXMeshPart& part = mesh.parts.at(partIndex); + for (int j = 0; j < mesh.parts.size(); j++) { + const FBXMeshPart& part = mesh.parts.at(j); bool atLeastOnePointInBounds = false; AABox thisPartBounds; @@ -483,63 +475,11 @@ void Model::recalculateMeshBoxes(bool pickAgainstTriangles) { int i2 = part.quadIndices[vIndex++]; int i3 = part.quadIndices[vIndex++]; - glm::vec3 v[3]; - int ok = 0; - if (meshIndex < _meshStates.size()) { - int quadPointIndexes[ 4 ] = {i0, i1, i2, i3}; - for (int pointInQuadIndex = 0; pointInQuadIndex < 4; pointInQuadIndex++) { - int vertexIndex = quadPointIndexes[pointInQuadIndex]; - glm::vec4 clusterIndices = mesh.clusterIndices[vertexIndex]; - glm::vec4 clusterWeights = mesh.clusterWeights[vertexIndex]; - - bool vSet = false; - for (int ci = 0; ci < 4; ci++) { - int clusterIndex = (int) clusterIndices[ci]; - float clusterWeight = clusterWeights[ci]; - if (clusterIndex < 0 || - clusterIndex >= mesh.clusters.size() || - clusterWeight == 0.0f) { - continue; - } - const FBXCluster& cluster = mesh.clusters.at(clusterIndex); - auto clusterMatrix = _meshStates[meshIndex].clusterMatrices[cluster.jointIndex]; - glm::vec3 meshVertex = mesh.vertices[vertexIndex]; - glm::vec3 fuh = transformPoint(clusterMatrix, meshVertex); - glm::vec3 tpoint = clusterWeight * (_translation + fuh); - v[pointInQuadIndex] += tpoint; - vSet = true; - } - if (vSet) { - ok++; - } - } - } - - - glm::vec3 v0; - glm::vec3 v1; - glm::vec3 v2; - glm::vec3 v3; - glm::vec3 mv0 = glm::vec3(mesh.modelTransform * glm::vec4(mesh.vertices[i0], 1.0f)); glm::vec3 mv1 = glm::vec3(mesh.modelTransform * glm::vec4(mesh.vertices[i1], 1.0f)); glm::vec3 mv2 = glm::vec3(mesh.modelTransform * glm::vec4(mesh.vertices[i2], 1.0f)); glm::vec3 mv3 = glm::vec3(mesh.modelTransform * glm::vec4(mesh.vertices[i3], 1.0f)); - if (ok == 4) { - okCount++; - v0 = v[0]; - v1 = v[1]; - v2 = v[2]; - v3 = v[3]; - } else { - notOkCount++; - v0 = calculateScaledOffsetPoint(mv0); - v1 = calculateScaledOffsetPoint(mv1); - v2 = calculateScaledOffsetPoint(mv2); - v3 = calculateScaledOffsetPoint(mv3); - } - // track the mesh parts in model space if (!atLeastOnePointInBounds) { thisPartBounds.setBox(mv0, 0.0f); @@ -551,6 +491,11 @@ void Model::recalculateMeshBoxes(bool pickAgainstTriangles) { thisPartBounds += mv2; thisPartBounds += mv3; + glm::vec3 v0 = calculateScaledOffsetPoint(mv0); + glm::vec3 v1 = calculateScaledOffsetPoint(mv1); + glm::vec3 v2 = calculateScaledOffsetPoint(mv2); + glm::vec3 v3 = calculateScaledOffsetPoint(mv3); + // Sam's recommended triangle slices Triangle tri1 = { v0, v1, v3 }; Triangle tri2 = { v1, v2, v3 }; @@ -561,6 +506,7 @@ void Model::recalculateMeshBoxes(bool pickAgainstTriangles) { thisMeshTriangles.push_back(tri1); thisMeshTriangles.push_back(tri2); + } } @@ -572,58 +518,10 @@ void Model::recalculateMeshBoxes(bool pickAgainstTriangles) { int i1 = part.triangleIndices[vIndex++]; int i2 = part.triangleIndices[vIndex++]; - glm::vec3 v[3]; - int ok = 0; - if (meshIndex < _meshStates.size()) { - int trianglePointIndexes[ 3 ] = {i0, i1, i2}; - for (int pointInTriIndex = 0; pointInTriIndex < 3; pointInTriIndex++) { - int vertexIndex = trianglePointIndexes[pointInTriIndex]; - glm::vec4 clusterIndices = mesh.clusterIndices[vertexIndex]; - glm::vec4 clusterWeights = mesh.clusterWeights[vertexIndex]; - - bool vSet = false; - for (int ci = 0; ci < 4; ci++) { - int clusterIndex = (int) clusterIndices[ci]; - float clusterWeight = clusterWeights[ci]; - if (clusterIndex < 0 || - clusterIndex >= mesh.clusters.size() || - clusterWeight == 0.0f) { - continue; - } - const FBXCluster& cluster = mesh.clusters.at(clusterIndex); - auto clusterMatrix = _meshStates[meshIndex].clusterMatrices[cluster.jointIndex]; - glm::vec3 meshVertex = mesh.vertices[vertexIndex]; - glm::vec3 fuh = transformPoint(clusterMatrix, meshVertex); - glm::vec3 tpoint = clusterWeight * (_translation + fuh); - v[pointInTriIndex] += tpoint; - vSet = true; - } - if (vSet) { - ok++; - } - } - } - glm::vec3 mv0 = glm::vec3(mesh.modelTransform * glm::vec4(mesh.vertices[i0], 1.0f)); glm::vec3 mv1 = glm::vec3(mesh.modelTransform * glm::vec4(mesh.vertices[i1], 1.0f)); glm::vec3 mv2 = glm::vec3(mesh.modelTransform * glm::vec4(mesh.vertices[i2], 1.0f)); - glm::vec3 v0; - glm::vec3 v1; - glm::vec3 v2; - - if (ok == 3) { - okCount++; - v0 = v[0]; - v1 = v[1]; - v2 = v[2]; - } else { - notOkCount++; - v0 = calculateScaledOffsetPoint(mv0); - v1 = calculateScaledOffsetPoint(mv1); - v2 = calculateScaledOffsetPoint(mv2); - } - // track the mesh parts in model space if (!atLeastOnePointInBounds) { thisPartBounds.setBox(mv0, 0.0f); @@ -634,20 +532,21 @@ void Model::recalculateMeshBoxes(bool pickAgainstTriangles) { thisPartBounds += mv1; thisPartBounds += mv2; + glm::vec3 v0 = calculateScaledOffsetPoint(mv0); + glm::vec3 v1 = calculateScaledOffsetPoint(mv1); + glm::vec3 v2 = calculateScaledOffsetPoint(mv2); + Triangle tri = { v0, v1, v2 }; thisMeshTriangles.push_back(tri); } } - _calculatedMeshPartBoxes[QPair(meshIndex, partIndex)] = thisPartBounds; + _calculatedMeshPartBoxes[QPair(i, j)] = thisPartBounds; } - _calculatedMeshTriangles[meshIndex] = thisMeshTriangles; + _calculatedMeshTriangles[i] = thisMeshTriangles; _calculatedMeshPartBoxesValid = true; } } - - qDebug() << "ok = " << okCount << " not-ok =" << notOkCount; - _calculatedMeshBoxesValid = true; _calculatedMeshTrianglesValid = pickAgainstTriangles; } diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index 66c5eb019e..6a7c9ec560 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -316,14 +316,11 @@ protected: float getLimbLength(int jointIndex) const; /// Allow sub classes to force invalidating the bboxes -public: void invalidCalculatedMeshBoxes() { _calculatedMeshBoxesValid = false; _calculatedMeshPartBoxesValid = false; _calculatedMeshTrianglesValid = false; } -protected: - // hook for derived classes to be notified when setUrl invalidates the current model. virtual void onInvalidate() {}; @@ -360,9 +357,7 @@ protected: bool _calculatedMeshTrianglesValid; QMutex _mutex; -public: void recalculateMeshBoxes(bool pickAgainstTriangles = false); -protected: void segregateMeshGroups(); // used to calculate our list of translucent vs opaque meshes static model::MaterialPointer _collisionHullMaterial;