pick against avatar's capsule and then against the T-pose mesh

This commit is contained in:
Seth Alves 2016-07-07 16:36:25 -07:00
parent 6786a07ac2
commit 11542aeca2
5 changed files with 52 additions and 132 deletions

View file

@ -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;
}

View file

@ -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; }

View file

@ -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;

View file

@ -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<Triangle> 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<int,int>(meshIndex, partIndex)] = thisPartBounds;
_calculatedMeshPartBoxes[QPair<int,int>(i, j)] = thisPartBounds;
}
_calculatedMeshTriangles[meshIndex] = thisMeshTriangles;
_calculatedMeshTriangles[i] = thisMeshTriangles;
_calculatedMeshPartBoxesValid = true;
}
}
qDebug() << "ok = " << okCount << " not-ok =" << notOkCount;
_calculatedMeshBoxesValid = true;
_calculatedMeshTrianglesValid = pickAgainstTriangles;
}

View file

@ -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;