mirror of
https://github.com/Armored-Dragon/overte.git
synced 2025-03-11 16:13:16 +01:00
pick against avatar's capsule and then against the T-pose mesh
This commit is contained in:
parent
6786a07ac2
commit
11542aeca2
5 changed files with 52 additions and 132 deletions
|
@ -1085,6 +1085,15 @@ void Avatar::computeShapeInfo(ShapeInfo& shapeInfo) {
|
||||||
shapeInfo.setOffset(uniformScale * _skeletonModel->getBoundingCapsuleOffset());
|
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) {
|
void Avatar::setMotionState(AvatarMotionState* motionState) {
|
||||||
_motionState = motionState;
|
_motionState = motionState;
|
||||||
}
|
}
|
||||||
|
|
|
@ -154,6 +154,7 @@ public:
|
||||||
virtual void rebuildCollisionShape();
|
virtual void rebuildCollisionShape();
|
||||||
|
|
||||||
virtual void computeShapeInfo(ShapeInfo& shapeInfo);
|
virtual void computeShapeInfo(ShapeInfo& shapeInfo);
|
||||||
|
void getCapsule(glm::vec3& start, glm::vec3& end, float& radius);
|
||||||
|
|
||||||
AvatarMotionState* getMotionState() { return _motionState; }
|
AvatarMotionState* getMotionState() { return _motionState; }
|
||||||
|
|
||||||
|
|
|
@ -429,18 +429,34 @@ RayToAvatarIntersectionResult AvatarManager::findRayIntersection(const PickRay&
|
||||||
glm::vec3 surfaceNormal;
|
glm::vec3 surfaceNormal;
|
||||||
|
|
||||||
SkeletonModelPointer avatarModel = avatar->getSkeletonModel();
|
SkeletonModelPointer avatarModel = avatar->getSkeletonModel();
|
||||||
AABox avatarBounds = avatarModel->getRenderableMeshBound();
|
|
||||||
if (!avatarBounds.findRayIntersection(ray.origin, normDirection, distance, face, surfaceNormal)) {
|
// It's better to intersect the ray against the avatar's actual mesh, but this is currently difficult to
|
||||||
// ray doesn't intersect avatar's bounding-box
|
// 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;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
avatarModel->invalidCalculatedMeshBoxes();
|
|
||||||
avatarModel->recalculateMeshBoxes(true);
|
|
||||||
|
|
||||||
QString extraInfo;
|
QString extraInfo;
|
||||||
bool intersects = avatarModel->findRayIntersectionAgainstSubMeshes(ray.origin, normDirection,
|
intersects = avatarModel->findRayIntersectionAgainstSubMeshes(ray.origin, normDirection,
|
||||||
distance, face, surfaceNormal, extraInfo, true);
|
distance, face, surfaceNormal, extraInfo, true);
|
||||||
|
|
||||||
if (intersects && (!result.intersects || distance < result.distance)) {
|
if (intersects && (!result.intersects || distance < result.distance)) {
|
||||||
result.intersects = true;
|
result.intersects = true;
|
||||||
|
|
|
@ -442,31 +442,23 @@ void Model::recalculateMeshBoxes(bool pickAgainstTriangles) {
|
||||||
PROFILE_RANGE(__FUNCTION__);
|
PROFILE_RANGE(__FUNCTION__);
|
||||||
bool calculatedMeshTrianglesNeeded = pickAgainstTriangles && !_calculatedMeshTrianglesValid;
|
bool calculatedMeshTrianglesNeeded = pickAgainstTriangles && !_calculatedMeshTrianglesValid;
|
||||||
|
|
||||||
if (!_calculatedMeshBoxesValid || calculatedMeshTrianglesNeeded ||
|
if (!_calculatedMeshBoxesValid || calculatedMeshTrianglesNeeded || (!_calculatedMeshPartBoxesValid && pickAgainstTriangles) ) {
|
||||||
(!_calculatedMeshPartBoxesValid && pickAgainstTriangles) ) {
|
|
||||||
const FBXGeometry& geometry = getFBXGeometry();
|
const FBXGeometry& geometry = getFBXGeometry();
|
||||||
int numberOfMeshes = geometry.meshes.size();
|
int numberOfMeshes = geometry.meshes.size();
|
||||||
_calculatedMeshBoxes.resize(numberOfMeshes);
|
_calculatedMeshBoxes.resize(numberOfMeshes);
|
||||||
_calculatedMeshTriangles.clear();
|
_calculatedMeshTriangles.clear();
|
||||||
_calculatedMeshTriangles.resize(numberOfMeshes);
|
_calculatedMeshTriangles.resize(numberOfMeshes);
|
||||||
_calculatedMeshPartBoxes.clear();
|
_calculatedMeshPartBoxes.clear();
|
||||||
|
for (int i = 0; i < numberOfMeshes; i++) {
|
||||||
|
const FBXMesh& mesh = geometry.meshes.at(i);
|
||||||
|
|
||||||
int okCount = 0;
|
|
||||||
int notOkCount = 0;
|
|
||||||
|
|
||||||
|
|
||||||
for (int meshIndex = 0; meshIndex < numberOfMeshes; meshIndex++) {
|
|
||||||
const FBXMesh& mesh = geometry.meshes.at(meshIndex);
|
|
||||||
Extents scaledMeshExtents = calculateScaledOffsetExtents(mesh.meshExtents, _translation, _rotation);
|
Extents scaledMeshExtents = calculateScaledOffsetExtents(mesh.meshExtents, _translation, _rotation);
|
||||||
|
|
||||||
_calculatedMeshBoxes[meshIndex] = AABox(scaledMeshExtents);
|
_calculatedMeshBoxes[i] = AABox(scaledMeshExtents);
|
||||||
|
|
||||||
if (pickAgainstTriangles) {
|
if (pickAgainstTriangles) {
|
||||||
QVector<Triangle> thisMeshTriangles;
|
QVector<Triangle> thisMeshTriangles;
|
||||||
for (int partIndex = 0; partIndex < mesh.parts.size(); partIndex++) {
|
for (int j = 0; j < mesh.parts.size(); j++) {
|
||||||
const FBXMeshPart& part = mesh.parts.at(partIndex);
|
const FBXMeshPart& part = mesh.parts.at(j);
|
||||||
|
|
||||||
bool atLeastOnePointInBounds = false;
|
bool atLeastOnePointInBounds = false;
|
||||||
AABox thisPartBounds;
|
AABox thisPartBounds;
|
||||||
|
@ -483,63 +475,11 @@ void Model::recalculateMeshBoxes(bool pickAgainstTriangles) {
|
||||||
int i2 = part.quadIndices[vIndex++];
|
int i2 = part.quadIndices[vIndex++];
|
||||||
int i3 = 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 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 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 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));
|
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
|
// track the mesh parts in model space
|
||||||
if (!atLeastOnePointInBounds) {
|
if (!atLeastOnePointInBounds) {
|
||||||
thisPartBounds.setBox(mv0, 0.0f);
|
thisPartBounds.setBox(mv0, 0.0f);
|
||||||
|
@ -551,6 +491,11 @@ void Model::recalculateMeshBoxes(bool pickAgainstTriangles) {
|
||||||
thisPartBounds += mv2;
|
thisPartBounds += mv2;
|
||||||
thisPartBounds += mv3;
|
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
|
// Sam's recommended triangle slices
|
||||||
Triangle tri1 = { v0, v1, v3 };
|
Triangle tri1 = { v0, v1, v3 };
|
||||||
Triangle tri2 = { v1, v2, v3 };
|
Triangle tri2 = { v1, v2, v3 };
|
||||||
|
@ -561,6 +506,7 @@ void Model::recalculateMeshBoxes(bool pickAgainstTriangles) {
|
||||||
|
|
||||||
thisMeshTriangles.push_back(tri1);
|
thisMeshTriangles.push_back(tri1);
|
||||||
thisMeshTriangles.push_back(tri2);
|
thisMeshTriangles.push_back(tri2);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -572,58 +518,10 @@ void Model::recalculateMeshBoxes(bool pickAgainstTriangles) {
|
||||||
int i1 = part.triangleIndices[vIndex++];
|
int i1 = part.triangleIndices[vIndex++];
|
||||||
int i2 = 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 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 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 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
|
// track the mesh parts in model space
|
||||||
if (!atLeastOnePointInBounds) {
|
if (!atLeastOnePointInBounds) {
|
||||||
thisPartBounds.setBox(mv0, 0.0f);
|
thisPartBounds.setBox(mv0, 0.0f);
|
||||||
|
@ -634,20 +532,21 @@ void Model::recalculateMeshBoxes(bool pickAgainstTriangles) {
|
||||||
thisPartBounds += mv1;
|
thisPartBounds += mv1;
|
||||||
thisPartBounds += mv2;
|
thisPartBounds += mv2;
|
||||||
|
|
||||||
|
glm::vec3 v0 = calculateScaledOffsetPoint(mv0);
|
||||||
|
glm::vec3 v1 = calculateScaledOffsetPoint(mv1);
|
||||||
|
glm::vec3 v2 = calculateScaledOffsetPoint(mv2);
|
||||||
|
|
||||||
Triangle tri = { v0, v1, v2 };
|
Triangle tri = { v0, v1, v2 };
|
||||||
|
|
||||||
thisMeshTriangles.push_back(tri);
|
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;
|
_calculatedMeshPartBoxesValid = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
qDebug() << "ok = " << okCount << " not-ok =" << notOkCount;
|
|
||||||
|
|
||||||
_calculatedMeshBoxesValid = true;
|
_calculatedMeshBoxesValid = true;
|
||||||
_calculatedMeshTrianglesValid = pickAgainstTriangles;
|
_calculatedMeshTrianglesValid = pickAgainstTriangles;
|
||||||
}
|
}
|
||||||
|
|
|
@ -316,14 +316,11 @@ protected:
|
||||||
float getLimbLength(int jointIndex) const;
|
float getLimbLength(int jointIndex) const;
|
||||||
|
|
||||||
/// Allow sub classes to force invalidating the bboxes
|
/// Allow sub classes to force invalidating the bboxes
|
||||||
public:
|
|
||||||
void invalidCalculatedMeshBoxes() {
|
void invalidCalculatedMeshBoxes() {
|
||||||
_calculatedMeshBoxesValid = false;
|
_calculatedMeshBoxesValid = false;
|
||||||
_calculatedMeshPartBoxesValid = false;
|
_calculatedMeshPartBoxesValid = false;
|
||||||
_calculatedMeshTrianglesValid = false;
|
_calculatedMeshTrianglesValid = false;
|
||||||
}
|
}
|
||||||
protected:
|
|
||||||
|
|
||||||
|
|
||||||
// hook for derived classes to be notified when setUrl invalidates the current model.
|
// hook for derived classes to be notified when setUrl invalidates the current model.
|
||||||
virtual void onInvalidate() {};
|
virtual void onInvalidate() {};
|
||||||
|
@ -360,9 +357,7 @@ protected:
|
||||||
bool _calculatedMeshTrianglesValid;
|
bool _calculatedMeshTrianglesValid;
|
||||||
QMutex _mutex;
|
QMutex _mutex;
|
||||||
|
|
||||||
public:
|
|
||||||
void recalculateMeshBoxes(bool pickAgainstTriangles = false);
|
void recalculateMeshBoxes(bool pickAgainstTriangles = false);
|
||||||
protected:
|
|
||||||
|
|
||||||
void segregateMeshGroups(); // used to calculate our list of translucent vs opaque meshes
|
void segregateMeshGroups(); // used to calculate our list of translucent vs opaque meshes
|
||||||
static model::MaterialPointer _collisionHullMaterial;
|
static model::MaterialPointer _collisionHullMaterial;
|
||||||
|
|
Loading…
Reference in a new issue