diff --git a/libraries/fbx/src/FBXReader.h b/libraries/fbx/src/FBXReader.h index 5910b8d312..6e51c413dc 100644 --- a/libraries/fbx/src/FBXReader.h +++ b/libraries/fbx/src/FBXReader.h @@ -300,7 +300,7 @@ public: QHash<QString, FBXMaterial> materials; - glm::mat4 offset; + glm::mat4 offset; // This includes offset, rotation, and scale as specified by the FST file int leftEyeJointIndex = -1; int rightEyeJointIndex = -1; diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 9dd3563887..d94bb67590 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -375,6 +375,14 @@ bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const g recalculateMeshBoxes(pickAgainstTriangles); } + glm::mat4 meshToModelMatrix = glm::scale(_scale) * glm::translate(_offset); + glm::mat4 meshToWorldMatrix = meshToModelMatrix * glm::translate(_translation) * glm::mat4_cast(_rotation); + glm::mat4 worldToMeshMatrix = glm::inverse(meshToWorldMatrix); + + glm::vec3 meshFrameOrigin = glm::vec3(worldToMeshMatrix * glm::vec4(origin, 1.0f)); + glm::vec3 meshFrameDirection = glm::vec3(worldToMeshMatrix * glm::vec4(direction, 0.0f)); + + for (const auto& subMeshBox : _calculatedMeshBoxes) { bool intersectedSubMesh = false; float subMeshDistance = std::numeric_limits<float>::max(); @@ -383,19 +391,24 @@ bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const g if (distanceToSubMesh < bestDistance) { if (pickAgainstTriangles) { - float subMeshDistance; + float subMeshDistance = 0.0f; glm::vec3 subMeshNormal; - const auto& meshTriangleSet = _meshTriangleSets[subMeshIndex]; - bool intersectedMesh = meshTriangleSet.findRayIntersection(origin, direction, subMeshDistance, subMeshNormal); + const auto& meshTriangleSet = _modelSpaceMeshTriangleSets[subMeshIndex]; + bool intersectedMesh = meshTriangleSet.findRayIntersection(meshFrameOrigin, meshFrameDirection, subMeshDistance, subMeshNormal); - if (intersectedMesh && subMeshDistance < bestDistance) { - bestDistance = subMeshDistance; - intersectedSomething = true; - face = subMeshFace; - surfaceNormal = subMeshNormal; - extraInfo = geometry.getModelNameOfMesh(subMeshIndex); + if (intersectedMesh) { + glm::vec3 meshIntersectionPoint = meshFrameOrigin + (meshFrameDirection * subMeshDistance); + glm::vec3 worldIntersectionPoint = glm::vec3(meshToWorldMatrix * glm::vec4(meshIntersectionPoint, 1.0f)); + float worldDistance = glm::distance(origin, worldIntersectionPoint); + + if (worldDistance < bestDistance) { + bestDistance = subMeshDistance; + intersectedSomething = true; + face = subMeshFace; + surfaceNormal = glm::vec3(meshToWorldMatrix * glm::vec4(subMeshNormal, 0.0f)); + extraInfo = geometry.getModelNameOfMesh(subMeshIndex); + } } - } else { // this is the non-triangle picking case... bestDistance = distanceToSubMesh; @@ -458,7 +471,13 @@ bool Model::convexHullContains(glm::vec3 point) { foreach(const AABox& subMeshBox, _calculatedMeshBoxes) { if (subMeshBox.contains(point)) { - if (_meshTriangleSets[subMeshIndex].convexHullContains(point)) { + glm::mat4 meshToModelMatrix = glm::scale(_scale) * glm::translate(_offset); + glm::mat4 meshToWorldMatrix = meshToModelMatrix * glm::translate(_translation) * glm::mat4_cast(_rotation); + glm::mat4 worldToMeshMatrix = glm::inverse(meshToWorldMatrix); + + glm::vec3 meshFramePoint = glm::vec3(worldToMeshMatrix * glm::vec4(point, 1.0f)); + + if (_modelSpaceMeshTriangleSets[subMeshIndex].convexHullContains(meshFramePoint)) { // It's inside this mesh, return true. _mutex.unlock(); return true; @@ -493,8 +512,9 @@ void Model::recalculateMeshBoxes(bool pickAgainstTriangles) { int numberOfMeshes = geometry.meshes.size(); _calculatedMeshBoxes.resize(numberOfMeshes); _calculatedMeshPartBoxes.clear(); - _meshTriangleSets.clear(); - _meshTriangleSets.resize(numberOfMeshes); + + _modelSpaceMeshTriangleSets.clear(); + _modelSpaceMeshTriangleSets.resize(numberOfMeshes); for (int i = 0; i < numberOfMeshes; i++) { const FBXMesh& mesh = geometry.meshes.at(i); @@ -503,9 +523,7 @@ void Model::recalculateMeshBoxes(bool pickAgainstTriangles) { _calculatedMeshBoxes[i] = AABox(scaledMeshExtents); if (pickAgainstTriangles) { - auto& thisMeshTriangleSet = _meshTriangleSets[i]; - QVector<Triangle> thisMeshTriangles; for (int j = 0; j < mesh.parts.size(); j++) { const FBXMeshPart& part = mesh.parts.at(j); @@ -540,24 +558,21 @@ 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); + // let's also track the model space version... (eventually using only this!) + // these points will be transformed by the FST's offset, which includes the + // scaling, rotation, and translation specified by the FST/FBX, this can't change + // at runtime, so we can safely store these in our TriangleSet + { + glm::vec3 v0 = glm::vec3(getFBXGeometry().offset * glm::vec4(mesh.vertices[i0], 1.0f)); + glm::vec3 v1 = glm::vec3(getFBXGeometry().offset * glm::vec4(mesh.vertices[i1], 1.0f)); + glm::vec3 v2 = glm::vec3(getFBXGeometry().offset * glm::vec4(mesh.vertices[i2], 1.0f)); + glm::vec3 v3 = glm::vec3(getFBXGeometry().offset * glm::vec4(mesh.vertices[i3], 1.0f)); - // Sam's recommended triangle slices - Triangle tri1 = { v0, v1, v3 }; - Triangle tri2 = { v1, v2, v3 }; - - // NOTE: Random guy on the internet's recommended triangle slices - //Triangle tri1 = { v0, v1, v2 }; - //Triangle tri2 = { v2, v3, v0 }; - - thisMeshTriangles.push_back(tri1); - thisMeshTriangles.push_back(tri2); - - thisMeshTriangleSet.insertTriangle(tri1); - thisMeshTriangleSet.insertTriangle(tri2); + Triangle tri1 = { v0, v1, v3 }; + Triangle tri2 = { v1, v2, v3 }; + _modelSpaceMeshTriangleSets[i].insertTriangle(tri1); + _modelSpaceMeshTriangleSets[i].insertTriangle(tri2); + } } } @@ -584,15 +599,18 @@ void Model::recalculateMeshBoxes(bool pickAgainstTriangles) { thisPartBounds += mv1; thisPartBounds += mv2; - glm::vec3 v0 = calculateScaledOffsetPoint(mv0); - glm::vec3 v1 = calculateScaledOffsetPoint(mv1); - glm::vec3 v2 = calculateScaledOffsetPoint(mv2); + // let's also track the model space version... (eventually using only this!) + // these points will be transformed by the FST's offset, which includes the + // scaling, rotation, and translation specified by the FST/FBX, this can't change + // at runtime, so we can safely store these in our TriangleSet + { + glm::vec3 v0 = glm::vec3(getFBXGeometry().offset * glm::vec4(mesh.vertices[i0], 1.0f)); + glm::vec3 v1 = glm::vec3(getFBXGeometry().offset * glm::vec4(mesh.vertices[i1], 1.0f)); + glm::vec3 v2 = glm::vec3(getFBXGeometry().offset * glm::vec4(mesh.vertices[i2], 1.0f)); - Triangle tri = { v0, v1, v2 }; - - thisMeshTriangles.push_back(tri); - - thisMeshTriangleSet.insertTriangle(tri); + Triangle tri = { v0, v1, v2 }; + _modelSpaceMeshTriangleSets[i].insertTriangle(tri); + } } } diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index bc3cf0e521..763112cebc 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -294,10 +294,10 @@ protected: SpatiallyNestable* _spatiallyNestableOverride; - glm::vec3 _translation; + glm::vec3 _translation; // this is the translation in world coordinates to the model's registration point glm::quat _rotation; glm::vec3 _scale; - glm::vec3 _offset; + glm::vec3 _offset; // this is the translation for the minimum extent of the model (in original mesh coordinate space) to the model's registration point static float FAKE_DIMENSION_PLACEHOLDER; @@ -363,7 +363,7 @@ protected: bool _calculatedMeshPartBoxesValid; QVector<AABox> _calculatedMeshBoxes; // world coordinate AABoxes for all sub mesh boxes bool _calculatedMeshBoxesValid; - QVector< TriangleSet > _meshTriangleSets; // world coordinate triangles for all sub meshes + QVector<TriangleSet> _modelSpaceMeshTriangleSets; // model space triangles for all sub meshes bool _calculatedMeshTrianglesValid; QMutex _mutex;