mirror of
https://github.com/JulianGro/overte.git
synced 2025-04-08 03:42:27 +02:00
Merge pull request #8205 from AndrewMeadows/model-cache-cleanup
decouple Geometry from its GeometryResource in ModelCache
This commit is contained in:
commit
496f3b14c7
7 changed files with 152 additions and 147 deletions
|
@ -709,9 +709,9 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) {
|
|||
// compute meshPart local transforms
|
||||
QVector<glm::mat4> localTransforms;
|
||||
const FBXGeometry& fbxGeometry = _model->getFBXGeometry();
|
||||
int32_t numMeshes = (int32_t)fbxGeometry.meshes.size();
|
||||
int32_t totalNumVertices = 0;
|
||||
for (int32_t i = 0; i < numMeshes; i++) {
|
||||
int numFbxMeshes = fbxGeometry.meshes.size();
|
||||
int totalNumVertices = 0;
|
||||
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);
|
||||
|
@ -730,10 +730,8 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) {
|
|||
return;
|
||||
}
|
||||
|
||||
auto& meshes = _model->getGeometry()->getGeometry()->getMeshes();
|
||||
|
||||
// the render geometry's mesh count should match that of the FBXGeometry
|
||||
assert(numMeshes == (int32_t)(meshes.size()));
|
||||
auto& meshes = _model->getGeometry()->getMeshes();
|
||||
int32_t numMeshes = (int32_t)(meshes.size());
|
||||
|
||||
ShapeInfo::PointCollection& pointCollection = info.getPointCollection();
|
||||
pointCollection.clear();
|
||||
|
|
|
@ -70,7 +70,7 @@ void GeometryMappingResource::downloadFinished(const QByteArray& data) {
|
|||
auto modelCache = DependencyManager::get<ModelCache>();
|
||||
GeometryExtra extra{ mapping, _textureBaseUrl };
|
||||
|
||||
// Get the raw GeometryResource, not the wrapped NetworkGeometry
|
||||
// Get the raw GeometryResource
|
||||
_geometryResource = modelCache->getResource(url, QUrl(), &extra).staticCast<GeometryResource>();
|
||||
// Avoid caching nested resources - their references will be held by the parent
|
||||
_geometryResource->_isCacheable = false;
|
||||
|
@ -90,8 +90,8 @@ void GeometryMappingResource::downloadFinished(const QByteArray& data) {
|
|||
|
||||
void GeometryMappingResource::onGeometryMappingLoaded(bool success) {
|
||||
if (success && _geometryResource) {
|
||||
_geometry = _geometryResource->_geometry;
|
||||
_shapes = _geometryResource->_shapes;
|
||||
_fbxGeometry = _geometryResource->_fbxGeometry;
|
||||
_meshParts = _geometryResource->_meshParts;
|
||||
_meshes = _geometryResource->_meshes;
|
||||
_materials = _geometryResource->_materials;
|
||||
|
||||
|
@ -200,31 +200,31 @@ void GeometryDefinitionResource::downloadFinished(const QByteArray& data) {
|
|||
|
||||
void GeometryDefinitionResource::setGeometryDefinition(FBXGeometry::Pointer fbxGeometry) {
|
||||
// Assume ownership of the geometry pointer
|
||||
_geometry = fbxGeometry;
|
||||
_fbxGeometry = fbxGeometry;
|
||||
|
||||
// Copy materials
|
||||
QHash<QString, size_t> materialIDAtlas;
|
||||
for (const FBXMaterial& material : _geometry->materials) {
|
||||
for (const FBXMaterial& material : _fbxGeometry->materials) {
|
||||
materialIDAtlas[material.materialID] = _materials.size();
|
||||
_materials.push_back(std::make_shared<NetworkMaterial>(material, _textureBaseUrl));
|
||||
}
|
||||
|
||||
std::shared_ptr<NetworkMeshes> meshes = std::make_shared<NetworkMeshes>();
|
||||
std::shared_ptr<NetworkShapes> shapes = std::make_shared<NetworkShapes>();
|
||||
std::shared_ptr<GeometryMeshes> meshes = std::make_shared<GeometryMeshes>();
|
||||
std::shared_ptr<GeometryMeshParts> parts = std::make_shared<GeometryMeshParts>();
|
||||
int meshID = 0;
|
||||
for (const FBXMesh& mesh : _geometry->meshes) {
|
||||
for (const FBXMesh& mesh : _fbxGeometry->meshes) {
|
||||
// Copy mesh pointers
|
||||
meshes->emplace_back(mesh._mesh);
|
||||
int partID = 0;
|
||||
for (const FBXMeshPart& part : mesh.parts) {
|
||||
// Construct local shapes
|
||||
shapes->push_back(std::make_shared<NetworkShape>(meshID, partID, (int)materialIDAtlas[part.materialID]));
|
||||
// Construct local parts
|
||||
parts->push_back(std::make_shared<MeshPart>(meshID, partID, (int)materialIDAtlas[part.materialID]));
|
||||
partID++;
|
||||
}
|
||||
meshID++;
|
||||
}
|
||||
_meshes = meshes;
|
||||
_shapes = shapes;
|
||||
_meshParts = parts;
|
||||
|
||||
finishedLoading(true);
|
||||
}
|
||||
|
@ -250,17 +250,15 @@ QSharedPointer<Resource> ModelCache::createResource(const QUrl& url, const QShar
|
|||
return QSharedPointer<Resource>(resource, &Resource::deleter);
|
||||
}
|
||||
|
||||
std::shared_ptr<NetworkGeometry> ModelCache::getGeometry(const QUrl& url, const QVariantHash& mapping, const QUrl& textureBaseUrl) {
|
||||
GeometryResource::Pointer ModelCache::getGeometryResource(const QUrl& url, const QVariantHash& mapping, const QUrl& textureBaseUrl) {
|
||||
GeometryExtra geometryExtra = { mapping, textureBaseUrl };
|
||||
GeometryResource::Pointer resource = getResource(url, QUrl(), &geometryExtra).staticCast<GeometryResource>();
|
||||
if (resource) {
|
||||
if (resource->isLoaded() && resource->shouldSetTextures()) {
|
||||
resource->setTextures();
|
||||
}
|
||||
return std::make_shared<NetworkGeometry>(resource);
|
||||
} else {
|
||||
return NetworkGeometry::Pointer();
|
||||
}
|
||||
return resource;
|
||||
}
|
||||
|
||||
const QVariantMap Geometry::getTextures() const {
|
||||
|
@ -278,9 +276,9 @@ const QVariantMap Geometry::getTextures() const {
|
|||
|
||||
// FIXME: The materials should only be copied when modified, but the Model currently caches the original
|
||||
Geometry::Geometry(const Geometry& geometry) {
|
||||
_geometry = geometry._geometry;
|
||||
_fbxGeometry = geometry._fbxGeometry;
|
||||
_meshes = geometry._meshes;
|
||||
_shapes = geometry._shapes;
|
||||
_meshParts = geometry._meshParts;
|
||||
|
||||
_materials.reserve(geometry._materials.size());
|
||||
for (const auto& material : geometry._materials) {
|
||||
|
@ -336,9 +334,9 @@ bool Geometry::areTexturesLoaded() const {
|
|||
return true;
|
||||
}
|
||||
|
||||
const std::shared_ptr<const NetworkMaterial> Geometry::getShapeMaterial(int shapeID) const {
|
||||
if ((shapeID >= 0) && (shapeID < (int)_shapes->size())) {
|
||||
int materialID = _shapes->at(shapeID)->materialID;
|
||||
const std::shared_ptr<const NetworkMaterial> Geometry::getShapeMaterial(int partID) const {
|
||||
if ((partID >= 0) && (partID < (int)_meshParts->size())) {
|
||||
int materialID = _meshParts->at(partID)->materialID;
|
||||
if ((materialID >= 0) && (materialID < (int)_materials.size())) {
|
||||
return _materials[materialID];
|
||||
}
|
||||
|
@ -352,7 +350,7 @@ void GeometryResource::deleter() {
|
|||
}
|
||||
|
||||
void GeometryResource::setTextures() {
|
||||
for (const FBXMaterial& material : _geometry->materials) {
|
||||
for (const FBXMaterial& material : _fbxGeometry->materials) {
|
||||
_materials.push_back(std::make_shared<NetworkMaterial>(material, _textureBaseUrl));
|
||||
}
|
||||
}
|
||||
|
@ -361,26 +359,40 @@ void GeometryResource::resetTextures() {
|
|||
_materials.clear();
|
||||
}
|
||||
|
||||
NetworkGeometry::NetworkGeometry(const GeometryResource::Pointer& networkGeometry) : _resource(networkGeometry) {
|
||||
connect(_resource.data(), &Resource::finished, this, &NetworkGeometry::resourceFinished);
|
||||
connect(_resource.data(), &Resource::onRefresh, this, &NetworkGeometry::resourceRefreshed);
|
||||
void GeometryResourceWatcher::startWatching() {
|
||||
connect(_resource.data(), &Resource::finished, this, &GeometryResourceWatcher::resourceFinished);
|
||||
connect(_resource.data(), &Resource::onRefresh, this, &GeometryResourceWatcher::resourceRefreshed);
|
||||
if (_resource->isLoaded()) {
|
||||
resourceFinished(!_resource->getURL().isEmpty());
|
||||
}
|
||||
}
|
||||
|
||||
void NetworkGeometry::resourceFinished(bool success) {
|
||||
// FIXME: Model is not set up to handle a refresh
|
||||
if (_instance) {
|
||||
return;
|
||||
}
|
||||
if (success) {
|
||||
_instance = std::make_shared<Geometry>(*_resource);
|
||||
}
|
||||
emit finished(success);
|
||||
void GeometryResourceWatcher::stopWatching() {
|
||||
disconnect(_resource.data(), &Resource::finished, this, &GeometryResourceWatcher::resourceFinished);
|
||||
disconnect(_resource.data(), &Resource::onRefresh, this, &GeometryResourceWatcher::resourceRefreshed);
|
||||
}
|
||||
|
||||
void NetworkGeometry::resourceRefreshed() {
|
||||
void GeometryResourceWatcher::setResource(GeometryResource::Pointer resource) {
|
||||
if (_resource) {
|
||||
stopWatching();
|
||||
}
|
||||
_resource = resource;
|
||||
if (_resource) {
|
||||
if (_resource->isLoaded()) {
|
||||
_geometryRef = std::make_shared<Geometry>(*_resource);
|
||||
} else {
|
||||
startWatching();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GeometryResourceWatcher::resourceFinished(bool success) {
|
||||
if (success) {
|
||||
_geometryRef = std::make_shared<Geometry>(*_resource);
|
||||
}
|
||||
}
|
||||
|
||||
void GeometryResourceWatcher::resourceRefreshed() {
|
||||
// FIXME: Model is not set up to handle a refresh
|
||||
// _instance.reset();
|
||||
}
|
||||
|
|
|
@ -22,52 +22,30 @@
|
|||
#include "TextureCache.h"
|
||||
|
||||
// Alias instead of derive to avoid copying
|
||||
using NetworkMesh = model::Mesh;
|
||||
|
||||
class NetworkTexture;
|
||||
class NetworkMaterial;
|
||||
class NetworkShape;
|
||||
class NetworkGeometry;
|
||||
class MeshPart;
|
||||
|
||||
class GeometryMappingResource;
|
||||
|
||||
/// Stores cached model geometries.
|
||||
class ModelCache : public ResourceCache, public Dependency {
|
||||
Q_OBJECT
|
||||
SINGLETON_DEPENDENCY
|
||||
|
||||
public:
|
||||
/// Loads a model geometry from the specified URL.
|
||||
std::shared_ptr<NetworkGeometry> getGeometry(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);
|
||||
|
||||
private:
|
||||
ModelCache();
|
||||
virtual ~ModelCache() = default;
|
||||
};
|
||||
|
||||
class Geometry {
|
||||
public:
|
||||
using Pointer = std::shared_ptr<Geometry>;
|
||||
using WeakPointer = std::weak_ptr<Geometry>;
|
||||
|
||||
Geometry() = default;
|
||||
Geometry(const Geometry& geometry);
|
||||
|
||||
// Immutable over lifetime
|
||||
using NetworkMeshes = std::vector<std::shared_ptr<const NetworkMesh>>;
|
||||
using NetworkShapes = std::vector<std::shared_ptr<const NetworkShape>>;
|
||||
using GeometryMeshes = std::vector<std::shared_ptr<const model::Mesh>>;
|
||||
using GeometryMeshParts = std::vector<std::shared_ptr<const MeshPart>>;
|
||||
|
||||
// Mutable, but must retain structure of vector
|
||||
using NetworkMaterials = std::vector<std::shared_ptr<NetworkMaterial>>;
|
||||
|
||||
const FBXGeometry& getGeometry() const { return *_geometry; }
|
||||
const NetworkMeshes& getMeshes() const { return *_meshes; }
|
||||
const FBXGeometry& getFBXGeometry() const { return *_fbxGeometry; }
|
||||
const GeometryMeshes& getMeshes() const { return *_meshes; }
|
||||
const std::shared_ptr<const NetworkMaterial> getShapeMaterial(int shapeID) const;
|
||||
|
||||
const QVariantMap getTextures() const;
|
||||
|
@ -79,9 +57,9 @@ protected:
|
|||
friend class GeometryMappingResource;
|
||||
|
||||
// Shared across all geometries, constant throughout lifetime
|
||||
std::shared_ptr<const FBXGeometry> _geometry;
|
||||
std::shared_ptr<const NetworkMeshes> _meshes;
|
||||
std::shared_ptr<const NetworkShapes> _shapes;
|
||||
std::shared_ptr<const FBXGeometry> _fbxGeometry;
|
||||
std::shared_ptr<const GeometryMeshes> _meshes;
|
||||
std::shared_ptr<const GeometryMeshParts> _meshParts;
|
||||
|
||||
// Copied to each geometry, mutable throughout lifetime via setTextures
|
||||
NetworkMaterials _materials;
|
||||
|
@ -108,7 +86,7 @@ protected:
|
|||
|
||||
// Geometries may not hold onto textures while cached - that is for the texture cache
|
||||
// Instead, these methods clear and reset textures from the geometry when caching/loading
|
||||
bool shouldSetTextures() const { return _geometry && _materials.empty(); }
|
||||
bool shouldSetTextures() const { return _fbxGeometry && _materials.empty(); }
|
||||
void setTextures();
|
||||
void resetTextures();
|
||||
|
||||
|
@ -118,22 +96,21 @@ protected:
|
|||
bool _isCacheable { true };
|
||||
};
|
||||
|
||||
class NetworkGeometry : public QObject {
|
||||
class GeometryResourceWatcher : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
using Pointer = std::shared_ptr<NetworkGeometry>;
|
||||
using Pointer = std::shared_ptr<GeometryResourceWatcher>;
|
||||
|
||||
NetworkGeometry() = delete;
|
||||
NetworkGeometry(const GeometryResource::Pointer& networkGeometry);
|
||||
GeometryResourceWatcher() = delete;
|
||||
GeometryResourceWatcher(Geometry::Pointer& geometryPtr) : _geometryRef(geometryPtr) {}
|
||||
|
||||
const QUrl& getURL() { return _resource->getURL(); }
|
||||
void setResource(GeometryResource::Pointer resource);
|
||||
|
||||
/// Returns the geometry, if it is loaded (must be checked!)
|
||||
const Geometry::Pointer& getGeometry() { return _instance; }
|
||||
QUrl getURL() const { return (bool)_resource ? _resource->getURL() : QUrl(); }
|
||||
|
||||
signals:
|
||||
/// Emitted when the NetworkGeometry loads (or fails to)
|
||||
void finished(bool success);
|
||||
private:
|
||||
void startWatching();
|
||||
void stopWatching();
|
||||
|
||||
private slots:
|
||||
void resourceFinished(bool success);
|
||||
|
@ -141,7 +118,27 @@ private slots:
|
|||
|
||||
private:
|
||||
GeometryResource::Pointer _resource;
|
||||
Geometry::Pointer _instance { nullptr };
|
||||
Geometry::Pointer& _geometryRef;
|
||||
};
|
||||
|
||||
/// Stores cached model geometries.
|
||||
class ModelCache : public ResourceCache, public Dependency {
|
||||
Q_OBJECT
|
||||
SINGLETON_DEPENDENCY
|
||||
|
||||
public:
|
||||
GeometryResource::Pointer getGeometryResource(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);
|
||||
|
||||
private:
|
||||
ModelCache();
|
||||
virtual ~ModelCache() = default;
|
||||
};
|
||||
|
||||
class NetworkMaterial : public model::Material {
|
||||
|
@ -185,9 +182,9 @@ private:
|
|||
bool _isOriginal { true };
|
||||
};
|
||||
|
||||
class NetworkShape {
|
||||
class MeshPart {
|
||||
public:
|
||||
NetworkShape(int mesh, int part, int material) : meshID { mesh }, partID { part }, materialID { material } {}
|
||||
MeshPart(int mesh, int part, int material) : meshID { mesh }, partID { part }, materialID { material } {}
|
||||
int meshID { -1 };
|
||||
int partID { -1 };
|
||||
int materialID { -1 };
|
||||
|
|
|
@ -402,8 +402,6 @@ private:
|
|||
QHash<Vec2FloatPairPair, GridBuffer> _gridBuffers;
|
||||
QHash<int, GridBuffer> _registeredGridBuffers;
|
||||
|
||||
QHash<QUrl, QWeakPointer<NetworkGeometry> > _networkGeometry;
|
||||
|
||||
gpu::ShaderPointer _simpleShader;
|
||||
gpu::ShaderPointer _unlitShader;
|
||||
static render::ShapePipelinePointer _simplePipeline;
|
||||
|
|
|
@ -310,7 +310,7 @@ ModelMeshPartPayload::ModelMeshPartPayload(Model* model, int _meshIndex, int par
|
|||
_shapeID(shapeIndex) {
|
||||
|
||||
assert(_model && _model->isLoaded());
|
||||
auto& modelMesh = _model->getGeometry()->getGeometry()->getMeshes().at(_meshIndex);
|
||||
auto& modelMesh = _model->getGeometry()->getMeshes().at(_meshIndex);
|
||||
updateMeshPart(modelMesh, partIndex);
|
||||
|
||||
updateTransform(transform, offsetTransform);
|
||||
|
@ -331,7 +331,7 @@ void ModelMeshPartPayload::initCache() {
|
|||
_isBlendShaped = !mesh.blendshapes.isEmpty();
|
||||
}
|
||||
|
||||
auto networkMaterial = _model->getGeometry()->getGeometry()->getShapeMaterial(_shapeID);
|
||||
auto networkMaterial = _model->getGeometry()->getShapeMaterial(_shapeID);
|
||||
if (networkMaterial) {
|
||||
_drawMaterial = networkMaterial;
|
||||
};
|
||||
|
@ -384,7 +384,7 @@ ItemKey ModelMeshPartPayload::getKey() const {
|
|||
ShapeKey ModelMeshPartPayload::getShapeKey() const {
|
||||
assert(_model->isLoaded());
|
||||
const FBXGeometry& geometry = _model->getFBXGeometry();
|
||||
const auto& networkMeshes = _model->getGeometry()->getGeometry()->getMeshes();
|
||||
const auto& networkMeshes = _model->getGeometry()->getMeshes();
|
||||
|
||||
// guard against partially loaded meshes
|
||||
if (_meshIndex >= (int)networkMeshes.size() || _meshIndex >= (int)geometry.meshes.size() || _meshIndex >= (int)_model->_meshStates.size()) {
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
using namespace std;
|
||||
|
||||
int nakedModelPointerTypeId = qRegisterMetaType<ModelPointer>();
|
||||
int weakNetworkGeometryPointerTypeId = qRegisterMetaType<std::weak_ptr<NetworkGeometry> >();
|
||||
int weakGeometryResourceBridgePointerTypeId = qRegisterMetaType<Geometry::WeakPointer >();
|
||||
int vec3VectorTypeId = qRegisterMetaType<QVector<glm::vec3> >();
|
||||
float Model::FAKE_DIMENSION_PLACEHOLDER = -1.0f;
|
||||
#define HTTP_INVALID_COM "http://invalid.com"
|
||||
|
@ -79,6 +79,10 @@ void initCollisionHullMaterials() {
|
|||
|
||||
Model::Model(RigPointer rig, QObject* parent) :
|
||||
QObject(parent),
|
||||
_renderGeometry(),
|
||||
_collisionGeometry(),
|
||||
_renderWatcher(_renderGeometry),
|
||||
_collisionWatcher(_collisionGeometry),
|
||||
_translation(0.0f),
|
||||
_rotation(),
|
||||
_scale(1.0f, 1.0f, 1.0f),
|
||||
|
@ -98,7 +102,6 @@ Model::Model(RigPointer rig, QObject* parent) :
|
|||
_calculatedMeshTrianglesValid(false),
|
||||
_meshGroupsKnown(false),
|
||||
_isWireframe(false),
|
||||
_renderCollisionHull(false),
|
||||
_rig(rig) {
|
||||
// we may have been created in the network thread, but we live in the main thread
|
||||
if (_viewState) {
|
||||
|
@ -116,7 +119,7 @@ AbstractViewStateInterface* Model::_viewState = NULL;
|
|||
|
||||
bool Model::needsFixupInScene() const {
|
||||
if (readyToAddToScene()) {
|
||||
if (_needsUpdateTextures && _geometry->getGeometry()->areTexturesLoaded()) {
|
||||
if (_needsUpdateTextures && _renderGeometry->areTexturesLoaded()) {
|
||||
_needsUpdateTextures = false;
|
||||
return true;
|
||||
}
|
||||
|
@ -793,13 +796,13 @@ int Model::getLastFreeJointIndex(int jointIndex) const {
|
|||
void Model::setTextures(const QVariantMap& textures) {
|
||||
if (isLoaded()) {
|
||||
_needsUpdateTextures = true;
|
||||
_geometry->getGeometry()->setTextures(textures);
|
||||
_renderGeometry->setTextures(textures);
|
||||
}
|
||||
}
|
||||
|
||||
void Model::setURL(const QUrl& url) {
|
||||
// don't recreate the geometry if it's the same URL
|
||||
if (_url == url && _geometry && _geometry->getURL() == url) {
|
||||
if (_url == url && _renderWatcher.getURL() == url) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -818,16 +821,16 @@ void Model::setURL(const QUrl& url) {
|
|||
invalidCalculatedMeshBoxes();
|
||||
deleteGeometry();
|
||||
|
||||
_geometry = DependencyManager::get<ModelCache>()->getGeometry(url);
|
||||
_renderWatcher.setResource(DependencyManager::get<ModelCache>()->getGeometryResource(url));
|
||||
onInvalidate();
|
||||
}
|
||||
|
||||
void Model::setCollisionModelURL(const QUrl& url) {
|
||||
if (_collisionUrl == url) {
|
||||
if (_collisionUrl == url && _collisionWatcher.getURL() == url) {
|
||||
return;
|
||||
}
|
||||
_collisionUrl = url;
|
||||
_collisionGeometry = DependencyManager::get<ModelCache>()->getGeometry(url);
|
||||
_collisionWatcher.setResource(DependencyManager::get<ModelCache>()->getGeometryResource(url));
|
||||
}
|
||||
|
||||
bool Model::getJointPositionInWorldFrame(int jointIndex, glm::vec3& position) const {
|
||||
|
@ -883,7 +886,7 @@ QStringList Model::getJointNames() const {
|
|||
class Blender : public QRunnable {
|
||||
public:
|
||||
|
||||
Blender(ModelPointer model, int blendNumber, const std::weak_ptr<NetworkGeometry>& geometry,
|
||||
Blender(ModelPointer model, int blendNumber, const Geometry::WeakPointer& geometry,
|
||||
const QVector<FBXMesh>& meshes, const QVector<float>& blendshapeCoefficients);
|
||||
|
||||
virtual void run();
|
||||
|
@ -892,12 +895,12 @@ private:
|
|||
|
||||
ModelPointer _model;
|
||||
int _blendNumber;
|
||||
std::weak_ptr<NetworkGeometry> _geometry;
|
||||
Geometry::WeakPointer _geometry;
|
||||
QVector<FBXMesh> _meshes;
|
||||
QVector<float> _blendshapeCoefficients;
|
||||
};
|
||||
|
||||
Blender::Blender(ModelPointer model, int blendNumber, const std::weak_ptr<NetworkGeometry>& geometry,
|
||||
Blender::Blender(ModelPointer model, int blendNumber, const Geometry::WeakPointer& geometry,
|
||||
const QVector<FBXMesh>& meshes, const QVector<float>& blendshapeCoefficients) :
|
||||
_model(model),
|
||||
_blendNumber(blendNumber),
|
||||
|
@ -940,7 +943,7 @@ void Blender::run() {
|
|||
// post the result to the geometry cache, which will dispatch to the model if still alive
|
||||
QMetaObject::invokeMethod(DependencyManager::get<ModelBlender>().data(), "setBlendedVertices",
|
||||
Q_ARG(ModelPointer, _model), Q_ARG(int, _blendNumber),
|
||||
Q_ARG(const std::weak_ptr<NetworkGeometry>&, _geometry), Q_ARG(const QVector<glm::vec3>&, vertices),
|
||||
Q_ARG(const Geometry::WeakPointer&, _geometry), Q_ARG(const QVector<glm::vec3>&, vertices),
|
||||
Q_ARG(const QVector<glm::vec3>&, normals));
|
||||
}
|
||||
|
||||
|
@ -1151,7 +1154,7 @@ bool Model::maybeStartBlender() {
|
|||
if (isLoaded()) {
|
||||
const FBXGeometry& fbxGeometry = getFBXGeometry();
|
||||
if (fbxGeometry.hasBlendedMeshes()) {
|
||||
QThreadPool::globalInstance()->start(new Blender(getThisPointer(), ++_blendNumber, _geometry,
|
||||
QThreadPool::globalInstance()->start(new Blender(getThisPointer(), ++_blendNumber, _renderGeometry,
|
||||
fbxGeometry.meshes, _blendshapeCoefficients));
|
||||
return true;
|
||||
}
|
||||
|
@ -1159,10 +1162,10 @@ bool Model::maybeStartBlender() {
|
|||
return false;
|
||||
}
|
||||
|
||||
void Model::setBlendedVertices(int blendNumber, const std::weak_ptr<NetworkGeometry>& geometry,
|
||||
void Model::setBlendedVertices(int blendNumber, const Geometry::WeakPointer& geometry,
|
||||
const QVector<glm::vec3>& vertices, const QVector<glm::vec3>& normals) {
|
||||
auto geometryRef = geometry.lock();
|
||||
if (!geometryRef || _geometry != geometryRef || _blendedVertexBuffers.empty() || blendNumber < _appliedBlendNumber) {
|
||||
if (!geometryRef || _renderGeometry != geometryRef || _blendedVertexBuffers.empty() || blendNumber < _appliedBlendNumber) {
|
||||
return;
|
||||
}
|
||||
_appliedBlendNumber = blendNumber;
|
||||
|
@ -1205,27 +1208,23 @@ AABox Model::getRenderableMeshBound() const {
|
|||
}
|
||||
|
||||
void Model::segregateMeshGroups() {
|
||||
NetworkGeometry::Pointer networkGeometry;
|
||||
Geometry::Pointer geometry;
|
||||
bool showingCollisionHull = false;
|
||||
if (_showCollisionHull && _collisionGeometry) {
|
||||
if (isCollisionLoaded()) {
|
||||
networkGeometry = _collisionGeometry;
|
||||
geometry = _collisionGeometry;
|
||||
showingCollisionHull = true;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
assert(isLoaded());
|
||||
networkGeometry = _geometry;
|
||||
geometry = _renderGeometry;
|
||||
}
|
||||
const FBXGeometry& geometry = networkGeometry->getGeometry()->getGeometry();
|
||||
const auto& networkMeshes = networkGeometry->getGeometry()->getMeshes();
|
||||
const auto& meshes = geometry->getMeshes();
|
||||
|
||||
// all of our mesh vectors must match in size
|
||||
auto geoMeshesSize = geometry.meshes.size();
|
||||
if ((int)networkMeshes.size() != geoMeshesSize ||
|
||||
// geometry.meshes.size() != _meshStates.size()) {
|
||||
geoMeshesSize > _meshStates.size()) {
|
||||
if ((int)meshes.size() != _meshStates.size()) {
|
||||
qDebug() << "WARNING!!!! Mesh Sizes don't match! We will not segregate mesh groups yet.";
|
||||
return;
|
||||
}
|
||||
|
@ -1249,23 +1248,25 @@ void Model::segregateMeshGroups() {
|
|||
|
||||
// Run through all of the meshes, and place them into their segregated, but unsorted buckets
|
||||
int shapeID = 0;
|
||||
for (int i = 0; i < (int)networkMeshes.size(); i++) {
|
||||
const FBXMesh& mesh = geometry.meshes.at(i);
|
||||
const auto& networkMesh = networkMeshes.at(i);
|
||||
uint32_t numMeshes = (uint32_t)meshes.size();
|
||||
for (uint32_t i = 0; i < numMeshes; i++) {
|
||||
const auto& mesh = meshes.at(i);
|
||||
if (mesh) {
|
||||
|
||||
// Create the render payloads
|
||||
int totalParts = mesh.parts.size();
|
||||
for (int partIndex = 0; partIndex < totalParts; partIndex++) {
|
||||
if (showingCollisionHull) {
|
||||
if (_collisionHullMaterials.empty()) {
|
||||
initCollisionHullMaterials();
|
||||
// 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<MeshPartPayload>(mesh, partIndex, _collisionHullMaterials[partIndex % NUM_COLLISION_HULL_COLORS], transform, offset);
|
||||
} else {
|
||||
_modelMeshRenderItemsSet << std::make_shared<ModelMeshPartPayload>(this, i, partIndex, shapeID, transform, offset);
|
||||
}
|
||||
_collisionRenderItemsSet << std::make_shared<MeshPartPayload>(networkMesh, partIndex, _collisionHullMaterials[partIndex % NUM_COLLISION_HULL_COLORS], transform, offset);
|
||||
} else {
|
||||
_modelMeshRenderItemsSet << std::make_shared<ModelMeshPartPayload>(this, i, partIndex, shapeID, transform, offset);
|
||||
}
|
||||
|
||||
shapeID++;
|
||||
shapeID++;
|
||||
}
|
||||
}
|
||||
}
|
||||
_meshGroupsKnown = true;
|
||||
|
@ -1328,7 +1329,7 @@ void ModelBlender::noteRequiresBlend(ModelPointer model) {
|
|||
}
|
||||
|
||||
void ModelBlender::setBlendedVertices(ModelPointer model, int blendNumber,
|
||||
const std::weak_ptr<NetworkGeometry>& geometry, const QVector<glm::vec3>& vertices, const QVector<glm::vec3>& normals) {
|
||||
const Geometry::WeakPointer& geometry, const QVector<glm::vec3>& vertices, const QVector<glm::vec3>& normals) {
|
||||
if (model) {
|
||||
model->setBlendedVertices(blendNumber, geometry, vertices, normals);
|
||||
}
|
||||
|
|
|
@ -97,7 +97,7 @@ public:
|
|||
bool showCollisionHull = false);
|
||||
void removeFromScene(std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges);
|
||||
void renderSetup(RenderArgs* args);
|
||||
bool isRenderable() const { return !_meshStates.isEmpty() || (isActive() && getGeometry()->getGeometry()->getMeshes().empty()); }
|
||||
bool isRenderable() const { return !_meshStates.isEmpty() || (isActive() && _renderGeometry->getMeshes().empty()); }
|
||||
|
||||
bool isVisible() const { return _isVisible; }
|
||||
|
||||
|
@ -107,11 +107,11 @@ public:
|
|||
bool maybeStartBlender();
|
||||
|
||||
/// Sets blended vertices computed in a separate thread.
|
||||
void setBlendedVertices(int blendNumber, const std::weak_ptr<NetworkGeometry>& geometry,
|
||||
void setBlendedVertices(int blendNumber, const Geometry::WeakPointer& geometry,
|
||||
const QVector<glm::vec3>& vertices, const QVector<glm::vec3>& normals);
|
||||
|
||||
bool isLoaded() const { return _geometry && _geometry->getGeometry(); }
|
||||
bool isCollisionLoaded() const { return _collisionGeometry && _collisionGeometry->getGeometry(); }
|
||||
bool isLoaded() const { return (bool)_renderGeometry; }
|
||||
bool isCollisionLoaded() const { return (bool)_collisionGeometry; }
|
||||
|
||||
void setIsWireframe(bool isWireframe) { _isWireframe = isWireframe; }
|
||||
bool isWireframe() const { return _isWireframe; }
|
||||
|
@ -128,18 +128,18 @@ public:
|
|||
virtual void updateClusterMatrices(glm::vec3 modelPosition, glm::quat modelOrientation);
|
||||
|
||||
/// Returns a reference to the shared geometry.
|
||||
const NetworkGeometry::Pointer& getGeometry() const { return _geometry; }
|
||||
const Geometry::Pointer& getGeometry() const { return _renderGeometry; }
|
||||
/// Returns a reference to the shared collision geometry.
|
||||
const NetworkGeometry::Pointer& getCollisionGeometry() const { return _collisionGeometry; }
|
||||
const Geometry::Pointer& getCollisionGeometry() const { return _collisionGeometry; }
|
||||
|
||||
const QVariantMap getTextures() const { assert(isLoaded()); return _geometry->getGeometry()->getTextures(); }
|
||||
const QVariantMap getTextures() const { assert(isLoaded()); return _renderGeometry->getTextures(); }
|
||||
void setTextures(const QVariantMap& textures);
|
||||
|
||||
/// Provided as a convenience, will crash if !isLoaded()
|
||||
// And so that getGeometry() isn't chained everywhere
|
||||
const FBXGeometry& getFBXGeometry() const { assert(isLoaded()); return getGeometry()->getGeometry()->getGeometry(); }
|
||||
const FBXGeometry& getFBXGeometry() const { assert(isLoaded()); return _renderGeometry->getFBXGeometry(); }
|
||||
/// Provided as a convenience, will crash if !isCollisionLoaded()
|
||||
const FBXGeometry& getCollisionFBXGeometry() const { assert(isCollisionLoaded()); return getCollisionGeometry()->getGeometry()->getGeometry(); }
|
||||
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.
|
||||
|
@ -263,7 +263,11 @@ protected:
|
|||
/// \return true if joint exists
|
||||
bool getJointPosition(int jointIndex, glm::vec3& position) const;
|
||||
|
||||
NetworkGeometry::Pointer _geometry;
|
||||
Geometry::Pointer _renderGeometry; // only ever set by its watcher
|
||||
Geometry::Pointer _collisionGeometry; // only ever set by its watcher
|
||||
|
||||
GeometryResourceWatcher _renderWatcher;
|
||||
GeometryResourceWatcher _collisionWatcher;
|
||||
|
||||
glm::vec3 _translation;
|
||||
glm::quat _rotation;
|
||||
|
@ -330,8 +334,6 @@ protected:
|
|||
void deleteGeometry();
|
||||
void initJointTransforms();
|
||||
|
||||
NetworkGeometry::Pointer _collisionGeometry;
|
||||
|
||||
float _pupilDilation;
|
||||
QVector<float> _blendshapeCoefficients;
|
||||
|
||||
|
@ -373,9 +375,6 @@ protected:
|
|||
|
||||
static AbstractViewStateInterface* _viewState;
|
||||
|
||||
bool _renderCollisionHull;
|
||||
|
||||
|
||||
QSet<std::shared_ptr<MeshPartPayload>> _collisionRenderItemsSet;
|
||||
QMap<render::ItemID, render::PayloadPointer> _collisionRenderItems;
|
||||
|
||||
|
@ -395,7 +394,7 @@ protected:
|
|||
};
|
||||
|
||||
Q_DECLARE_METATYPE(ModelPointer)
|
||||
Q_DECLARE_METATYPE(std::weak_ptr<NetworkGeometry>)
|
||||
Q_DECLARE_METATYPE(Geometry::WeakPointer)
|
||||
|
||||
/// Handle management of pending models that need blending
|
||||
class ModelBlender : public QObject, public Dependency {
|
||||
|
@ -408,7 +407,7 @@ public:
|
|||
void noteRequiresBlend(ModelPointer model);
|
||||
|
||||
public slots:
|
||||
void setBlendedVertices(ModelPointer model, int blendNumber, const std::weak_ptr<NetworkGeometry>& geometry,
|
||||
void setBlendedVertices(ModelPointer model, int blendNumber, const Geometry::WeakPointer& geometry,
|
||||
const QVector<glm::vec3>& vertices, const QVector<glm::vec3>& normals);
|
||||
|
||||
private:
|
||||
|
|
Loading…
Reference in a new issue