From 9908723bb9192da863862671d474630d02d7e952 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 3 Mar 2017 22:27:38 -0800 Subject: [PATCH] fist cut at basic TriangleSet class --- libraries/render-utils/src/Model.cpp | 65 +++++++++++++++----------- libraries/render-utils/src/Model.h | 3 +- libraries/shared/src/AABox.h | 2 + libraries/shared/src/TriangleSet.cpp | 69 ++++++++++++++++++++++++++++ libraries/shared/src/TriangleSet.h | 33 +++++++++++++ 5 files changed, 144 insertions(+), 28 deletions(-) create mode 100644 libraries/shared/src/TriangleSet.cpp create mode 100644 libraries/shared/src/TriangleSet.h diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index adfffe2614..9dd3563887 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -376,24 +376,26 @@ bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const g } for (const auto& subMeshBox : _calculatedMeshBoxes) { + bool intersectedSubMesh = false; + float subMeshDistance = std::numeric_limits::max(); if (subMeshBox.findRayIntersection(origin, direction, distanceToSubMesh, subMeshFace, subMeshSurfaceNormal)) { if (distanceToSubMesh < bestDistance) { if (pickAgainstTriangles) { - // check our triangles here.... - const QVector& meshTriangles = _calculatedMeshTriangles[subMeshIndex]; - for(const auto& triangle : meshTriangles) { - float thisTriangleDistance; - if (findRayTriangleIntersection(origin, direction, triangle, thisTriangleDistance)) { - if (thisTriangleDistance < bestDistance) { - bestDistance = thisTriangleDistance; - intersectedSomething = true; - face = subMeshFace; - surfaceNormal = triangle.getNormal(); - extraInfo = geometry.getModelNameOfMesh(subMeshIndex); - } - } + + float subMeshDistance; + glm::vec3 subMeshNormal; + const auto& meshTriangleSet = _meshTriangleSets[subMeshIndex]; + bool intersectedMesh = meshTriangleSet.findRayIntersection(origin, direction, subMeshDistance, subMeshNormal); + + if (intersectedMesh && subMeshDistance < bestDistance) { + bestDistance = subMeshDistance; + intersectedSomething = true; + face = subMeshFace; + surfaceNormal = subMeshNormal; + extraInfo = geometry.getModelNameOfMesh(subMeshIndex); } + } else { // this is the non-triangle picking case... bestDistance = distanceToSubMesh; @@ -401,9 +403,13 @@ bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const g face = subMeshFace; surfaceNormal = subMeshSurfaceNormal; extraInfo = geometry.getModelNameOfMesh(subMeshIndex); + + intersectedSubMesh = true; } } } + + subMeshIndex++; } _mutex.unlock(); @@ -451,18 +457,8 @@ bool Model::convexHullContains(glm::vec3 point) { int subMeshIndex = 0; foreach(const AABox& subMeshBox, _calculatedMeshBoxes) { if (subMeshBox.contains(point)) { - bool insideMesh = true; - // To be inside the sub mesh, we need to be behind every triangles' planes - const QVector& meshTriangles = _calculatedMeshTriangles[subMeshIndex]; - foreach (const Triangle& triangle, meshTriangles) { - if (!isPointBehindTrianglesPlane(point, triangle.v0, triangle.v1, triangle.v2)) { - // it's not behind at least one so we bail - insideMesh = false; - break; - } - } - if (insideMesh) { + if (_meshTriangleSets[subMeshIndex].convexHullContains(point)) { // It's inside this mesh, return true. _mutex.unlock(); return true; @@ -486,12 +482,20 @@ void Model::recalculateMeshBoxes(bool pickAgainstTriangles) { bool calculatedMeshTrianglesNeeded = pickAgainstTriangles && !_calculatedMeshTrianglesValid; if (!_calculatedMeshBoxesValid || calculatedMeshTrianglesNeeded || (!_calculatedMeshPartBoxesValid && pickAgainstTriangles) ) { + + if (pickAgainstTriangles) { + qDebug() << "RECALCULATING triangles!"; + } else { + qDebug() << "RECALCULATING boxes!"; + } + const FBXGeometry& geometry = getFBXGeometry(); int numberOfMeshes = geometry.meshes.size(); _calculatedMeshBoxes.resize(numberOfMeshes); - _calculatedMeshTriangles.clear(); - _calculatedMeshTriangles.resize(numberOfMeshes); _calculatedMeshPartBoxes.clear(); + _meshTriangleSets.clear(); + _meshTriangleSets.resize(numberOfMeshes); + for (int i = 0; i < numberOfMeshes; i++) { const FBXMesh& mesh = geometry.meshes.at(i); Extents scaledMeshExtents = calculateScaledOffsetExtents(mesh.meshExtents, _translation, _rotation); @@ -499,6 +503,8 @@ void Model::recalculateMeshBoxes(bool pickAgainstTriangles) { _calculatedMeshBoxes[i] = AABox(scaledMeshExtents); if (pickAgainstTriangles) { + auto& thisMeshTriangleSet = _meshTriangleSets[i]; + QVector thisMeshTriangles; for (int j = 0; j < mesh.parts.size(); j++) { const FBXMeshPart& part = mesh.parts.at(j); @@ -550,6 +556,9 @@ void Model::recalculateMeshBoxes(bool pickAgainstTriangles) { thisMeshTriangles.push_back(tri1); thisMeshTriangles.push_back(tri2); + thisMeshTriangleSet.insertTriangle(tri1); + thisMeshTriangleSet.insertTriangle(tri2); + } } @@ -582,11 +591,13 @@ void Model::recalculateMeshBoxes(bool pickAgainstTriangles) { Triangle tri = { v0, v1, v2 }; thisMeshTriangles.push_back(tri); + + thisMeshTriangleSet.insertTriangle(tri); + } } _calculatedMeshPartBoxes[QPair(i, j)] = thisPartBounds; } - _calculatedMeshTriangles[i] = thisMeshTriangles; _calculatedMeshPartBoxesValid = true; } } diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index 7c373274e4..bc3cf0e521 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -28,6 +28,7 @@ #include #include #include +#include #include "GeometryCache.h" #include "TextureCache.h" @@ -362,8 +363,8 @@ protected: bool _calculatedMeshPartBoxesValid; QVector _calculatedMeshBoxes; // world coordinate AABoxes for all sub mesh boxes bool _calculatedMeshBoxesValid; + QVector< TriangleSet > _meshTriangleSets; // world coordinate triangles for all sub meshes - QVector< QVector > _calculatedMeshTriangles; // world coordinate triangles for all sub meshes bool _calculatedMeshTrianglesValid; QMutex _mutex; diff --git a/libraries/shared/src/AABox.h b/libraries/shared/src/AABox.h index 2f0b09d67a..ccc7b6e302 100644 --- a/libraries/shared/src/AABox.h +++ b/libraries/shared/src/AABox.h @@ -109,6 +109,8 @@ public: bool isInvalid() const { return _corner == INFINITY_VECTOR; } + void clear() { _corner = INFINITY_VECTOR; _scale = glm::vec3(0.0f); } + private: glm::vec3 getClosestPointOnFace(const glm::vec3& point, BoxFace face) const; glm::vec3 getClosestPointOnFace(const glm::vec4& origin, const glm::vec4& direction, BoxFace face) const; diff --git a/libraries/shared/src/TriangleSet.cpp b/libraries/shared/src/TriangleSet.cpp new file mode 100644 index 0000000000..3264c259d3 --- /dev/null +++ b/libraries/shared/src/TriangleSet.cpp @@ -0,0 +1,69 @@ +// +// TriangleSet.cpp +// libraries/entities/src +// +// Created by Brad Hefta-Gaub on 3/2/2017. +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "GLMHelpers.h" +#include "TriangleSet.h" + +void TriangleSet::insertTriangle(const Triangle& t) { + _triangles.push_back(t); + + _bounds += t.v0; + _bounds += t.v1; + _bounds += t.v2; +} + +void TriangleSet::clear() { + _triangles.clear(); + _bounds.clear(); +} + +// Determine of the given ray (origin/direction) in model space intersects with any triangles +// in the set. If an intersection occurs, the distance and surface normal will be provided. +bool TriangleSet::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, + float& distance, glm::vec3& surfaceNormal) const { + + float bestDistance = std::numeric_limits::max(); + float thisTriangleDistance; + bool intersectedSomething = false; + + for (const auto& triangle : _triangles) { + if (findRayTriangleIntersection(origin, direction, triangle, thisTriangleDistance)) { + if (thisTriangleDistance < bestDistance) { + bestDistance = thisTriangleDistance; + intersectedSomething = true; + surfaceNormal = triangle.getNormal(); + distance = bestDistance; + //face = subMeshFace; + //extraInfo = geometry.getModelNameOfMesh(subMeshIndex); + } + } + } + return intersectedSomething; +} + + +bool TriangleSet::convexHullContains(const glm::vec3& point) const { + if (!_bounds.contains(point)) { + return false; + } + + bool insideMesh = true; // optimistic + for (const auto& triangle : _triangles) { + if (!isPointBehindTrianglesPlane(point, triangle.v0, triangle.v1, triangle.v2)) { + // it's not behind at least one so we bail + insideMesh = false; + break; + } + + } + return insideMesh; +} + diff --git a/libraries/shared/src/TriangleSet.h b/libraries/shared/src/TriangleSet.h new file mode 100644 index 0000000000..3aef3966b6 --- /dev/null +++ b/libraries/shared/src/TriangleSet.h @@ -0,0 +1,33 @@ +// +// TriangleSet.h +// libraries/entities/src +// +// Created by Brad Hefta-Gaub on 3/2/2017. +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include + +#include "AABox.h" +#include "GeometryUtil.h" + +class TriangleSet { +public: + void insertTriangle(const Triangle& t); + void clear(); + + // Determine of the given ray (origin/direction) in model space intersects with any triangles + // in the set. If an intersection occurs, the distance and surface normal will be provided. + bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, + float& distance, glm::vec3& surfaceNormal) const; + + bool convexHullContains(const glm::vec3& point) const; // this point is "inside" all triangles + const AABox& getBounds() const; + +private: + QVector _triangles; + AABox _bounds; +};