mirror of
https://github.com/overte-org/overte.git
synced 2025-04-17 14:46:40 +02:00
Merge pull request #10178 from sethalves/fix-compound-collision-hulls
Fix compound collision hulls
This commit is contained in:
commit
b9afcd3f0a
8 changed files with 75 additions and 28 deletions
|
@ -14,6 +14,7 @@
|
|||
|
||||
#include <QJsonDocument>
|
||||
#include <QtCore/QThread>
|
||||
#include <QUrlQuery>
|
||||
#include <glm/gtx/transform.hpp>
|
||||
|
||||
#include <AbstractViewStateInterface.h>
|
||||
|
@ -611,7 +612,7 @@ void RenderableModelEntityItem::setShapeType(ShapeType type) {
|
|||
ModelEntityItem::setShapeType(type);
|
||||
if (getShapeType() == SHAPE_TYPE_COMPOUND) {
|
||||
if (!_compoundShapeResource && !getCompoundShapeURL().isEmpty()) {
|
||||
_compoundShapeResource = DependencyManager::get<ModelCache>()->getGeometryResource(getCompoundShapeURL());
|
||||
_compoundShapeResource = DependencyManager::get<ModelCache>()->getCollisionGeometryResource(getCompoundShapeURL());
|
||||
}
|
||||
} else if (_compoundShapeResource && !getCompoundShapeURL().isEmpty()) {
|
||||
// the compoundURL has been set but the shapeType does not agree
|
||||
|
@ -620,8 +621,16 @@ void RenderableModelEntityItem::setShapeType(ShapeType type) {
|
|||
}
|
||||
|
||||
void RenderableModelEntityItem::setCompoundShapeURL(const QString& url) {
|
||||
// because the caching system only allows one Geometry per url, and because this url might also be used
|
||||
// as a visual model, we need to change this url in some way. We add a "collision-hull" query-arg so it
|
||||
// will end up in a different hash-key in ResourceCache. TODO: It would be better to use the same URL and
|
||||
// parse it twice.
|
||||
auto currentCompoundShapeURL = getCompoundShapeURL();
|
||||
ModelEntityItem::setCompoundShapeURL(url);
|
||||
QUrl hullURL(url);
|
||||
QUrlQuery queryArgs(hullURL);
|
||||
queryArgs.addQueryItem("collision-hull", "");
|
||||
hullURL.setQuery(queryArgs);
|
||||
ModelEntityItem::setCompoundShapeURL(hullURL.toString());
|
||||
|
||||
if (getCompoundShapeURL() != currentCompoundShapeURL || !_model) {
|
||||
EntityTreePointer tree = getTree();
|
||||
|
@ -629,7 +638,7 @@ void RenderableModelEntityItem::setCompoundShapeURL(const QString& url) {
|
|||
QMetaObject::invokeMethod(tree.get(), "callLoader", Qt::QueuedConnection, Q_ARG(EntityItemID, getID()));
|
||||
}
|
||||
if (getShapeType() == SHAPE_TYPE_COMPOUND) {
|
||||
_compoundShapeResource = DependencyManager::get<ModelCache>()->getGeometryResource(url);
|
||||
_compoundShapeResource = DependencyManager::get<ModelCache>()->getCollisionGeometryResource(hullURL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -661,7 +670,8 @@ bool RenderableModelEntityItem::isReadyToComputeShape() {
|
|||
}
|
||||
return true;
|
||||
} else if (!getCompoundShapeURL().isEmpty()) {
|
||||
_compoundShapeResource = DependencyManager::get<ModelCache>()->getGeometryResource(getCompoundShapeURL());
|
||||
_compoundShapeResource =
|
||||
DependencyManager::get<ModelCache>()->getCollisionGeometryResource(getCompoundShapeURL());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -302,7 +302,8 @@ QNetworkReply* OBJReader::request(QUrl& url, bool isTest) {
|
|||
}
|
||||
|
||||
|
||||
bool OBJReader::parseOBJGroup(OBJTokenizer& tokenizer, const QVariantHash& mapping, FBXGeometry& geometry, float& scaleGuess) {
|
||||
bool OBJReader::parseOBJGroup(OBJTokenizer& tokenizer, const QVariantHash& mapping, FBXGeometry& geometry,
|
||||
float& scaleGuess, bool combineParts) {
|
||||
FaceGroup faces;
|
||||
FBXMesh& mesh = geometry.meshes[0];
|
||||
mesh.parts.append(FBXMeshPart());
|
||||
|
@ -348,6 +349,9 @@ bool OBJReader::parseOBJGroup(OBJTokenizer& tokenizer, const QVariantHash& mappi
|
|||
}
|
||||
QByteArray groupName = tokenizer.getDatum();
|
||||
currentGroup = groupName;
|
||||
if (!combineParts) {
|
||||
currentMaterialName = QString("part-") + QString::number(_partCounter++);
|
||||
}
|
||||
} else if (token == "mtllib" && !_url.isEmpty()) {
|
||||
if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) {
|
||||
break;
|
||||
|
@ -361,7 +365,9 @@ bool OBJReader::parseOBJGroup(OBJTokenizer& tokenizer, const QVariantHash& mappi
|
|||
}
|
||||
QString nextName = tokenizer.getDatum();
|
||||
if (nextName != currentMaterialName) {
|
||||
currentMaterialName = nextName;
|
||||
if (combineParts) {
|
||||
currentMaterialName = nextName;
|
||||
}
|
||||
#ifdef WANT_DEBUG
|
||||
qCDebug(modelformat) << "OBJ Reader new current material:" << currentMaterialName;
|
||||
#endif
|
||||
|
@ -419,7 +425,7 @@ done:
|
|||
}
|
||||
|
||||
|
||||
FBXGeometry* OBJReader::readOBJ(QByteArray& model, const QVariantHash& mapping, const QUrl& url) {
|
||||
FBXGeometry* OBJReader::readOBJ(QByteArray& model, const QVariantHash& mapping, bool combineParts, const QUrl& url) {
|
||||
PROFILE_RANGE_EX(resource_parse, __FUNCTION__, 0xffff0000, nullptr);
|
||||
QBuffer buffer { &model };
|
||||
buffer.open(QIODevice::ReadOnly);
|
||||
|
@ -438,7 +444,7 @@ FBXGeometry* OBJReader::readOBJ(QByteArray& model, const QVariantHash& mapping,
|
|||
try {
|
||||
// call parseOBJGroup as long as it's returning true. Each successful call will
|
||||
// add a new meshPart to the geometry's single mesh.
|
||||
while (parseOBJGroup(tokenizer, mapping, geometry, scaleGuess)) {}
|
||||
while (parseOBJGroup(tokenizer, mapping, geometry, scaleGuess, combineParts)) {}
|
||||
|
||||
FBXMesh& mesh = geometry.meshes[0];
|
||||
mesh.meshIndex = 0;
|
||||
|
|
|
@ -22,7 +22,7 @@ public:
|
|||
glm::vec3 getVec3();
|
||||
glm::vec2 getVec2();
|
||||
float getFloat() { return std::stof((nextToken() != OBJTokenizer::DATUM_TOKEN) ? nullptr : getDatum().data()); }
|
||||
|
||||
|
||||
private:
|
||||
QIODevice* _device;
|
||||
QByteArray _datum;
|
||||
|
@ -73,15 +73,18 @@ public:
|
|||
QHash<QString, OBJMaterial> materials;
|
||||
|
||||
QNetworkReply* request(QUrl& url, bool isTest);
|
||||
FBXGeometry* readOBJ(QByteArray& model, const QVariantHash& mapping, const QUrl& url = QUrl());
|
||||
|
||||
FBXGeometry* readOBJ(QByteArray& model, const QVariantHash& mapping, bool combineParts, const QUrl& url = QUrl());
|
||||
|
||||
private:
|
||||
QUrl _url;
|
||||
|
||||
QHash<QByteArray, bool> librariesSeen;
|
||||
bool parseOBJGroup(OBJTokenizer& tokenizer, const QVariantHash& mapping, FBXGeometry& geometry, float& scaleGuess);
|
||||
bool parseOBJGroup(OBJTokenizer& tokenizer, const QVariantHash& mapping, FBXGeometry& geometry,
|
||||
float& scaleGuess, bool combineParts);
|
||||
void parseMaterialLibrary(QIODevice* device);
|
||||
bool isValidTexture(const QByteArray &filename); // true if the file exists. TODO?: check content-type header and that it is a supported format.
|
||||
|
||||
int _partCounter { 0 };
|
||||
};
|
||||
|
||||
// What are these utilities doing here? One is used by fbx loading code in VHACD Utils, and the other a general debugging utility.
|
||||
|
|
|
@ -32,6 +32,7 @@ class GeometryExtra {
|
|||
public:
|
||||
const QVariantHash& mapping;
|
||||
const QUrl& textureBaseUrl;
|
||||
bool combineParts;
|
||||
};
|
||||
|
||||
QUrl resolveTextureBaseUrl(const QUrl& url, const QUrl& textureBaseUrl) {
|
||||
|
@ -89,7 +90,7 @@ void GeometryMappingResource::downloadFinished(const QByteArray& data) {
|
|||
}
|
||||
|
||||
auto modelCache = DependencyManager::get<ModelCache>();
|
||||
GeometryExtra extra{ mapping, _textureBaseUrl };
|
||||
GeometryExtra extra{ mapping, _textureBaseUrl, false };
|
||||
|
||||
// Get the raw GeometryResource
|
||||
_geometryResource = modelCache->getResource(url, QUrl(), &extra).staticCast<GeometryResource>();
|
||||
|
@ -129,8 +130,8 @@ void GeometryMappingResource::onGeometryMappingLoaded(bool success) {
|
|||
class GeometryReader : public QRunnable {
|
||||
public:
|
||||
GeometryReader(QWeakPointer<Resource>& resource, const QUrl& url, const QVariantHash& mapping,
|
||||
const QByteArray& data) :
|
||||
_resource(resource), _url(url), _mapping(mapping), _data(data) {
|
||||
const QByteArray& data, bool combineParts) :
|
||||
_resource(resource), _url(url), _mapping(mapping), _data(data), _combineParts(combineParts) {
|
||||
|
||||
DependencyManager::get<StatTracker>()->incrementStat("PendingProcessing");
|
||||
}
|
||||
|
@ -142,6 +143,7 @@ private:
|
|||
QUrl _url;
|
||||
QVariantHash _mapping;
|
||||
QByteArray _data;
|
||||
bool _combineParts;
|
||||
};
|
||||
|
||||
void GeometryReader::run() {
|
||||
|
@ -178,7 +180,7 @@ void GeometryReader::run() {
|
|||
throw QString("empty geometry, possibly due to an unsupported FBX version");
|
||||
}
|
||||
} else if (_url.path().toLower().endsWith(".obj")) {
|
||||
fbxGeometry.reset(OBJReader().readOBJ(_data, _mapping, _url));
|
||||
fbxGeometry.reset(OBJReader().readOBJ(_data, _mapping, _combineParts, _url));
|
||||
} else {
|
||||
throw QString("unsupported format");
|
||||
}
|
||||
|
@ -209,8 +211,8 @@ void GeometryReader::run() {
|
|||
class GeometryDefinitionResource : public GeometryResource {
|
||||
Q_OBJECT
|
||||
public:
|
||||
GeometryDefinitionResource(const QUrl& url, const QVariantHash& mapping, const QUrl& textureBaseUrl) :
|
||||
GeometryResource(url, resolveTextureBaseUrl(url, textureBaseUrl)), _mapping(mapping) {}
|
||||
GeometryDefinitionResource(const QUrl& url, const QVariantHash& mapping, const QUrl& textureBaseUrl, bool combineParts) :
|
||||
GeometryResource(url, resolveTextureBaseUrl(url, textureBaseUrl)), _mapping(mapping), _combineParts(combineParts) {}
|
||||
|
||||
QString getType() const override { return "GeometryDefinition"; }
|
||||
|
||||
|
@ -221,10 +223,11 @@ protected:
|
|||
|
||||
private:
|
||||
QVariantHash _mapping;
|
||||
bool _combineParts;
|
||||
};
|
||||
|
||||
void GeometryDefinitionResource::downloadFinished(const QByteArray& data) {
|
||||
QThreadPool::globalInstance()->start(new GeometryReader(_self, _url, _mapping, data));
|
||||
QThreadPool::globalInstance()->start(new GeometryReader(_self, _url, _mapping, data, _combineParts));
|
||||
}
|
||||
|
||||
void GeometryDefinitionResource::setGeometryDefinition(FBXGeometry::Pointer fbxGeometry) {
|
||||
|
@ -265,7 +268,7 @@ ModelCache::ModelCache() {
|
|||
}
|
||||
|
||||
QSharedPointer<Resource> ModelCache::createResource(const QUrl& url, const QSharedPointer<Resource>& fallback,
|
||||
const void* extra) {
|
||||
const void* extra) {
|
||||
Resource* resource = nullptr;
|
||||
if (url.path().toLower().endsWith(".fst")) {
|
||||
resource = new GeometryMappingResource(url);
|
||||
|
@ -273,14 +276,30 @@ QSharedPointer<Resource> ModelCache::createResource(const QUrl& url, const QShar
|
|||
const GeometryExtra* geometryExtra = static_cast<const GeometryExtra*>(extra);
|
||||
auto mapping = geometryExtra ? geometryExtra->mapping : QVariantHash();
|
||||
auto textureBaseUrl = geometryExtra ? geometryExtra->textureBaseUrl : QUrl();
|
||||
resource = new GeometryDefinitionResource(url, mapping, textureBaseUrl);
|
||||
bool combineParts = geometryExtra ? geometryExtra->combineParts : true;
|
||||
resource = new GeometryDefinitionResource(url, mapping, textureBaseUrl, combineParts);
|
||||
}
|
||||
|
||||
return QSharedPointer<Resource>(resource, &Resource::deleter);
|
||||
}
|
||||
|
||||
GeometryResource::Pointer ModelCache::getGeometryResource(const QUrl& url, const QVariantHash& mapping, const QUrl& textureBaseUrl) {
|
||||
GeometryExtra geometryExtra = { mapping, textureBaseUrl };
|
||||
GeometryResource::Pointer ModelCache::getGeometryResource(const QUrl& url,
|
||||
const QVariantHash& mapping, const QUrl& textureBaseUrl) {
|
||||
bool combineParts = true;
|
||||
GeometryExtra geometryExtra = { mapping, textureBaseUrl, combineParts };
|
||||
GeometryResource::Pointer resource = getResource(url, QUrl(), &geometryExtra).staticCast<GeometryResource>();
|
||||
if (resource) {
|
||||
if (resource->isLoaded() && resource->shouldSetTextures()) {
|
||||
resource->setTextures();
|
||||
}
|
||||
}
|
||||
return resource;
|
||||
}
|
||||
|
||||
GeometryResource::Pointer ModelCache::getCollisionGeometryResource(const QUrl& url,
|
||||
const QVariantHash& mapping, const QUrl& textureBaseUrl) {
|
||||
bool combineParts = false;
|
||||
GeometryExtra geometryExtra = { mapping, textureBaseUrl, combineParts };
|
||||
GeometryResource::Pointer resource = getResource(url, QUrl(), &geometryExtra).staticCast<GeometryResource>();
|
||||
if (resource) {
|
||||
if (resource->isLoaded() && resource->shouldSetTextures()) {
|
||||
|
|
|
@ -136,13 +136,18 @@ class ModelCache : public ResourceCache, public Dependency {
|
|||
|
||||
public:
|
||||
GeometryResource::Pointer getGeometryResource(const QUrl& url,
|
||||
const QVariantHash& mapping = QVariantHash(), const QUrl& textureBaseUrl = QUrl());
|
||||
const QVariantHash& mapping = QVariantHash(),
|
||||
const QUrl& textureBaseUrl = QUrl());
|
||||
|
||||
GeometryResource::Pointer getCollisionGeometryResource(const QUrl& url,
|
||||
const QVariantHash& mapping = QVariantHash(),
|
||||
const QUrl& textureBaseUrl = QUrl());
|
||||
|
||||
protected:
|
||||
friend class GeometryMappingResource;
|
||||
|
||||
virtual QSharedPointer<Resource> createResource(const QUrl& url, const QSharedPointer<Resource>& fallback,
|
||||
const void* extra) override;
|
||||
const void* extra) override;
|
||||
|
||||
private:
|
||||
ModelCache();
|
||||
|
|
|
@ -295,8 +295,8 @@ protected:
|
|||
|
||||
/// Creates a new resource.
|
||||
virtual QSharedPointer<Resource> createResource(const QUrl& url, const QSharedPointer<Resource>& fallback,
|
||||
const void* extra) = 0;
|
||||
|
||||
const void* extra) = 0;
|
||||
|
||||
void addUnusedResource(const QSharedPointer<Resource>& resource);
|
||||
void removeUnusedResource(const QSharedPointer<Resource>& resource);
|
||||
|
||||
|
|
|
@ -43,7 +43,8 @@ bool vhacd::VHACDUtil::loadFBX(const QString filename, FBXGeometry& result) {
|
|||
QByteArray fbxContents = fbx.readAll();
|
||||
FBXGeometry* geom;
|
||||
if (filename.toLower().endsWith(".obj")) {
|
||||
geom = OBJReader().readOBJ(fbxContents, QVariantHash());
|
||||
bool combineParts = false;
|
||||
geom = OBJReader().readOBJ(fbxContents, QVariantHash(), combineParts);
|
||||
} else if (filename.toLower().endsWith(".fbx")) {
|
||||
geom = readFBX(fbxContents, QVariantHash(), filename);
|
||||
} else {
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
//
|
||||
|
||||
#include <QCommandLineParser>
|
||||
#include <Trace.h>
|
||||
#include <VHACD.h>
|
||||
#include "VHACDUtilApp.h"
|
||||
#include "VHACDUtil.h"
|
||||
|
@ -98,6 +99,8 @@ VHACDUtilApp::VHACDUtilApp(int argc, char* argv[]) :
|
|||
{
|
||||
vhacd::VHACDUtil vUtil;
|
||||
|
||||
DependencyManager::set<tracing::Tracer>();
|
||||
|
||||
// parse command-line
|
||||
QCommandLineParser parser;
|
||||
parser.setApplicationDescription("High Fidelity Object Decomposer");
|
||||
|
|
Loading…
Reference in a new issue