mirror of
https://github.com/overte-org/overte.git
synced 2025-08-10 03:40:20 +02:00
Merge pull request #4499 from sethalves/multi-hull-collisions
Multi hull collisions
This commit is contained in:
commit
10af59296d
19 changed files with 279 additions and 51 deletions
|
@ -345,6 +345,13 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
|
||||||
// put the NodeList and datagram processing on the node thread
|
// put the NodeList and datagram processing on the node thread
|
||||||
nodeList->moveToThread(nodeThread);
|
nodeList->moveToThread(nodeThread);
|
||||||
|
|
||||||
|
// geometry background downloads need to happen on the Datagram Processor Thread. The idle loop will
|
||||||
|
// emit checkBackgroundDownloads to cause the GeometryCache to check it's queue for requested background
|
||||||
|
// downloads.
|
||||||
|
QSharedPointer<GeometryCache> geometryCacheP = DependencyManager::get<GeometryCache>();
|
||||||
|
ResourceCache *geometryCache = geometryCacheP.data();
|
||||||
|
connect(this, &Application::checkBackgroundDownloads, geometryCache, &ResourceCache::checkAsynchronousGets);
|
||||||
|
|
||||||
// connect the DataProcessor processDatagrams slot to the QUDPSocket readyRead() signal
|
// connect the DataProcessor processDatagrams slot to the QUDPSocket readyRead() signal
|
||||||
connect(&nodeList->getNodeSocket(), &QUdpSocket::readyRead, _datagramProcessor, &DatagramProcessor::processDatagrams);
|
connect(&nodeList->getNodeSocket(), &QUdpSocket::readyRead, _datagramProcessor, &DatagramProcessor::processDatagrams);
|
||||||
|
|
||||||
|
@ -1557,6 +1564,9 @@ void Application::idle() {
|
||||||
idleTimer->start(2);
|
idleTimer->start(2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// check for any requested background downloads.
|
||||||
|
emit checkBackgroundDownloads();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::setFullscreen(bool fullscreen) {
|
void Application::setFullscreen(bool fullscreen) {
|
||||||
|
|
|
@ -333,6 +333,7 @@ signals:
|
||||||
|
|
||||||
void svoImportRequested(const QString& url);
|
void svoImportRequested(const QString& url);
|
||||||
|
|
||||||
|
void checkBackgroundDownloads();
|
||||||
void domainConnectionRefused(const QString& reason);
|
void domainConnectionRefused(const QString& reason);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
|
|
|
@ -266,6 +266,26 @@ bool RenderableModelEntityItem::findDetailedRayIntersection(const glm::vec3& ori
|
||||||
return _model->findRayIntersectionAgainstSubMeshes(origin, direction, distance, face, extraInfo, precisionPicking);
|
return _model->findRayIntersectionAgainstSubMeshes(origin, direction, distance, face, extraInfo, precisionPicking);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RenderableModelEntityItem::setCollisionModelURL(const QString& url) {
|
||||||
|
ModelEntityItem::setCollisionModelURL(url);
|
||||||
|
if (_model) {
|
||||||
|
_model->setCollisionModelURL(QUrl(url));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RenderableModelEntityItem::hasCollisionModel() const {
|
||||||
|
if (_model) {
|
||||||
|
return ! _model->getCollisionURL().isEmpty();
|
||||||
|
} else {
|
||||||
|
return !_collisionModelURL.isEmpty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const QString& RenderableModelEntityItem::getCollisionModelURL() const {
|
||||||
|
assert (!_model || _collisionModelURL == _model->getCollisionURL().toString());
|
||||||
|
return _collisionModelURL;
|
||||||
|
}
|
||||||
|
|
||||||
bool RenderableModelEntityItem::isReadyToComputeShape() {
|
bool RenderableModelEntityItem::isReadyToComputeShape() {
|
||||||
|
|
||||||
if (!_model) {
|
if (!_model) {
|
||||||
|
@ -294,13 +314,67 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) {
|
||||||
const QSharedPointer<NetworkGeometry> collisionNetworkGeometry = _model->getCollisionGeometry();
|
const QSharedPointer<NetworkGeometry> collisionNetworkGeometry = _model->getCollisionGeometry();
|
||||||
const FBXGeometry& fbxGeometry = collisionNetworkGeometry->getFBXGeometry();
|
const FBXGeometry& fbxGeometry = collisionNetworkGeometry->getFBXGeometry();
|
||||||
|
|
||||||
|
AABox aaBox;
|
||||||
_points.clear();
|
_points.clear();
|
||||||
|
unsigned int i = 0;
|
||||||
foreach (const FBXMesh& mesh, fbxGeometry.meshes) {
|
foreach (const FBXMesh& mesh, fbxGeometry.meshes) {
|
||||||
_points << mesh.vertices;
|
|
||||||
|
foreach (const FBXMeshPart &meshPart, mesh.parts) {
|
||||||
|
QVector<glm::vec3> pointsInPart;
|
||||||
|
unsigned int triangleCount = meshPart.triangleIndices.size() / 3;
|
||||||
|
assert((unsigned int)meshPart.triangleIndices.size() == triangleCount*3);
|
||||||
|
for (unsigned int j = 0; j < triangleCount; j++) {
|
||||||
|
unsigned int p0Index = meshPart.triangleIndices[j*3];
|
||||||
|
unsigned int p1Index = meshPart.triangleIndices[j*3+1];
|
||||||
|
unsigned int p2Index = meshPart.triangleIndices[j*3+2];
|
||||||
|
|
||||||
|
assert(p0Index < (unsigned int)mesh.vertices.size());
|
||||||
|
assert(p1Index < (unsigned int)mesh.vertices.size());
|
||||||
|
assert(p2Index < (unsigned int)mesh.vertices.size());
|
||||||
|
|
||||||
|
glm::vec3 p0 = mesh.vertices[p0Index];
|
||||||
|
glm::vec3 p1 = mesh.vertices[p1Index];
|
||||||
|
glm::vec3 p2 = mesh.vertices[p2Index];
|
||||||
|
|
||||||
|
aaBox += p0;
|
||||||
|
aaBox += p1;
|
||||||
|
aaBox += p2;
|
||||||
|
|
||||||
|
if (!pointsInPart.contains(p0)) {
|
||||||
|
pointsInPart << p0;
|
||||||
|
}
|
||||||
|
if (!pointsInPart.contains(p1)) {
|
||||||
|
pointsInPart << p1;
|
||||||
|
}
|
||||||
|
if (!pointsInPart.contains(p2)) {
|
||||||
|
pointsInPart << p2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QVector<glm::vec3> newMeshPoints;
|
||||||
|
_points << newMeshPoints;
|
||||||
|
_points[i++] << pointsInPart;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
info.setParams(getShapeType(), 0.5f * getDimensions(), _collisionModelURL);
|
// make sure we aren't about to divide by zero
|
||||||
info.setConvexHull(_points);
|
glm::vec3 aaBoxDim = aaBox.getDimensions();
|
||||||
|
aaBoxDim = glm::clamp(aaBoxDim, glm::vec3(FLT_EPSILON), aaBoxDim);
|
||||||
|
|
||||||
|
glm::vec3 scale = _dimensions / aaBoxDim;
|
||||||
|
|
||||||
|
// multiply each point by scale before handing the point-set off to the physics engine
|
||||||
|
for (int i = 0; i < _points.size(); i++) {
|
||||||
|
for (int j = 0; j < _points[i].size(); j++) {
|
||||||
|
// compensate for registraion
|
||||||
|
_points[i][j] += _model->getOffset();
|
||||||
|
// scale so the collision points match the model points
|
||||||
|
_points[i][j] *= scale;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
info.setParams(getShapeType(), _dimensions, _collisionModelURL);
|
||||||
|
info.setConvexHulls(_points);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -308,7 +382,9 @@ ShapeType RenderableModelEntityItem::getShapeType() const {
|
||||||
// XXX make hull an option in edit.js ?
|
// XXX make hull an option in edit.js ?
|
||||||
if (!_model || _model->getCollisionURL().isEmpty()) {
|
if (!_model || _model->getCollisionURL().isEmpty()) {
|
||||||
return _shapeType;
|
return _shapeType;
|
||||||
} else {
|
} else if (_points.size() == 1) {
|
||||||
return SHAPE_TYPE_CONVEX_HULL;
|
return SHAPE_TYPE_CONVEX_HULL;
|
||||||
|
} else {
|
||||||
|
return SHAPE_TYPE_COMPOUND;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,6 +52,10 @@ public:
|
||||||
|
|
||||||
bool needsToCallUpdate() const;
|
bool needsToCallUpdate() const;
|
||||||
|
|
||||||
|
virtual void setCollisionModelURL(const QString& url);
|
||||||
|
virtual bool hasCollisionModel() const;
|
||||||
|
virtual const QString& getCollisionModelURL() const;
|
||||||
|
|
||||||
bool isReadyToComputeShape();
|
bool isReadyToComputeShape();
|
||||||
void computeShapeInfo(ShapeInfo& info);
|
void computeShapeInfo(ShapeInfo& info);
|
||||||
ShapeType getShapeType() const;
|
ShapeType getShapeType() const;
|
||||||
|
@ -66,7 +70,7 @@ private:
|
||||||
QString _currentTextures;
|
QString _currentTextures;
|
||||||
QStringList _originalTextures;
|
QStringList _originalTextures;
|
||||||
bool _originalTexturesRead;
|
bool _originalTexturesRead;
|
||||||
QVector<glm::vec3> _points;
|
QVector<QVector<glm::vec3>> _points;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_RenderableModelEntityItem_h
|
#endif // hifi_RenderableModelEntityItem_h
|
||||||
|
|
|
@ -281,6 +281,13 @@ void ModelEntityItem::updateShapeType(ShapeType type) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ModelEntityItem::setCollisionModelURL(const QString& url) {
|
||||||
|
if (_collisionModelURL != url) {
|
||||||
|
_collisionModelURL = url;
|
||||||
|
_dirtyFlags |= EntityItem::DIRTY_SHAPE | EntityItem::DIRTY_MASS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void ModelEntityItem::setAnimationURL(const QString& url) {
|
void ModelEntityItem::setAnimationURL(const QString& url) {
|
||||||
_dirtyFlags |= EntityItem::DIRTY_UPDATEABLE;
|
_dirtyFlags |= EntityItem::DIRTY_UPDATEABLE;
|
||||||
_animationURL = url;
|
_animationURL = url;
|
||||||
|
|
|
@ -57,13 +57,13 @@ public:
|
||||||
const rgbColor& getColor() const { return _color; }
|
const rgbColor& getColor() const { return _color; }
|
||||||
xColor getXColor() const { xColor color = { _color[RED_INDEX], _color[GREEN_INDEX], _color[BLUE_INDEX] }; return color; }
|
xColor getXColor() const { xColor color = { _color[RED_INDEX], _color[GREEN_INDEX], _color[BLUE_INDEX] }; return color; }
|
||||||
bool hasModel() const { return !_modelURL.isEmpty(); }
|
bool hasModel() const { return !_modelURL.isEmpty(); }
|
||||||
bool hasCollisionModel() const { return !_collisionModelURL.isEmpty(); }
|
virtual bool hasCollisionModel() const { return !_collisionModelURL.isEmpty(); }
|
||||||
|
|
||||||
static const QString DEFAULT_MODEL_URL;
|
static const QString DEFAULT_MODEL_URL;
|
||||||
const QString& getModelURL() const { return _modelURL; }
|
const QString& getModelURL() const { return _modelURL; }
|
||||||
|
|
||||||
static const QString DEFAULT_COLLISION_MODEL_URL;
|
static const QString DEFAULT_COLLISION_MODEL_URL;
|
||||||
const QString& getCollisionModelURL() const { return _collisionModelURL; }
|
virtual const QString& getCollisionModelURL() const { return _collisionModelURL; }
|
||||||
|
|
||||||
bool hasAnimation() const { return !_animationURL.isEmpty(); }
|
bool hasAnimation() const { return !_animationURL.isEmpty(); }
|
||||||
static const QString DEFAULT_ANIMATION_URL;
|
static const QString DEFAULT_ANIMATION_URL;
|
||||||
|
@ -78,7 +78,7 @@ public:
|
||||||
|
|
||||||
// model related properties
|
// model related properties
|
||||||
void setModelURL(const QString& url) { _modelURL = url; }
|
void setModelURL(const QString& url) { _modelURL = url; }
|
||||||
void setCollisionModelURL(const QString& url) { _collisionModelURL = url; }
|
virtual void setCollisionModelURL(const QString& url);
|
||||||
void setAnimationURL(const QString& url);
|
void setAnimationURL(const QString& url);
|
||||||
static const float DEFAULT_ANIMATION_FRAME_INDEX;
|
static const float DEFAULT_ANIMATION_FRAME_INDEX;
|
||||||
void setAnimationFrameIndex(float value);
|
void setAnimationFrameIndex(float value);
|
||||||
|
|
|
@ -249,7 +249,20 @@ bool parseOBJGroup(OBJTokenizer &tokenizer, const QVariantHash& mapping,
|
||||||
} else if (indices.count() == 4) {
|
} else if (indices.count() == 4) {
|
||||||
meshPart.quadIndices << indices;
|
meshPart.quadIndices << indices;
|
||||||
} else {
|
} else {
|
||||||
qDebug() << "no support for more than 4 vertices on a face in OBJ files";
|
// some obj writers (maya) will write a face with lots of points.
|
||||||
|
for (int i = 1; i < indices.count() - 1; i++) {
|
||||||
|
// break the face into triangles
|
||||||
|
meshPart.triangleIndices.append(indices[0]);
|
||||||
|
meshPart.triangleIndices.append(indices[i]);
|
||||||
|
meshPart.triangleIndices.append(indices[i+1]);
|
||||||
|
}
|
||||||
|
if (indices.count() == normalIndices.count()) {
|
||||||
|
for (int i = 1; i < normalIndices.count() - 1; i++) {
|
||||||
|
faceNormalIndexes.append(normalIndices[0]);
|
||||||
|
faceNormalIndexes.append(normalIndices[i]);
|
||||||
|
faceNormalIndexes.append(normalIndices[i+1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// something we don't (yet) care about
|
// something we don't (yet) care about
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
|
|
||||||
#include <SharedUtil.h>
|
#include <SharedUtil.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
#include "NetworkAccessManager.h"
|
#include "NetworkAccessManager.h"
|
||||||
#include "ResourceCache.h"
|
#include "ResourceCache.h"
|
||||||
|
@ -48,32 +49,40 @@ void ResourceCache::refresh(const QUrl& url) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ResourceCache::getResourceAsynchronously(const QUrl& url) {
|
||||||
|
qDebug() << "ResourceCache::getResourceAsynchronously" << url.toString();
|
||||||
|
_resourcesToBeGottenLock.lockForWrite();
|
||||||
|
_resourcesToBeGotten.enqueue(QUrl(url));
|
||||||
|
_resourcesToBeGottenLock.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ResourceCache::checkAsynchronousGets() {
|
||||||
|
assert(QThread::currentThread() == thread());
|
||||||
|
if (!_resourcesToBeGotten.isEmpty()) {
|
||||||
|
_resourcesToBeGottenLock.lockForWrite();
|
||||||
|
QUrl url = _resourcesToBeGotten.dequeue();
|
||||||
|
_resourcesToBeGottenLock.unlock();
|
||||||
|
getResource(url);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QSharedPointer<Resource> ResourceCache::getResource(const QUrl& url, const QUrl& fallback,
|
QSharedPointer<Resource> ResourceCache::getResource(const QUrl& url, const QUrl& fallback,
|
||||||
bool delayLoad, void* extra, bool block) {
|
bool delayLoad, void* extra) {
|
||||||
|
QSharedPointer<Resource> resource = _resources.value(url);
|
||||||
|
if (!resource.isNull()) {
|
||||||
|
return resource;
|
||||||
|
}
|
||||||
|
|
||||||
if (QThread::currentThread() != thread()) {
|
if (QThread::currentThread() != thread()) {
|
||||||
// This will re-call this method in the main thread. If block is true and the main thread
|
assert(delayLoad);
|
||||||
// is waiting on a lock, we'll deadlock here.
|
getResourceAsynchronously(url);
|
||||||
if (block) {
|
return QSharedPointer<Resource>();
|
||||||
QSharedPointer<Resource> result;
|
|
||||||
QMetaObject::invokeMethod(this, "getResource", Qt::BlockingQueuedConnection,
|
|
||||||
Q_RETURN_ARG(QSharedPointer<Resource>, result), Q_ARG(const QUrl&, url),
|
|
||||||
Q_ARG(const QUrl&, fallback), Q_ARG(bool, delayLoad), Q_ARG(void*, extra));
|
|
||||||
return result;
|
|
||||||
} else {
|
|
||||||
// Queue the re-invocation of this method, but if the main thread is blocked, don't wait. The
|
|
||||||
// return value may be NULL -- it's expected that this will be called again later, in order
|
|
||||||
// to receive the actual Resource.
|
|
||||||
QMetaObject::invokeMethod(this, "getResource", Qt::QueuedConnection,
|
|
||||||
Q_ARG(const QUrl&, url),
|
|
||||||
Q_ARG(const QUrl&, fallback), Q_ARG(bool, delayLoad), Q_ARG(void*, extra));
|
|
||||||
return _resources.value(url);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!url.isValid() && !url.isEmpty() && fallback.isValid()) {
|
if (!url.isValid() && !url.isEmpty() && fallback.isValid()) {
|
||||||
return getResource(fallback, QUrl(), delayLoad);
|
return getResource(fallback, QUrl(), delayLoad);
|
||||||
}
|
}
|
||||||
QSharedPointer<Resource> resource = _resources.value(url);
|
|
||||||
if (resource.isNull()) {
|
if (resource.isNull()) {
|
||||||
resource = createResource(url, fallback.isValid() ?
|
resource = createResource(url, fallback.isValid() ?
|
||||||
getResource(fallback, QUrl(), true) : QSharedPointer<Resource>(), delayLoad, extra);
|
getResource(fallback, QUrl(), true) : QSharedPointer<Resource>(), delayLoad, extra);
|
||||||
|
|
|
@ -21,6 +21,8 @@
|
||||||
#include <QSharedPointer>
|
#include <QSharedPointer>
|
||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
#include <QWeakPointer>
|
#include <QWeakPointer>
|
||||||
|
#include <QReadWriteLock>
|
||||||
|
#include <QQueue>
|
||||||
|
|
||||||
#include <DependencyManager.h>
|
#include <DependencyManager.h>
|
||||||
|
|
||||||
|
@ -79,6 +81,9 @@ public:
|
||||||
|
|
||||||
void refresh(const QUrl& url);
|
void refresh(const QUrl& url);
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void checkAsynchronousGets();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
qint64 _unusedResourcesMaxSize = DEFAULT_UNUSED_MAX_SIZE;
|
qint64 _unusedResourcesMaxSize = DEFAULT_UNUSED_MAX_SIZE;
|
||||||
qint64 _unusedResourcesSize = 0;
|
qint64 _unusedResourcesSize = 0;
|
||||||
|
@ -89,7 +94,7 @@ protected:
|
||||||
/// \param delayLoad if true, don't load the resource immediately; wait until load is first requested
|
/// \param delayLoad if true, don't load the resource immediately; wait until load is first requested
|
||||||
/// \param extra extra data to pass to the creator, if appropriate
|
/// \param extra extra data to pass to the creator, if appropriate
|
||||||
Q_INVOKABLE QSharedPointer<Resource> getResource(const QUrl& url, const QUrl& fallback = QUrl(),
|
Q_INVOKABLE QSharedPointer<Resource> getResource(const QUrl& url, const QUrl& fallback = QUrl(),
|
||||||
bool delayLoad = false, void* extra = NULL, bool block = true);
|
bool delayLoad = false, void* extra = NULL);
|
||||||
|
|
||||||
/// Creates a new resource.
|
/// Creates a new resource.
|
||||||
virtual QSharedPointer<Resource> createResource(const QUrl& url,
|
virtual QSharedPointer<Resource> createResource(const QUrl& url,
|
||||||
|
@ -109,6 +114,11 @@ private:
|
||||||
int _lastLRUKey = 0;
|
int _lastLRUKey = 0;
|
||||||
|
|
||||||
static int _requestLimit;
|
static int _requestLimit;
|
||||||
|
|
||||||
|
void getResourceAsynchronously(const QUrl& url);
|
||||||
|
QReadWriteLock _resourcesToBeGottenLock;
|
||||||
|
QQueue<QUrl> _resourcesToBeGotten;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Base class for resources.
|
/// Base class for resources.
|
||||||
|
|
|
@ -169,7 +169,9 @@ void EntityMotionState::updateObjectVelocities() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void EntityMotionState::computeShapeInfo(ShapeInfo& shapeInfo) {
|
void EntityMotionState::computeShapeInfo(ShapeInfo& shapeInfo) {
|
||||||
_entity->computeShapeInfo(shapeInfo);
|
if (_entity->isReadyToComputeShape()) {
|
||||||
|
_entity->computeShapeInfo(shapeInfo);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
float EntityMotionState::computeMass(const ShapeInfo& shapeInfo) const {
|
float EntityMotionState::computeMass(const ShapeInfo& shapeInfo) const {
|
||||||
|
|
|
@ -29,6 +29,9 @@ int ShapeInfoUtil::toBulletShapeType(int shapeInfoType) {
|
||||||
case SHAPE_TYPE_CONVEX_HULL:
|
case SHAPE_TYPE_CONVEX_HULL:
|
||||||
bulletShapeType = CONVEX_HULL_SHAPE_PROXYTYPE;
|
bulletShapeType = CONVEX_HULL_SHAPE_PROXYTYPE;
|
||||||
break;
|
break;
|
||||||
|
case SHAPE_TYPE_COMPOUND:
|
||||||
|
bulletShapeType = COMPOUND_SHAPE_PROXYTYPE;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return bulletShapeType;
|
return bulletShapeType;
|
||||||
}
|
}
|
||||||
|
@ -48,6 +51,9 @@ int ShapeInfoUtil::fromBulletShapeType(int bulletShapeType) {
|
||||||
case CONVEX_HULL_SHAPE_PROXYTYPE:
|
case CONVEX_HULL_SHAPE_PROXYTYPE:
|
||||||
shapeInfoType = SHAPE_TYPE_CONVEX_HULL;
|
shapeInfoType = SHAPE_TYPE_CONVEX_HULL;
|
||||||
break;
|
break;
|
||||||
|
case COMPOUND_SHAPE_PROXYTYPE:
|
||||||
|
shapeInfoType = SHAPE_TYPE_COMPOUND;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return shapeInfoType;
|
return shapeInfoType;
|
||||||
}
|
}
|
||||||
|
@ -70,12 +76,34 @@ void ShapeInfoUtil::collectInfoFromShape(const btCollisionShape* shape, ShapeInf
|
||||||
const btConvexHullShape* convexHullShape = static_cast<const btConvexHullShape*>(shape);
|
const btConvexHullShape* convexHullShape = static_cast<const btConvexHullShape*>(shape);
|
||||||
const int numPoints = convexHullShape->getNumPoints();
|
const int numPoints = convexHullShape->getNumPoints();
|
||||||
const btVector3* btPoints = convexHullShape->getUnscaledPoints();
|
const btVector3* btPoints = convexHullShape->getUnscaledPoints();
|
||||||
QVector<glm::vec3> points;
|
QVector<QVector<glm::vec3>> points;
|
||||||
|
QVector<glm::vec3> childPoints;
|
||||||
for (int i = 0; i < numPoints; i++) {
|
for (int i = 0; i < numPoints; i++) {
|
||||||
glm::vec3 point(btPoints->getX(), btPoints->getY(), btPoints->getZ());
|
glm::vec3 point(btPoints->getX(), btPoints->getY(), btPoints->getZ());
|
||||||
points << point;
|
childPoints << point;
|
||||||
}
|
}
|
||||||
info.setConvexHull(points);
|
points << childPoints;
|
||||||
|
info.setConvexHulls(points);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SHAPE_TYPE_COMPOUND: {
|
||||||
|
const btCompoundShape* compoundShape = static_cast<const btCompoundShape*>(shape);
|
||||||
|
const int numChildShapes = compoundShape->getNumChildShapes();
|
||||||
|
QVector<QVector<glm::vec3>> points;
|
||||||
|
for (int i = 0; i < numChildShapes; i ++) {
|
||||||
|
const btCollisionShape* childShape = compoundShape->getChildShape(i);
|
||||||
|
const btConvexHullShape* convexHullShape = static_cast<const btConvexHullShape*>(childShape);
|
||||||
|
const int numPoints = convexHullShape->getNumPoints();
|
||||||
|
const btVector3* btPoints = convexHullShape->getUnscaledPoints();
|
||||||
|
|
||||||
|
QVector<glm::vec3> childPoints;
|
||||||
|
for (int j = 0; j < numPoints; j++) {
|
||||||
|
glm::vec3 point(btPoints->getX(), btPoints->getY(), btPoints->getZ());
|
||||||
|
childPoints << point;
|
||||||
|
}
|
||||||
|
points << childPoints;
|
||||||
|
}
|
||||||
|
info.setConvexHulls(points);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default: {
|
default: {
|
||||||
|
@ -108,12 +136,32 @@ btCollisionShape* ShapeInfoUtil::createShapeFromInfo(const ShapeInfo& info) {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SHAPE_TYPE_CONVEX_HULL: {
|
case SHAPE_TYPE_CONVEX_HULL: {
|
||||||
shape = new btConvexHullShape();
|
auto hull = new btConvexHullShape();
|
||||||
const QVector<glm::vec3>& points = info.getPoints();
|
const QVector<QVector<glm::vec3>>& points = info.getPoints();
|
||||||
foreach (glm::vec3 point, points) {
|
foreach (glm::vec3 point, points[0]) {
|
||||||
btVector3 btPoint(point[0], point[1], point[2]);
|
btVector3 btPoint(point[0], point[1], point[2]);
|
||||||
static_cast<btConvexHullShape*>(shape)->addPoint(btPoint);
|
hull->addPoint(btPoint, false);
|
||||||
}
|
}
|
||||||
|
hull->recalcLocalAabb();
|
||||||
|
shape = hull;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SHAPE_TYPE_COMPOUND: {
|
||||||
|
auto compound = new btCompoundShape();
|
||||||
|
const QVector<QVector<glm::vec3>>& points = info.getPoints();
|
||||||
|
|
||||||
|
btTransform trans;
|
||||||
|
trans.setIdentity();
|
||||||
|
foreach (QVector<glm::vec3> hullPoints, points) {
|
||||||
|
auto hull = new btConvexHullShape();
|
||||||
|
foreach (glm::vec3 point, hullPoints) {
|
||||||
|
btVector3 btPoint(point[0], point[1], point[2]);
|
||||||
|
hull->addPoint(btPoint, false);
|
||||||
|
}
|
||||||
|
hull->recalcLocalAabb();
|
||||||
|
compound->addChildShape (trans, hull);
|
||||||
|
}
|
||||||
|
shape = compound;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,8 @@
|
||||||
// translates between ShapeInfo and btShape
|
// translates between ShapeInfo and btShape
|
||||||
|
|
||||||
namespace ShapeInfoUtil {
|
namespace ShapeInfoUtil {
|
||||||
|
|
||||||
|
// XXX is collectInfoFromShape no longer strictly needed?
|
||||||
void collectInfoFromShape(const btCollisionShape* shape, ShapeInfo& info);
|
void collectInfoFromShape(const btCollisionShape* shape, ShapeInfo& info);
|
||||||
|
|
||||||
btCollisionShape* createShapeFromInfo(const ShapeInfo& info);
|
btCollisionShape* createShapeFromInfo(const ShapeInfo& info);
|
||||||
|
|
|
@ -9,6 +9,8 @@
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
#include <glm/gtx/norm.hpp>
|
#include <glm/gtx/norm.hpp>
|
||||||
|
|
||||||
#include "ShapeInfoUtil.h"
|
#include "ShapeInfoUtil.h"
|
||||||
|
@ -35,6 +37,7 @@ btCollisionShape* ShapeManager::getShape(const ShapeInfo& info) {
|
||||||
const float MIN_SHAPE_DIAGONAL_SQUARED = 3.0e-4f; // 1 cm cube
|
const float MIN_SHAPE_DIAGONAL_SQUARED = 3.0e-4f; // 1 cm cube
|
||||||
const float MAX_SHAPE_DIAGONAL_SQUARED = 3.0e4f; // 100 m cube
|
const float MAX_SHAPE_DIAGONAL_SQUARED = 3.0e4f; // 100 m cube
|
||||||
if (diagonal < MIN_SHAPE_DIAGONAL_SQUARED || diagonal > MAX_SHAPE_DIAGONAL_SQUARED) {
|
if (diagonal < MIN_SHAPE_DIAGONAL_SQUARED || diagonal > MAX_SHAPE_DIAGONAL_SQUARED) {
|
||||||
|
// qDebug() << "ShapeManager::getShape -- not making shape due to size" << diagonal;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
DoubleHashKey key = info.getHash();
|
DoubleHashKey key = info.getHash();
|
||||||
|
@ -100,6 +103,18 @@ void ShapeManager::collectGarbage() {
|
||||||
DoubleHashKey& key = _pendingGarbage[i];
|
DoubleHashKey& key = _pendingGarbage[i];
|
||||||
ShapeReference* shapeRef = _shapeMap.find(key);
|
ShapeReference* shapeRef = _shapeMap.find(key);
|
||||||
if (shapeRef && shapeRef->refCount == 0) {
|
if (shapeRef && shapeRef->refCount == 0) {
|
||||||
|
// if the shape we're about to delete is compound, delete the children first.
|
||||||
|
auto shapeType = ShapeInfoUtil::fromBulletShapeType(shapeRef->shape->getShapeType());
|
||||||
|
if (shapeType == SHAPE_TYPE_COMPOUND) {
|
||||||
|
const btCompoundShape* compoundShape = static_cast<const btCompoundShape*>(shapeRef->shape);
|
||||||
|
const int numChildShapes = compoundShape->getNumChildShapes();
|
||||||
|
QVector<QVector<glm::vec3>> points;
|
||||||
|
for (int i = 0; i < numChildShapes; i ++) {
|
||||||
|
const btCollisionShape* childShape = compoundShape->getChildShape(i);
|
||||||
|
delete childShape;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
delete shapeRef->shape;
|
delete shapeRef->shape;
|
||||||
_shapeMap.remove(key);
|
_shapeMap.remove(key);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1771,8 +1771,8 @@ void GeometryCache::renderLine(const glm::vec2& p1, const glm::vec2& p2,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
QSharedPointer<NetworkGeometry> GeometryCache::getGeometry(const QUrl& url, const QUrl& fallback, bool delayLoad, bool block) {
|
QSharedPointer<NetworkGeometry> GeometryCache::getGeometry(const QUrl& url, const QUrl& fallback, bool delayLoad) {
|
||||||
return getResource(url, fallback, delayLoad, NULL, block).staticCast<NetworkGeometry>();
|
return getResource(url, fallback, delayLoad, NULL).staticCast<NetworkGeometry>();
|
||||||
}
|
}
|
||||||
|
|
||||||
QSharedPointer<Resource> GeometryCache::createResource(const QUrl& url,
|
QSharedPointer<Resource> GeometryCache::createResource(const QUrl& url,
|
||||||
|
|
|
@ -203,8 +203,7 @@ public:
|
||||||
/// Loads geometry from the specified URL.
|
/// Loads geometry from the specified URL.
|
||||||
/// \param fallback a fallback URL to load if the desired one is unavailable
|
/// \param fallback a fallback URL to load if the desired one is unavailable
|
||||||
/// \param delayLoad if true, don't load the geometry immediately; wait until load is first requested
|
/// \param delayLoad if true, don't load the geometry immediately; wait until load is first requested
|
||||||
QSharedPointer<NetworkGeometry> getGeometry(const QUrl& url, const QUrl& fallback = QUrl(),
|
QSharedPointer<NetworkGeometry> getGeometry(const QUrl& url, const QUrl& fallback = QUrl(), bool delayLoad = false);
|
||||||
bool delayLoad = false, bool block = true);
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
|
|
|
@ -325,6 +325,8 @@ void Model::init() {
|
||||||
_skinTranslucentProgram = gpu::ShaderPointer(gpu::Shader::createProgram(skinModelVertex, modelTranslucentPixel));
|
_skinTranslucentProgram = gpu::ShaderPointer(gpu::Shader::createProgram(skinModelVertex, modelTranslucentPixel));
|
||||||
makeResult = gpu::Shader::makeProgram(*_skinTranslucentProgram, slotBindings);
|
makeResult = gpu::Shader::makeProgram(*_skinTranslucentProgram, slotBindings);
|
||||||
initSkinProgram(_skinTranslucentProgram, _skinTranslucentLocations);
|
initSkinProgram(_skinTranslucentProgram, _skinTranslucentLocations);
|
||||||
|
|
||||||
|
(void) makeResult; // quiet compiler
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1032,12 +1034,22 @@ void Model::setURL(const QUrl& url, const QUrl& fallback, bool retainCurrent, bo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Model::setCollisionModelURL(const QUrl& url, const QUrl& fallback, bool delayLoad) {
|
|
||||||
|
const QSharedPointer<NetworkGeometry> Model::getCollisionGeometry(bool delayLoad)
|
||||||
|
{
|
||||||
|
if (_collisionGeometry.isNull() && !_collisionUrl.isEmpty()) {
|
||||||
|
_collisionGeometry = DependencyManager::get<GeometryCache>()->getGeometry(_collisionUrl, QUrl(), delayLoad);
|
||||||
|
}
|
||||||
|
|
||||||
|
return _collisionGeometry;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Model::setCollisionModelURL(const QUrl& url) {
|
||||||
if (_collisionUrl == url) {
|
if (_collisionUrl == url) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_collisionUrl = url;
|
_collisionUrl = url;
|
||||||
_collisionGeometry = DependencyManager::get<GeometryCache>()->getGeometry(url, fallback, delayLoad);
|
_collisionGeometry = DependencyManager::get<GeometryCache>()->getGeometry(url, QUrl(), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Model::getJointPositionInWorldFrame(int jointIndex, glm::vec3& position) const {
|
bool Model::getJointPositionInWorldFrame(int jointIndex, glm::vec3& position) const {
|
||||||
|
|
|
@ -109,7 +109,7 @@ public:
|
||||||
const QUrl& getURL() const { return _url; }
|
const QUrl& getURL() const { return _url; }
|
||||||
|
|
||||||
// Set the model to use for collisions
|
// Set the model to use for collisions
|
||||||
Q_INVOKABLE void setCollisionModelURL(const QUrl& url, const QUrl& fallback = QUrl(), bool delayLoad = false);
|
Q_INVOKABLE void setCollisionModelURL(const QUrl& url);
|
||||||
const QUrl& getCollisionURL() const { return _collisionUrl; }
|
const QUrl& getCollisionURL() const { return _collisionUrl; }
|
||||||
|
|
||||||
/// Sets the distance parameter used for LOD computations.
|
/// Sets the distance parameter used for LOD computations.
|
||||||
|
@ -134,7 +134,7 @@ public:
|
||||||
const QSharedPointer<NetworkGeometry>& getGeometry() const { return _geometry; }
|
const QSharedPointer<NetworkGeometry>& getGeometry() const { return _geometry; }
|
||||||
|
|
||||||
/// Returns a reference to the shared collision geometry.
|
/// Returns a reference to the shared collision geometry.
|
||||||
const QSharedPointer<NetworkGeometry> getCollisionGeometry() {return _collisionGeometry; }
|
const QSharedPointer<NetworkGeometry> getCollisionGeometry(bool delayLoad = true);
|
||||||
|
|
||||||
/// Returns the number of joint states in the model.
|
/// Returns the number of joint states in the model.
|
||||||
int getJointStateCount() const { return _jointStates.size(); }
|
int getJointStateCount() const { return _jointStates.size(); }
|
||||||
|
|
|
@ -23,6 +23,7 @@ void ShapeInfo::clear() {
|
||||||
|
|
||||||
void ShapeInfo::setParams(ShapeType type, const glm::vec3& halfExtents, QString url) {
|
void ShapeInfo::setParams(ShapeType type, const glm::vec3& halfExtents, QString url) {
|
||||||
_type = type;
|
_type = type;
|
||||||
|
_points.clear();
|
||||||
switch(type) {
|
switch(type) {
|
||||||
case SHAPE_TYPE_NONE:
|
case SHAPE_TYPE_NONE:
|
||||||
_halfExtents = glm::vec3(0.0f);
|
_halfExtents = glm::vec3(0.0f);
|
||||||
|
@ -37,6 +38,12 @@ void ShapeInfo::setParams(ShapeType type, const glm::vec3& halfExtents, QString
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SHAPE_TYPE_CONVEX_HULL:
|
case SHAPE_TYPE_CONVEX_HULL:
|
||||||
|
_url = QUrl(url);
|
||||||
|
// halfExtents aren't used by convex-hull or compound convex-hull except as part of
|
||||||
|
// the generation of the key for the ShapeManager.
|
||||||
|
_halfExtents = halfExtents;
|
||||||
|
break;
|
||||||
|
case SHAPE_TYPE_COMPOUND:
|
||||||
_url = QUrl(url);
|
_url = QUrl(url);
|
||||||
_halfExtents = halfExtents;
|
_halfExtents = halfExtents;
|
||||||
break;
|
break;
|
||||||
|
@ -47,31 +54,44 @@ void ShapeInfo::setParams(ShapeType type, const glm::vec3& halfExtents, QString
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShapeInfo::setBox(const glm::vec3& halfExtents) {
|
void ShapeInfo::setBox(const glm::vec3& halfExtents) {
|
||||||
|
_url = "";
|
||||||
_type = SHAPE_TYPE_BOX;
|
_type = SHAPE_TYPE_BOX;
|
||||||
_halfExtents = halfExtents;
|
_halfExtents = halfExtents;
|
||||||
|
_points.clear();
|
||||||
_doubleHashKey.clear();
|
_doubleHashKey.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShapeInfo::setSphere(float radius) {
|
void ShapeInfo::setSphere(float radius) {
|
||||||
|
_url = "";
|
||||||
_type = SHAPE_TYPE_SPHERE;
|
_type = SHAPE_TYPE_SPHERE;
|
||||||
_halfExtents = glm::vec3(radius, radius, radius);
|
_halfExtents = glm::vec3(radius, radius, radius);
|
||||||
|
_points.clear();
|
||||||
_doubleHashKey.clear();
|
_doubleHashKey.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShapeInfo::setEllipsoid(const glm::vec3& halfExtents) {
|
void ShapeInfo::setEllipsoid(const glm::vec3& halfExtents) {
|
||||||
|
_url = "";
|
||||||
_type = SHAPE_TYPE_ELLIPSOID;
|
_type = SHAPE_TYPE_ELLIPSOID;
|
||||||
_halfExtents = halfExtents;
|
_halfExtents = halfExtents;
|
||||||
|
_points.clear();
|
||||||
_doubleHashKey.clear();
|
_doubleHashKey.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShapeInfo::setConvexHull(const QVector<glm::vec3>& points) {
|
void ShapeInfo::setConvexHulls(const QVector<QVector<glm::vec3>>& points) {
|
||||||
_type = SHAPE_TYPE_CONVEX_HULL;
|
if (points.size() == 1) {
|
||||||
|
_type = SHAPE_TYPE_CONVEX_HULL;
|
||||||
|
} else {
|
||||||
|
_type = SHAPE_TYPE_COMPOUND;
|
||||||
|
}
|
||||||
_points = points;
|
_points = points;
|
||||||
|
_doubleHashKey.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShapeInfo::setCapsuleY(float radius, float halfHeight) {
|
void ShapeInfo::setCapsuleY(float radius, float halfHeight) {
|
||||||
|
_url = "";
|
||||||
_type = SHAPE_TYPE_CAPSULE_Y;
|
_type = SHAPE_TYPE_CAPSULE_Y;
|
||||||
_halfExtents = glm::vec3(radius, halfHeight, radius);
|
_halfExtents = glm::vec3(radius, halfHeight, radius);
|
||||||
|
_points.clear();
|
||||||
_doubleHashKey.clear();
|
_doubleHashKey.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -44,14 +44,14 @@ public:
|
||||||
void setBox(const glm::vec3& halfExtents);
|
void setBox(const glm::vec3& halfExtents);
|
||||||
void setSphere(float radius);
|
void setSphere(float radius);
|
||||||
void setEllipsoid(const glm::vec3& halfExtents);
|
void setEllipsoid(const glm::vec3& halfExtents);
|
||||||
void setConvexHull(const QVector<glm::vec3>& points);
|
void setConvexHulls(const QVector<QVector<glm::vec3>>& points);
|
||||||
void setCapsuleY(float radius, float halfHeight);
|
void setCapsuleY(float radius, float halfHeight);
|
||||||
|
|
||||||
const int getType() const { return _type; }
|
const int getType() const { return _type; }
|
||||||
|
|
||||||
const glm::vec3& getHalfExtents() const { return _halfExtents; }
|
const glm::vec3& getHalfExtents() const { return _halfExtents; }
|
||||||
|
|
||||||
const QVector<glm::vec3>& getPoints() const { return _points; }
|
const QVector<QVector<glm::vec3>>& getPoints() const { return _points; }
|
||||||
|
|
||||||
void clearPoints () { _points.clear(); }
|
void clearPoints () { _points.clear(); }
|
||||||
void appendToPoints (const QVector<glm::vec3>& newPoints) { _points << newPoints; }
|
void appendToPoints (const QVector<glm::vec3>& newPoints) { _points << newPoints; }
|
||||||
|
@ -64,8 +64,8 @@ protected:
|
||||||
ShapeType _type = SHAPE_TYPE_NONE;
|
ShapeType _type = SHAPE_TYPE_NONE;
|
||||||
glm::vec3 _halfExtents = glm::vec3(0.0f);
|
glm::vec3 _halfExtents = glm::vec3(0.0f);
|
||||||
DoubleHashKey _doubleHashKey;
|
DoubleHashKey _doubleHashKey;
|
||||||
QVector<glm::vec3> _points; // points for convex collision hull
|
QVector<QVector<glm::vec3>> _points; // points for convex collision hulls
|
||||||
QUrl _url; // url for model of convex collision hull
|
QUrl _url; // url for model of convex collision hulls
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_ShapeInfo_h
|
#endif // hifi_ShapeInfo_h
|
||||||
|
|
Loading…
Reference in a new issue