From e086792eac89af80dd7a48131b1cf1117fb785ca Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 12 Jul 2016 17:09:33 -0700 Subject: [PATCH 01/45] enforce coding standards --- libraries/physics/src/ShapeManager.cpp | 4 ++-- libraries/physics/src/ShapeManager.h | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/libraries/physics/src/ShapeManager.cpp b/libraries/physics/src/ShapeManager.cpp index 4fa660239c..35046adcfd 100644 --- a/libraries/physics/src/ShapeManager.cpp +++ b/libraries/physics/src/ShapeManager.cpp @@ -30,13 +30,13 @@ ShapeManager::~ShapeManager() { btCollisionShape* ShapeManager::getShape(const ShapeInfo& info) { if (info.getType() == SHAPE_TYPE_NONE) { - return NULL; + return nullptr; } const float MIN_SHAPE_DIAGONAL_SQUARED = 3.0e-4f; // 1 cm cube if (4.0f * glm::length2(info.getHalfExtents()) < MIN_SHAPE_DIAGONAL_SQUARED) { // tiny shapes are not supported // qCDebug(physics) << "ShapeManager::getShape -- not making shape due to size" << diagonal; - return NULL; + return nullptr; } DoubleHashKey key = info.getHash(); diff --git a/libraries/physics/src/ShapeManager.h b/libraries/physics/src/ShapeManager.h index 0c411f5f62..cdb2b78789 100644 --- a/libraries/physics/src/ShapeManager.h +++ b/libraries/physics/src/ShapeManager.h @@ -43,11 +43,12 @@ public: private: bool releaseShapeByKey(const DoubleHashKey& key); - struct ShapeReference { + class ShapeReference { + public: int refCount; btCollisionShape* shape; DoubleHashKey key; - ShapeReference() : refCount(0), shape(NULL) {} + ShapeReference() : refCount(0), shape(nullptr) {} }; btHashMap _shapeMap; From af1be8ccd4e6a1a309d9ceb613f037eba3d24657 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 12 Jul 2016 17:26:17 -0700 Subject: [PATCH 02/45] remove whitespace --- libraries/shared/src/DoubleHashKey.cpp | 6 +++--- libraries/shared/src/DoubleHashKey.h | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/libraries/shared/src/DoubleHashKey.cpp b/libraries/shared/src/DoubleHashKey.cpp index 794604d21b..ded2f073eb 100644 --- a/libraries/shared/src/DoubleHashKey.cpp +++ b/libraries/shared/src/DoubleHashKey.cpp @@ -12,7 +12,7 @@ #include "DoubleHashKey.h" const uint32_t NUM_PRIMES = 64; -const uint32_t PRIMES[] = { +const uint32_t PRIMES[] = { 4194301U, 4194287U, 4194277U, 4194271U, 4194247U, 4194217U, 4194199U, 4194191U, 4194187U, 4194181U, 4194173U, 4194167U, 4194143U, 4194137U, 4194131U, 4194107U, 4194103U, 4194023U, 4194011U, 4194007U, 4193977U, 4193971U, 4193963U, 4193957U, @@ -27,8 +27,8 @@ uint32_t DoubleHashKey::hashFunction(uint32_t value, uint32_t primeIndex) { uint32_t hash = PRIMES[primeIndex % NUM_PRIMES] * (value + 1U); hash += ~(hash << 15); hash ^= (hash >> 10); - hash += (hash << 3); - hash ^= (hash >> 6); + hash += (hash << 3); + hash ^= (hash >> 6); hash += ~(hash << 11); return hash ^ (hash >> 16); } diff --git a/libraries/shared/src/DoubleHashKey.h b/libraries/shared/src/DoubleHashKey.h index 3b08bf7c1a..ca92a7197f 100644 --- a/libraries/shared/src/DoubleHashKey.h +++ b/libraries/shared/src/DoubleHashKey.h @@ -22,9 +22,9 @@ public: DoubleHashKey() : _hash(0), _hash2(0) { } - DoubleHashKey(uint32_t value, uint32_t primeIndex = 0) : - _hash(hashFunction(value, primeIndex)), - _hash2(hashFunction2(value)) { + DoubleHashKey(uint32_t value, uint32_t primeIndex = 0) : + _hash(hashFunction(value, primeIndex)), + _hash2(hashFunction2(value)) { } void clear() { _hash = 0; _hash2 = 0; } From 9f26836b436d5d31428650216be7ae43abce0e41 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 13 Jul 2016 14:03:53 -0700 Subject: [PATCH 03/45] added basic CollisionGeometryCache container --- .../physics/src/CollisionGeometryCache.cpp | 79 +++++++++++++++++++ .../physics/src/CollisionGeometryCache.h | 62 +++++++++++++++ 2 files changed, 141 insertions(+) create mode 100644 libraries/physics/src/CollisionGeometryCache.cpp create mode 100644 libraries/physics/src/CollisionGeometryCache.h diff --git a/libraries/physics/src/CollisionGeometryCache.cpp b/libraries/physics/src/CollisionGeometryCache.cpp new file mode 100644 index 0000000000..b474d44c32 --- /dev/null +++ b/libraries/physics/src/CollisionGeometryCache.cpp @@ -0,0 +1,79 @@ +// +// CollisionGeometryCache.cpp +// libraries/physcis/src +// +// Created by Andrew Meadows 2016.07.13 +// Copyright 2016 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 + +//#include "ShapeFactory.h" +#include "CollisionGeometryCache.h" + +int foo = 0; + +GeometryPointer createGeometryFromShape(CollisionGeometryCache::Key key) { + return std::make_shared(++foo); +} + +CollisionGeometryCache::CollisionGeometryCache() { +} + +CollisionGeometryCache::~CollisionGeometryCache() { + _geometryMap.clear(); + _pendingGarbage.clear(); +} + +GeometryPointer CollisionGeometryCache::getGeometry(CollisionGeometryCache::Key key) { + if (!key) { + return GeometryPointer(); + } + GeometryPointer geometry = 0; + + CollisionGeometryMap::const_iterator itr = _geometryMap.find(key); + if (itr != _geometryMap.end()) { + // make geometry and add it to map + geometry = createGeometryFromShape(key); + if (geometry) { + _geometryMap.insert(std::make_pair(key, geometry)); + } + } + return geometry; +} + +bool CollisionGeometryCache::releaseGeometry(CollisionGeometryCache::Key key) { + if (!key) { + return false; + } + CollisionGeometryMap::const_iterator itr = _geometryMap.find(key); + if (itr != _geometryMap.end()) { + assert((*itr).second.use_count() != 1); + if ((*itr).second.use_count() == 2) { + // we hold all of the references inside the cache so we'll try to delete later + _pendingGarbage.push_back(key); + } + return true; + } + return false; +} + +void CollisionGeometryCache::collectGarbage() { + int numShapes = _pendingGarbage.size(); + for (int i = 0; i < numShapes; ++i) { + CollisionGeometryCache::Key key = _pendingGarbage[i]; + CollisionGeometryMap::const_iterator itr = _geometryMap.find(key); + if (itr != _geometryMap.end()) { + if ((*itr).second.use_count() == 1) { + // we hold the only reference + _geometryMap.erase(itr); + } + } + } + _pendingGarbage.clear(); +} + diff --git a/libraries/physics/src/CollisionGeometryCache.h b/libraries/physics/src/CollisionGeometryCache.h new file mode 100644 index 0000000000..f6a7a6f3e8 --- /dev/null +++ b/libraries/physics/src/CollisionGeometryCache.h @@ -0,0 +1,62 @@ +// +// CollisionGeometryCache.h +// libraries/physcis/src +// +// Created by Andrew Meadows 2016.07.13 +// Copyright 2016 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 +// + +#ifndef hifi_CollisionGeometryCache +#define hifi_CollisionGeometryCache + +#include +#include +#include +//#include +//#include + +class btCollisionShape; + +// BEGIN TEST HACK +using GeometryPointer = std::shared_ptr; +// END TEST HACK + +namespace std { + template <> + struct hash { + std::size_t operator()(btCollisionShape* key) const { + return (hash()((void*)key)); + } + }; +} + +class CollisionGeometryCache { +public: + using Key = btCollisionShape const *; + + CollisionGeometryCache(); + ~CollisionGeometryCache(); + + /// \return pointer to geometry + GeometryPointer getGeometry(Key key); + + /// \return true if geometry was found and released + bool releaseGeometry(Key key); + + /// delete geometries that have zero references + void collectGarbage(); + + // validation methods + uint32_t getNumGeometries() const { return (uint32_t)_geometryMap.size(); } + bool hasGeometry(Key key) const { return _geometryMap.find(key) == _geometryMap.end(); } + +private: + using CollisionGeometryMap = std::unordered_map; + CollisionGeometryMap _geometryMap; + std::vector _pendingGarbage; +}; + +#endif // hifi_CollisionGeometryCache From 8d3f592e68b6c435531c0038dd55351467ab378c Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 13 Jul 2016 15:17:50 -0700 Subject: [PATCH 04/45] rename class to be more correct --- ...Cache.cpp => CollisionRenderMeshCache.cpp} | 30 +++++++++---------- ...etryCache.h => CollisionRenderMeshCache.h} | 28 ++++++++--------- 2 files changed, 28 insertions(+), 30 deletions(-) rename libraries/physics/src/{CollisionGeometryCache.cpp => CollisionRenderMeshCache.cpp} (62%) rename libraries/physics/src/{CollisionGeometryCache.h => CollisionRenderMeshCache.h} (60%) diff --git a/libraries/physics/src/CollisionGeometryCache.cpp b/libraries/physics/src/CollisionRenderMeshCache.cpp similarity index 62% rename from libraries/physics/src/CollisionGeometryCache.cpp rename to libraries/physics/src/CollisionRenderMeshCache.cpp index b474d44c32..14d02951a1 100644 --- a/libraries/physics/src/CollisionGeometryCache.cpp +++ b/libraries/physics/src/CollisionRenderMeshCache.cpp @@ -1,5 +1,5 @@ // -// CollisionGeometryCache.cpp +// CollisionRenderMeshCache.cpp // libraries/physcis/src // // Created by Andrew Meadows 2016.07.13 @@ -13,32 +13,32 @@ //#include //#include "ShapeFactory.h" -#include "CollisionGeometryCache.h" +#include "CollisionRenderMeshCache.h" int foo = 0; -GeometryPointer createGeometryFromShape(CollisionGeometryCache::Key key) { +MeshPointer createMeshFromShape(CollisionRenderMeshCache::Key key) { return std::make_shared(++foo); } -CollisionGeometryCache::CollisionGeometryCache() { +CollisionRenderMeshCache::CollisionRenderMeshCache() { } -CollisionGeometryCache::~CollisionGeometryCache() { +CollisionRenderMeshCache::~CollisionRenderMeshCache() { _geometryMap.clear(); _pendingGarbage.clear(); } -GeometryPointer CollisionGeometryCache::getGeometry(CollisionGeometryCache::Key key) { +MeshPointer CollisionRenderMeshCache::getMesh(CollisionRenderMeshCache::Key key) { if (!key) { - return GeometryPointer(); + return MeshPointer(); } - GeometryPointer geometry = 0; + MeshPointer geometry = 0; - CollisionGeometryMap::const_iterator itr = _geometryMap.find(key); + CollisionMeshMap::const_iterator itr = _geometryMap.find(key); if (itr != _geometryMap.end()) { // make geometry and add it to map - geometry = createGeometryFromShape(key); + geometry = createMeshFromShape(key); if (geometry) { _geometryMap.insert(std::make_pair(key, geometry)); } @@ -46,11 +46,11 @@ GeometryPointer CollisionGeometryCache::getGeometry(CollisionGeometryCache::Key return geometry; } -bool CollisionGeometryCache::releaseGeometry(CollisionGeometryCache::Key key) { +bool CollisionRenderMeshCache::releaseMesh(CollisionRenderMeshCache::Key key) { if (!key) { return false; } - CollisionGeometryMap::const_iterator itr = _geometryMap.find(key); + CollisionMeshMap::const_iterator itr = _geometryMap.find(key); if (itr != _geometryMap.end()) { assert((*itr).second.use_count() != 1); if ((*itr).second.use_count() == 2) { @@ -62,11 +62,11 @@ bool CollisionGeometryCache::releaseGeometry(CollisionGeometryCache::Key key) { return false; } -void CollisionGeometryCache::collectGarbage() { +void CollisionRenderMeshCache::collectGarbage() { int numShapes = _pendingGarbage.size(); for (int i = 0; i < numShapes; ++i) { - CollisionGeometryCache::Key key = _pendingGarbage[i]; - CollisionGeometryMap::const_iterator itr = _geometryMap.find(key); + CollisionRenderMeshCache::Key key = _pendingGarbage[i]; + CollisionMeshMap::const_iterator itr = _geometryMap.find(key); if (itr != _geometryMap.end()) { if ((*itr).second.use_count() == 1) { // we hold the only reference diff --git a/libraries/physics/src/CollisionGeometryCache.h b/libraries/physics/src/CollisionRenderMeshCache.h similarity index 60% rename from libraries/physics/src/CollisionGeometryCache.h rename to libraries/physics/src/CollisionRenderMeshCache.h index f6a7a6f3e8..3b39ef80f8 100644 --- a/libraries/physics/src/CollisionGeometryCache.h +++ b/libraries/physics/src/CollisionRenderMeshCache.h @@ -1,5 +1,5 @@ // -// CollisionGeometryCache.h +// CollisionRenderMeshCache.h // libraries/physcis/src // // Created by Andrew Meadows 2016.07.13 @@ -9,19 +9,17 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#ifndef hifi_CollisionGeometryCache -#define hifi_CollisionGeometryCache +#ifndef hifi_CollisionRenderMeshCache_h +#define hifi_CollisionRenderMeshCache_h #include #include #include -//#include -//#include class btCollisionShape; // BEGIN TEST HACK -using GeometryPointer = std::shared_ptr; +using MeshPointer = std::shared_ptr; // END TEST HACK namespace std { @@ -33,30 +31,30 @@ namespace std { }; } -class CollisionGeometryCache { +class CollisionRenderMeshCache { public: using Key = btCollisionShape const *; - CollisionGeometryCache(); - ~CollisionGeometryCache(); + CollisionRenderMeshCache(); + ~CollisionRenderMeshCache(); /// \return pointer to geometry - GeometryPointer getGeometry(Key key); + MeshPointer getMesh(Key key); /// \return true if geometry was found and released - bool releaseGeometry(Key key); + bool releaseMesh(Key key); /// delete geometries that have zero references void collectGarbage(); // validation methods uint32_t getNumGeometries() const { return (uint32_t)_geometryMap.size(); } - bool hasGeometry(Key key) const { return _geometryMap.find(key) == _geometryMap.end(); } + bool hasMesh(Key key) const { return _geometryMap.find(key) == _geometryMap.end(); } private: - using CollisionGeometryMap = std::unordered_map; - CollisionGeometryMap _geometryMap; + using CollisionMeshMap = std::unordered_map; + CollisionMeshMap _geometryMap; std::vector _pendingGarbage; }; -#endif // hifi_CollisionGeometryCache +#endif // hifi_CollisionRenderMeshCache_h From d59c997e64b994b2b32d928d2c8be36e06ceffc7 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 13 Jul 2016 16:32:22 -0700 Subject: [PATCH 05/45] remove stubbery, make physics lib depend on model --- libraries/model/src/model/Geometry.h | 2 +- libraries/physics/CMakeLists.txt | 2 +- .../physics/src/CollisionRenderMeshCache.cpp | 47 ++++++++++++------- .../physics/src/CollisionRenderMeshCache.h | 10 ++-- 4 files changed, 36 insertions(+), 25 deletions(-) diff --git a/libraries/model/src/model/Geometry.h b/libraries/model/src/model/Geometry.h index a3e95c68c0..4256f0be03 100755 --- a/libraries/model/src/model/Geometry.h +++ b/libraries/model/src/model/Geometry.h @@ -130,7 +130,7 @@ protected: void evalVertexStream(); }; -typedef std::shared_ptr< Mesh > MeshPointer; +using MeshPointer = std::shared_ptr< Mesh >; class Geometry { diff --git a/libraries/physics/CMakeLists.txt b/libraries/physics/CMakeLists.txt index b734c9ac2e..7733c019e0 100644 --- a/libraries/physics/CMakeLists.txt +++ b/libraries/physics/CMakeLists.txt @@ -1,5 +1,5 @@ set(TARGET_NAME physics) setup_hifi_library() -link_hifi_libraries(shared fbx entities) +link_hifi_libraries(shared fbx entities model) target_bullet() diff --git a/libraries/physics/src/CollisionRenderMeshCache.cpp b/libraries/physics/src/CollisionRenderMeshCache.cpp index 14d02951a1..e563c05e90 100644 --- a/libraries/physics/src/CollisionRenderMeshCache.cpp +++ b/libraries/physics/src/CollisionRenderMeshCache.cpp @@ -9,16 +9,31 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "CollisionRenderMeshCache.h" + #include //#include //#include "ShapeFactory.h" -#include "CollisionRenderMeshCache.h" +#include -int foo = 0; -MeshPointer createMeshFromShape(CollisionRenderMeshCache::Key key) { - return std::make_shared(++foo); +model::MeshPointer createMeshFromShape(const btCollisionShape* shape) { + if (!shape) { + return std::make_shared(); + } + int32_t shapeType = shape->getShapeType(); + if (shapeType == (int32_t)COMPOUND_SHAPE_PROXYTYPE) { + const btCompoundShape* compoundShape = static_cast(shape); + int32_t numSubShapes = compoundShape->getNumChildShapes(); + for (int i = 0; i < numSubShapes; ++i) { + const btCollisionShape* childShape = compoundShape->getChildShape(i); + std::cout << "adebug " << i << " " << (void*)(childShape) << std::endl; // adebug + } + } else if (shape->isConvex()) { + std::cout << "adebug " << (void*)(shape)<< std::endl; // adebug + } + return std::make_shared(); } CollisionRenderMeshCache::CollisionRenderMeshCache() { @@ -29,21 +44,19 @@ CollisionRenderMeshCache::~CollisionRenderMeshCache() { _pendingGarbage.clear(); } -MeshPointer CollisionRenderMeshCache::getMesh(CollisionRenderMeshCache::Key key) { - if (!key) { - return MeshPointer(); - } - MeshPointer geometry = 0; - - CollisionMeshMap::const_iterator itr = _geometryMap.find(key); - if (itr != _geometryMap.end()) { - // make geometry and add it to map - geometry = createMeshFromShape(key); - if (geometry) { - _geometryMap.insert(std::make_pair(key, geometry)); +model::MeshPointer CollisionRenderMeshCache::getMesh(CollisionRenderMeshCache::Key key) { + model::MeshPointer mesh; + if (key) { + CollisionMeshMap::const_iterator itr = _geometryMap.find(key); + if (itr != _geometryMap.end()) { + // make mesh and add it to map + mesh = createMeshFromShape(key); + if (mesh) { + _geometryMap.insert(std::make_pair(key, mesh)); + } } } - return geometry; + return mesh; } bool CollisionRenderMeshCache::releaseMesh(CollisionRenderMeshCache::Key key) { diff --git a/libraries/physics/src/CollisionRenderMeshCache.h b/libraries/physics/src/CollisionRenderMeshCache.h index 3b39ef80f8..03083048d8 100644 --- a/libraries/physics/src/CollisionRenderMeshCache.h +++ b/libraries/physics/src/CollisionRenderMeshCache.h @@ -16,11 +16,9 @@ #include #include -class btCollisionShape; +#include -// BEGIN TEST HACK -using MeshPointer = std::shared_ptr; -// END TEST HACK +class btCollisionShape; namespace std { template <> @@ -39,7 +37,7 @@ public: ~CollisionRenderMeshCache(); /// \return pointer to geometry - MeshPointer getMesh(Key key); + model::MeshPointer getMesh(Key key); /// \return true if geometry was found and released bool releaseMesh(Key key); @@ -52,7 +50,7 @@ public: bool hasMesh(Key key) const { return _geometryMap.find(key) == _geometryMap.end(); } private: - using CollisionMeshMap = std::unordered_map; + using CollisionMeshMap = std::unordered_map; CollisionMeshMap _geometryMap; std::vector _pendingGarbage; }; From d0295f3876204e00bd3677c53e82497636e68e20 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 14 Jul 2016 11:43:23 -0700 Subject: [PATCH 06/45] remove cruft include --- libraries/physics/src/ShapeFactory.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/physics/src/ShapeFactory.cpp b/libraries/physics/src/ShapeFactory.cpp index 67072d46d4..8576a9caee 100644 --- a/libraries/physics/src/ShapeFactory.cpp +++ b/libraries/physics/src/ShapeFactory.cpp @@ -10,7 +10,6 @@ // #include -#include #include // for MILLIMETERS_PER_METER From 1e95e489cba359b80dd4566bf579a419b323ba13 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 14 Jul 2016 11:43:33 -0700 Subject: [PATCH 07/45] make mesh around btConvexShape, copy to model::Mesh --- .../physics/src/CollisionRenderMeshCache.cpp | 59 +++++++++++++++++-- .../physics/src/CollisionRenderMeshCache.h | 2 +- 2 files changed, 55 insertions(+), 6 deletions(-) diff --git a/libraries/physics/src/CollisionRenderMeshCache.cpp b/libraries/physics/src/CollisionRenderMeshCache.cpp index e563c05e90..c7ce892e52 100644 --- a/libraries/physics/src/CollisionRenderMeshCache.cpp +++ b/libraries/physics/src/CollisionRenderMeshCache.cpp @@ -12,28 +12,77 @@ #include "CollisionRenderMeshCache.h" #include -//#include -//#include "ShapeFactory.h" #include +#include +#include // for MAX_HULL_POINTS + +float verts[3 * MAX_HULL_POINTS]; + +void copyHullToMesh(const btShapeHull& hull, model::MeshPointer mesh) { + if ((bool)mesh) { + const uint32_t* hullIndices = hull.getIndexPointer(); + int32_t numIndices = hull.numIndices(); + assert(numIndices <= 6 * MAX_HULL_POINTS); + + { // new part + model::Mesh::Part part; + part._startIndex = mesh->getIndexBuffer().getNumElements(); + part._numIndices = (model::Index)numIndices; + part._baseVertex = mesh->getVertexBuffer().getNumElements(); + + gpu::BufferView::Size numBytes = sizeof(model::Mesh::Part); + const gpu::Byte* data = reinterpret_cast(&part); + mesh->getPartBuffer()._buffer->append(numBytes, data); + } + + { // new vertices + const btVector3* hullVertices = hull.getVertexPointer(); + int32_t numVertices = hull.numVertices(); + assert(numVertices <= MAX_HULL_POINTS); + for (int32_t i = 0; i < numVertices; ++i) { + float* data = verts + 3 * i; + data[0] = hullVertices[i].getX(); + data[1] = hullVertices[i].getY(); + data[2] = hullVertices[i].getZ(); + } + + gpu::BufferView::Size numBytes = sizeof(float) * (3 * numVertices); + const gpu::Byte* data = reinterpret_cast(verts); + mesh->getVertexBuffer()._buffer->append(numBytes, data); + } + + { // new indices + gpu::BufferView::Size numBytes = (gpu::BufferView::Size)(sizeof(uint32_t) * hull.numIndices()); + const gpu::Byte* data = reinterpret_cast(hullIndices); + mesh->getIndexBuffer()._buffer->append(numBytes, data); + } + } +} model::MeshPointer createMeshFromShape(const btCollisionShape* shape) { if (!shape) { return std::make_shared(); } + model::MeshPointer mesh = std::make_shared(); int32_t shapeType = shape->getShapeType(); if (shapeType == (int32_t)COMPOUND_SHAPE_PROXYTYPE) { + const btScalar MARGIN = 0.0f; const btCompoundShape* compoundShape = static_cast(shape); int32_t numSubShapes = compoundShape->getNumChildShapes(); for (int i = 0; i < numSubShapes; ++i) { const btCollisionShape* childShape = compoundShape->getChildShape(i); - std::cout << "adebug " << i << " " << (void*)(childShape) << std::endl; // adebug + if (childShape->isConvex()) { + const btConvexShape* convexShape = static_cast(childShape); + btShapeHull shapeHull(convexShape); + shapeHull.buildHull(MARGIN); + copyHullToMesh(shapeHull, mesh); + } } } else if (shape->isConvex()) { - std::cout << "adebug " << (void*)(shape)<< std::endl; // adebug } - return std::make_shared(); + return mesh; } CollisionRenderMeshCache::CollisionRenderMeshCache() { diff --git a/libraries/physics/src/CollisionRenderMeshCache.h b/libraries/physics/src/CollisionRenderMeshCache.h index 03083048d8..05da3750c3 100644 --- a/libraries/physics/src/CollisionRenderMeshCache.h +++ b/libraries/physics/src/CollisionRenderMeshCache.h @@ -31,7 +31,7 @@ namespace std { class CollisionRenderMeshCache { public: - using Key = btCollisionShape const *; + using Key = const btCollisionShape*; CollisionRenderMeshCache(); ~CollisionRenderMeshCache(); From 06d40afeacbaacb13de1e0b2e924481d9282b00f Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 14 Jul 2016 13:30:57 -0700 Subject: [PATCH 08/45] don't forget to use the transform of child shapes --- .../physics/src/CollisionRenderMeshCache.cpp | 102 +++++++++--------- 1 file changed, 53 insertions(+), 49 deletions(-) diff --git a/libraries/physics/src/CollisionRenderMeshCache.cpp b/libraries/physics/src/CollisionRenderMeshCache.cpp index c7ce892e52..6cf2f91ce2 100644 --- a/libraries/physics/src/CollisionRenderMeshCache.cpp +++ b/libraries/physics/src/CollisionRenderMeshCache.cpp @@ -20,67 +20,71 @@ float verts[3 * MAX_HULL_POINTS]; -void copyHullToMesh(const btShapeHull& hull, model::MeshPointer mesh) { - if ((bool)mesh) { - const uint32_t* hullIndices = hull.getIndexPointer(); - int32_t numIndices = hull.numIndices(); - assert(numIndices <= 6 * MAX_HULL_POINTS); +void copyShapeToMesh(const btTransform& transform, const btConvexShape* shape, model::MeshPointer mesh) { + assert((bool)mesh); + assert(shape); - { // new part - model::Mesh::Part part; - part._startIndex = mesh->getIndexBuffer().getNumElements(); - part._numIndices = (model::Index)numIndices; - part._baseVertex = mesh->getVertexBuffer().getNumElements(); + btShapeHull hull(shape); + const btScalar MARGIN = 0.0f; + hull.buildHull(MARGIN); - gpu::BufferView::Size numBytes = sizeof(model::Mesh::Part); - const gpu::Byte* data = reinterpret_cast(&part); - mesh->getPartBuffer()._buffer->append(numBytes, data); + const uint32_t* hullIndices = hull.getIndexPointer(); + int32_t numIndices = hull.numIndices(); + assert(numIndices <= 6 * MAX_HULL_POINTS); + + { // new part + model::Mesh::Part part; + part._startIndex = mesh->getIndexBuffer().getNumElements(); + part._numIndices = (model::Index)numIndices; + part._baseVertex = mesh->getVertexBuffer().getNumElements(); + + gpu::BufferView::Size numBytes = sizeof(model::Mesh::Part); + const gpu::Byte* data = reinterpret_cast(&part); + mesh->getPartBuffer()._buffer->append(numBytes, data); + } + + { // new vertices + const btVector3* hullVertices = hull.getVertexPointer(); + int32_t numVertices = hull.numVertices(); + assert(numVertices <= MAX_HULL_POINTS); + for (int32_t i = 0; i < numVertices; ++i) { + btVector3 transformedPoint = transform * hullVertices[i]; + memcpy(transformedPoint.m_floats, verts + 3 * i, 3 * sizeof(float)); + //data[0] = transformedPoint.getX(); + //data[1] = transformedPoint.getY(); + //data[2] = transformedPoint.getZ(); } - { // new vertices - const btVector3* hullVertices = hull.getVertexPointer(); - int32_t numVertices = hull.numVertices(); - assert(numVertices <= MAX_HULL_POINTS); - for (int32_t i = 0; i < numVertices; ++i) { - float* data = verts + 3 * i; - data[0] = hullVertices[i].getX(); - data[1] = hullVertices[i].getY(); - data[2] = hullVertices[i].getZ(); - } + gpu::BufferView::Size numBytes = sizeof(float) * (3 * numVertices); + const gpu::Byte* data = reinterpret_cast(verts); + mesh->getVertexBuffer()._buffer->append(numBytes, data); + } - gpu::BufferView::Size numBytes = sizeof(float) * (3 * numVertices); - const gpu::Byte* data = reinterpret_cast(verts); - mesh->getVertexBuffer()._buffer->append(numBytes, data); - } - - { // new indices - gpu::BufferView::Size numBytes = (gpu::BufferView::Size)(sizeof(uint32_t) * hull.numIndices()); - const gpu::Byte* data = reinterpret_cast(hullIndices); - mesh->getIndexBuffer()._buffer->append(numBytes, data); - } + { // new indices + gpu::BufferView::Size numBytes = (gpu::BufferView::Size)(sizeof(uint32_t) * hull.numIndices()); + const gpu::Byte* data = reinterpret_cast(hullIndices); + mesh->getIndexBuffer()._buffer->append(numBytes, data); } } model::MeshPointer createMeshFromShape(const btCollisionShape* shape) { - if (!shape) { - return std::make_shared(); - } model::MeshPointer mesh = std::make_shared(); - int32_t shapeType = shape->getShapeType(); - if (shapeType == (int32_t)COMPOUND_SHAPE_PROXYTYPE) { - const btScalar MARGIN = 0.0f; - const btCompoundShape* compoundShape = static_cast(shape); - int32_t numSubShapes = compoundShape->getNumChildShapes(); - for (int i = 0; i < numSubShapes; ++i) { - const btCollisionShape* childShape = compoundShape->getChildShape(i); - if (childShape->isConvex()) { - const btConvexShape* convexShape = static_cast(childShape); - btShapeHull shapeHull(convexShape); - shapeHull.buildHull(MARGIN); - copyHullToMesh(shapeHull, mesh); + if (shape) { + int32_t shapeType = shape->getShapeType(); + if (shapeType == (int32_t)COMPOUND_SHAPE_PROXYTYPE) { + const btCompoundShape* compoundShape = static_cast(shape); + int32_t numSubShapes = compoundShape->getNumChildShapes(); + for (int i = 0; i < numSubShapes; ++i) { + const btCollisionShape* childShape = compoundShape->getChildShape(i); + if (childShape->isConvex()) { + const btConvexShape* convexShape = static_cast(childShape); + copyShapeToMesh(compoundShape->getChildTransform(i), convexShape, mesh); + } } + } else if (shape->isConvex()) { + const btConvexShape* convexShape = static_cast(shape); + copyShapeToMesh(btTransform(), convexShape, mesh); } - } else if (shape->isConvex()) { } return mesh; } From b79af55e16f56f9b5e20a3e73e7fb6e4d87b5379 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 14 Jul 2016 13:35:03 -0700 Subject: [PATCH 09/45] fix ref accounting for garbage collection --- libraries/physics/src/CollisionRenderMeshCache.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/physics/src/CollisionRenderMeshCache.cpp b/libraries/physics/src/CollisionRenderMeshCache.cpp index 6cf2f91ce2..3714d9d464 100644 --- a/libraries/physics/src/CollisionRenderMeshCache.cpp +++ b/libraries/physics/src/CollisionRenderMeshCache.cpp @@ -119,7 +119,7 @@ bool CollisionRenderMeshCache::releaseMesh(CollisionRenderMeshCache::Key key) { CollisionMeshMap::const_iterator itr = _geometryMap.find(key); if (itr != _geometryMap.end()) { assert((*itr).second.use_count() != 1); - if ((*itr).second.use_count() == 2) { + if ((*itr).second.use_count() == 1) { // we hold all of the references inside the cache so we'll try to delete later _pendingGarbage.push_back(key); } From e473edff4adc4b1458b6cab964ddd7c09d3af467 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 14 Jul 2016 14:04:26 -0700 Subject: [PATCH 10/45] fix shapeManagerTests --- tests/physics/src/ShapeManagerTests.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tests/physics/src/ShapeManagerTests.cpp b/tests/physics/src/ShapeManagerTests.cpp index c8805132fa..24d4a5ab35 100644 --- a/tests/physics/src/ShapeManagerTests.cpp +++ b/tests/physics/src/ShapeManagerTests.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include "ShapeManagerTests.h" @@ -197,6 +198,7 @@ void ShapeManagerTests::addCompoundShape() { ShapeInfo::PointCollection pointCollection; int numHulls = 5; glm::vec3 offsetNormal(1.0f, 0.0f, 0.0f); + Extents extents; for (int i = 0; i < numHulls; ++i) { glm::vec3 offset = (float)(i - numHulls/2) * offsetNormal; ShapeInfo::PointList pointList; @@ -204,13 +206,16 @@ void ShapeManagerTests::addCompoundShape() { for (int j = 0; j < numHullPoints; ++j) { glm::vec3 point = radius * tetrahedron[j] + offset; pointList.push_back(point); + extents.addPoint(point); } pointCollection.push_back(pointList); } // create the ShapeInfo ShapeInfo info; - info.setPointCollection(hulls); + glm::vec3 halfExtents = 0.5f * (extents.maximum - extents.minimum); + info.setParams(SHAPE_TYPE_COMPOUND, halfExtents); + info.setPointCollection(pointCollection); // create the shape ShapeManager shapeManager; From c1216cbcaf98fedfda93be43576fcb24a5cf87f8 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 14 Jul 2016 15:05:47 -0700 Subject: [PATCH 11/45] stubbery for CollisionRenderMeshCacheTests --- tests/physics/CMakeLists.txt | 2 +- .../src/CollisionRenderMeshCacheTests.cpp | 41 +++++++++++++++++++ .../src/CollisionRenderMeshCacheTests.h | 24 +++++++++++ 3 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 tests/physics/src/CollisionRenderMeshCacheTests.cpp create mode 100644 tests/physics/src/CollisionRenderMeshCacheTests.h diff --git a/tests/physics/CMakeLists.txt b/tests/physics/CMakeLists.txt index cc3df5ea8e..755886ebbf 100644 --- a/tests/physics/CMakeLists.txt +++ b/tests/physics/CMakeLists.txt @@ -2,7 +2,7 @@ # Declare dependencies macro (SETUP_TESTCASE_DEPENDENCIES) target_bullet() - link_hifi_libraries(shared physics) + link_hifi_libraries(shared physics gpu model) package_libraries_for_deployment() endmacro () diff --git a/tests/physics/src/CollisionRenderMeshCacheTests.cpp b/tests/physics/src/CollisionRenderMeshCacheTests.cpp new file mode 100644 index 0000000000..58b45f6400 --- /dev/null +++ b/tests/physics/src/CollisionRenderMeshCacheTests.cpp @@ -0,0 +1,41 @@ +// +// CollisionRenderMeshCacheTests.cpp +// tests/physics/src +// +// Created by Andrew Meadows on 2014.10.30 +// Copyright 2014 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 +#include + +#include "CollisionRenderMeshCacheTests.h" + +QTEST_MAIN(CollisionRenderMeshCacheTests) + + +void CollisionRenderMeshCacheTests::test001() { + CollisionRenderMeshCache cache; + + // create a compound shape + int32_t numSubShapes = 3; + + + // get the mesh + + // get the mesh again + + // forget the mesh once + + // collect garbage + + // forget the mesh a second time + + // collect garbage + +} + diff --git a/tests/physics/src/CollisionRenderMeshCacheTests.h b/tests/physics/src/CollisionRenderMeshCacheTests.h new file mode 100644 index 0000000000..d927bf8cab --- /dev/null +++ b/tests/physics/src/CollisionRenderMeshCacheTests.h @@ -0,0 +1,24 @@ +// +// CollisionRenderMeshCacheTests.h +// tests/physics/src +// +// Created by Andrew Meadows on 2014.10.30 +// Copyright 2014 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 +// + +#ifndef hifi_CollisionRenderMeshCacheTests_h +#define hifi_CollisionRenderMeshCacheTests_h + +#include + +class CollisionRenderMeshCacheTests : public QObject { + Q_OBJECT + +private slots: + void test001(); +}; + +#endif // hifi_CollisionRenderMeshCacheTests_h From 0d84e6ece5c8d99ef0f8572991edcb389e9df31b Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 14 Jul 2016 18:03:25 -0700 Subject: [PATCH 12/45] first CollisionRenderMeshCache unit test --- .../src/CollisionRenderMeshCacheTests.cpp | 242 +++++++++++++++++- tests/physics/src/MeshUtil.cpp | 45 ++++ tests/physics/src/MeshUtil.h | 61 +++++ 3 files changed, 343 insertions(+), 5 deletions(-) create mode 100644 tests/physics/src/MeshUtil.cpp create mode 100644 tests/physics/src/MeshUtil.h diff --git a/tests/physics/src/CollisionRenderMeshCacheTests.cpp b/tests/physics/src/CollisionRenderMeshCacheTests.cpp index 58b45f6400..b4ed49b605 100644 --- a/tests/physics/src/CollisionRenderMeshCacheTests.cpp +++ b/tests/physics/src/CollisionRenderMeshCacheTests.cpp @@ -9,20 +9,123 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include -#include -#include - #include "CollisionRenderMeshCacheTests.h" +#include +#include + +#include +#include + +#include +#include // for MAX_HULL_POINTS + +#include "MeshUtil.cpp" + + QTEST_MAIN(CollisionRenderMeshCacheTests) +btVector3 directions[] = { + btVector3(1.0f, 1.0f, 1.0f), + btVector3(1.0f, 1.0f, -1.0f), + btVector3(1.0f, -1.0f, 1.0f), + btVector3(1.0f, -1.0f, -1.0f), + btVector3(-1.0f, 1.0f, 1.0f), + btVector3(-1.0f, 1.0f, -1.0f), + btVector3(-1.0f, -1.0f, 1.0f), + btVector3(-1.0f, -1.0f, -1.0f) +}; +void computeCubePoints(const btVector3& center, btScalar radius, uint32_t numPoints, + btAlignedObjectArray& points) { + points.reserve(points.size() + 8); + for (uint32_t i = 0; i < 8; ++i) { + points.push_back(center + radius * directions[i]); + } +} + +float randomFloat() { + return (float)rand() / (float)RAND_MAX; +} + +btBoxShape* createRandomCubeShape() { + //const btScalar MAX_RADIUS = 3.0; + //const btScalar MIN_RADIUS = 0.5; + //btScalar radius = randomFloat() * (MAX_RADIUS - MIN_RADIUS) + MIN_RADIUS; + btScalar radius = 0.5f; + btVector3 halfExtents(radius, radius, radius); + + btBoxShape* shape = new btBoxShape(halfExtents); + return shape; +} + +void CollisionRenderMeshCacheTests::test001() { + // make a box shape + btBoxShape* box = createRandomCubeShape(); + + // wrap it with a ShapeHull + btShapeHull hull(box); + //const btScalar MARGIN = 0.01f; + const btScalar MARGIN = 0.00f; + hull.buildHull(MARGIN); + + // verify the vertex count is capped + uint32_t numVertices = (uint32_t)hull.numVertices(); + QVERIFY(numVertices <= MAX_HULL_POINTS); + + // verify the mesh is inside the radius + btVector3 halfExtents = box->getHalfExtentsWithMargin(); + btScalar acceptableRadiusError = 0.01f; + btScalar maxRadius = halfExtents.length() + acceptableRadiusError; + const btVector3* meshVertices = hull.getVertexPointer(); + for (uint32_t i = 0; i < numVertices; ++i) { + btVector3 vertex = meshVertices[i]; + QVERIFY(vertex.length() <= maxRadius); + } + + // verify the index count is capped + uint32_t numIndices = (uint32_t)hull.numIndices(); + QVERIFY(numIndices < 6 * MAX_HULL_POINTS); + + // verify the index count is a multiple of 3 + QVERIFY(numIndices % 3 == 0); + + // verify the mesh is closed + const uint32_t* meshIndices = hull.getIndexPointer(); + bool isClosed = MeshUtil::isClosedManifold(meshIndices, numIndices); + QVERIFY(isClosed); + + // verify the triangle normals are outward using right-hand-rule + const uint32_t INDICES_PER_TRIANGLE = 3; + for (uint32_t i = 0; i < numIndices; i += INDICES_PER_TRIANGLE) { + btVector3 A = meshVertices[meshIndices[i]]; + btVector3 B = meshVertices[meshIndices[i+1]]; + btVector3 C = meshVertices[meshIndices[i+2]]; + + btVector3 face = (B - A).cross(C - B); + btVector3 center = (A + B + C) / 3.0f; + QVERIFY(face.dot(center) > 0.0f); + } + + delete box; +} + +#ifdef FOO void CollisionRenderMeshCacheTests::test001() { CollisionRenderMeshCache cache; // create a compound shape - int32_t numSubShapes = 3; + btScalar radiusA = 1.0f; + btScalar radiusB = 1.5f; + btScalar radiusC = 2.75f; + + btVector3 centerA(radiusA, 0.0f, 0.0f); + btVector3 centerB(0.0f, radiusB, 0.0f); + btVector3 centerC(0.0f, 0.0f, radiusC); + + btCompoundShape compoundShape = new btCompoundShape(); + for (uint32_t i = 0; i < numSubShapes; ++i) { + } // get the mesh @@ -38,4 +141,133 @@ void CollisionRenderMeshCacheTests::test001() { // collect garbage } +#endif // FOO +/* +void CollisionRenderMeshCacheTests::addManyShapes() { + ShapeManager shapeManager; + + QVector shapes; + + int numSizes = 100; + float startSize = 1.0f; + float endSize = 99.0f; + float deltaSize = (endSize - startSize) / (float)numSizes; + ShapeInfo info; + for (int i = 0; i < numSizes; ++i) { + // make a sphere + float s = startSize + (float)i * deltaSize; + glm::vec3 scale(s, 1.23f + s, s - 0.573f); + info.setBox(0.5f * scale); + btCollisionShape* shape = shapeManager.getShape(info); + shapes.push_back(shape); + QCOMPARE(shape != nullptr, true); + + // make a box + float radius = 0.5f * s; + info.setSphere(radius); + shape = shapeManager.getShape(info); + shapes.push_back(shape); + QCOMPARE(shape != nullptr, true); + } + + // verify shape count + int numShapes = shapeManager.getNumShapes(); + QCOMPARE(numShapes, 2 * numSizes); + + // release each shape by pointer + for (int i = 0; i < numShapes; ++i) { + btCollisionShape* shape = shapes[i]; + bool success = shapeManager.releaseShape(shape); + QCOMPARE(success, true); + } + + // verify zero references + for (int i = 0; i < numShapes; ++i) { + btCollisionShape* shape = shapes[i]; + int numReferences = shapeManager.getNumReferences(shape); + QCOMPARE(numReferences, 0); + } +} + +void CollisionRenderMeshCacheTests::addBoxShape() { + ShapeInfo info; + glm::vec3 halfExtents(1.23f, 4.56f, 7.89f); + info.setBox(halfExtents); + + ShapeManager shapeManager; + btCollisionShape* shape = shapeManager.getShape(info); + + ShapeInfo otherInfo = info; + btCollisionShape* otherShape = shapeManager.getShape(otherInfo); + QCOMPARE(shape, otherShape); +} + +void CollisionRenderMeshCacheTests::addSphereShape() { + ShapeInfo info; + float radius = 1.23f; + info.setSphere(radius); + + ShapeManager shapeManager; + btCollisionShape* shape = shapeManager.getShape(info); + + ShapeInfo otherInfo = info; + btCollisionShape* otherShape = shapeManager.getShape(otherInfo); + QCOMPARE(shape, otherShape); +} + +void CollisionRenderMeshCacheTests::addCompoundShape() { + // initialize some points for generating tetrahedral convex hulls + QVector tetrahedron; + tetrahedron.push_back(glm::vec3(1.0f, 1.0f, 1.0f)); + tetrahedron.push_back(glm::vec3(1.0f, -1.0f, -1.0f)); + tetrahedron.push_back(glm::vec3(-1.0f, 1.0f, -1.0f)); + tetrahedron.push_back(glm::vec3(-1.0f, -1.0f, 1.0f)); + int numHullPoints = tetrahedron.size(); + + // compute the points of the hulls + ShapeInfo::PointCollection pointCollection; + int numHulls = 5; + glm::vec3 offsetNormal(1.0f, 0.0f, 0.0f); + for (int i = 0; i < numHulls; ++i) { + glm::vec3 offset = (float)(i - numHulls/2) * offsetNormal; + ShapeInfo::PointList pointList; + float radius = (float)(i + 1); + for (int j = 0; j < numHullPoints; ++j) { + glm::vec3 point = radius * tetrahedron[j] + offset; + pointList.push_back(point); + } + pointCollection.push_back(pointList); + } + + // create the ShapeInfo + ShapeInfo info; + info.setPointCollection(hulls); + + // create the shape + ShapeManager shapeManager; + btCollisionShape* shape = shapeManager.getShape(info); + QVERIFY(shape != nullptr); + + // verify the shape is correct type + QCOMPARE(shape->getShapeType(), (int)COMPOUND_SHAPE_PROXYTYPE); + + // verify the shape has correct number of children + btCompoundShape* compoundShape = static_cast(shape); + QCOMPARE(compoundShape->getNumChildShapes(), numHulls); + + // verify manager has only one shape + QCOMPARE(shapeManager.getNumShapes(), 1); + QCOMPARE(shapeManager.getNumReferences(info), 1); + + // release the shape + shapeManager.releaseShape(shape); + QCOMPARE(shapeManager.getNumShapes(), 1); + QCOMPARE(shapeManager.getNumReferences(info), 0); + + // collect garbage + shapeManager.collectGarbage(); + QCOMPARE(shapeManager.getNumShapes(), 0); + QCOMPARE(shapeManager.getNumReferences(info), 0); +} +*/ diff --git a/tests/physics/src/MeshUtil.cpp b/tests/physics/src/MeshUtil.cpp new file mode 100644 index 0000000000..d3eb815948 --- /dev/null +++ b/tests/physics/src/MeshUtil.cpp @@ -0,0 +1,45 @@ +// +// MeshUtil.cpp +// tests/physics/src +// +// Created by Andrew Meadows 2016.07.14 +// Copyright 2016 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 "MeshUtil.h" + +#include + +// returns false if any edge has only one adjacent triangle +bool MeshUtil::isClosedManifold(const uint32_t* meshIndices, uint32_t numIndices) { + using EdgeList = std::unordered_map; + EdgeList edges; + + // count the triangles for each edge + const uint32_t TRIANGLE_STRIDE = 3; + for (uint32_t i = 0; i < numIndices; i += TRIANGLE_STRIDE) { + MeshUtil::TriangleEdge edge; + // the triangles indices are stored in sequential order + for (uint32_t j = 0; j < 3; ++j) { + edge.setIndices(meshIndices[i + j], meshIndices[i + ((j + 1) % 3)]); + + EdgeList::iterator edgeEntry = edges.find(edge); + if (edgeEntry == edges.end()) { + edges.insert(std::pair(edge, 1)); + } else { + edgeEntry->second += 1; + } + } + } + // scan for outside edge + for (auto& edgeEntry : edges) { + if (edgeEntry.second == 1) { + return false; + } + } + return true; +} + diff --git a/tests/physics/src/MeshUtil.h b/tests/physics/src/MeshUtil.h new file mode 100644 index 0000000000..82d33d631b --- /dev/null +++ b/tests/physics/src/MeshUtil.h @@ -0,0 +1,61 @@ +// +// MeshUtil.h +// tests/physics/src +// +// Created by Andrew Meadows 2016.07.14 +// Copyright 2016 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 +// + +#ifndef hifi_MeshUtil_h +#define hifi_MeshUtil_h + +#include + +namespace MeshUtil { + +class TriangleEdge { +public: + TriangleEdge() {} + TriangleEdge(uint32_t A, uint32_t B) { + setIndices(A, B); + } + void setIndices(uint32_t A, uint32_t B) { + if (A < B) { + _indexA = A; + _indexB = B; + } else { + _indexA = B; + _indexB = A; + } + } + bool operator==(const TriangleEdge& other) const { + return _indexA == other._indexA && _indexB == other._indexB; + } + + uint32_t getIndexA() const { return _indexA; } + uint32_t getIndexB() const { return _indexB; } +private: + uint32_t _indexA { (uint32_t)(-1) }; + uint32_t _indexB { (uint32_t)(-1) }; +}; + +bool isClosedManifold(const uint32_t* meshIndices, uint32_t numIndices); + +} // MeshUtil namespace + +namespace std { + template <> + struct hash { + std::size_t operator()(const MeshUtil::TriangleEdge& edge) const { + // use Cantor's pairing function to generate a hash of ZxZ --> Z + uint32_t ab = edge.getIndexA() + edge.getIndexB(); + return hash()((ab * (ab + 1)) / 2 + edge.getIndexB()); + } + }; +} + + +#endif // hifi_MeshUtil_h From cbacb02010d139add3bf88ce99cd51aa581191e7 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 15 Jul 2016 11:28:11 -0700 Subject: [PATCH 13/45] more unit tests for CollisionRenderMeshCache --- .../physics/src/CollisionRenderMeshCache.cpp | 41 ++- .../physics/src/CollisionRenderMeshCache.h | 10 +- .../src/CollisionRenderMeshCacheTests.cpp | 342 +++++++++--------- .../src/CollisionRenderMeshCacheTests.h | 4 +- 4 files changed, 208 insertions(+), 189 deletions(-) diff --git a/libraries/physics/src/CollisionRenderMeshCache.cpp b/libraries/physics/src/CollisionRenderMeshCache.cpp index 3714d9d464..14386c6f48 100644 --- a/libraries/physics/src/CollisionRenderMeshCache.cpp +++ b/libraries/physics/src/CollisionRenderMeshCache.cpp @@ -68,9 +68,19 @@ void copyShapeToMesh(const btTransform& transform, const btConvexShape* shape, m } model::MeshPointer createMeshFromShape(const btCollisionShape* shape) { - model::MeshPointer mesh = std::make_shared(); - if (shape) { - int32_t shapeType = shape->getShapeType(); + model::MeshPointer mesh; + if (!shape) { + return mesh; + } + + int32_t shapeType = shape->getShapeType(); + if (shapeType == (int32_t)COMPOUND_SHAPE_PROXYTYPE || shape->isConvex()) { + // create the mesh and allocate buffers for it + mesh = std::make_shared(); + mesh->setVertexBuffer(gpu::BufferView(new gpu::Buffer(), mesh->getVertexBuffer()._element)); + mesh->setIndexBuffer(gpu::BufferView(new gpu::Buffer(), mesh->getIndexBuffer()._element)); + mesh->setPartBuffer(gpu::BufferView(new gpu::Buffer(), mesh->getPartBuffer()._element)); + if (shapeType == (int32_t)COMPOUND_SHAPE_PROXYTYPE) { const btCompoundShape* compoundShape = static_cast(shape); int32_t numSubShapes = compoundShape->getNumChildShapes(); @@ -81,7 +91,8 @@ model::MeshPointer createMeshFromShape(const btCollisionShape* shape) { copyShapeToMesh(compoundShape->getChildTransform(i), convexShape, mesh); } } - } else if (shape->isConvex()) { + } else { + // shape is convex const btConvexShape* convexShape = static_cast(shape); copyShapeToMesh(btTransform(), convexShape, mesh); } @@ -93,20 +104,22 @@ CollisionRenderMeshCache::CollisionRenderMeshCache() { } CollisionRenderMeshCache::~CollisionRenderMeshCache() { - _geometryMap.clear(); + _meshMap.clear(); _pendingGarbage.clear(); } model::MeshPointer CollisionRenderMeshCache::getMesh(CollisionRenderMeshCache::Key key) { model::MeshPointer mesh; if (key) { - CollisionMeshMap::const_iterator itr = _geometryMap.find(key); - if (itr != _geometryMap.end()) { + CollisionMeshMap::const_iterator itr = _meshMap.find(key); + if (itr == _meshMap.end()) { // make mesh and add it to map mesh = createMeshFromShape(key); if (mesh) { - _geometryMap.insert(std::make_pair(key, mesh)); + _meshMap.insert(std::make_pair(key, mesh)); } + } else { + mesh = itr->second; } } return mesh; @@ -116,12 +129,12 @@ bool CollisionRenderMeshCache::releaseMesh(CollisionRenderMeshCache::Key key) { if (!key) { return false; } - CollisionMeshMap::const_iterator itr = _geometryMap.find(key); - if (itr != _geometryMap.end()) { + CollisionMeshMap::const_iterator itr = _meshMap.find(key); + if (itr != _meshMap.end()) { assert((*itr).second.use_count() != 1); + _pendingGarbage.push_back(key); if ((*itr).second.use_count() == 1) { // we hold all of the references inside the cache so we'll try to delete later - _pendingGarbage.push_back(key); } return true; } @@ -132,11 +145,11 @@ void CollisionRenderMeshCache::collectGarbage() { int numShapes = _pendingGarbage.size(); for (int i = 0; i < numShapes; ++i) { CollisionRenderMeshCache::Key key = _pendingGarbage[i]; - CollisionMeshMap::const_iterator itr = _geometryMap.find(key); - if (itr != _geometryMap.end()) { + CollisionMeshMap::const_iterator itr = _meshMap.find(key); + if (itr != _meshMap.end()) { if ((*itr).second.use_count() == 1) { // we hold the only reference - _geometryMap.erase(itr); + _meshMap.erase(itr); } } } diff --git a/libraries/physics/src/CollisionRenderMeshCache.h b/libraries/physics/src/CollisionRenderMeshCache.h index 05da3750c3..ad3c86562b 100644 --- a/libraries/physics/src/CollisionRenderMeshCache.h +++ b/libraries/physics/src/CollisionRenderMeshCache.h @@ -23,8 +23,8 @@ class btCollisionShape; namespace std { template <> struct hash { - std::size_t operator()(btCollisionShape* key) const { - return (hash()((void*)key)); + std::size_t operator()(btCollisionShape* shape) const { + return (hash()((void*)shape)); } }; } @@ -46,12 +46,12 @@ public: void collectGarbage(); // validation methods - uint32_t getNumGeometries() const { return (uint32_t)_geometryMap.size(); } - bool hasMesh(Key key) const { return _geometryMap.find(key) == _geometryMap.end(); } + uint32_t getNumMeshes() const { return (uint32_t)_meshMap.size(); } + bool hasMesh(Key key) const { return _meshMap.find(key) == _meshMap.end(); } private: using CollisionMeshMap = std::unordered_map; - CollisionMeshMap _geometryMap; + CollisionMeshMap _meshMap; std::vector _pendingGarbage; }; diff --git a/tests/physics/src/CollisionRenderMeshCacheTests.cpp b/tests/physics/src/CollisionRenderMeshCacheTests.cpp index b4ed49b605..085c9a2fe3 100644 --- a/tests/physics/src/CollisionRenderMeshCacheTests.cpp +++ b/tests/physics/src/CollisionRenderMeshCacheTests.cpp @@ -25,48 +25,53 @@ QTEST_MAIN(CollisionRenderMeshCacheTests) -btVector3 directions[] = { - btVector3(1.0f, 1.0f, 1.0f), - btVector3(1.0f, 1.0f, -1.0f), - btVector3(1.0f, -1.0f, 1.0f), - btVector3(1.0f, -1.0f, -1.0f), - btVector3(-1.0f, 1.0f, 1.0f), - btVector3(-1.0f, 1.0f, -1.0f), - btVector3(-1.0f, -1.0f, 1.0f), - btVector3(-1.0f, -1.0f, -1.0f) +const float INV_SQRT_THREE = 0.577350269f; + +const uint32_t numSphereDirections = 6 + 8; +btVector3 sphereDirections[] = { + btVector3(1.0f, 0.0f, 0.0f), + btVector3(-1.0f, 0.0f, 0.0f), + btVector3(0.0f, 1.0f, 0.0f), + btVector3(0.0f, -1.0f, 0.0f), + btVector3(0.0f, 0.0f, 1.0f), + btVector3(0.0f, 0.0f, -1.0f), + btVector3(INV_SQRT_THREE, INV_SQRT_THREE, INV_SQRT_THREE), + btVector3(INV_SQRT_THREE, INV_SQRT_THREE, -INV_SQRT_THREE), + btVector3(INV_SQRT_THREE, -INV_SQRT_THREE, INV_SQRT_THREE), + btVector3(INV_SQRT_THREE, -INV_SQRT_THREE, -INV_SQRT_THREE), + btVector3(-INV_SQRT_THREE, INV_SQRT_THREE, INV_SQRT_THREE), + btVector3(-INV_SQRT_THREE, INV_SQRT_THREE, -INV_SQRT_THREE), + btVector3(-INV_SQRT_THREE, -INV_SQRT_THREE, INV_SQRT_THREE), + btVector3(-INV_SQRT_THREE, -INV_SQRT_THREE, -INV_SQRT_THREE) }; -void computeCubePoints(const btVector3& center, btScalar radius, uint32_t numPoints, - btAlignedObjectArray& points) { - points.reserve(points.size() + 8); - for (uint32_t i = 0; i < 8; ++i) { - points.push_back(center + radius * directions[i]); - } -} - float randomFloat() { - return (float)rand() / (float)RAND_MAX; + return 2.0f * ((float)rand() / (float)RAND_MAX) - 1.0f; } -btBoxShape* createRandomCubeShape() { - //const btScalar MAX_RADIUS = 3.0; - //const btScalar MIN_RADIUS = 0.5; - //btScalar radius = randomFloat() * (MAX_RADIUS - MIN_RADIUS) + MIN_RADIUS; - btScalar radius = 0.5f; - btVector3 halfExtents(radius, radius, radius); - - btBoxShape* shape = new btBoxShape(halfExtents); +btBoxShape* createBoxShape(const btVector3& extent) { + btBoxShape* shape = new btBoxShape(0.5f * extent); return shape; } -void CollisionRenderMeshCacheTests::test001() { +btConvexHullShape* createConvexHull(float radius) { + btConvexHullShape* hull = new btConvexHullShape(); + for (uint32_t i = 0; i < numSphereDirections; ++i) { + btVector3 point = radius * sphereDirections[i]; + hull->addPoint(point, false); + } + hull->recalcLocalAabb(); + return hull; +} + +void CollisionRenderMeshCacheTests::testShapeHullManifold() { // make a box shape - btBoxShape* box = createRandomCubeShape(); + btVector3 extent(1.0f, 2.0f, 3.0f); + btBoxShape* box = createBoxShape(extent); // wrap it with a ShapeHull btShapeHull hull(box); - //const btScalar MARGIN = 0.01f; - const btScalar MARGIN = 0.00f; + const float MARGIN = 0.0f; hull.buildHull(MARGIN); // verify the vertex count is capped @@ -75,8 +80,8 @@ void CollisionRenderMeshCacheTests::test001() { // verify the mesh is inside the radius btVector3 halfExtents = box->getHalfExtentsWithMargin(); - btScalar acceptableRadiusError = 0.01f; - btScalar maxRadius = halfExtents.length() + acceptableRadiusError; + float ACCEPTABLE_EXTENTS_ERROR = 0.01f; + float maxRadius = halfExtents.length() + ACCEPTABLE_EXTENTS_ERROR; const btVector3* meshVertices = hull.getVertexPointer(); for (uint32_t i = 0; i < numVertices; ++i) { btVector3 vertex = meshVertices[i]; @@ -107,167 +112,166 @@ void CollisionRenderMeshCacheTests::test001() { QVERIFY(face.dot(center) > 0.0f); } + // delete unmanaged memory delete box; } -#ifdef FOO -void CollisionRenderMeshCacheTests::test001() { - CollisionRenderMeshCache cache; +void CollisionRenderMeshCacheTests::testCompoundShape() { + uint32_t numSubShapes = 3; - // create a compound shape - btScalar radiusA = 1.0f; - btScalar radiusB = 1.5f; - btScalar radiusC = 2.75f; + btVector3 centers[] = { + btVector3(1.0f, 0.0f, 0.0f), + btVector3(0.0f, -2.0f, 0.0f), + btVector3(0.0f, 0.0f, 3.0f), + }; - btVector3 centerA(radiusA, 0.0f, 0.0f); - btVector3 centerB(0.0f, radiusB, 0.0f); - btVector3 centerC(0.0f, 0.0f, radiusC); + float radii[] = { 3.0f, 2.0f, 1.0f }; - btCompoundShape compoundShape = new btCompoundShape(); + btCompoundShape* compoundShape = new btCompoundShape(); for (uint32_t i = 0; i < numSubShapes; ++i) { + btTransform transform; + transform.setOrigin(centers[i]); + btConvexHullShape* hull = createConvexHull(radii[i]); + compoundShape->addChildShape(transform, hull); } + // create the cache + CollisionRenderMeshCache cache; + QVERIFY(cache.getNumMeshes() == 0); - // get the mesh + // get the mesh once + model::MeshPointer mesh = cache.getMesh(compoundShape); + QVERIFY((bool)mesh); + QVERIFY(cache.getNumMeshes() == 1); // get the mesh again + model::MeshPointer mesh2 = cache.getMesh(compoundShape); + QVERIFY(mesh2 == mesh); + QVERIFY(cache.getNumMeshes() == 1); // forget the mesh once + cache.releaseMesh(compoundShape); + mesh.reset(); + QVERIFY(cache.getNumMeshes() == 1); - // collect garbage + // collect garbage (should still cache mesh) + cache.collectGarbage(); + QVERIFY(cache.getNumMeshes() == 1); - // forget the mesh a second time + // forget the mesh a second time (should still cache mesh) + cache.releaseMesh(compoundShape); + mesh2.reset(); + QVERIFY(cache.getNumMeshes() == 1); - // collect garbage + // collect garbage (should no longer cache mesh) + cache.collectGarbage(); + QVERIFY(cache.getNumMeshes() == 0); + // delete unmanaged memory + for (int i = 0; i < compoundShape->getNumChildShapes(); ++i) { + delete compoundShape->getChildShape(i); + } + delete compoundShape; } -#endif // FOO -/* -void CollisionRenderMeshCacheTests::addManyShapes() { - ShapeManager shapeManager; - - QVector shapes; - - int numSizes = 100; - float startSize = 1.0f; - float endSize = 99.0f; - float deltaSize = (endSize - startSize) / (float)numSizes; - ShapeInfo info; - for (int i = 0; i < numSizes; ++i) { - // make a sphere - float s = startSize + (float)i * deltaSize; - glm::vec3 scale(s, 1.23f + s, s - 0.573f); - info.setBox(0.5f * scale); - btCollisionShape* shape = shapeManager.getShape(info); - shapes.push_back(shape); - QCOMPARE(shape != nullptr, true); - - // make a box - float radius = 0.5f * s; - info.setSphere(radius); - shape = shapeManager.getShape(info); - shapes.push_back(shape); - QCOMPARE(shape != nullptr, true); +void CollisionRenderMeshCacheTests::testMultipleShapes() { + // shapeA is compound of hulls + uint32_t numSubShapes = 3; + btVector3 centers[] = { + btVector3(1.0f, 0.0f, 0.0f), + btVector3(0.0f, -2.0f, 0.0f), + btVector3(0.0f, 0.0f, 3.0f), + }; + float radii[] = { 3.0f, 2.0f, 1.0f }; + btCompoundShape* shapeA = new btCompoundShape(); + for (uint32_t i = 0; i < numSubShapes; ++i) { + btTransform transform; + transform.setOrigin(centers[i]); + btConvexHullShape* hull = createConvexHull(radii[i]); + shapeA->addChildShape(transform, hull); } - // verify shape count - int numShapes = shapeManager.getNumShapes(); - QCOMPARE(numShapes, 2 * numSizes); - - // release each shape by pointer - for (int i = 0; i < numShapes; ++i) { - btCollisionShape* shape = shapes[i]; - bool success = shapeManager.releaseShape(shape); - QCOMPARE(success, true); + // shapeB is compound of boxes + btVector3 extents[] = { + btVector3(1.0f, 2.0f, 3.0f), + btVector3(2.0f, 3.0f, 1.0f), + btVector3(3.0f, 1.0f, 2.0f), + }; + btCompoundShape* shapeB = new btCompoundShape(); + for (uint32_t i = 0; i < numSubShapes; ++i) { + btTransform transform; + transform.setOrigin(centers[i]); + btBoxShape* box = createBoxShape(extents[i]); + shapeB->addChildShape(transform, box); } - // verify zero references - for (int i = 0; i < numShapes; ++i) { - btCollisionShape* shape = shapes[i]; - int numReferences = shapeManager.getNumReferences(shape); - QCOMPARE(numReferences, 0); + // shapeC is just a box + btVector3 extentC(7.0f, 3.0f, 5.0f); + btBoxShape* shapeC = createBoxShape(extentC); + + // create the cache + CollisionRenderMeshCache cache; + QVERIFY(cache.getNumMeshes() == 0); + + // get the meshes + model::MeshPointer meshA = cache.getMesh(shapeA); + model::MeshPointer meshB = cache.getMesh(shapeB); + model::MeshPointer meshC = cache.getMesh(shapeC); + QVERIFY((bool)meshA); + QVERIFY((bool)meshB); + QVERIFY((bool)meshC); + QVERIFY(cache.getNumMeshes() == 3); + + // get the meshes again + model::MeshPointer meshA2 = cache.getMesh(shapeA); + model::MeshPointer meshB2 = cache.getMesh(shapeB); + model::MeshPointer meshC2 = cache.getMesh(shapeC); + QVERIFY(meshA == meshA2); + QVERIFY(meshB == meshB2); + QVERIFY(meshC == meshC2); + QVERIFY(cache.getNumMeshes() == 3); + + // forget the meshes once + cache.releaseMesh(shapeA); + cache.releaseMesh(shapeB); + cache.releaseMesh(shapeC); + meshA2.reset(); + meshB2.reset(); + meshC2.reset(); + QVERIFY(cache.getNumMeshes() == 3); + + // collect garbage (should still cache mesh) + cache.collectGarbage(); + QVERIFY(cache.getNumMeshes() == 3); + + // forget again, one mesh at a time... + // shapeA... + cache.releaseMesh(shapeA); + meshA.reset(); + QVERIFY(cache.getNumMeshes() == 3); + cache.collectGarbage(); + QVERIFY(cache.getNumMeshes() == 2); + // shapeB... + cache.releaseMesh(shapeB); + meshB.reset(); + QVERIFY(cache.getNumMeshes() == 2); + cache.collectGarbage(); + QVERIFY(cache.getNumMeshes() == 1); + // shapeC... + cache.releaseMesh(shapeC); + meshC.reset(); + QVERIFY(cache.getNumMeshes() == 1); + cache.collectGarbage(); + QVERIFY(cache.getNumMeshes() == 0); + + // delete unmanaged memory + for (int i = 0; i < shapeA->getNumChildShapes(); ++i) { + delete shapeA->getChildShape(i); } -} - -void CollisionRenderMeshCacheTests::addBoxShape() { - ShapeInfo info; - glm::vec3 halfExtents(1.23f, 4.56f, 7.89f); - info.setBox(halfExtents); - - ShapeManager shapeManager; - btCollisionShape* shape = shapeManager.getShape(info); - - ShapeInfo otherInfo = info; - btCollisionShape* otherShape = shapeManager.getShape(otherInfo); - QCOMPARE(shape, otherShape); -} - -void CollisionRenderMeshCacheTests::addSphereShape() { - ShapeInfo info; - float radius = 1.23f; - info.setSphere(radius); - - ShapeManager shapeManager; - btCollisionShape* shape = shapeManager.getShape(info); - - ShapeInfo otherInfo = info; - btCollisionShape* otherShape = shapeManager.getShape(otherInfo); - QCOMPARE(shape, otherShape); -} - -void CollisionRenderMeshCacheTests::addCompoundShape() { - // initialize some points for generating tetrahedral convex hulls - QVector tetrahedron; - tetrahedron.push_back(glm::vec3(1.0f, 1.0f, 1.0f)); - tetrahedron.push_back(glm::vec3(1.0f, -1.0f, -1.0f)); - tetrahedron.push_back(glm::vec3(-1.0f, 1.0f, -1.0f)); - tetrahedron.push_back(glm::vec3(-1.0f, -1.0f, 1.0f)); - int numHullPoints = tetrahedron.size(); - - // compute the points of the hulls - ShapeInfo::PointCollection pointCollection; - int numHulls = 5; - glm::vec3 offsetNormal(1.0f, 0.0f, 0.0f); - for (int i = 0; i < numHulls; ++i) { - glm::vec3 offset = (float)(i - numHulls/2) * offsetNormal; - ShapeInfo::PointList pointList; - float radius = (float)(i + 1); - for (int j = 0; j < numHullPoints; ++j) { - glm::vec3 point = radius * tetrahedron[j] + offset; - pointList.push_back(point); - } - pointCollection.push_back(pointList); + delete shapeA; + for (int i = 0; i < shapeB->getNumChildShapes(); ++i) { + delete shapeB->getChildShape(i); } - - // create the ShapeInfo - ShapeInfo info; - info.setPointCollection(hulls); - - // create the shape - ShapeManager shapeManager; - btCollisionShape* shape = shapeManager.getShape(info); - QVERIFY(shape != nullptr); - - // verify the shape is correct type - QCOMPARE(shape->getShapeType(), (int)COMPOUND_SHAPE_PROXYTYPE); - - // verify the shape has correct number of children - btCompoundShape* compoundShape = static_cast(shape); - QCOMPARE(compoundShape->getNumChildShapes(), numHulls); - - // verify manager has only one shape - QCOMPARE(shapeManager.getNumShapes(), 1); - QCOMPARE(shapeManager.getNumReferences(info), 1); - - // release the shape - shapeManager.releaseShape(shape); - QCOMPARE(shapeManager.getNumShapes(), 1); - QCOMPARE(shapeManager.getNumReferences(info), 0); - - // collect garbage - shapeManager.collectGarbage(); - QCOMPARE(shapeManager.getNumShapes(), 0); - QCOMPARE(shapeManager.getNumReferences(info), 0); + delete shapeB; + delete shapeC; } -*/ diff --git a/tests/physics/src/CollisionRenderMeshCacheTests.h b/tests/physics/src/CollisionRenderMeshCacheTests.h index d927bf8cab..640314a2a0 100644 --- a/tests/physics/src/CollisionRenderMeshCacheTests.h +++ b/tests/physics/src/CollisionRenderMeshCacheTests.h @@ -18,7 +18,9 @@ class CollisionRenderMeshCacheTests : public QObject { Q_OBJECT private slots: - void test001(); + void testShapeHullManifold(); + void testCompoundShape(); + void testMultipleShapes(); }; #endif // hifi_CollisionRenderMeshCacheTests_h From 1ed76ae44215b3fa1ad85ee2bb554e02d6195ff0 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 15 Jul 2016 14:11:40 -0700 Subject: [PATCH 14/45] added virtual ObjectMotionState::setShape() --- libraries/physics/src/ObjectMotionState.cpp | 37 +++++++++++---------- libraries/physics/src/ObjectMotionState.h | 3 +- 2 files changed, 21 insertions(+), 19 deletions(-) diff --git a/libraries/physics/src/ObjectMotionState.cpp b/libraries/physics/src/ObjectMotionState.cpp index f915121718..64b1e9c527 100644 --- a/libraries/physics/src/ObjectMotionState.cpp +++ b/libraries/physics/src/ObjectMotionState.cpp @@ -64,16 +64,17 @@ ShapeManager* ObjectMotionState::getShapeManager() { ObjectMotionState::ObjectMotionState(btCollisionShape* shape) : _motionType(MOTION_TYPE_STATIC), - _shape(shape), + _shape(nullptr), _body(nullptr), _mass(0.0f), _lastKinematicStep(worldSimulationStep) { + setShape(shape); } ObjectMotionState::~ObjectMotionState() { assert(!_body); - releaseShape(); + setShape(nullptr); _type = MOTIONSTATE_TYPE_INVALID; } @@ -114,13 +115,6 @@ glm::vec3 ObjectMotionState::getBodyAngularVelocity() const { return bulletToGLM(_body->getAngularVelocity()); } -void ObjectMotionState::releaseShape() { - if (_shape) { - shapeManager->releaseShape(_shape); - _shape = nullptr; - } -} - void ObjectMotionState::setMotionType(PhysicsMotionType motionType) { _motionType = motionType; } @@ -165,6 +159,15 @@ void ObjectMotionState::setRigidBody(btRigidBody* body) { } } +void ObjectMotionState::setShape(btCollisionShape* shape) { + if (_shape != shape) { + if (_shape) { + getShapeManager()->releaseShape(_shape); + } + _shape = shape; + } +} + void ObjectMotionState::handleEasyChanges(uint32_t& flags) { if (flags & Simulation::DIRTY_POSITION) { btTransform worldTrans = _body->getWorldTransform(); @@ -265,15 +268,15 @@ bool ObjectMotionState::handleHardAndEasyChanges(uint32_t& flags, PhysicsEngine* return true; } } - getShapeManager()->releaseShape(_shape); - if (_shape != newShape) { - _shape = newShape; - _body->setCollisionShape(_shape); - - updateCCDConfiguration(); - } else { - // huh... the shape didn't actually change, so we clear the DIRTY_SHAPE flag + if (_shape == newShape) { + // the shape didn't actually change, so we clear the DIRTY_SHAPE flag flags &= ~Simulation::DIRTY_SHAPE; + // and clear the reference we just created + getShapeManager()->releaseShape(_shape); + } else { + _body->setCollisionShape(newShape); + setShape(newShape); + updateCCDConfiguration(); } } if (flags & EASY_DIRTY_PHYSICS_FLAGS) { diff --git a/libraries/physics/src/ObjectMotionState.h b/libraries/physics/src/ObjectMotionState.h index c0c10c6f71..ca9b80a3b3 100644 --- a/libraries/physics/src/ObjectMotionState.h +++ b/libraries/physics/src/ObjectMotionState.h @@ -113,8 +113,6 @@ public: btCollisionShape* getShape() const { return _shape; } btRigidBody* getRigidBody() const { return _body; } - void releaseShape(); - virtual bool isMoving() const = 0; // These pure virtual methods must be implemented for each MotionState type @@ -157,6 +155,7 @@ protected: void updateCCDConfiguration(); void setRigidBody(btRigidBody* body); + virtual void setShape(btCollisionShape* shape); MotionStateType _type = MOTIONSTATE_TYPE_INVALID; // type of MotionState PhysicsMotionType _motionType; // type of motion: KINEMATIC, DYNAMIC, or STATIC From b2dfa49a6ffe600bb3af355259c0ea2ab6eccb10 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 15 Jul 2016 15:24:57 -0700 Subject: [PATCH 15/45] stubbery for alerting entity that shape changed --- .../entities-renderer/src/RenderableModelEntityItem.h | 2 ++ libraries/entities/src/EntityItem.h | 7 +++++++ libraries/physics/src/EntityMotionState.cpp | 8 ++++++++ libraries/physics/src/EntityMotionState.h | 7 ++++--- libraries/physics/src/ObjectMotionState.h | 2 +- 5 files changed, 22 insertions(+), 4 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.h b/libraries/entities-renderer/src/RenderableModelEntityItem.h index a3d9e4db98..22469cf0ef 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.h +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.h @@ -61,6 +61,8 @@ public: virtual bool isReadyToComputeShape() override; virtual void computeShapeInfo(ShapeInfo& info) override; + void setCollisionShape(const btCollisionShape* shape) override {} + virtual bool contains(const glm::vec3& point) const override; virtual bool shouldBePhysical() const override; diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 9fe83b53cb..1ad1d938a7 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -44,6 +44,7 @@ class EntityTreeElementExtraEncodeData; class EntityActionInterface; class EntityItemProperties; class EntityTree; +class btCollisionShape; typedef std::shared_ptr EntityTreePointer; typedef std::shared_ptr EntityActionPointer; typedef std::shared_ptr EntityTreeElementPointer; @@ -324,6 +325,12 @@ public: /// return preferred shape type (actual physical shape may differ) virtual ShapeType getShapeType() const { return SHAPE_TYPE_NONE; } + virtual void setCollisionShape(const btCollisionShape* shape) {} + + // these are only needed because the names don't match + virtual const glm::quat getRotation() const { return getOrientation(); } + virtual void setRotation(glm::quat orientation) { setOrientation(orientation); } + // updateFoo() methods to be used when changes need to be accumulated in the _dirtyFlags virtual void updateRegistrationPoint(const glm::vec3& value); void updatePosition(const glm::vec3& value); diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 08d207fa72..4b6823dd8a 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -271,6 +271,14 @@ btCollisionShape* EntityMotionState::computeNewShape() { return getShapeManager()->getShape(shapeInfo); } +void EntityMotionState::setShape(btCollisionShape* shape) { + bool shapeChanged = (_shape != shape); + ObjectMotionState::setShape(shape); + if (shapeChanged) { + _entity->setCollisionShape(_shape); + } +} + bool EntityMotionState::isCandidateForOwnership() const { assert(_body); assert(_entity); diff --git a/libraries/physics/src/EntityMotionState.h b/libraries/physics/src/EntityMotionState.h index 8f1532bf8f..2c39da9164 100644 --- a/libraries/physics/src/EntityMotionState.h +++ b/libraries/physics/src/EntityMotionState.h @@ -88,9 +88,10 @@ protected: bool entityTreeIsLocked() const; #endif - virtual bool isReadyToComputeShape() const override; - virtual btCollisionShape* computeNewShape() override; - virtual void setMotionType(PhysicsMotionType motionType); + bool isReadyToComputeShape() const override; + btCollisionShape* computeNewShape() override; + void setShape(btCollisionShape* shape) override; + void setMotionType(PhysicsMotionType motionType) override; // In the glorious future (when entities lib depends on physics lib) the EntityMotionState will be // properly "owned" by the EntityItem and will be deleted by it in the dtor. In pursuit of that diff --git a/libraries/physics/src/ObjectMotionState.h b/libraries/physics/src/ObjectMotionState.h index ca9b80a3b3..ccaef17fd1 100644 --- a/libraries/physics/src/ObjectMotionState.h +++ b/libraries/physics/src/ObjectMotionState.h @@ -151,7 +151,7 @@ public: protected: virtual bool isReadyToComputeShape() const = 0; virtual btCollisionShape* computeNewShape() = 0; - void setMotionType(PhysicsMotionType motionType); + virtual void setMotionType(PhysicsMotionType motionType); void updateCCDConfiguration(); void setRigidBody(btRigidBody* body); From 499150bbed02387aa881002116ea137440bc960a Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 15 Jul 2016 15:56:52 -0700 Subject: [PATCH 16/45] finish hook alert for new entity collision shape --- libraries/entities-renderer/src/RenderableModelEntityItem.cpp | 4 ++++ libraries/entities-renderer/src/RenderableModelEntityItem.h | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index ac447417aa..2ff5e236fc 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -917,6 +917,10 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) { } } +void RenderableModelEntityItem::setCollisionShape(const btCollisionShape* shape) { + // TODO: generate collision mesh and update _model +} + bool RenderableModelEntityItem::contains(const glm::vec3& point) const { if (EntityItem::contains(point) && _model && _model->isCollisionLoaded()) { return _model->getCollisionFBXGeometry().convexHullContains(worldToEntity(point)); diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.h b/libraries/entities-renderer/src/RenderableModelEntityItem.h index 22469cf0ef..412cb6f296 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.h +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.h @@ -61,7 +61,7 @@ public: virtual bool isReadyToComputeShape() override; virtual void computeShapeInfo(ShapeInfo& info) override; - void setCollisionShape(const btCollisionShape* shape) override {} + void setCollisionShape(const btCollisionShape* shape) override; virtual bool contains(const glm::vec3& point) const override; From 726928c14c061d958b96362d73e88efda367ccdf Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 19 Jul 2016 09:38:54 -0700 Subject: [PATCH 17/45] creae collision Geometry from mesh --- libraries/entities-renderer/CMakeLists.txt | 2 +- .../src/RenderableModelEntityItem.cpp | 17 ++++++++++++- .../src/RenderableModelEntityItem.h | 1 + .../src/model-networking/ModelCache.h | 7 +++--- .../physics/src/CollisionRenderMeshCache.cpp | 24 ++++++++++++------- .../physics/src/CollisionRenderMeshCache.h | 4 +++- libraries/render-utils/src/Model.cpp | 22 +++++++++++++++++ libraries/render-utils/src/Model.h | 3 ++- 8 files changed, 64 insertions(+), 16 deletions(-) diff --git a/libraries/entities-renderer/CMakeLists.txt b/libraries/entities-renderer/CMakeLists.txt index 0063f4a701..9218b94fe1 100644 --- a/libraries/entities-renderer/CMakeLists.txt +++ b/libraries/entities-renderer/CMakeLists.txt @@ -1,7 +1,7 @@ set(TARGET_NAME entities-renderer) AUTOSCRIBE_SHADER_LIB(gpu model procedural render render-utils) setup_hifi_library(Widgets Network Script) -link_hifi_libraries(shared gpu procedural model model-networking script-engine render render-utils) +link_hifi_libraries(shared gpu procedural model model-networking script-engine render render-utils physics) target_bullet() diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 2ff5e236fc..cdf94017ff 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -17,6 +17,7 @@ #include #include +#include #include #include #include @@ -917,8 +918,22 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) { } } +static CollisionRenderMeshCache collisionMeshCache; + void RenderableModelEntityItem::setCollisionShape(const btCollisionShape* shape) { - // TODO: generate collision mesh and update _model + const void* key = static_cast(shape); + if (_collisionMeshKey != key) { + if (_collisionMeshKey) { + // releasing the shape is not strictly necessary, but + // we do it as hint to the cache's garbage collection system + collisionMeshCache.releaseMesh(_collisionMeshKey); + } + _collisionMeshKey = key; + model::MeshPointer mesh = collisionMeshCache.getMesh(_collisionMeshKey); + if (_model) { + _model->setCollisionMesh(mesh); + } + } } bool RenderableModelEntityItem::contains(const glm::vec3& point) const { diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.h b/libraries/entities-renderer/src/RenderableModelEntityItem.h index 412cb6f296..1f44260f65 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.h +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.h @@ -119,6 +119,7 @@ private: bool getAnimationFrame(); bool _needsJointSimulation { false }; + const void* _collisionMeshKey { nullptr }; }; #endif // hifi_RenderableModelEntityItem_h diff --git a/libraries/model-networking/src/model-networking/ModelCache.h b/libraries/model-networking/src/model-networking/ModelCache.h index 5c1aafdd45..fa93d3c899 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.h +++ b/libraries/model-networking/src/model-networking/ModelCache.h @@ -111,13 +111,12 @@ public: QUrl getURL() const { return (bool)_resource ? _resource->getURL() : QUrl(); } -signals: - void finished(bool success); - -private: void startWatching(); void stopWatching(); +signals: + void finished(bool success); + private slots: void resourceFinished(bool success); void resourceRefreshed(); diff --git a/libraries/physics/src/CollisionRenderMeshCache.cpp b/libraries/physics/src/CollisionRenderMeshCache.cpp index 14386c6f48..22f0b986ab 100644 --- a/libraries/physics/src/CollisionRenderMeshCache.cpp +++ b/libraries/physics/src/CollisionRenderMeshCache.cpp @@ -67,12 +67,16 @@ void copyShapeToMesh(const btTransform& transform, const btConvexShape* shape, m } } -model::MeshPointer createMeshFromShape(const btCollisionShape* shape) { +model::MeshPointer createMeshFromShape(const void* pointer) { model::MeshPointer mesh; - if (!shape) { + if (!pointer) { return mesh; } + // pointer must actually be a const btCollisionShape*, but it only + // needs to be valid here when its render mesh is created. + const btCollisionShape* shape = static_cast(pointer); + int32_t shapeType = shape->getShapeType(); if (shapeType == (int32_t)COMPOUND_SHAPE_PROXYTYPE || shape->isConvex()) { // create the mesh and allocate buffers for it @@ -84,7 +88,7 @@ model::MeshPointer createMeshFromShape(const btCollisionShape* shape) { if (shapeType == (int32_t)COMPOUND_SHAPE_PROXYTYPE) { const btCompoundShape* compoundShape = static_cast(shape); int32_t numSubShapes = compoundShape->getNumChildShapes(); - for (int i = 0; i < numSubShapes; ++i) { + for (int32_t i = 0; i < numSubShapes; ++i) { const btCollisionShape* childShape = compoundShape->getChildShape(i); if (childShape->isConvex()) { const btConvexShape* convexShape = static_cast(childShape); @@ -122,6 +126,10 @@ model::MeshPointer CollisionRenderMeshCache::getMesh(CollisionRenderMeshCache::K mesh = itr->second; } } + const uint32_t MAX_NUM_PENDING_GARBAGE = 20; + if (_pendingGarbage.size() > MAX_NUM_PENDING_GARBAGE) { + collectGarbage(); + } return mesh; } @@ -131,19 +139,19 @@ bool CollisionRenderMeshCache::releaseMesh(CollisionRenderMeshCache::Key key) { } CollisionMeshMap::const_iterator itr = _meshMap.find(key); if (itr != _meshMap.end()) { + // we hold at least one reference, and the outer scope also holds at least one + // so we assert that the reference count is not 1 assert((*itr).second.use_count() != 1); + _pendingGarbage.push_back(key); - if ((*itr).second.use_count() == 1) { - // we hold all of the references inside the cache so we'll try to delete later - } return true; } return false; } void CollisionRenderMeshCache::collectGarbage() { - int numShapes = _pendingGarbage.size(); - for (int i = 0; i < numShapes; ++i) { + uint32_t numShapes = _pendingGarbage.size(); + for (int32_t i = 0; i < numShapes; ++i) { CollisionRenderMeshCache::Key key = _pendingGarbage[i]; CollisionMeshMap::const_iterator itr = _meshMap.find(key); if (itr != _meshMap.end()) { diff --git a/libraries/physics/src/CollisionRenderMeshCache.h b/libraries/physics/src/CollisionRenderMeshCache.h index ad3c86562b..0c789f3da9 100644 --- a/libraries/physics/src/CollisionRenderMeshCache.h +++ b/libraries/physics/src/CollisionRenderMeshCache.h @@ -18,6 +18,7 @@ #include +/* class btCollisionShape; namespace std { @@ -28,10 +29,11 @@ namespace std { } }; } +*/ class CollisionRenderMeshCache { public: - using Key = const btCollisionShape*; + using Key = const void*; // must actually be a const btCollisionShape* CollisionRenderMeshCache(); ~CollisionRenderMeshCache(); diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index a6e1bb53f4..35e40403cf 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -1336,6 +1336,28 @@ bool Model::initWhenReady(render::ScenePointer scene) { return false; } +class CollisionRenderGeometry : public Geometry { +public: + CollisionRenderGeometry(model::MeshPointer mesh) { + _fbxGeometry = std::make_shared(); + std::shared_ptr meshes = std::make_shared(); + meshes->push_back(mesh); + _meshes = meshes; + _meshParts = std::shared_ptr(); + } +}; + +void Model::setCollisionMesh(model::MeshPointer mesh) { + _collisionWatcher.stopWatching(); + _collisionGeometry = std::make_shared(mesh); + + if (_showCollisionHull) { + // TODO: need to trigger: + // (a) reconstruction of RenderItems + // (b) and reinsertion into scene if we are showing collision geometry + } +} + ModelBlender::ModelBlender() : _pendingBlenders(0) { } diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index 15c8e0326a..d6580b8413 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -249,6 +249,7 @@ public slots: signals: void setURLFinished(bool success); void setCollisionModelURLFinished(bool success); + void setCollisionMesh(model::MeshPointer mesh); protected: @@ -282,7 +283,7 @@ protected: bool getJointPosition(int jointIndex, glm::vec3& position) const; Geometry::Pointer _renderGeometry; // only ever set by its watcher - Geometry::Pointer _collisionGeometry; // only ever set by its watcher + Geometry::Pointer _collisionGeometry; GeometryResourceWatcher _renderWatcher; GeometryResourceWatcher _collisionWatcher; From d8fa0d1dd1f0c4b5ff6ef817941f1b7e241b8965 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 19 Jul 2016 09:43:59 -0700 Subject: [PATCH 18/45] segregateMeshGroups() --> createRenderItems() --- libraries/render-utils/src/Model.cpp | 8 ++++---- libraries/render-utils/src/Model.h | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 35e40403cf..afb5cbcfb6 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -575,7 +575,7 @@ void Model::renderSetup(RenderArgs* args) { } if (!_meshGroupsKnown && isLoaded()) { - segregateMeshGroups(); + createRenderItems(); } } @@ -600,7 +600,7 @@ bool Model::addToScene(std::shared_ptr scene, bool showCollisionHull) { if ((!_meshGroupsKnown || showCollisionHull != _showCollisionHull) && isLoaded()) { _showCollisionHull = showCollisionHull; - segregateMeshGroups(); + createRenderItems(); } bool somethingAdded = false; @@ -1236,7 +1236,7 @@ AABox Model::getRenderableMeshBound() const { } } -void Model::segregateMeshGroups() { +void Model::createRenderItems() { Geometry::Pointer geometry; bool showingCollisionHull = false; if (_showCollisionHull && _collisionGeometry) { @@ -1303,7 +1303,7 @@ void Model::segregateMeshGroups() { bool Model::initWhenReady(render::ScenePointer scene) { if (isActive() && isRenderable() && !_meshGroupsKnown && isLoaded()) { - segregateMeshGroups(); + createRenderItems(); render::PendingChanges pendingChanges; diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index d6580b8413..55a55a3d27 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -377,7 +377,7 @@ protected: void recalculateMeshBoxes(bool pickAgainstTriangles = false); - void segregateMeshGroups(); // used to calculate our list of translucent vs opaque meshes + void createRenderItems(); // used to calculate our list of translucent vs opaque meshes static model::MaterialPointer _collisionHullMaterial; bool _meshGroupsKnown; From 6b0ae654ba3aa143960cad2cbcfbd57caf6a54a0 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 21 Jul 2016 17:11:04 -0700 Subject: [PATCH 19/45] cleanup logic around creating RenderItems --- .../src/RenderableModelEntityItem.cpp | 47 ++-- .../src/RenderableModelEntityItem.h | 2 - .../src/RenderableZoneEntityItem.cpp | 2 +- .../render-utils/src/MeshPartPayload.cpp | 5 +- libraries/render-utils/src/Model.cpp | 236 +++++++++++------- libraries/render-utils/src/Model.h | 24 +- 6 files changed, 195 insertions(+), 121 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index cdf94017ff..6e5d1c7959 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -177,6 +177,24 @@ void RenderableModelEntityItem::doInitialModelSimulation() { _needsInitialSimulation = false; } +// TODO: we need a solution for changes to the postion/rotation/etc of a model... +// this current code path only addresses that in this setup case... not the changing/moving case +bool RenderableModelEntityItem::readyToAddToScene(RenderArgs* renderArgs) { + if (!_model && renderArgs) { + // TODO: this getModel() appears to be about 3% of model render time. We should optimize + PerformanceTimer perfTimer("getModel"); + EntityTreeRenderer* renderer = static_cast(renderArgs->_renderer); + getModel(renderer); + } + if (renderArgs && _model && _needsInitialSimulation && _model->isActive() && _model->isLoaded()) { + // make sure to simulate so everything gets set up correctly for rendering + doInitialModelSimulation(); + _model->renderSetup(renderArgs); + } + bool ready = !_needsInitialSimulation && _model && _model->readyToAddToScene(); + return ready; +} + class RenderableModelEntityItemMeta { public: RenderableModelEntityItemMeta(EntityItemPointer entity) : entity(entity){ } @@ -215,21 +233,21 @@ namespace render { bool RenderableModelEntityItem::addToScene(EntityItemPointer self, std::shared_ptr scene, render::PendingChanges& pendingChanges) { _myMetaItem = scene->allocateID(); - + auto renderData = std::make_shared(self); auto renderPayload = std::make_shared(renderData); - + pendingChanges.resetItem(_myMetaItem, renderPayload); - + if (_model) { render::Item::Status::Getters statusGetters; makeEntityItemStatusGetters(getThisPointer(), statusGetters); - - // note: we don't care if the model fails to add items, we always added our meta item and therefore we return - // true so that the system knows our meta item is in the scene! - _model->addToScene(scene, pendingChanges, statusGetters, _showCollisionHull); + + // note: we don't mind if the model fails to add, we'll retry (in render()) until it succeeds + _model->addToScene(scene, pendingChanges, statusGetters); } + // we've successfully added _myMetaItem so we always return true return true; } @@ -416,19 +434,20 @@ void RenderableModelEntityItem::render(RenderArgs* args) { // Remap textures for the next frame to avoid flicker remapTextures(); - // check to see if when we added our models to the scene they were ready, if they were not ready, then - // fix them up in the scene - bool shouldShowCollisionHull = (args->_debugFlags & (int)RenderArgs::RENDER_DEBUG_HULLS) > 0 - && getShapeType() == SHAPE_TYPE_COMPOUND; - if (_model->needsFixupInScene() || _showCollisionHull != shouldShowCollisionHull) { - _showCollisionHull = shouldShowCollisionHull; + // update whether the model should be showing collision mesh + // (this may flag for fixupInScene) + bool shouldShowCollisionHull = getShapeType() != SHAPE_TYPE_STATIC_MESH && + (args->_debugFlags & (int)RenderArgs::RENDER_DEBUG_HULLS) > 0; + _model->setShowCollisionMesh(shouldShowCollisionHull); + + if (_model->needsFixupInScene()) { render::PendingChanges pendingChanges; _model->removeFromScene(scene, pendingChanges); render::Item::Status::Getters statusGetters; makeEntityItemStatusGetters(getThisPointer(), statusGetters); - _model->addToScene(scene, pendingChanges, statusGetters, _showCollisionHull); + _model->addToScene(scene, pendingChanges, statusGetters); scene->enqueuePendingChanges(pendingChanges); } diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.h b/libraries/entities-renderer/src/RenderableModelEntityItem.h index 1f44260f65..16cd9c8bc5 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.h +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.h @@ -114,8 +114,6 @@ private: render::ItemID _myMetaItem{ render::Item::INVALID_ITEM_ID }; - bool _showCollisionHull = false; - bool getAnimationFrame(); bool _needsJointSimulation { false }; diff --git a/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp b/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp index ef47a777c2..9aa52f5ad3 100644 --- a/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp @@ -122,7 +122,7 @@ void RenderableZoneEntityItem::render(RenderArgs* args) { _model->removeFromScene(scene, pendingChanges); render::Item::Status::Getters statusGetters; makeEntityItemStatusGetters(getThisPointer(), statusGetters); - _model->addToScene(scene, pendingChanges, false); + _model->addToScene(scene, pendingChanges); scene->enqueuePendingChanges(pendingChanges); diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index 1c8c89d6db..8913a62d9d 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -414,8 +414,7 @@ ShapeKey ModelMeshPartPayload::getShapeKey() const { // if our index is ever out of range for either meshes or networkMeshes, then skip it, and set our _meshGroupsKnown // to false to rebuild out mesh groups. if (_meshIndex < 0 || _meshIndex >= (int)networkMeshes.size() || _meshIndex > geometry.meshes.size()) { - _model->_meshGroupsKnown = false; // regenerate these lists next time around. - _model->_readyWhenAdded = false; // in case any of our users are using scenes + _model->_needsFixupInScene = true; // trigger remove/add cycle _model->invalidCalculatedMeshBoxes(); // if we have to reload, we need to assume our mesh boxes are all invalid return ShapeKey::Builder::invalid(); } @@ -533,7 +532,7 @@ void ModelMeshPartPayload::startFade() { void ModelMeshPartPayload::render(RenderArgs* args) const { PerformanceTimer perfTimer("ModelMeshPartPayload::render"); - if (!_model->_readyWhenAdded || !_model->_isVisible) { + if (!_model->addedToScene() || !_model->isVisible()) { return; // bail asap } diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index afb5cbcfb6..075e550dd5 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -100,7 +100,6 @@ Model::Model(RigPointer rig, QObject* parent) : _calculatedMeshPartBoxesValid(false), _calculatedMeshBoxesValid(false), _calculatedMeshTrianglesValid(false), - _meshGroupsKnown(false), _isWireframe(false), _rig(rig) { @@ -121,19 +120,33 @@ Model::~Model() { AbstractViewStateInterface* Model::_viewState = NULL; +void Model::setShowCollisionMesh(bool value) { + if (_showCollisionHull != value) { + _showCollisionHull = value; + _needsFixupInScene = true; + } +} + bool Model::needsFixupInScene() const { - if (readyToAddToScene()) { - if (_needsUpdateTextures && _renderGeometry->areTexturesLoaded()) { - _needsUpdateTextures = false; + if ((_needsFixupInScene || !_addedToScene) && !_needsReload && isLoaded()) { + if (_showCollisionHull && _collisionGeometry) { return true; } - if (!_readyWhenAdded) { + if (!_meshStates.isEmpty() || (_renderGeometry && _renderGeometry->getMeshes().empty())) { + if (_needsUpdateTextures) { + if (!_renderGeometry->areTexturesLoaded()) { + return false; + } + _needsUpdateTextures = false; + } return true; } } return false; } +// TODO?: should we combine translation and rotation into single method to avoid double-work? +// (figure out where we call these) void Model::setTranslation(const glm::vec3& translation) { _translation = translation; updateRenderItems(); @@ -172,6 +185,9 @@ void Model::setOffset(const glm::vec3& offset) { } void Model::updateRenderItems() { + if (!_addedToScene) { + return; + } _needsUpdateClusterMatrices = true; _renderItemsNeedUpdate = false; @@ -574,8 +590,8 @@ void Model::renderSetup(RenderArgs* args) { } } - if (!_meshGroupsKnown && isLoaded()) { - createRenderItems(); + if (!_addedToScene && isLoaded()) { + createRenderItemSet(); } } @@ -596,43 +612,46 @@ void Model::setVisibleInScene(bool newValue, std::shared_ptr scen bool Model::addToScene(std::shared_ptr scene, render::PendingChanges& pendingChanges, - render::Item::Status::Getters& statusGetters, - bool showCollisionHull) { - if ((!_meshGroupsKnown || showCollisionHull != _showCollisionHull) && isLoaded()) { - _showCollisionHull = showCollisionHull; - createRenderItems(); + render::Item::Status::Getters& statusGetters) { + bool readyToRender = (_showCollisionHull && _collisionGeometry) || isLoaded(); + if (!_addedToScene && readyToRender) { + createRenderItemSet(); } bool somethingAdded = false; - - if (_modelMeshRenderItems.empty()) { - foreach (auto renderItem, _modelMeshRenderItemsSet) { - auto item = scene->allocateID(); - auto renderPayload = std::make_shared(renderItem); - if (statusGetters.size()) { - renderPayload->addStatusGetters(statusGetters); + if (_showCollisionHull && _collisionGeometry) { + if (_collisionRenderItems.empty()) { + foreach (auto renderItem, _collisionRenderItemsSet) { + auto item = scene->allocateID(); + auto renderPayload = std::make_shared(renderItem); + if (statusGetters.size()) { + renderPayload->addStatusGetters(statusGetters); + } + pendingChanges.resetItem(item, renderPayload); + _collisionRenderItems.insert(item, renderPayload); } - pendingChanges.resetItem(item, renderPayload); - _modelMeshRenderItems.insert(item, renderPayload); - somethingAdded = true; + somethingAdded = !_collisionRenderItems.empty(); } - } - if (_collisionRenderItems.empty()) { - foreach (auto renderItem, _collisionRenderItemsSet) { - auto item = scene->allocateID(); - auto renderPayload = std::make_shared(renderItem); - if (statusGetters.size()) { - renderPayload->addStatusGetters(statusGetters); + } else { + if (_modelMeshRenderItems.empty()) { + foreach (auto renderItem, _modelMeshRenderItemsSet) { + auto item = scene->allocateID(); + auto renderPayload = std::make_shared(renderItem); + if (statusGetters.size()) { + renderPayload->addStatusGetters(statusGetters); + } + pendingChanges.resetItem(item, renderPayload); + _modelMeshRenderItems.insert(item, renderPayload); } - pendingChanges.resetItem(item, renderPayload); - _collisionRenderItems.insert(item, renderPayload); - somethingAdded = true; + somethingAdded = !_modelMeshRenderItems.empty(); } } - updateRenderItems(); - - _readyWhenAdded = readyToAddToScene(); + if (somethingAdded) { + _addedToScene = true; + updateRenderItems(); + _needsFixupInScene = false; + } return somethingAdded; } @@ -643,13 +662,13 @@ void Model::removeFromScene(std::shared_ptr scene, render::Pendin } _modelMeshRenderItems.clear(); _modelMeshRenderItemsSet.clear(); + foreach (auto item, _collisionRenderItems.keys()) { pendingChanges.removeItem(item); } _collisionRenderItems.clear(); _collisionRenderItemsSet.clear(); - _meshGroupsKnown = false; - _readyWhenAdded = false; + _addedToScene = false; } void Model::renderDebugMeshBoxes(gpu::Batch& batch) { @@ -804,6 +823,7 @@ int Model::getLastFreeJointIndex(int jointIndex) const { void Model::setTextures(const QVariantMap& textures) { if (isLoaded()) { _needsUpdateTextures = true; + _needsFixupInScene = true; _renderGeometry->setTextures(textures); } } @@ -825,8 +845,8 @@ void Model::setURL(const QUrl& url) { _needsReload = true; _needsUpdateTextures = true; - _meshGroupsKnown = false; _visualGeometryRequestFailed = false; + _needsFixupInScene = true; invalidCalculatedMeshBoxes(); deleteGeometry(); @@ -1236,21 +1256,21 @@ AABox Model::getRenderableMeshBound() const { } } -void Model::createRenderItems() { - Geometry::Pointer geometry; - bool showingCollisionHull = false; +void Model::createRenderItemSet() { if (_showCollisionHull && _collisionGeometry) { - if (isCollisionLoaded()) { - geometry = _collisionGeometry; - showingCollisionHull = true; - } else { - return; + if (_collisionRenderItemsSet.empty()) { + createCollisionRenderItemSet(); } } else { - assert(isLoaded()); - geometry = _renderGeometry; + if (_modelMeshRenderItemsSet.empty()) { + createVisibleRenderItemSet(); + } } - const auto& meshes = geometry->getMeshes(); +}; + +void Model::createVisibleRenderItemSet() { + assert(isLoaded()); + const auto& meshes = _renderGeometry->getMeshes(); // all of our mesh vectors must match in size if ((int)meshes.size() != _meshStates.size()) { @@ -1259,13 +1279,9 @@ void Model::createRenderItems() { } // We should not have any existing renderItems if we enter this section of code - Q_ASSERT(_modelMeshRenderItems.isEmpty()); Q_ASSERT(_modelMeshRenderItemsSet.isEmpty()); - Q_ASSERT(_collisionRenderItems.isEmpty()); - Q_ASSERT(_collisionRenderItemsSet.isEmpty()); _modelMeshRenderItemsSet.clear(); - _collisionRenderItemsSet.clear(); Transform transform; transform.setTranslation(_translation); @@ -1280,60 +1296,98 @@ void Model::createRenderItems() { uint32_t numMeshes = (uint32_t)meshes.size(); for (uint32_t i = 0; i < numMeshes; i++) { const auto& mesh = meshes.at(i); - if (mesh) { + if (!mesh) { + continue; + } - // Create the render payloads - int numParts = (int)mesh->getNumParts(); - for (int partIndex = 0; partIndex < numParts; partIndex++) { - if (showingCollisionHull) { - if (_collisionHullMaterials.empty()) { - initCollisionHullMaterials(); - } - _collisionRenderItemsSet << std::make_shared(mesh, partIndex, _collisionHullMaterials[partIndex % NUM_COLLISION_HULL_COLORS], transform, offset); - } else { - _modelMeshRenderItemsSet << std::make_shared(this, i, partIndex, shapeID, transform, offset); - } - - shapeID++; - } + // Create the render payloads + int numParts = (int)mesh->getNumParts(); + for (int partIndex = 0; partIndex < numParts; partIndex++) { + _modelMeshRenderItemsSet << std::make_shared(this, i, partIndex, shapeID, transform, offset); + shapeID++; } } - _meshGroupsKnown = true; +} + +void Model::createCollisionRenderItemSet() { + assert((bool)_collisionGeometry); + if (_collisionHullMaterials.empty()) { + initCollisionHullMaterials(); + } + + const auto& meshes = _collisionGeometry->getMeshes(); + + // We should not have any existing renderItems if we enter this section of code + Q_ASSERT(_collisionRenderItemsSet.isEmpty()); + + Transform transform; + transform.setTranslation(_translation); + transform.setRotation(_rotation); + + Transform offset; + offset.setScale(_scale); + offset.postTranslate(_offset); + + // Run through all of the meshes, and place them into their segregated, but unsorted buckets + uint32_t numMeshes = (uint32_t)meshes.size(); + for (uint32_t i = 0; i < numMeshes; i++) { + const auto& mesh = meshes.at(i); + if (!mesh) { + continue; + } + + // Create the render payloads + int numParts = (int)mesh->getNumParts(); + for (int partIndex = 0; partIndex < numParts; partIndex++) { + model::MaterialPointer& material = _collisionHullMaterials[partIndex % NUM_COLLISION_HULL_COLORS]; + _collisionRenderItemsSet << std::make_shared(mesh, partIndex, material, transform, offset); + } + } +} + +bool Model::isRenderable() const { + return !_meshStates.isEmpty() || (isLoaded() && _renderGeometry->getMeshes().empty()); } bool Model::initWhenReady(render::ScenePointer scene) { - if (isActive() && isRenderable() && !_meshGroupsKnown && isLoaded()) { - createRenderItems(); + // NOTE: this only called by SkeletonModel + if (_addedToScene || !isRenderable()) { + return false; + } - render::PendingChanges pendingChanges; + createRenderItemSet(); - Transform transform; - transform.setTranslation(_translation); - transform.setRotation(_rotation); + render::PendingChanges pendingChanges; - Transform offset; - offset.setScale(_scale); - offset.postTranslate(_offset); - - foreach (auto renderItem, _modelMeshRenderItemsSet) { - auto item = scene->allocateID(); - auto renderPayload = std::make_shared(renderItem); - _modelMeshRenderItems.insert(item, renderPayload); - pendingChanges.resetItem(item, renderPayload); - } + bool addedPendingChanges = false; + if (_showCollisionHull && _collisionGeometry) { foreach (auto renderItem, _collisionRenderItemsSet) { auto item = scene->allocateID(); auto renderPayload = std::make_shared(renderItem); _collisionRenderItems.insert(item, renderPayload); pendingChanges.resetItem(item, renderPayload); } - scene->enqueuePendingChanges(pendingChanges); - updateRenderItems(); - - _readyWhenAdded = true; - return true; + addedPendingChanges = !_collisionRenderItems.empty(); + } else { + foreach (auto renderItem, _modelMeshRenderItemsSet) { + auto item = scene->allocateID(); + auto renderPayload = std::make_shared(renderItem); + _modelMeshRenderItems.insert(item, renderPayload); + pendingChanges.resetItem(item, renderPayload); + } + addedPendingChanges = !_modelMeshRenderItems.empty(); } - return false; + _addedToScene = addedPendingChanges; + if (addedPendingChanges) { + scene->enqueuePendingChanges(pendingChanges); + // NOTE: updateRender items enqueues identical pendingChanges (using a lambda) + // so it looks like we're doing double work here, but I don't want to remove the call + // for fear there is some sideeffect we'll miss. -- Andrew 2016.07.21 + // TODO: figure out if we really need this call to updateRenderItems() or not. + updateRenderItems(); + } + + return true; } class CollisionRenderGeometry : public Geometry { diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index 55a55a3d27..b30b0b0d76 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -81,24 +81,25 @@ public: // new Scene/Engine rendering support void setVisibleInScene(bool newValue, std::shared_ptr scene); bool needsFixupInScene() const; + + void setShowCollisionMesh(bool value); + bool readyToAddToScene(RenderArgs* renderArgs = nullptr) const { return !_needsReload && isRenderable() && isActive(); } bool needsReload() const { return _needsReload; } bool initWhenReady(render::ScenePointer scene); bool addToScene(std::shared_ptr scene, - render::PendingChanges& pendingChanges, - bool showCollisionHull = false) { + render::PendingChanges& pendingChanges) { auto getters = render::Item::Status::Getters(0); - return addToScene(scene, pendingChanges, getters, showCollisionHull); + return addToScene(scene, pendingChanges, getters); } bool addToScene(std::shared_ptr scene, render::PendingChanges& pendingChanges, - render::Item::Status::Getters& statusGetters, - bool showCollisionHull = false); + render::Item::Status::Getters& statusGetters); void removeFromScene(std::shared_ptr scene, render::PendingChanges& pendingChanges); void renderSetup(RenderArgs* args); - bool isRenderable() const { return !_meshStates.isEmpty() || (isActive() && _renderGeometry->getMeshes().empty()); } + bool isRenderable() const; bool isVisible() const { return _isVisible; } @@ -239,6 +240,7 @@ public: // returns 'true' if needs fullUpdate after geometry change bool updateGeometry(); + void setCollisionMesh(model::MeshPointer mesh); void setLoadingPriority(float priority) { _loadingPriority = priority; } @@ -249,9 +251,9 @@ public slots: signals: void setURLFinished(bool success); void setCollisionModelURLFinished(bool success); - void setCollisionMesh(model::MeshPointer mesh); protected: + bool addedToScene() const { return _addedToScene; } void setPupilDilation(float dilation) { _pupilDilation = dilation; } float getPupilDilation() const { return _pupilDilation; } @@ -377,10 +379,11 @@ protected: void recalculateMeshBoxes(bool pickAgainstTriangles = false); - void createRenderItems(); // used to calculate our list of translucent vs opaque meshes + void createRenderItemSet(); + void createVisibleRenderItemSet(); + void createCollisionRenderItemSet(); static model::MaterialPointer _collisionHullMaterial; - bool _meshGroupsKnown; bool _isWireframe; @@ -397,7 +400,8 @@ protected: QSet> _modelMeshRenderItemsSet; QMap _modelMeshRenderItems; - bool _readyWhenAdded { false }; + bool _addedToScene { false }; // has been added to scene + bool _needsFixupInScene { true }; // needs to be removed/re-added to scene bool _needsReload { true }; bool _needsUpdateClusterMatrices { true }; bool _showCollisionHull { false }; From 25fb7aacad3e9e49674ae8686c27aa20a48375fb Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 26 Jul 2016 07:53:11 -0700 Subject: [PATCH 20/45] ShapeManager hands out const shape pointers --- interface/src/avatar/AvatarManager.cpp | 2 +- interface/src/avatar/AvatarMotionState.cpp | 4 ++-- interface/src/avatar/AvatarMotionState.h | 4 ++-- libraries/physics/src/PhysicalEntitySimulation.cpp | 2 +- libraries/physics/src/PhysicsEngine.cpp | 6 +++--- libraries/physics/src/ShapeFactory.cpp | 14 +++++++++----- libraries/physics/src/ShapeFactory.h | 4 ++-- libraries/physics/src/ShapeManager.cpp | 4 ++-- libraries/physics/src/ShapeManager.h | 4 ++-- 9 files changed, 24 insertions(+), 20 deletions(-) diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index bd76d2bd81..441130bd83 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -367,7 +367,7 @@ void AvatarManager::addAvatarToSimulation(Avatar* avatar) { ShapeInfo shapeInfo; avatar->computeShapeInfo(shapeInfo); - btCollisionShape* shape = ObjectMotionState::getShapeManager()->getShape(shapeInfo); + btCollisionShape* shape = const_cast(ObjectMotionState::getShapeManager()->getShape(shapeInfo)); if (shape) { // we don't add to the simulation now, we put it on a list to be added later AvatarMotionState* motionState = new AvatarMotionState(avatar, shape); diff --git a/interface/src/avatar/AvatarMotionState.cpp b/interface/src/avatar/AvatarMotionState.cpp index 9cc3095ae2..335245670b 100644 --- a/interface/src/avatar/AvatarMotionState.cpp +++ b/interface/src/avatar/AvatarMotionState.cpp @@ -17,7 +17,7 @@ #include "AvatarMotionState.h" #include "BulletUtil.h" -AvatarMotionState::AvatarMotionState(Avatar* avatar, btCollisionShape* shape) : ObjectMotionState(shape), _avatar(avatar) { +AvatarMotionState::AvatarMotionState(Avatar* avatar, const btCollisionShape* shape) : ObjectMotionState(shape), _avatar(avatar) { assert(_avatar); _type = MOTIONSTATE_TYPE_AVATAR; if (_shape) { @@ -47,7 +47,7 @@ PhysicsMotionType AvatarMotionState::computePhysicsMotionType() const { } // virtual and protected -btCollisionShape* AvatarMotionState::computeNewShape() { +const btCollisionShape* AvatarMotionState::computeNewShape() { ShapeInfo shapeInfo; _avatar->computeShapeInfo(shapeInfo); return getShapeManager()->getShape(shapeInfo); diff --git a/interface/src/avatar/AvatarMotionState.h b/interface/src/avatar/AvatarMotionState.h index 04aa5ea57c..66824d6e37 100644 --- a/interface/src/avatar/AvatarMotionState.h +++ b/interface/src/avatar/AvatarMotionState.h @@ -20,7 +20,7 @@ class Avatar; class AvatarMotionState : public ObjectMotionState { public: - AvatarMotionState(Avatar* avatar, btCollisionShape* shape); + AvatarMotionState(Avatar* avatar, const btCollisionShape* shape); virtual PhysicsMotionType getMotionType() const override { return _motionType; } @@ -72,7 +72,7 @@ protected: ~AvatarMotionState(); virtual bool isReadyToComputeShape() const override { return true; } - virtual btCollisionShape* computeNewShape() override; + virtual const btCollisionShape* computeNewShape() override; // The AvatarMotionState keeps a RAW backpointer to its Avatar because all AvatarMotionState // instances are "owned" by their corresponding Avatar instance and are deleted in the Avatar dtor. diff --git a/libraries/physics/src/PhysicalEntitySimulation.cpp b/libraries/physics/src/PhysicalEntitySimulation.cpp index 9714059e7c..be420604b3 100644 --- a/libraries/physics/src/PhysicalEntitySimulation.cpp +++ b/libraries/physics/src/PhysicalEntitySimulation.cpp @@ -225,7 +225,7 @@ void PhysicalEntitySimulation::getObjectsToAddToPhysics(VectorOfMotionStates& re << "at" << entity->getPosition() << " will be reduced"; } } - btCollisionShape* shape = ObjectMotionState::getShapeManager()->getShape(shapeInfo); + btCollisionShape* shape = const_cast(ObjectMotionState::getShapeManager()->getShape(shapeInfo)); if (shape) { EntityMotionState* motionState = new EntityMotionState(shape, entity); entity->setPhysicsInfo(static_cast(motionState)); diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index aa6c1b4e40..1c6d5d535e 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -76,7 +76,7 @@ void PhysicsEngine::addObjectToDynamicsWorld(ObjectMotionState* motionState) { switch(motionType) { case MOTION_TYPE_KINEMATIC: { if (!body) { - btCollisionShape* shape = motionState->getShape(); + btCollisionShape* shape = const_cast(motionState->getShape()); assert(shape); body = new btRigidBody(mass, motionState, shape, inertia); motionState->setRigidBody(body); @@ -93,7 +93,7 @@ void PhysicsEngine::addObjectToDynamicsWorld(ObjectMotionState* motionState) { } case MOTION_TYPE_DYNAMIC: { mass = motionState->getMass(); - btCollisionShape* shape = motionState->getShape(); + btCollisionShape* shape = const_cast(motionState->getShape()); assert(shape); shape->calculateLocalInertia(mass, inertia); if (!body) { @@ -120,7 +120,7 @@ void PhysicsEngine::addObjectToDynamicsWorld(ObjectMotionState* motionState) { default: { if (!body) { assert(motionState->getShape()); - body = new btRigidBody(mass, motionState, motionState->getShape(), inertia); + body = new btRigidBody(mass, motionState, const_cast(motionState->getShape()), inertia); motionState->setRigidBody(body); } else { body->setMassProps(mass, inertia); diff --git a/libraries/physics/src/ShapeFactory.cpp b/libraries/physics/src/ShapeFactory.cpp index 8576a9caee..f11b0f95dc 100644 --- a/libraries/physics/src/ShapeFactory.cpp +++ b/libraries/physics/src/ShapeFactory.cpp @@ -247,7 +247,7 @@ void deleteStaticMeshArray(btTriangleIndexVertexArray* dataArray) { delete dataArray; } -btCollisionShape* ShapeFactory::createShapeFromInfo(const ShapeInfo& info) { +const btCollisionShape* ShapeFactory::createShapeFromInfo(const ShapeInfo& info) { btCollisionShape* shape = NULL; int type = info.getType(); switch(type) { @@ -359,10 +359,14 @@ btCollisionShape* ShapeFactory::createShapeFromInfo(const ShapeInfo& info) { return shape; } -void ShapeFactory::deleteShape(btCollisionShape* shape) { +void ShapeFactory::deleteShape(const btCollisionShape* shape) { assert(shape); - if (shape->getShapeType() == (int)COMPOUND_SHAPE_PROXYTYPE) { - btCompoundShape* compoundShape = static_cast(shape); + // ShapeFactory is responsible for deleting all shapes, even the const ones that are stored + // in the ShapeManager, so we must cast to non-const here when deleting. + // so we cast to non-const here when deleting memory. + btCollisionShape* nonConstShape = const_cast(shape); + if (nonConstShape->getShapeType() == (int)COMPOUND_SHAPE_PROXYTYPE) { + btCompoundShape* compoundShape = static_cast(nonConstShape); const int numChildShapes = compoundShape->getNumChildShapes(); for (int i = 0; i < numChildShapes; i ++) { btCollisionShape* childShape = compoundShape->getChildShape(i); @@ -374,7 +378,7 @@ void ShapeFactory::deleteShape(btCollisionShape* shape) { } } } - delete shape; + delete nonConstShape; } // the dataArray must be created before we create the StaticMeshShape diff --git a/libraries/physics/src/ShapeFactory.h b/libraries/physics/src/ShapeFactory.h index 6202612eb9..a1022104dd 100644 --- a/libraries/physics/src/ShapeFactory.h +++ b/libraries/physics/src/ShapeFactory.h @@ -20,8 +20,8 @@ // translates between ShapeInfo and btShape namespace ShapeFactory { - btCollisionShape* createShapeFromInfo(const ShapeInfo& info); - void deleteShape(btCollisionShape* shape); + const btCollisionShape* createShapeFromInfo(const ShapeInfo& info); + void deleteShape(const btCollisionShape* shape); //btTriangleIndexVertexArray* createStaticMeshArray(const ShapeInfo& info); //void deleteStaticMeshArray(btTriangleIndexVertexArray* dataArray); diff --git a/libraries/physics/src/ShapeManager.cpp b/libraries/physics/src/ShapeManager.cpp index 35046adcfd..b61fb0037b 100644 --- a/libraries/physics/src/ShapeManager.cpp +++ b/libraries/physics/src/ShapeManager.cpp @@ -28,7 +28,7 @@ ShapeManager::~ShapeManager() { _shapeMap.clear(); } -btCollisionShape* ShapeManager::getShape(const ShapeInfo& info) { +const btCollisionShape* ShapeManager::getShape(const ShapeInfo& info) { if (info.getType() == SHAPE_TYPE_NONE) { return nullptr; } @@ -45,7 +45,7 @@ btCollisionShape* ShapeManager::getShape(const ShapeInfo& info) { shapeRef->refCount++; return shapeRef->shape; } - btCollisionShape* shape = ShapeFactory::createShapeFromInfo(info); + const btCollisionShape* shape = ShapeFactory::createShapeFromInfo(info); if (shape) { ShapeReference newRef; newRef.refCount = 1; diff --git a/libraries/physics/src/ShapeManager.h b/libraries/physics/src/ShapeManager.h index cdb2b78789..261c06ddb9 100644 --- a/libraries/physics/src/ShapeManager.h +++ b/libraries/physics/src/ShapeManager.h @@ -26,7 +26,7 @@ public: ~ShapeManager(); /// \return pointer to shape - btCollisionShape* getShape(const ShapeInfo& info); + const btCollisionShape* getShape(const ShapeInfo& info); /// \return true if shape was found and released bool releaseShape(const btCollisionShape* shape); @@ -46,7 +46,7 @@ private: class ShapeReference { public: int refCount; - btCollisionShape* shape; + const btCollisionShape* shape; DoubleHashKey key; ShapeReference() : refCount(0), shape(nullptr) {} }; From daff897fc4bd16e0a7b71a77b6fda6355aafbf4d Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 26 Jul 2016 07:54:31 -0700 Subject: [PATCH 21/45] const shapes, and use *MotionState::setShape() --- libraries/physics/src/EntityMotionState.cpp | 14 ++++++++------ libraries/physics/src/EntityMotionState.h | 4 ++-- libraries/physics/src/ObjectMotionState.cpp | 12 ++++++------ libraries/physics/src/ObjectMotionState.h | 10 +++++----- 4 files changed, 21 insertions(+), 19 deletions(-) diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 4b6823dd8a..b70927d501 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -46,7 +46,7 @@ bool entityTreeIsLocked() { EntityMotionState::EntityMotionState(btCollisionShape* shape, EntityItemPointer entity) : - ObjectMotionState(shape), + ObjectMotionState(nullptr), _entityPtr(entity), _entity(entity.get()), _serverPosition(0.0f), @@ -71,6 +71,9 @@ EntityMotionState::EntityMotionState(btCollisionShape* shape, EntityItemPointer assert(_entity); assert(entityTreeIsLocked()); setMass(_entity->computeMass()); + // we need the side-effects of EntityMotionState::setShape() so we call it explicitly here + // rather than pass the legit shape pointer to the ObjectMotionState ctor above. + setShape(shape); } EntityMotionState::~EntityMotionState() { @@ -264,17 +267,16 @@ bool EntityMotionState::isReadyToComputeShape() const { } // virtual and protected -btCollisionShape* EntityMotionState::computeNewShape() { +const btCollisionShape* EntityMotionState::computeNewShape() { ShapeInfo shapeInfo; assert(entityTreeIsLocked()); _entity->computeShapeInfo(shapeInfo); return getShapeManager()->getShape(shapeInfo); } -void EntityMotionState::setShape(btCollisionShape* shape) { - bool shapeChanged = (_shape != shape); - ObjectMotionState::setShape(shape); - if (shapeChanged) { +void EntityMotionState::setShape(const btCollisionShape* shape) { + if (_shape != shape) { + ObjectMotionState::setShape(shape); _entity->setCollisionShape(_shape); } } diff --git a/libraries/physics/src/EntityMotionState.h b/libraries/physics/src/EntityMotionState.h index 2c39da9164..194d82805f 100644 --- a/libraries/physics/src/EntityMotionState.h +++ b/libraries/physics/src/EntityMotionState.h @@ -89,8 +89,8 @@ protected: #endif bool isReadyToComputeShape() const override; - btCollisionShape* computeNewShape() override; - void setShape(btCollisionShape* shape) override; + const btCollisionShape* computeNewShape() override; + void setShape(const btCollisionShape* shape) override; void setMotionType(PhysicsMotionType motionType) override; // In the glorious future (when entities lib depends on physics lib) the EntityMotionState will be diff --git a/libraries/physics/src/ObjectMotionState.cpp b/libraries/physics/src/ObjectMotionState.cpp index 64b1e9c527..38f079c1d4 100644 --- a/libraries/physics/src/ObjectMotionState.cpp +++ b/libraries/physics/src/ObjectMotionState.cpp @@ -62,14 +62,13 @@ ShapeManager* ObjectMotionState::getShapeManager() { return shapeManager; } -ObjectMotionState::ObjectMotionState(btCollisionShape* shape) : +ObjectMotionState::ObjectMotionState(const btCollisionShape* shape) : _motionType(MOTION_TYPE_STATIC), - _shape(nullptr), + _shape(shape), _body(nullptr), _mass(0.0f), _lastKinematicStep(worldSimulationStep) { - setShape(shape); } ObjectMotionState::~ObjectMotionState() { @@ -154,12 +153,13 @@ void ObjectMotionState::setRigidBody(btRigidBody* body) { _body = body; if (_body) { _body->setUserPointer(this); + assert(_body->getCollisionShape() == _shape); } updateCCDConfiguration(); } } -void ObjectMotionState::setShape(btCollisionShape* shape) { +void ObjectMotionState::setShape(const btCollisionShape* shape) { if (_shape != shape) { if (_shape) { getShapeManager()->releaseShape(_shape); @@ -254,7 +254,7 @@ bool ObjectMotionState::handleHardAndEasyChanges(uint32_t& flags, PhysicsEngine* if (!isReadyToComputeShape()) { return false; } - btCollisionShape* newShape = computeNewShape(); + const btCollisionShape* newShape = computeNewShape(); if (!newShape) { qCDebug(physics) << "Warning: failed to generate new shape!"; // failed to generate new shape! --> keep old shape and remove shape-change flag @@ -274,7 +274,7 @@ bool ObjectMotionState::handleHardAndEasyChanges(uint32_t& flags, PhysicsEngine* // and clear the reference we just created getShapeManager()->releaseShape(_shape); } else { - _body->setCollisionShape(newShape); + _body->setCollisionShape(const_cast(newShape)); setShape(newShape); updateCCDConfiguration(); } diff --git a/libraries/physics/src/ObjectMotionState.h b/libraries/physics/src/ObjectMotionState.h index ccaef17fd1..a7894998a8 100644 --- a/libraries/physics/src/ObjectMotionState.h +++ b/libraries/physics/src/ObjectMotionState.h @@ -78,7 +78,7 @@ public: static void setShapeManager(ShapeManager* manager); static ShapeManager* getShapeManager(); - ObjectMotionState(btCollisionShape* shape); + ObjectMotionState(const btCollisionShape* shape); ~ObjectMotionState(); virtual void handleEasyChanges(uint32_t& flags); @@ -110,7 +110,7 @@ public: virtual PhysicsMotionType computePhysicsMotionType() const = 0; - btCollisionShape* getShape() const { return _shape; } + const btCollisionShape* getShape() const { return _shape; } btRigidBody* getRigidBody() const { return _body; } virtual bool isMoving() const = 0; @@ -150,17 +150,17 @@ public: protected: virtual bool isReadyToComputeShape() const = 0; - virtual btCollisionShape* computeNewShape() = 0; + virtual const btCollisionShape* computeNewShape() = 0; virtual void setMotionType(PhysicsMotionType motionType); void updateCCDConfiguration(); void setRigidBody(btRigidBody* body); - virtual void setShape(btCollisionShape* shape); + virtual void setShape(const btCollisionShape* shape); MotionStateType _type = MOTIONSTATE_TYPE_INVALID; // type of MotionState PhysicsMotionType _motionType; // type of motion: KINEMATIC, DYNAMIC, or STATIC - btCollisionShape* _shape; + const btCollisionShape* _shape; btRigidBody* _body; float _mass; From 26f5d3cfaa382dcf075ba7f8f503e7b2305bbcb3 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 26 Jul 2016 07:55:34 -0700 Subject: [PATCH 22/45] fix render geometry for collision shapes --- .../physics/src/CollisionRenderMeshCache.cpp | 84 ++++++++++++------- libraries/render-utils/src/Model.cpp | 23 +++-- 2 files changed, 67 insertions(+), 40 deletions(-) diff --git a/libraries/physics/src/CollisionRenderMeshCache.cpp b/libraries/physics/src/CollisionRenderMeshCache.cpp index 22f0b986ab..ef2f9013ef 100644 --- a/libraries/physics/src/CollisionRenderMeshCache.cpp +++ b/libraries/physics/src/CollisionRenderMeshCache.cpp @@ -18,53 +18,69 @@ #include // for MAX_HULL_POINTS -float verts[3 * MAX_HULL_POINTS]; +const int32_t MAX_HULL_INDICES = 6 * MAX_HULL_POINTS; +float tempVertexBuffer[3 * MAX_HULL_POINTS]; +model::Index tempIndexBuffer[MAX_HULL_INDICES]; -void copyShapeToMesh(const btTransform& transform, const btConvexShape* shape, model::MeshPointer mesh) { - assert((bool)mesh); +//void copyShapeToMesh(const btTransform& transform, const btConvexShape* shape, model::MeshPointer mesh) { +void copyShapeToMesh(const btTransform& transform, const btConvexShape* shape, + gpu::BufferView& vertices, gpu::BufferView& indices, gpu::BufferView& parts) { assert(shape); btShapeHull hull(shape); const btScalar MARGIN = 0.0f; hull.buildHull(MARGIN); - const uint32_t* hullIndices = hull.getIndexPointer(); - int32_t numIndices = hull.numIndices(); - assert(numIndices <= 6 * MAX_HULL_POINTS); + int32_t numHullIndices = hull.numIndices(); + assert(numHullIndices <= MAX_HULL_INDICES); + + int32_t numHullVertices = hull.numVertices(); + assert(numHullVertices <= MAX_HULL_POINTS); { // new part model::Mesh::Part part; - part._startIndex = mesh->getIndexBuffer().getNumElements(); - part._numIndices = (model::Index)numIndices; - part._baseVertex = mesh->getVertexBuffer().getNumElements(); + part._startIndex = indices.getNumElements(); + part._numIndices = (model::Index)numHullIndices; + // FIXME: the render code cannot handle the case where part._baseVertex != 0 + //part._baseVertex = vertices.getNumElements(); // DOES NOT WORK + part._baseVertex = 0; gpu::BufferView::Size numBytes = sizeof(model::Mesh::Part); const gpu::Byte* data = reinterpret_cast(&part); - mesh->getPartBuffer()._buffer->append(numBytes, data); + parts._buffer->append(numBytes, data); + parts._size = parts._buffer->getSize(); } + model::Index indexOffset = vertices.getNumElements(); { // new vertices const btVector3* hullVertices = hull.getVertexPointer(); - int32_t numVertices = hull.numVertices(); - assert(numVertices <= MAX_HULL_POINTS); - for (int32_t i = 0; i < numVertices; ++i) { + assert(numHullVertices <= MAX_HULL_POINTS); + for (int32_t i = 0; i < numHullVertices; ++i) { btVector3 transformedPoint = transform * hullVertices[i]; - memcpy(transformedPoint.m_floats, verts + 3 * i, 3 * sizeof(float)); - //data[0] = transformedPoint.getX(); - //data[1] = transformedPoint.getY(); - //data[2] = transformedPoint.getZ(); + memcpy(tempVertexBuffer + 3 * i, transformedPoint.m_floats, 3 * sizeof(float)); } - gpu::BufferView::Size numBytes = sizeof(float) * (3 * numVertices); - const gpu::Byte* data = reinterpret_cast(verts); - mesh->getVertexBuffer()._buffer->append(numBytes, data); + gpu::BufferView::Size numBytes = sizeof(float) * (3 * numHullVertices); + const gpu::Byte* data = reinterpret_cast(tempVertexBuffer); + vertices._buffer->append(numBytes, data); + vertices._size = vertices._buffer->getSize(); } { // new indices - gpu::BufferView::Size numBytes = (gpu::BufferView::Size)(sizeof(uint32_t) * hull.numIndices()); - const gpu::Byte* data = reinterpret_cast(hullIndices); - mesh->getIndexBuffer()._buffer->append(numBytes, data); + const uint32_t* hullIndices = hull.getIndexPointer(); + // FIXME: the render code cannot handle the case where part._baseVertex != 0 + // so we must add an offset to each index + for (int32_t i = 0; i < numHullIndices; ++i) { + tempIndexBuffer[i] = hullIndices[i] + indexOffset; + } + const gpu::Byte* data = reinterpret_cast(tempIndexBuffer); + gpu::BufferView::Size numBytes = (gpu::BufferView::Size)(sizeof(model::Index) * numHullIndices); + indices._buffer->append(numBytes, data); + indices._size = indices._buffer->getSize(); } + + gpu::BufferView::Iterator partItr = parts.cbegin(); + gpu::Size numParts = parts.getNumElements(); } model::MeshPointer createMeshFromShape(const void* pointer) { @@ -73,17 +89,18 @@ model::MeshPointer createMeshFromShape(const void* pointer) { return mesh; } - // pointer must actually be a const btCollisionShape*, but it only - // needs to be valid here when its render mesh is created. + // pointer must be a const btCollisionShape* (cast to void*), but it only + // needs to be valid here when its render mesh is created, after this call + // the cache doesn't care what happens to the shape behind the pointer const btCollisionShape* shape = static_cast(pointer); int32_t shapeType = shape->getShapeType(); if (shapeType == (int32_t)COMPOUND_SHAPE_PROXYTYPE || shape->isConvex()) { // create the mesh and allocate buffers for it mesh = std::make_shared(); - mesh->setVertexBuffer(gpu::BufferView(new gpu::Buffer(), mesh->getVertexBuffer()._element)); - mesh->setIndexBuffer(gpu::BufferView(new gpu::Buffer(), mesh->getIndexBuffer()._element)); - mesh->setPartBuffer(gpu::BufferView(new gpu::Buffer(), mesh->getPartBuffer()._element)); + gpu::BufferView vertices(new gpu::Buffer(), mesh->getVertexBuffer()._element); + gpu::BufferView indices(new gpu::Buffer(), mesh->getIndexBuffer()._element); + gpu::BufferView parts(new gpu::Buffer(), mesh->getPartBuffer()._element); if (shapeType == (int32_t)COMPOUND_SHAPE_PROXYTYPE) { const btCompoundShape* compoundShape = static_cast(shape); @@ -92,14 +109,19 @@ model::MeshPointer createMeshFromShape(const void* pointer) { const btCollisionShape* childShape = compoundShape->getChildShape(i); if (childShape->isConvex()) { const btConvexShape* convexShape = static_cast(childShape); - copyShapeToMesh(compoundShape->getChildTransform(i), convexShape, mesh); + copyShapeToMesh(compoundShape->getChildTransform(i), convexShape, vertices, indices, parts); } } } else { // shape is convex const btConvexShape* convexShape = static_cast(shape); - copyShapeToMesh(btTransform(), convexShape, mesh); + btTransform transform; + transform.setIdentity(); + copyShapeToMesh(transform, convexShape, vertices, indices, parts); } + mesh->setVertexBuffer(vertices); + mesh->setIndexBuffer(indices); + mesh->setPartBuffer(parts); } return mesh; } @@ -151,7 +173,7 @@ bool CollisionRenderMeshCache::releaseMesh(CollisionRenderMeshCache::Key key) { void CollisionRenderMeshCache::collectGarbage() { uint32_t numShapes = _pendingGarbage.size(); - for (int32_t i = 0; i < numShapes; ++i) { + for (uint32_t i = 0; i < numShapes; ++i) { CollisionRenderMeshCache::Key key = _pendingGarbage[i]; CollisionMeshMap::const_iterator itr = _meshMap.find(key); if (itr != _meshMap.end()) { diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 075e550dd5..bbb0294e21 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -219,10 +219,6 @@ void Model::updateRenderItems() { modelMeshOffset.postTranslate(self->_offset); } - // only apply offset only, collision mesh does not share the same unit scale as the FBX file's mesh. - Transform collisionMeshOffset; - collisionMeshOffset.postTranslate(self->_offset); - uint32_t deleteGeometryCounter = self->_deleteGeometryCounter; render::PendingChanges pendingChanges; @@ -243,6 +239,11 @@ void Model::updateRenderItems() { }); } + // collision mesh does not share the same unit scale as the FBX file's mesh: only apply offset + Transform collisionMeshOffset; + // adebug FIXME: recover correct behavior for collisionURL shapes + //collisionMeshOffset.postTranslate(self->_offset); + collisionMeshOffset.setIdentity(); foreach (auto itemID, self->_collisionRenderItems.keys()) { pendingChanges.updateItem(itemID, [modelTransform, collisionMeshOffset](MeshPartPayload& data) { // update the model transform for this render item. @@ -1321,12 +1322,16 @@ void Model::createCollisionRenderItemSet() { Q_ASSERT(_collisionRenderItemsSet.isEmpty()); Transform transform; - transform.setTranslation(_translation); - transform.setRotation(_rotation); + transform.setIdentity(); + // adebug FIXME: recover correct behavior for collisionURL + //transform.setTranslation(_translation); + //transform.setRotation(_rotation); Transform offset; - offset.setScale(_scale); - offset.postTranslate(_offset); + // adebug FIXME: recover correct behavior for collisionURL + offset.setIdentity(); + //offset.setScale(_scale); + //offset.postTranslate(_offset); // Run through all of the meshes, and place them into their segregated, but unsorted buckets uint32_t numMeshes = (uint32_t)meshes.size(); @@ -1339,7 +1344,7 @@ void Model::createCollisionRenderItemSet() { // Create the render payloads int numParts = (int)mesh->getNumParts(); for (int partIndex = 0; partIndex < numParts; partIndex++) { - model::MaterialPointer& material = _collisionHullMaterials[partIndex % NUM_COLLISION_HULL_COLORS]; + model::MaterialPointer& material = _collisionHullMaterials[partIndex % NUM_COLLISION_HULL_COLORS]; _collisionRenderItemsSet << std::make_shared(mesh, partIndex, material, transform, offset); } } From 3b772d2fe6ff000ddee1c760ec503647c1b0d70e Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 26 Jul 2016 17:06:40 -0700 Subject: [PATCH 23/45] fallback to SIMPLE_COMPOUND when can't do COMPOUND --- libraries/entities/src/ModelEntityItem.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/entities/src/ModelEntityItem.cpp b/libraries/entities/src/ModelEntityItem.cpp index 8e925b2f79..b098247524 100644 --- a/libraries/entities/src/ModelEntityItem.cpp +++ b/libraries/entities/src/ModelEntityItem.cpp @@ -282,8 +282,8 @@ ShapeType ModelEntityItem::computeTrueShapeType() const { type = SHAPE_TYPE_COMPOUND; } if (type == SHAPE_TYPE_COMPOUND && !hasCompoundShapeURL()) { - // no compoundURL set --> fall back to NONE - type = SHAPE_TYPE_NONE; + // no compoundURL set --> fall back to SIMPLE_COMPOUND + type = SHAPE_TYPE_SIMPLE_COMPOUND; } return type; } From 481d6990a3b188f53d36236e7aeaefb0e9c367ee Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 26 Jul 2016 17:07:16 -0700 Subject: [PATCH 24/45] trigger collision shape render mesh creation --- libraries/render-utils/src/Model.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index bbb0294e21..546631232e 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -1411,6 +1411,7 @@ void Model::setCollisionMesh(model::MeshPointer mesh) { _collisionGeometry = std::make_shared(mesh); if (_showCollisionHull) { + _needsFixupInScene = true; // TODO: need to trigger: // (a) reconstruction of RenderItems // (b) and reinsertion into scene if we are showing collision geometry From 1f84ef3053317ba5e1ba0259ffe31f7574f8599e Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 26 Jul 2016 17:07:43 -0700 Subject: [PATCH 25/45] compute normals for collision mesh geometry --- .../physics/src/CollisionRenderMeshCache.cpp | 91 ++++++++++++------- 1 file changed, 60 insertions(+), 31 deletions(-) diff --git a/libraries/physics/src/CollisionRenderMeshCache.cpp b/libraries/physics/src/CollisionRenderMeshCache.cpp index ef2f9013ef..8b27bbae24 100644 --- a/libraries/physics/src/CollisionRenderMeshCache.cpp +++ b/libraries/physics/src/CollisionRenderMeshCache.cpp @@ -19,17 +19,19 @@ #include // for MAX_HULL_POINTS const int32_t MAX_HULL_INDICES = 6 * MAX_HULL_POINTS; -float tempVertexBuffer[3 * MAX_HULL_POINTS]; +const int32_t MAX_HULL_NORMALS = MAX_HULL_INDICES; +float tempVertices[MAX_HULL_NORMALS]; model::Index tempIndexBuffer[MAX_HULL_INDICES]; -//void copyShapeToMesh(const btTransform& transform, const btConvexShape* shape, model::MeshPointer mesh) { -void copyShapeToMesh(const btTransform& transform, const btConvexShape* shape, - gpu::BufferView& vertices, gpu::BufferView& indices, gpu::BufferView& parts) { +bool copyShapeToMesh(const btTransform& transform, const btConvexShape* shape, + gpu::BufferView& vertices, gpu::BufferView& indices, gpu::BufferView& parts, + gpu::BufferView& normals) { assert(shape); btShapeHull hull(shape); - const btScalar MARGIN = 0.0f; - hull.buildHull(MARGIN); + if (!hull.buildHull(shape->getMargin())) { + return false; + } int32_t numHullIndices = hull.numIndices(); assert(numHullIndices <= MAX_HULL_INDICES); @@ -51,20 +53,8 @@ void copyShapeToMesh(const btTransform& transform, const btConvexShape* shape, parts._size = parts._buffer->getSize(); } + const int32_t SIZE_OF_VEC3 = 3 * sizeof(float); model::Index indexOffset = vertices.getNumElements(); - { // new vertices - const btVector3* hullVertices = hull.getVertexPointer(); - assert(numHullVertices <= MAX_HULL_POINTS); - for (int32_t i = 0; i < numHullVertices; ++i) { - btVector3 transformedPoint = transform * hullVertices[i]; - memcpy(tempVertexBuffer + 3 * i, transformedPoint.m_floats, 3 * sizeof(float)); - } - - gpu::BufferView::Size numBytes = sizeof(float) * (3 * numHullVertices); - const gpu::Byte* data = reinterpret_cast(tempVertexBuffer); - vertices._buffer->append(numBytes, data); - vertices._size = vertices._buffer->getSize(); - } { // new indices const uint32_t* hullIndices = hull.getIndexPointer(); @@ -78,9 +68,37 @@ void copyShapeToMesh(const btTransform& transform, const btConvexShape* shape, indices._buffer->append(numBytes, data); indices._size = indices._buffer->getSize(); } + { // new vertices + const btVector3* hullVertices = hull.getVertexPointer(); + assert(numHullVertices <= MAX_HULL_POINTS); + for (int32_t i = 0; i < numHullVertices; ++i) { + btVector3 transformedPoint = transform * hullVertices[i]; + memcpy(tempVertices + 3 * i, transformedPoint.m_floats, SIZE_OF_VEC3); + } + gpu::BufferView::Size numBytes = sizeof(float) * (3 * numHullVertices); + const gpu::Byte* data = reinterpret_cast(tempVertices); + vertices._buffer->append(numBytes, data); + vertices._size = vertices._buffer->getSize(); + } + { // new normals + // compute average point + btVector3 avgVertex(0.0f, 0.0f, 0.0f); + const btVector3* hullVertices = hull.getVertexPointer(); + for (int i = 0; i < numHullVertices; ++i) { + avgVertex += hullVertices[i]; + } + avgVertex = transform * (avgVertex * (1.0f / (float)numHullVertices)); - gpu::BufferView::Iterator partItr = parts.cbegin(); - gpu::Size numParts = parts.getNumElements(); + for (int i = 0; i < numHullVertices; ++i) { + btVector3 norm = (transform * hullVertices[i] - avgVertex).normalize(); + memcpy(tempVertices + 3 * i, norm.m_floats, SIZE_OF_VEC3); + } + gpu::BufferView::Size numBytes = sizeof(float) * (3 * numHullVertices); + const gpu::Byte* data = reinterpret_cast(tempVertices); + normals._buffer->append(numBytes, data); + normals._size = vertices._buffer->getSize(); + } + return true; } model::MeshPointer createMeshFromShape(const void* pointer) { @@ -96,12 +114,13 @@ model::MeshPointer createMeshFromShape(const void* pointer) { int32_t shapeType = shape->getShapeType(); if (shapeType == (int32_t)COMPOUND_SHAPE_PROXYTYPE || shape->isConvex()) { - // create the mesh and allocate buffers for it - mesh = std::make_shared(); - gpu::BufferView vertices(new gpu::Buffer(), mesh->getVertexBuffer()._element); - gpu::BufferView indices(new gpu::Buffer(), mesh->getIndexBuffer()._element); - gpu::BufferView parts(new gpu::Buffer(), mesh->getPartBuffer()._element); + // allocate buffers for it + gpu::BufferView vertices(new gpu::Buffer(), gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ)); + gpu::BufferView indices(new gpu::Buffer(), gpu::Element(gpu::SCALAR, gpu::UINT32, gpu::INDEX)); + gpu::BufferView parts(new gpu::Buffer(), gpu::Element(gpu::VEC4, gpu::UINT32, gpu::PART)); + gpu::BufferView normals(new gpu::Buffer(), gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ)); + int32_t numSuccesses = 0; if (shapeType == (int32_t)COMPOUND_SHAPE_PROXYTYPE) { const btCompoundShape* compoundShape = static_cast(shape); int32_t numSubShapes = compoundShape->getNumChildShapes(); @@ -109,7 +128,9 @@ model::MeshPointer createMeshFromShape(const void* pointer) { const btCollisionShape* childShape = compoundShape->getChildShape(i); if (childShape->isConvex()) { const btConvexShape* convexShape = static_cast(childShape); - copyShapeToMesh(compoundShape->getChildTransform(i), convexShape, vertices, indices, parts); + if (copyShapeToMesh(compoundShape->getChildTransform(i), convexShape, vertices, indices, parts, normals)) { + numSuccesses++; + } } } } else { @@ -117,11 +138,19 @@ model::MeshPointer createMeshFromShape(const void* pointer) { const btConvexShape* convexShape = static_cast(shape); btTransform transform; transform.setIdentity(); - copyShapeToMesh(transform, convexShape, vertices, indices, parts); + if (copyShapeToMesh(transform, convexShape, vertices, indices, parts, normals)) { + numSuccesses++; + } + } + if (numSuccesses > 0) { + mesh = std::make_shared(); + mesh->setVertexBuffer(vertices); + mesh->setIndexBuffer(indices); + mesh->setPartBuffer(parts); + mesh->addAttribute(gpu::Stream::NORMAL, normals); + } else { + // TODO: log failure message here } - mesh->setVertexBuffer(vertices); - mesh->setIndexBuffer(indices); - mesh->setPartBuffer(parts); } return mesh; } From 329c5432ed67a116316c818b3f486d4c464ad9cf Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 26 Jul 2016 17:28:02 -0700 Subject: [PATCH 26/45] _showCollisionHull --> _showCollisionGeometry --- libraries/render-utils/src/Model.cpp | 30 ++++++++++++++-------------- libraries/render-utils/src/Model.h | 3 +-- 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 546631232e..4e4edb0202 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -37,9 +37,9 @@ float Model::FAKE_DIMENSION_PLACEHOLDER = -1.0f; #define HTTP_INVALID_COM "http://invalid.com" const int NUM_COLLISION_HULL_COLORS = 24; -std::vector _collisionHullMaterials; +std::vector _collisionMaterials; -void initCollisionHullMaterials() { +void initCollisionMaterials() { // generates bright colors in red, green, blue, yellow, magenta, and cyan spectrums // (no browns, greys, or dark shades) float component[NUM_COLLISION_HULL_COLORS] = { @@ -50,7 +50,7 @@ void initCollisionHullMaterials() { 1.0f, 1.0f, 1.0f, 1.0f, 0.8f, 0.6f, 0.4f, 0.2f }; - _collisionHullMaterials.reserve(NUM_COLLISION_HULL_COLORS); + _collisionMaterials.reserve(NUM_COLLISION_HULL_COLORS); // each component gets the same cuve // but offset by a multiple of one third the full width @@ -72,7 +72,7 @@ void initCollisionHullMaterials() { material->setAlbedo(glm::vec3(red, green, blue)); material->setMetallic(0.02f); material->setRoughness(0.5f); - _collisionHullMaterials.push_back(material); + _collisionMaterials.push_back(material); } } } @@ -121,15 +121,15 @@ Model::~Model() { AbstractViewStateInterface* Model::_viewState = NULL; void Model::setShowCollisionMesh(bool value) { - if (_showCollisionHull != value) { - _showCollisionHull = value; + if (_showCollisionGeometry != value) { + _showCollisionGeometry = value; _needsFixupInScene = true; } } bool Model::needsFixupInScene() const { if ((_needsFixupInScene || !_addedToScene) && !_needsReload && isLoaded()) { - if (_showCollisionHull && _collisionGeometry) { + if (_showCollisionGeometry && _collisionGeometry) { return true; } if (!_meshStates.isEmpty() || (_renderGeometry && _renderGeometry->getMeshes().empty())) { @@ -614,13 +614,13 @@ void Model::setVisibleInScene(bool newValue, std::shared_ptr scen bool Model::addToScene(std::shared_ptr scene, render::PendingChanges& pendingChanges, render::Item::Status::Getters& statusGetters) { - bool readyToRender = (_showCollisionHull && _collisionGeometry) || isLoaded(); + bool readyToRender = (_showCollisionGeometry && _collisionGeometry) || isLoaded(); if (!_addedToScene && readyToRender) { createRenderItemSet(); } bool somethingAdded = false; - if (_showCollisionHull && _collisionGeometry) { + if (_showCollisionGeometry && _collisionGeometry) { if (_collisionRenderItems.empty()) { foreach (auto renderItem, _collisionRenderItemsSet) { auto item = scene->allocateID(); @@ -1258,7 +1258,7 @@ AABox Model::getRenderableMeshBound() const { } void Model::createRenderItemSet() { - if (_showCollisionHull && _collisionGeometry) { + if (_showCollisionGeometry && _collisionGeometry) { if (_collisionRenderItemsSet.empty()) { createCollisionRenderItemSet(); } @@ -1312,8 +1312,8 @@ void Model::createVisibleRenderItemSet() { void Model::createCollisionRenderItemSet() { assert((bool)_collisionGeometry); - if (_collisionHullMaterials.empty()) { - initCollisionHullMaterials(); + if (_collisionMaterials.empty()) { + initCollisionMaterials(); } const auto& meshes = _collisionGeometry->getMeshes(); @@ -1344,7 +1344,7 @@ void Model::createCollisionRenderItemSet() { // Create the render payloads int numParts = (int)mesh->getNumParts(); for (int partIndex = 0; partIndex < numParts; partIndex++) { - model::MaterialPointer& material = _collisionHullMaterials[partIndex % NUM_COLLISION_HULL_COLORS]; + model::MaterialPointer& material = _collisionMaterials[partIndex % NUM_COLLISION_HULL_COLORS]; _collisionRenderItemsSet << std::make_shared(mesh, partIndex, material, transform, offset); } } @@ -1365,7 +1365,7 @@ bool Model::initWhenReady(render::ScenePointer scene) { render::PendingChanges pendingChanges; bool addedPendingChanges = false; - if (_showCollisionHull && _collisionGeometry) { + if (_showCollisionGeometry && _collisionGeometry) { foreach (auto renderItem, _collisionRenderItemsSet) { auto item = scene->allocateID(); auto renderPayload = std::make_shared(renderItem); @@ -1410,7 +1410,7 @@ void Model::setCollisionMesh(model::MeshPointer mesh) { _collisionWatcher.stopWatching(); _collisionGeometry = std::make_shared(mesh); - if (_showCollisionHull) { + if (_showCollisionGeometry) { _needsFixupInScene = true; // TODO: need to trigger: // (a) reconstruction of RenderItems diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index b30b0b0d76..9a0f2e6713 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -382,7 +382,6 @@ protected: void createRenderItemSet(); void createVisibleRenderItemSet(); void createCollisionRenderItemSet(); - static model::MaterialPointer _collisionHullMaterial; bool _isWireframe; @@ -404,7 +403,7 @@ protected: bool _needsFixupInScene { true }; // needs to be removed/re-added to scene bool _needsReload { true }; bool _needsUpdateClusterMatrices { true }; - bool _showCollisionHull { false }; + bool _showCollisionGeometry { false }; mutable bool _needsUpdateTextures { true }; friend class ModelMeshPartPayload; From 191b7f0f39e3b5c92a060b650d82b4aed89b3e76 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 27 Jul 2016 13:52:50 -0700 Subject: [PATCH 27/45] variable namechange: Hull --> Mesh --- libraries/entities-renderer/src/RenderableModelEntityItem.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 6e5d1c7959..b80a003e8e 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -436,9 +436,9 @@ void RenderableModelEntityItem::render(RenderArgs* args) { // update whether the model should be showing collision mesh // (this may flag for fixupInScene) - bool shouldShowCollisionHull = getShapeType() != SHAPE_TYPE_STATIC_MESH && + bool shouldShowCollisionMesh = getShapeType() != SHAPE_TYPE_STATIC_MESH && (args->_debugFlags & (int)RenderArgs::RENDER_DEBUG_HULLS) > 0; - _model->setShowCollisionMesh(shouldShowCollisionHull); + _model->setShowCollisionMesh(shouldShowCollisionMesh); if (_model->needsFixupInScene()) { render::PendingChanges pendingChanges; From fe4198530f83030cb20bfbed76be698173944005 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 27 Jul 2016 13:52:55 -0700 Subject: [PATCH 28/45] don't render raw compound collision geometry --- .../render-utils/src/MeshPartPayload.cpp | 4 +- libraries/render-utils/src/MeshPartPayload.h | 2 +- libraries/render-utils/src/Model.cpp | 46 ++++++++----------- libraries/render-utils/src/Model.h | 1 + 4 files changed, 22 insertions(+), 31 deletions(-) diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index 8913a62d9d..42dd41c739 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -46,11 +46,9 @@ template <> void payloadRender(const MeshPartPayload::Pointer& payload, RenderAr } } -MeshPartPayload::MeshPartPayload(const std::shared_ptr& mesh, int partIndex, model::MaterialPointer material, const Transform& transform, const Transform& offsetTransform) { - +MeshPartPayload::MeshPartPayload(const std::shared_ptr& mesh, int partIndex, model::MaterialPointer material) { updateMeshPart(mesh, partIndex); updateMaterial(material); - updateTransform(transform, offsetTransform); } void MeshPartPayload::updateMeshPart(const std::shared_ptr& drawMesh, int partIndex) { diff --git a/libraries/render-utils/src/MeshPartPayload.h b/libraries/render-utils/src/MeshPartPayload.h index 29478b3b4e..a934863846 100644 --- a/libraries/render-utils/src/MeshPartPayload.h +++ b/libraries/render-utils/src/MeshPartPayload.h @@ -26,7 +26,7 @@ class Model; class MeshPartPayload { public: MeshPartPayload() {} - MeshPartPayload(const std::shared_ptr& mesh, int partIndex, model::MaterialPointer material, const Transform& transform, const Transform& offsetTransform); + MeshPartPayload(const std::shared_ptr& mesh, int partIndex, model::MaterialPointer material); typedef render::Payload Payload; typedef Payload::DataPointer Pointer; diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 4e4edb0202..ce8ebfb00a 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -121,15 +121,17 @@ Model::~Model() { AbstractViewStateInterface* Model::_viewState = NULL; void Model::setShowCollisionMesh(bool value) { - if (_showCollisionGeometry != value) { - _showCollisionGeometry = value; - _needsFixupInScene = true; + if (_readyToShowCollisionGeometry) { + if (_showCollisionGeometry != value) { + _showCollisionGeometry = value; + _needsFixupInScene = true; + } } } bool Model::needsFixupInScene() const { if ((_needsFixupInScene || !_addedToScene) && !_needsReload && isLoaded()) { - if (_showCollisionGeometry && _collisionGeometry) { + if (_showCollisionGeometry && _readyToShowCollisionGeometry && _collisionGeometry) { return true; } if (!_meshStates.isEmpty() || (_renderGeometry && _renderGeometry->getMeshes().empty())) { @@ -241,8 +243,6 @@ void Model::updateRenderItems() { // collision mesh does not share the same unit scale as the FBX file's mesh: only apply offset Transform collisionMeshOffset; - // adebug FIXME: recover correct behavior for collisionURL shapes - //collisionMeshOffset.postTranslate(self->_offset); collisionMeshOffset.setIdentity(); foreach (auto itemID, self->_collisionRenderItems.keys()) { pendingChanges.updateItem(itemID, [modelTransform, collisionMeshOffset](MeshPartPayload& data) { @@ -614,13 +614,13 @@ void Model::setVisibleInScene(bool newValue, std::shared_ptr scen bool Model::addToScene(std::shared_ptr scene, render::PendingChanges& pendingChanges, render::Item::Status::Getters& statusGetters) { - bool readyToRender = (_showCollisionGeometry && _collisionGeometry) || isLoaded(); + bool readyToRender = (_showCollisionGeometry && _readyToShowCollisionGeometry && _collisionGeometry) || isLoaded(); if (!_addedToScene && readyToRender) { createRenderItemSet(); } bool somethingAdded = false; - if (_showCollisionGeometry && _collisionGeometry) { + if (_showCollisionGeometry && _readyToShowCollisionGeometry && _collisionGeometry) { if (_collisionRenderItems.empty()) { foreach (auto renderItem, _collisionRenderItemsSet) { auto item = scene->allocateID(); @@ -1258,7 +1258,7 @@ AABox Model::getRenderableMeshBound() const { } void Model::createRenderItemSet() { - if (_showCollisionGeometry && _collisionGeometry) { + if (_showCollisionGeometry && _readyToShowCollisionGeometry && _collisionGeometry) { if (_collisionRenderItemsSet.empty()) { createCollisionRenderItemSet(); } @@ -1321,18 +1321,6 @@ void Model::createCollisionRenderItemSet() { // We should not have any existing renderItems if we enter this section of code Q_ASSERT(_collisionRenderItemsSet.isEmpty()); - Transform transform; - transform.setIdentity(); - // adebug FIXME: recover correct behavior for collisionURL - //transform.setTranslation(_translation); - //transform.setRotation(_rotation); - - Transform offset; - // adebug FIXME: recover correct behavior for collisionURL - offset.setIdentity(); - //offset.setScale(_scale); - //offset.postTranslate(_offset); - // Run through all of the meshes, and place them into their segregated, but unsorted buckets uint32_t numMeshes = (uint32_t)meshes.size(); for (uint32_t i = 0; i < numMeshes; i++) { @@ -1345,7 +1333,7 @@ void Model::createCollisionRenderItemSet() { int numParts = (int)mesh->getNumParts(); for (int partIndex = 0; partIndex < numParts; partIndex++) { model::MaterialPointer& material = _collisionMaterials[partIndex % NUM_COLLISION_HULL_COLORS]; - _collisionRenderItemsSet << std::make_shared(mesh, partIndex, material, transform, offset); + _collisionRenderItemsSet << std::make_shared(mesh, partIndex, material); } } } @@ -1365,7 +1353,7 @@ bool Model::initWhenReady(render::ScenePointer scene) { render::PendingChanges pendingChanges; bool addedPendingChanges = false; - if (_showCollisionGeometry && _collisionGeometry) { + if (_showCollisionGeometry && _readyToShowCollisionGeometry && _collisionGeometry) { foreach (auto renderItem, _collisionRenderItemsSet) { auto item = scene->allocateID(); auto renderPayload = std::make_shared(renderItem); @@ -1387,7 +1375,7 @@ bool Model::initWhenReady(render::ScenePointer scene) { scene->enqueuePendingChanges(pendingChanges); // NOTE: updateRender items enqueues identical pendingChanges (using a lambda) // so it looks like we're doing double work here, but I don't want to remove the call - // for fear there is some sideeffect we'll miss. -- Andrew 2016.07.21 + // for fear there is some side effect we'll miss. -- Andrew 2016.07.21 // TODO: figure out if we really need this call to updateRenderItems() or not. updateRenderItems(); } @@ -1410,11 +1398,15 @@ void Model::setCollisionMesh(model::MeshPointer mesh) { _collisionWatcher.stopWatching(); _collisionGeometry = std::make_shared(mesh); + // HACK: we don't want to show the _collisionGeometry until we're ready (e.g. it has been created) + // hence we track whether it has been created using _readyToShowCollisionGeoemtry, because there + // is an ambiguous case where _collisionGeometry is valid (from CompoundURL) but has not yet been + // properly computed (zeroed offset transform) using the CollisionRenderMeshCache. + // + // TODO: At the moment we create the collision mesh for every model that has a collision shape + // as soon as we know the shape, but we SHOULD only ever create the render mesh when we need it. if (_showCollisionGeometry) { _needsFixupInScene = true; - // TODO: need to trigger: - // (a) reconstruction of RenderItems - // (b) and reinsertion into scene if we are showing collision geometry } } diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index 9a0f2e6713..3fc681261a 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -404,6 +404,7 @@ protected: bool _needsReload { true }; bool _needsUpdateClusterMatrices { true }; bool _showCollisionGeometry { false }; + bool _readyToShowCollisionGeometry { false }; mutable bool _needsUpdateTextures { true }; friend class ModelMeshPartPayload; From ef597265d76bcc1f3a0e7e0ba7a75b7816f1800e Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 28 Jul 2016 07:30:27 -0700 Subject: [PATCH 29/45] remove unimplemented declaration --- libraries/networking/src/ResourceCache.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/libraries/networking/src/ResourceCache.h b/libraries/networking/src/ResourceCache.h index a2a5b4cbbe..eba84dddd4 100644 --- a/libraries/networking/src/ResourceCache.h +++ b/libraries/networking/src/ResourceCache.h @@ -226,8 +226,6 @@ private: void resetResourceCounters(); void removeResource(const QUrl& url, qint64 size = 0); - void getResourceAsynchronously(const QUrl& url); - static int _requestLimit; static int _requestsActive; From b0a0293e6e0a19b0efa911c96a23ea9065f20208 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 28 Jul 2016 07:31:32 -0700 Subject: [PATCH 30/45] move compoundResource out of Model class --- .../src/EntityTreeRenderer.cpp | 18 -------- .../src/EntityTreeRenderer.h | 1 - .../src/RenderableModelEntityItem.cpp | 46 +++++++++++++------ .../src/RenderableModelEntityItem.h | 2 + libraries/entities/src/EntityTree.h | 1 - libraries/render-utils/src/Model.cpp | 43 ++++------------- libraries/render-utils/src/Model.h | 9 ---- 7 files changed, 42 insertions(+), 78 deletions(-) diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index 39031acaa1..209a27739b 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -499,22 +499,6 @@ ModelPointer EntityTreeRenderer::getModelForEntityItem(EntityItemPointer entityI return result; } -const FBXGeometry* EntityTreeRenderer::getCollisionGeometryForEntity(EntityItemPointer entityItem) { - const FBXGeometry* result = NULL; - - if (entityItem->getType() == EntityTypes::Model) { - std::shared_ptr modelEntityItem = - std::dynamic_pointer_cast(entityItem); - if (modelEntityItem->hasCompoundShapeURL()) { - ModelPointer model = modelEntityItem->getModel(this); - if (model && model->isCollisionLoaded()) { - result = &model->getCollisionFBXGeometry(); - } - } - } - return result; -} - void EntityTreeRenderer::processEraseMessage(ReceivedMessage& message, const SharedNodePointer& sourceNode) { std::static_pointer_cast(_tree)->processEraseMessage(message, sourceNode); } @@ -536,7 +520,6 @@ ModelPointer EntityTreeRenderer::allocateModel(const QString& url, const QString model->setLoadingPriority(loadingPriority); model->init(); model->setURL(QUrl(url)); - model->setCollisionModelURL(QUrl(collisionUrl)); return model; } @@ -553,7 +536,6 @@ ModelPointer EntityTreeRenderer::updateModel(ModelPointer model, const QString& } model->setURL(QUrl(newUrl)); - model->setCollisionModelURL(QUrl(collisionUrl)); return model; } diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.h b/libraries/entities-renderer/src/EntityTreeRenderer.h index 5d634fa6ca..5664f33041 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.h +++ b/libraries/entities-renderer/src/EntityTreeRenderer.h @@ -65,7 +65,6 @@ public: virtual const FBXGeometry* getGeometryForEntity(EntityItemPointer entityItem) override; virtual ModelPointer getModelForEntityItem(EntityItemPointer entityItem) override; - virtual const FBXGeometry* getCollisionGeometryForEntity(EntityItemPointer entityItem) override; /// clears the tree virtual void clear() override; diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index b80a003e8e..84646d7607 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -494,7 +494,7 @@ ModelPointer RenderableModelEntityItem::getModel(EntityTreeRenderer* renderer) { _model = _myRenderer->allocateModel(getModelURL(), getCompoundShapeURL(), renderer->getEntityLoadingPriority(*this)); _needsInitialSimulation = true; // If we need to change URLs, update it *after rendering* (to avoid access violations) - } else if ((QUrl(getModelURL()) != _model->getURL() || QUrl(getCompoundShapeURL()) != _model->getCollisionURL())) { + } else if (QUrl(getModelURL()) != _model->getURL()) { QMetaObject::invokeMethod(_myRenderer, "updateModel", Qt::QueuedConnection, Q_ARG(ModelPointer, _model), Q_ARG(const QString&, getModelURL()), @@ -566,6 +566,18 @@ bool RenderableModelEntityItem::findDetailedRayIntersection(const glm::vec3& ori face, surfaceNormal, extraInfo, precisionPicking); } +void RenderableModelEntityItem::setShapeType(ShapeType type) { + ModelEntityItem::setShapeType(type); + if (_shapeType == SHAPE_TYPE_COMPOUND) { + if (!_compoundShapeResource && !_compoundShapeURL.isEmpty()) { + _compoundShapeResource = DependencyManager::get()->getGeometryResource(getCompoundShapeURL()); + } + } else if (_compoundShapeResource && !_compoundShapeURL.isEmpty()) { + // the compoundURL has been set but the shapeType does not agree + _compoundShapeResource.reset(); + } +} + void RenderableModelEntityItem::setCompoundShapeURL(const QString& url) { auto currentCompoundShapeURL = getCompoundShapeURL(); ModelEntityItem::setCompoundShapeURL(url); @@ -575,6 +587,9 @@ void RenderableModelEntityItem::setCompoundShapeURL(const QString& url) { if (tree) { QMetaObject::invokeMethod(tree.get(), "callLoader", Qt::QueuedConnection, Q_ARG(EntityItemID, getID())); } + if (_shapeType == SHAPE_TYPE_COMPOUND) { + _compoundShapeResource = DependencyManager::get()->getGeometryResource(url); + } } } @@ -582,7 +597,7 @@ bool RenderableModelEntityItem::isReadyToComputeShape() { ShapeType type = getShapeType(); if (type == SHAPE_TYPE_COMPOUND) { - if (!_model || _model->getCollisionURL().isEmpty()) { + if (!_model || _compoundShapeURL.isEmpty()) { EntityTreePointer tree = getTree(); if (tree) { QMetaObject::invokeMethod(tree.get(), "callLoader", Qt::QueuedConnection, Q_ARG(EntityItemID, getID())); @@ -595,15 +610,18 @@ bool RenderableModelEntityItem::isReadyToComputeShape() { return false; } - if (_model->isLoaded() && _model->isCollisionLoaded()) { - // we have both URLs AND both geometries AND they are both fully loaded. - if (_needsInitialSimulation) { - // the _model's offset will be wrong until _needsInitialSimulation is false - PerformanceTimer perfTimer("_model->simulate"); - doInitialModelSimulation(); + if (_model->isLoaded()) { + if (_compoundShapeResource && _compoundShapeResource->isLoaded()) { + // we have both URLs AND both geometries AND they are both fully loaded. + if (_needsInitialSimulation) { + // the _model's offset will be wrong until _needsInitialSimulation is false + PerformanceTimer perfTimer("_model->simulate"); + doInitialModelSimulation(); + } + return true; + } else if (!_compoundShapeURL.isEmpty()) { + _compoundShapeResource = DependencyManager::get()->getGeometryResource(_compoundShapeURL); } - - return true; } // the model is still being downloaded. @@ -625,8 +643,8 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) { // should never fall in here when collision model not fully loaded // hence we assert that all geometries exist and are loaded - assert(_model && _model->isLoaded() && _model->isCollisionLoaded()); - const FBXGeometry& collisionGeometry = _model->getCollisionFBXGeometry(); + assert(_model && _model->isLoaded() && _compoundShapeResource && _compoundShapeResource->isLoaded()); + const FBXGeometry& collisionGeometry = _compoundShapeResource->getFBXGeometry(); ShapeInfo::PointCollection& pointCollection = info.getPointCollection(); pointCollection.clear(); @@ -956,8 +974,8 @@ void RenderableModelEntityItem::setCollisionShape(const btCollisionShape* shape) } bool RenderableModelEntityItem::contains(const glm::vec3& point) const { - if (EntityItem::contains(point) && _model && _model->isCollisionLoaded()) { - return _model->getCollisionFBXGeometry().convexHullContains(worldToEntity(point)); + if (EntityItem::contains(point) && _model && _compoundShapeResource && _compoundShapeResource->isLoaded()) { + return _compoundShapeResource->getFBXGeometry().convexHullContains(worldToEntity(point)); } return false; diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.h b/libraries/entities-renderer/src/RenderableModelEntityItem.h index 16cd9c8bc5..09468dfae0 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.h +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.h @@ -56,6 +56,7 @@ public: virtual bool needsToCallUpdate() const override; virtual void update(const quint64& now) override; + virtual void setShapeType(ShapeType type) override; virtual void setCompoundShapeURL(const QString& url) override; virtual bool isReadyToComputeShape() override; @@ -100,6 +101,7 @@ private: QVariantMap parseTexturesToMap(QString textures); void remapTextures(); + GeometryResource::Pointer _compoundShapeResource; ModelPointer _model = nullptr; bool _needsInitialSimulation = true; bool _needsModelReload = true; diff --git a/libraries/entities/src/EntityTree.h b/libraries/entities/src/EntityTree.h index 15daf3bf3c..7dc999aac2 100644 --- a/libraries/entities/src/EntityTree.h +++ b/libraries/entities/src/EntityTree.h @@ -40,7 +40,6 @@ class EntityItemFBXService { public: virtual const FBXGeometry* getGeometryForEntity(EntityItemPointer entityItem) = 0; virtual ModelPointer getModelForEntityItem(EntityItemPointer entityItem) = 0; - virtual const FBXGeometry* getCollisionGeometryForEntity(EntityItemPointer entityItem) = 0; }; diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index ce8ebfb00a..d1269f769a 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -82,7 +82,6 @@ Model::Model(RigPointer rig, QObject* parent) : _renderGeometry(), _collisionGeometry(), _renderWatcher(_renderGeometry), - _collisionWatcher(_collisionGeometry), _translation(0.0f), _rotation(), _scale(1.0f, 1.0f, 1.0f), @@ -111,7 +110,6 @@ Model::Model(RigPointer rig, QObject* parent) : setSnapModelToRegistrationPoint(true, glm::vec3(0.5f)); connect(&_renderWatcher, &GeometryResourceWatcher::finished, this, &Model::loadURLFinished); - connect(&_collisionWatcher, &GeometryResourceWatcher::finished, this, &Model::loadCollisionModelURLFinished); } Model::~Model() { @@ -121,17 +119,15 @@ Model::~Model() { AbstractViewStateInterface* Model::_viewState = NULL; void Model::setShowCollisionMesh(bool value) { - if (_readyToShowCollisionGeometry) { - if (_showCollisionGeometry != value) { - _showCollisionGeometry = value; - _needsFixupInScene = true; - } + if (_showCollisionGeometry != value) { + _showCollisionGeometry = value; + _needsFixupInScene = true; } } bool Model::needsFixupInScene() const { if ((_needsFixupInScene || !_addedToScene) && !_needsReload && isLoaded()) { - if (_showCollisionGeometry && _readyToShowCollisionGeometry && _collisionGeometry) { + if (_showCollisionGeometry && _collisionGeometry) { return true; } if (!_meshStates.isEmpty() || (_renderGeometry && _renderGeometry->getMeshes().empty())) { @@ -614,13 +610,13 @@ void Model::setVisibleInScene(bool newValue, std::shared_ptr scen bool Model::addToScene(std::shared_ptr scene, render::PendingChanges& pendingChanges, render::Item::Status::Getters& statusGetters) { - bool readyToRender = (_showCollisionGeometry && _readyToShowCollisionGeometry && _collisionGeometry) || isLoaded(); + bool readyToRender = (_showCollisionGeometry && _collisionGeometry) || isLoaded(); if (!_addedToScene && readyToRender) { createRenderItemSet(); } bool somethingAdded = false; - if (_showCollisionGeometry && _readyToShowCollisionGeometry && _collisionGeometry) { + if (_showCollisionGeometry && _collisionGeometry) { if (_collisionRenderItems.empty()) { foreach (auto renderItem, _collisionRenderItemsSet) { auto item = scene->allocateID(); @@ -864,23 +860,6 @@ void Model::loadURLFinished(bool success) { emit setURLFinished(success); } -void Model::setCollisionModelURL(const QUrl& url) { - if (_collisionUrl == url && _collisionWatcher.getURL() == url) { - return; - } - _collisionUrl = url; - _collisionGeometryRequestFailed = false; - _collisionWatcher.setResource(DependencyManager::get()->getGeometryResource(url)); -} - -void Model::loadCollisionModelURLFinished(bool success) { - if (!success) { - _collisionGeometryRequestFailed = true; - } - - emit setCollisionModelURLFinished(success); -} - bool Model::getJointPositionInWorldFrame(int jointIndex, glm::vec3& position) const { return _rig->getJointPositionInWorldFrame(jointIndex, position, _translation, _rotation); } @@ -1258,7 +1237,7 @@ AABox Model::getRenderableMeshBound() const { } void Model::createRenderItemSet() { - if (_showCollisionGeometry && _readyToShowCollisionGeometry && _collisionGeometry) { + if (_showCollisionGeometry && _collisionGeometry) { if (_collisionRenderItemsSet.empty()) { createCollisionRenderItemSet(); } @@ -1353,7 +1332,7 @@ bool Model::initWhenReady(render::ScenePointer scene) { render::PendingChanges pendingChanges; bool addedPendingChanges = false; - if (_showCollisionGeometry && _readyToShowCollisionGeometry && _collisionGeometry) { + if (_showCollisionGeometry && _collisionGeometry) { foreach (auto renderItem, _collisionRenderItemsSet) { auto item = scene->allocateID(); auto renderPayload = std::make_shared(renderItem); @@ -1395,14 +1374,8 @@ public: }; void Model::setCollisionMesh(model::MeshPointer mesh) { - _collisionWatcher.stopWatching(); _collisionGeometry = std::make_shared(mesh); - // HACK: we don't want to show the _collisionGeometry until we're ready (e.g. it has been created) - // hence we track whether it has been created using _readyToShowCollisionGeoemtry, because there - // is an ambiguous case where _collisionGeometry is valid (from CompoundURL) but has not yet been - // properly computed (zeroed offset transform) using the CollisionRenderMeshCache. - // // TODO: At the moment we create the collision mesh for every model that has a collision shape // as soon as we know the shape, but we SHOULD only ever create the render mesh when we need it. if (_showCollisionGeometry) { diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index 3fc681261a..edb8f0b6ae 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -115,7 +115,6 @@ public: const QVector& vertices, const QVector& normals); bool isLoaded() const { return (bool)_renderGeometry; } - bool isCollisionLoaded() const { return (bool)_collisionGeometry; } void setIsWireframe(bool isWireframe) { _isWireframe = isWireframe; } bool isWireframe() const { return _isWireframe; } @@ -142,13 +141,9 @@ public: /// Provided as a convenience, will crash if !isLoaded() // And so that getGeometry() isn't chained everywhere const FBXGeometry& getFBXGeometry() const { assert(isLoaded()); return _renderGeometry->getFBXGeometry(); } - /// Provided as a convenience, will crash if !isCollisionLoaded() - const FBXGeometry& getCollisionFBXGeometry() const { assert(isCollisionLoaded()); return _collisionGeometry->getFBXGeometry(); } // Set the model to use for collisions. // Should only be called from the model's rendering thread to avoid access violations of changed geometry. - Q_INVOKABLE void setCollisionModelURL(const QUrl& url); - const QUrl& getCollisionURL() const { return _collisionUrl; } bool isActive() const { return isLoaded(); } @@ -246,7 +241,6 @@ public: public slots: void loadURLFinished(bool success); - void loadCollisionModelURLFinished(bool success); signals: void setURLFinished(bool success); @@ -288,7 +282,6 @@ protected: Geometry::Pointer _collisionGeometry; GeometryResourceWatcher _renderWatcher; - GeometryResourceWatcher _collisionWatcher; glm::vec3 _translation; glm::quat _rotation; @@ -356,7 +349,6 @@ protected: QVector _blendshapeCoefficients; QUrl _url; - QUrl _collisionUrl; bool _isVisible; gpu::Buffers _blendedVertexBuffers; @@ -404,7 +396,6 @@ protected: bool _needsReload { true }; bool _needsUpdateClusterMatrices { true }; bool _showCollisionGeometry { false }; - bool _readyToShowCollisionGeometry { false }; mutable bool _needsUpdateTextures { true }; friend class ModelMeshPartPayload; From eb65be5478af994c813b3c3a34a130218d07e9d7 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 28 Jul 2016 07:37:54 -0700 Subject: [PATCH 31/45] remove cruft argument from allocateModel() --- libraries/entities-renderer/src/EntityTreeRenderer.cpp | 5 ++--- libraries/entities-renderer/src/EntityTreeRenderer.h | 2 +- .../entities-renderer/src/RenderableModelEntityItem.cpp | 5 ++--- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index 209a27739b..25352255fa 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -503,15 +503,14 @@ void EntityTreeRenderer::processEraseMessage(ReceivedMessage& message, const Sha std::static_pointer_cast(_tree)->processEraseMessage(message, sourceNode); } -ModelPointer EntityTreeRenderer::allocateModel(const QString& url, const QString& collisionUrl, float loadingPriority) { +ModelPointer EntityTreeRenderer::allocateModel(const QString& url, loadingPriority) { ModelPointer model = nullptr; // Only create and delete models on the thread that owns the EntityTreeRenderer if (QThread::currentThread() != thread()) { QMetaObject::invokeMethod(this, "allocateModel", Qt::BlockingQueuedConnection, Q_RETURN_ARG(ModelPointer, model), - Q_ARG(const QString&, url), - Q_ARG(const QString&, collisionUrl)); + Q_ARG(const QString&, url)); return model; } diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.h b/libraries/entities-renderer/src/EntityTreeRenderer.h index 5664f33041..7ca11ccdbb 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.h +++ b/libraries/entities-renderer/src/EntityTreeRenderer.h @@ -73,7 +73,7 @@ public: void reloadEntityScripts(); /// if a renderable entity item needs a model, we will allocate it for them - Q_INVOKABLE ModelPointer allocateModel(const QString& url, const QString& collisionUrl, float loadingPriority = 0.0f); + Q_INVOKABLE ModelPointer allocateModel(const QString& url, float loadingPriority = 0.0f); /// if a renderable entity item needs to update the URL of a model, we will handle that for the entity Q_INVOKABLE ModelPointer updateModel(ModelPointer original, const QString& newUrl, const QString& collisionUrl); diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 84646d7607..93ad4e17d5 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -491,14 +491,13 @@ ModelPointer RenderableModelEntityItem::getModel(EntityTreeRenderer* renderer) { if (!getModelURL().isEmpty()) { // If we don't have a model, allocate one *immediately* if (!_model) { - _model = _myRenderer->allocateModel(getModelURL(), getCompoundShapeURL(), renderer->getEntityLoadingPriority(*this)); + _model = _myRenderer->allocateModel(getModelURL(), renderer->getEntityLoadingPriority(*this)); _needsInitialSimulation = true; // If we need to change URLs, update it *after rendering* (to avoid access violations) } else if (QUrl(getModelURL()) != _model->getURL()) { QMetaObject::invokeMethod(_myRenderer, "updateModel", Qt::QueuedConnection, Q_ARG(ModelPointer, _model), - Q_ARG(const QString&, getModelURL()), - Q_ARG(const QString&, getCompoundShapeURL())); + Q_ARG(const QString&, getModelURL())); _needsInitialSimulation = true; } // Else we can just return the _model From 68dd66daec3e855344e07ceacb0e54a7ce9c02e4 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 28 Jul 2016 09:33:25 -0700 Subject: [PATCH 32/45] create collision render geometry only when needed --- .../src/RenderableModelEntityItem.cpp | 38 +++++++++++------ .../src/RenderableModelEntityItem.h | 1 + libraries/render-utils/src/Model.cpp | 42 +++++-------------- libraries/render-utils/src/Model.h | 3 -- 4 files changed, 37 insertions(+), 47 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 93ad4e17d5..2d03f76ae6 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -29,6 +29,9 @@ #include "RenderableModelEntityItem.h" #include "RenderableEntityItem.h" +static CollisionRenderMeshCache collisionMeshCache; + + EntityItemPointer RenderableModelEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { EntityItemPointer entity{ new RenderableModelEntityItem(entityID, properties.getDimensionsInitialized()) }; entity->setProperties(properties); @@ -434,11 +437,28 @@ void RenderableModelEntityItem::render(RenderArgs* args) { // Remap textures for the next frame to avoid flicker remapTextures(); - // update whether the model should be showing collision mesh - // (this may flag for fixupInScene) - bool shouldShowCollisionMesh = getShapeType() != SHAPE_TYPE_STATIC_MESH && + // update whether the model should be showing collision mesh (this may flag for fixupInScene) + ShapeType type = getShapeType(); + bool shouldShowCollisionGeometry = type != SHAPE_TYPE_STATIC_MESH && + type != SHAPE_TYPE_NONE && (args->_debugFlags & (int)RenderArgs::RENDER_DEBUG_HULLS) > 0; - _model->setShowCollisionMesh(shouldShowCollisionMesh); + if (shouldShowCollisionGeometry != _showCollisionGeometry) { + _showCollisionGeometry = shouldShowCollisionGeometry; + if (_showCollisionGeometry) { + // NOTE: it is OK if _collisionMeshKey is nullptr + model::MeshPointer mesh = collisionMeshCache.getMesh(_collisionMeshKey); + // NOTE: the model will render the collisionGeometry if it has one + _model->setCollisionMesh(mesh); + } else { + // release mesh + if (_collisionMeshKey) { + collisionMeshCache.releaseMesh(_collisionMeshKey); + } + // clear model's collision geometry + model::MeshPointer mesh = nullptr; + _model->setCollisionMesh(mesh); + } + } if (_model->needsFixupInScene()) { render::PendingChanges pendingChanges; @@ -954,21 +974,15 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) { } } -static CollisionRenderMeshCache collisionMeshCache; - void RenderableModelEntityItem::setCollisionShape(const btCollisionShape* shape) { const void* key = static_cast(shape); if (_collisionMeshKey != key) { if (_collisionMeshKey) { - // releasing the shape is not strictly necessary, but - // we do it as hint to the cache's garbage collection system collisionMeshCache.releaseMesh(_collisionMeshKey); } _collisionMeshKey = key; - model::MeshPointer mesh = collisionMeshCache.getMesh(_collisionMeshKey); - if (_model) { - _model->setCollisionMesh(mesh); - } + // toggle _showCollisionGeometry forces re-evaluation later + _showCollisionGeometry = !_showCollisionGeometry; } } diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.h b/libraries/entities-renderer/src/RenderableModelEntityItem.h index 09468dfae0..3c2333e679 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.h +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.h @@ -119,6 +119,7 @@ private: bool getAnimationFrame(); bool _needsJointSimulation { false }; + bool _showCollisionGeometry { false }; const void* _collisionMeshKey { nullptr }; }; diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index d1269f769a..ca0994b837 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -118,29 +118,8 @@ Model::~Model() { AbstractViewStateInterface* Model::_viewState = NULL; -void Model::setShowCollisionMesh(bool value) { - if (_showCollisionGeometry != value) { - _showCollisionGeometry = value; - _needsFixupInScene = true; - } -} - bool Model::needsFixupInScene() const { - if ((_needsFixupInScene || !_addedToScene) && !_needsReload && isLoaded()) { - if (_showCollisionGeometry && _collisionGeometry) { - return true; - } - if (!_meshStates.isEmpty() || (_renderGeometry && _renderGeometry->getMeshes().empty())) { - if (_needsUpdateTextures) { - if (!_renderGeometry->areTexturesLoaded()) { - return false; - } - _needsUpdateTextures = false; - } - return true; - } - } - return false; + return (_needsFixupInScene || !_addedToScene) && !_needsReload && isLoaded(); } // TODO?: should we combine translation and rotation into single method to avoid double-work? @@ -610,13 +589,13 @@ void Model::setVisibleInScene(bool newValue, std::shared_ptr scen bool Model::addToScene(std::shared_ptr scene, render::PendingChanges& pendingChanges, render::Item::Status::Getters& statusGetters) { - bool readyToRender = (_showCollisionGeometry && _collisionGeometry) || isLoaded(); + bool readyToRender = _collisionGeometry || isLoaded(); if (!_addedToScene && readyToRender) { createRenderItemSet(); } bool somethingAdded = false; - if (_showCollisionGeometry && _collisionGeometry) { + if (_collisionGeometry) { if (_collisionRenderItems.empty()) { foreach (auto renderItem, _collisionRenderItemsSet) { auto item = scene->allocateID(); @@ -1237,7 +1216,7 @@ AABox Model::getRenderableMeshBound() const { } void Model::createRenderItemSet() { - if (_showCollisionGeometry && _collisionGeometry) { + if (_collisionGeometry) { if (_collisionRenderItemsSet.empty()) { createCollisionRenderItemSet(); } @@ -1332,7 +1311,7 @@ bool Model::initWhenReady(render::ScenePointer scene) { render::PendingChanges pendingChanges; bool addedPendingChanges = false; - if (_showCollisionGeometry && _collisionGeometry) { + if (_collisionGeometry) { foreach (auto renderItem, _collisionRenderItemsSet) { auto item = scene->allocateID(); auto renderPayload = std::make_shared(renderItem); @@ -1374,13 +1353,12 @@ public: }; void Model::setCollisionMesh(model::MeshPointer mesh) { - _collisionGeometry = std::make_shared(mesh); - - // TODO: At the moment we create the collision mesh for every model that has a collision shape - // as soon as we know the shape, but we SHOULD only ever create the render mesh when we need it. - if (_showCollisionGeometry) { - _needsFixupInScene = true; + if (mesh) { + _collisionGeometry = std::make_shared(mesh); + } else { + _collisionGeometry.reset(); } + _needsFixupInScene = true; } ModelBlender::ModelBlender() : diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index edb8f0b6ae..08a3a2fc54 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -82,8 +82,6 @@ public: void setVisibleInScene(bool newValue, std::shared_ptr scene); bool needsFixupInScene() const; - void setShowCollisionMesh(bool value); - bool readyToAddToScene(RenderArgs* renderArgs = nullptr) const { return !_needsReload && isRenderable() && isActive(); } @@ -395,7 +393,6 @@ protected: bool _needsFixupInScene { true }; // needs to be removed/re-added to scene bool _needsReload { true }; bool _needsUpdateClusterMatrices { true }; - bool _showCollisionGeometry { false }; mutable bool _needsUpdateTextures { true }; friend class ModelMeshPartPayload; From 83426fd5a8c0c4804e584fbff2bd24d7800c9baf Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 28 Jul 2016 10:30:28 -0700 Subject: [PATCH 33/45] handle transitions to/from STATIC_MESH when rendering collision geometry --- .../src/RenderableModelEntityItem.cpp | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 2d03f76ae6..d47c9afab6 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -438,13 +438,11 @@ void RenderableModelEntityItem::render(RenderArgs* args) { remapTextures(); // update whether the model should be showing collision mesh (this may flag for fixupInScene) - ShapeType type = getShapeType(); - bool shouldShowCollisionGeometry = type != SHAPE_TYPE_STATIC_MESH && - type != SHAPE_TYPE_NONE && - (args->_debugFlags & (int)RenderArgs::RENDER_DEBUG_HULLS) > 0; - if (shouldShowCollisionGeometry != _showCollisionGeometry) { - _showCollisionGeometry = shouldShowCollisionGeometry; - if (_showCollisionGeometry) { + bool showingCollisionGeometry = (bool)(args->_debugFlags & (int)RenderArgs::RENDER_DEBUG_HULLS); + if (showingCollisionGeometry != _showCollisionGeometry) { + ShapeType type = getShapeType(); + _showCollisionGeometry = showingCollisionGeometry; + if (_showCollisionGeometry && type != SHAPE_TYPE_STATIC_MESH && type != SHAPE_TYPE_NONE) { // NOTE: it is OK if _collisionMeshKey is nullptr model::MeshPointer mesh = collisionMeshCache.getMesh(_collisionMeshKey); // NOTE: the model will render the collisionGeometry if it has one From 269b7ae7c163644b6b2549b69b0ecfb3d751f9d8 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 28 Jul 2016 11:44:54 -0700 Subject: [PATCH 34/45] remove commented out cruft --- libraries/physics/src/CollisionRenderMeshCache.h | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/libraries/physics/src/CollisionRenderMeshCache.h b/libraries/physics/src/CollisionRenderMeshCache.h index 0c789f3da9..910b43996e 100644 --- a/libraries/physics/src/CollisionRenderMeshCache.h +++ b/libraries/physics/src/CollisionRenderMeshCache.h @@ -18,18 +18,6 @@ #include -/* -class btCollisionShape; - -namespace std { - template <> - struct hash { - std::size_t operator()(btCollisionShape* shape) const { - return (hash()((void*)shape)); - } - }; -} -*/ class CollisionRenderMeshCache { public: From 48c73acae0616e674558da5a9871dd960bfd3e28 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 28 Jul 2016 11:46:02 -0700 Subject: [PATCH 35/45] restore privacy of GeometryResourceWatcher methods --- libraries/model-networking/src/model-networking/ModelCache.h | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/model-networking/src/model-networking/ModelCache.h b/libraries/model-networking/src/model-networking/ModelCache.h index fa93d3c899..bcca846625 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.h +++ b/libraries/model-networking/src/model-networking/ModelCache.h @@ -111,6 +111,7 @@ public: QUrl getURL() const { return (bool)_resource ? _resource->getURL() : QUrl(); } +private: void startWatching(); void stopWatching(); From e5547122599d5f06d4d93c3e8d1012903c763e9e Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 28 Jul 2016 12:07:13 -0700 Subject: [PATCH 36/45] remove entities-renderer dependency on physics lib --- libraries/entities-renderer/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/entities-renderer/CMakeLists.txt b/libraries/entities-renderer/CMakeLists.txt index 9218b94fe1..0063f4a701 100644 --- a/libraries/entities-renderer/CMakeLists.txt +++ b/libraries/entities-renderer/CMakeLists.txt @@ -1,7 +1,7 @@ set(TARGET_NAME entities-renderer) AUTOSCRIBE_SHADER_LIB(gpu model procedural render render-utils) setup_hifi_library(Widgets Network Script) -link_hifi_libraries(shared gpu procedural model model-networking script-engine render render-utils physics) +link_hifi_libraries(shared gpu procedural model model-networking script-engine render render-utils) target_bullet() From d801b3521c66671833b810fa2f42e9a9b0ec5794 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 28 Jul 2016 14:18:39 -0700 Subject: [PATCH 37/45] fix warnings on windows --- libraries/physics/src/CollisionRenderMeshCache.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/physics/src/CollisionRenderMeshCache.cpp b/libraries/physics/src/CollisionRenderMeshCache.cpp index 8b27bbae24..bd6b761f4e 100644 --- a/libraries/physics/src/CollisionRenderMeshCache.cpp +++ b/libraries/physics/src/CollisionRenderMeshCache.cpp @@ -41,7 +41,7 @@ bool copyShapeToMesh(const btTransform& transform, const btConvexShape* shape, { // new part model::Mesh::Part part; - part._startIndex = indices.getNumElements(); + part._startIndex = (model::Index)indices.getNumElements(); part._numIndices = (model::Index)numHullIndices; // FIXME: the render code cannot handle the case where part._baseVertex != 0 //part._baseVertex = vertices.getNumElements(); // DOES NOT WORK @@ -54,7 +54,7 @@ bool copyShapeToMesh(const btTransform& transform, const btConvexShape* shape, } const int32_t SIZE_OF_VEC3 = 3 * sizeof(float); - model::Index indexOffset = vertices.getNumElements(); + model::Index indexOffset = (model::Index)vertices.getNumElements(); { // new indices const uint32_t* hullIndices = hull.getIndexPointer(); @@ -201,7 +201,7 @@ bool CollisionRenderMeshCache::releaseMesh(CollisionRenderMeshCache::Key key) { } void CollisionRenderMeshCache::collectGarbage() { - uint32_t numShapes = _pendingGarbage.size(); + uint32_t numShapes = (uint32_t)_pendingGarbage.size(); for (uint32_t i = 0; i < numShapes; ++i) { CollisionRenderMeshCache::Key key = _pendingGarbage[i]; CollisionMeshMap::const_iterator itr = _meshMap.find(key); From 2f16aca114194575d734fbd983a8bbb5da9fca01 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 17 Aug 2016 09:57:53 -0700 Subject: [PATCH 38/45] remove cruft and fix typo in rebase --- libraries/entities-renderer/src/EntityTreeRenderer.cpp | 2 +- libraries/entities-renderer/src/RenderableModelEntityItem.cpp | 2 ++ libraries/render-utils/src/Model.h | 3 --- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index 25352255fa..bc045a99d7 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -503,7 +503,7 @@ void EntityTreeRenderer::processEraseMessage(ReceivedMessage& message, const Sha std::static_pointer_cast(_tree)->processEraseMessage(message, sourceNode); } -ModelPointer EntityTreeRenderer::allocateModel(const QString& url, loadingPriority) { +ModelPointer EntityTreeRenderer::allocateModel(const QString& url, float loadingPriority) { ModelPointer model = nullptr; // Only create and delete models on the thread that owns the EntityTreeRenderer diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index d47c9afab6..3ba48b931d 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -180,6 +180,7 @@ void RenderableModelEntityItem::doInitialModelSimulation() { _needsInitialSimulation = false; } +/* // TODO: we need a solution for changes to the postion/rotation/etc of a model... // this current code path only addresses that in this setup case... not the changing/moving case bool RenderableModelEntityItem::readyToAddToScene(RenderArgs* renderArgs) { @@ -197,6 +198,7 @@ bool RenderableModelEntityItem::readyToAddToScene(RenderArgs* renderArgs) { bool ready = !_needsInitialSimulation && _model && _model->readyToAddToScene(); return ready; } +*/ class RenderableModelEntityItemMeta { public: diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index 08a3a2fc54..ff702d1ec5 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -82,9 +82,6 @@ public: void setVisibleInScene(bool newValue, std::shared_ptr scene); bool needsFixupInScene() const; - bool readyToAddToScene(RenderArgs* renderArgs = nullptr) const { - return !_needsReload && isRenderable() && isActive(); - } bool needsReload() const { return _needsReload; } bool initWhenReady(render::ScenePointer scene); bool addToScene(std::shared_ptr scene, From e4317adcf19f24737f282d4fa88e4c25ea8ed3c4 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 17 Aug 2016 09:58:39 -0700 Subject: [PATCH 39/45] remove cruft --- .../src/RenderableModelEntityItem.cpp | 20 ------------------- 1 file changed, 20 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 3ba48b931d..970969f1c9 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -180,26 +180,6 @@ void RenderableModelEntityItem::doInitialModelSimulation() { _needsInitialSimulation = false; } -/* -// TODO: we need a solution for changes to the postion/rotation/etc of a model... -// this current code path only addresses that in this setup case... not the changing/moving case -bool RenderableModelEntityItem::readyToAddToScene(RenderArgs* renderArgs) { - if (!_model && renderArgs) { - // TODO: this getModel() appears to be about 3% of model render time. We should optimize - PerformanceTimer perfTimer("getModel"); - EntityTreeRenderer* renderer = static_cast(renderArgs->_renderer); - getModel(renderer); - } - if (renderArgs && _model && _needsInitialSimulation && _model->isActive() && _model->isLoaded()) { - // make sure to simulate so everything gets set up correctly for rendering - doInitialModelSimulation(); - _model->renderSetup(renderArgs); - } - bool ready = !_needsInitialSimulation && _model && _model->readyToAddToScene(); - return ready; -} -*/ - class RenderableModelEntityItemMeta { public: RenderableModelEntityItemMeta(EntityItemPointer entity) : entity(entity){ } From acaa77b75a3ea064575fde92e48d19892d390cd9 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 22 Aug 2016 09:06:13 -0700 Subject: [PATCH 40/45] remove cruft from debug efforts --- libraries/entities/src/EntityItem.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 1ad1d938a7..e572bf4de8 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -327,10 +327,6 @@ public: virtual void setCollisionShape(const btCollisionShape* shape) {} - // these are only needed because the names don't match - virtual const glm::quat getRotation() const { return getOrientation(); } - virtual void setRotation(glm::quat orientation) { setOrientation(orientation); } - // updateFoo() methods to be used when changes need to be accumulated in the _dirtyFlags virtual void updateRegistrationPoint(const glm::vec3& value); void updatePosition(const glm::vec3& value); From 19cd4648adfd8216cc30f71e42a295a407bede03 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 24 Aug 2016 11:21:47 -0700 Subject: [PATCH 41/45] scale collision render mesh correctly --- libraries/entities/src/EntityItem.cpp | 2 +- libraries/physics/src/CollisionRenderMeshCache.cpp | 4 ---- libraries/render-utils/src/Model.cpp | 9 +++++++-- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 29cbfd79e6..68636415f8 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -2213,4 +2213,4 @@ void EntityItem::globalizeProperties(EntityItemProperties& properties, const QSt } QUuid empty; properties.setParentID(empty); -} \ No newline at end of file +} diff --git a/libraries/physics/src/CollisionRenderMeshCache.cpp b/libraries/physics/src/CollisionRenderMeshCache.cpp index bd6b761f4e..517e25e1c4 100644 --- a/libraries/physics/src/CollisionRenderMeshCache.cpp +++ b/libraries/physics/src/CollisionRenderMeshCache.cpp @@ -190,10 +190,6 @@ bool CollisionRenderMeshCache::releaseMesh(CollisionRenderMeshCache::Key key) { } CollisionMeshMap::const_iterator itr = _meshMap.find(key); if (itr != _meshMap.end()) { - // we hold at least one reference, and the outer scope also holds at least one - // so we assert that the reference count is not 1 - assert((*itr).second.use_count() != 1); - _pendingGarbage.push_back(key); return true; } diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index ca0994b837..6f435b2c8d 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -166,6 +166,11 @@ void Model::updateRenderItems() { return; } + glm::vec3 scale = getScale(); + if (_collisionGeometry) { + // _collisionGeometry is already scaled + scale = glm::vec3(1.0f); + } _needsUpdateClusterMatrices = true; _renderItemsNeedUpdate = false; @@ -173,7 +178,7 @@ void Model::updateRenderItems() { // the application will ensure only the last lambda is actually invoked. void* key = (void*)this; std::weak_ptr weakSelf = shared_from_this(); - AbstractViewStateInterface::instance()->pushPostUpdateLambda(key, [weakSelf]() { + AbstractViewStateInterface::instance()->pushPostUpdateLambda(key, [weakSelf, scale]() { // do nothing, if the model has already been destroyed. auto self = weakSelf.lock(); @@ -184,7 +189,7 @@ void Model::updateRenderItems() { render::ScenePointer scene = AbstractViewStateInterface::instance()->getMain3DScene(); Transform modelTransform; - modelTransform.setScale(self->_scale); + modelTransform.setScale(scale); modelTransform.setTranslation(self->_translation); modelTransform.setRotation(self->_rotation); From 502146b1718df33b43ca9505d41185073c6dc194 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 24 Aug 2016 17:50:13 -0700 Subject: [PATCH 42/45] distribute reg offset to compound children --- libraries/physics/src/ShapeFactory.cpp | 28 ++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/libraries/physics/src/ShapeFactory.cpp b/libraries/physics/src/ShapeFactory.cpp index f11b0f95dc..a67e0053da 100644 --- a/libraries/physics/src/ShapeFactory.cpp +++ b/libraries/physics/src/ShapeFactory.cpp @@ -346,14 +346,26 @@ const btCollisionShape* ShapeFactory::createShapeFromInfo(const ShapeInfo& info) } if (shape) { if (glm::length2(info.getOffset()) > MIN_SHAPE_OFFSET * MIN_SHAPE_OFFSET) { - // this shape has an offset, which we support by wrapping the true shape - // in a btCompoundShape with a local transform - auto compound = new btCompoundShape(); - btTransform trans; - trans.setIdentity(); - trans.setOrigin(glmToBullet(info.getOffset())); - compound->addChildShape(trans, shape); - shape = compound; + // we need to apply an offset + btTransform offset; + offset.setIdentity(); + offset.setOrigin(glmToBullet(info.getOffset())); + + if (shape->getShapeType() == (int)COMPOUND_SHAPE_PROXYTYPE) { + // this shape is already compound + // walk through the child shapes and adjust their transforms + btCompoundShape* compound = static_cast(shape); + int32_t numSubShapes = compound->getNumChildShapes(); + for (int32_t i = 0; i < numSubShapes; ++i) { + compound->updateChildTransform(i, offset * compound->getChildTransform(i), false); + } + compound->recalculateLocalAabb(); + } else { + // wrap this shape in a compound + auto compound = new btCompoundShape(); + compound->addChildShape(offset, shape); + shape = compound; + } } } return shape; From b95cb566cd377a6ff968ede4852c3bd9b5eda5f6 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 24 Aug 2016 17:51:33 -0700 Subject: [PATCH 43/45] fix collision mesh for non-trivial registration --- .../src/RenderableModelEntityItem.cpp | 34 ++++++++++--------- .../src/RenderableModelEntityItem.h | 2 +- libraries/render-utils/src/Model.cpp | 9 ++++- 3 files changed, 27 insertions(+), 18 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 970969f1c9..fc3245f322 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -631,7 +631,7 @@ bool RenderableModelEntityItem::isReadyToComputeShape() { return true; } -void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) { +void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& shapeInfo) { const uint32_t TRIANGLE_STRIDE = 3; const uint32_t QUAD_STRIDE = 4; @@ -645,7 +645,7 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) { assert(_model && _model->isLoaded() && _compoundShapeResource && _compoundShapeResource->isLoaded()); const FBXGeometry& collisionGeometry = _compoundShapeResource->getFBXGeometry(); - ShapeInfo::PointCollection& pointCollection = info.getPointCollection(); + ShapeInfo::PointCollection& pointCollection = shapeInfo.getPointCollection(); pointCollection.clear(); uint32_t i = 0; @@ -721,15 +721,14 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) { glm::vec3 scaleToFit = dimensions / _model->getFBXGeometry().getUnscaledMeshExtents().size(); // multiply each point by scale before handing the point-set off to the physics engine. // also determine the extents of the collision model. + glm::vec3 registrationOffset = dimensions * (ENTITY_ITEM_DEFAULT_REGISTRATION_POINT - getRegistrationPoint()); for (int32_t i = 0; i < pointCollection.size(); i++) { for (int32_t j = 0; j < pointCollection[i].size(); j++) { - // compensate for registration - pointCollection[i][j] += _model->getOffset(); - // scale so the collision points match the model points - pointCollection[i][j] *= scaleToFit; + // back compensate for registration so we can apply that offset to the shapeInfo later + pointCollection[i][j] = scaleToFit * (pointCollection[i][j] + _model->getOffset()) - registrationOffset; } } - info.setParams(type, dimensions, _compoundShapeURL); + shapeInfo.setParams(type, dimensions, _compoundShapeURL); } else if (type >= SHAPE_TYPE_SIMPLE_HULL && type <= SHAPE_TYPE_STATIC_MESH) { // should never fall in here when model not fully loaded assert(_model && _model->isLoaded()); @@ -742,29 +741,31 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) { const FBXGeometry& fbxGeometry = _model->getFBXGeometry(); int numFbxMeshes = fbxGeometry.meshes.size(); int totalNumVertices = 0; + glm::mat4 invRegistraionOffset = glm::translate(dimensions * (getRegistrationPoint() - ENTITY_ITEM_DEFAULT_REGISTRATION_POINT)); for (int i = 0; i < numFbxMeshes; i++) { const FBXMesh& mesh = fbxGeometry.meshes.at(i); if (mesh.clusters.size() > 0) { const FBXCluster& cluster = mesh.clusters.at(0); auto jointMatrix = _model->getRig()->getJointTransform(cluster.jointIndex); - localTransforms.push_back(jointMatrix * cluster.inverseBindMatrix); + // we backtranslate by the registration offset so we can apply that offset to the shapeInfo later + localTransforms.push_back(invRegistraionOffset * jointMatrix * cluster.inverseBindMatrix); } else { glm::mat4 identity; - localTransforms.push_back(identity); + localTransforms.push_back(invRegistraionOffset); } totalNumVertices += mesh.vertices.size(); } const int32_t MAX_VERTICES_PER_STATIC_MESH = 1e6; if (totalNumVertices > MAX_VERTICES_PER_STATIC_MESH) { qWarning() << "model" << getModelURL() << "has too many vertices" << totalNumVertices << "and will collide as a box."; - info.setParams(SHAPE_TYPE_BOX, 0.5f * dimensions); + shapeInfo.setParams(SHAPE_TYPE_BOX, 0.5f * dimensions); return; } auto& meshes = _model->getGeometry()->getMeshes(); int32_t numMeshes = (int32_t)(meshes.size()); - ShapeInfo::PointCollection& pointCollection = info.getPointCollection(); + ShapeInfo::PointCollection& pointCollection = shapeInfo.getPointCollection(); pointCollection.clear(); if (type == SHAPE_TYPE_SIMPLE_COMPOUND) { pointCollection.resize(numMeshes); @@ -772,7 +773,7 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) { pointCollection.resize(1); } - ShapeInfo::TriangleIndices& triangleIndices = info.getTriangleIndices(); + ShapeInfo::TriangleIndices& triangleIndices = shapeInfo.getTriangleIndices(); triangleIndices.clear(); Extents extents; @@ -946,12 +947,13 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) { } } - info.setParams(type, 0.5f * dimensions, _modelURL); + shapeInfo.setParams(type, 0.5f * dimensions, _modelURL); } else { - ModelEntityItem::computeShapeInfo(info); - info.setParams(type, 0.5f * dimensions); - adjustShapeInfoByRegistration(info); + ModelEntityItem::computeShapeInfo(shapeInfo); + shapeInfo.setParams(type, 0.5f * dimensions); } + // finally apply the registration offset to the shapeInfo + adjustShapeInfoByRegistration(shapeInfo); } void RenderableModelEntityItem::setCollisionShape(const btCollisionShape* shape) { diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.h b/libraries/entities-renderer/src/RenderableModelEntityItem.h index 3c2333e679..e785e61d22 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.h +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.h @@ -60,7 +60,7 @@ public: virtual void setCompoundShapeURL(const QString& url) override; virtual bool isReadyToComputeShape() override; - virtual void computeShapeInfo(ShapeInfo& info) override; + virtual void computeShapeInfo(ShapeInfo& shapeInfo) override; void setCollisionShape(const btCollisionShape* shape) override; diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 6f435b2c8d..3a7308c277 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -1284,6 +1284,11 @@ void Model::createCollisionRenderItemSet() { // We should not have any existing renderItems if we enter this section of code Q_ASSERT(_collisionRenderItemsSet.isEmpty()); + Transform identity; + identity.setIdentity(); + Transform offset; + offset.postTranslate(_offset); + // Run through all of the meshes, and place them into their segregated, but unsorted buckets uint32_t numMeshes = (uint32_t)meshes.size(); for (uint32_t i = 0; i < numMeshes; i++) { @@ -1296,7 +1301,9 @@ void Model::createCollisionRenderItemSet() { int numParts = (int)mesh->getNumParts(); for (int partIndex = 0; partIndex < numParts; partIndex++) { model::MaterialPointer& material = _collisionMaterials[partIndex % NUM_COLLISION_HULL_COLORS]; - _collisionRenderItemsSet << std::make_shared(mesh, partIndex, material); + auto payload = std::make_shared(mesh, partIndex, material); + payload->updateTransform(identity, offset); + _collisionRenderItemsSet << payload; } } } From c337cc92e5ebc8ef805ae3d5152c80cf0325feae Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 25 Aug 2016 08:51:53 -0700 Subject: [PATCH 44/45] remove crufty comment --- libraries/render-utils/src/Model.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index ff702d1ec5..7a193b1d47 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -137,9 +137,6 @@ public: // And so that getGeometry() isn't chained everywhere const FBXGeometry& getFBXGeometry() const { assert(isLoaded()); return _renderGeometry->getFBXGeometry(); } - // Set the model to use for collisions. - // Should only be called from the model's rendering thread to avoid access violations of changed geometry. - bool isActive() const { return isLoaded(); } bool didVisualGeometryRequestFail() const { return _visualGeometryRequestFailed; } @@ -176,6 +173,7 @@ public: bool getJointPositionInWorldFrame(int jointIndex, glm::vec3& position) const; bool getJointRotationInWorldFrame(int jointIndex, glm::quat& rotation) const; bool getJointCombinedRotation(int jointIndex, glm::quat& rotation) const; + /// \param jointIndex index of joint in model structure /// \param rotation[out] rotation of joint in model-frame /// \return true if joint exists From d7bb5559877b21f7bfe6df3254a7e30012273a6b Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 25 Aug 2016 08:53:08 -0700 Subject: [PATCH 45/45] make menu wording more correct --- interface/src/Menu.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/Menu.h b/interface/src/Menu.h index d47b6842a5..ee00644746 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -137,7 +137,7 @@ namespace MenuOption { const QString Overlays = "Overlays"; const QString PackageModel = "Package Model..."; const QString Pair = "Pair"; - const QString PhysicsShowHulls = "Draw Collision Hulls"; + const QString PhysicsShowHulls = "Draw Collision Shapes"; const QString PhysicsShowOwned = "Highlight Simulation Ownership"; const QString PipelineWarnings = "Log Render Pipeline Warnings"; const QString Preferences = "General...";