From 45c73439eb0b64af64164098d2696a1cc7b54107 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 2 Feb 2017 13:34:22 -0800 Subject: [PATCH 1/6] use type definition --- libraries/model-networking/src/model-networking/ModelCache.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/model-networking/src/model-networking/ModelCache.h b/libraries/model-networking/src/model-networking/ModelCache.h index bcca846625..adef3ce2b5 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.h +++ b/libraries/model-networking/src/model-networking/ModelCache.h @@ -159,7 +159,7 @@ protected: class Texture { public: QString name; - QSharedPointer texture; + NetworkTexturePointer texture; }; using Textures = std::vector; From 24b1f3ddbc90d903937663ebf7b8708068a5e9c4 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 2 Feb 2017 13:34:44 -0800 Subject: [PATCH 2/6] cleanup whitespace --- libraries/fbx/src/FBXReader_Material.cpp | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/libraries/fbx/src/FBXReader_Material.cpp b/libraries/fbx/src/FBXReader_Material.cpp index 8c0f4b34ac..f3d0c30a41 100644 --- a/libraries/fbx/src/FBXReader_Material.cpp +++ b/libraries/fbx/src/FBXReader_Material.cpp @@ -47,10 +47,10 @@ FBXTexture FBXReader::getTexture(const QString& textureID) { texture.texcoordSet = 0; if (_textureParams.contains(textureID)) { auto p = _textureParams.value(textureID); - + texture.transform.setTranslation(p.translation); texture.transform.setRotation(glm::quat(glm::radians(p.rotation))); - + auto scaling = p.scaling; // Protect from bad scaling which should never happen if (scaling.x == 0.0f) { @@ -63,7 +63,7 @@ FBXTexture FBXReader::getTexture(const QString& textureID) { scaling.z = 1.0f; } texture.transform.setScale(scaling); - + if ((p.UVSet != "map1") && (p.UVSet != "UVSet0")) { texture.texcoordSet = 1; } @@ -78,11 +78,10 @@ void FBXReader::consolidateFBXMaterials(const QVariantHash& mapping) { QJsonDocument materialMapDocument = QJsonDocument::fromJson(materialMapString.toUtf8()); QJsonObject materialMap = materialMapDocument.object(); - // foreach (const QString& materialID, materials) { for (QHash::iterator it = _fbxMaterials.begin(); it != _fbxMaterials.end(); it++) { FBXMaterial& material = (*it); - // Maya is the exporting the shading model and we aretrying to use it + // Maya is the exporting the shading model and we are trying to use it bool isMaterialLambert = (material.shadingModel.toLower() == "lambert"); // the pure material associated with this part @@ -127,21 +126,19 @@ void FBXReader::consolidateFBXMaterials(const QVariantHash& mapping) { detectDifferentUVs |= (transparentTexture.texcoordSet != 0) || (!transparentTexture.transform.isIdentity()); } - - FBXTexture normalTexture; QString bumpTextureID = bumpTextures.value(material.materialID); QString normalTextureID = normalTextures.value(material.materialID); if (!normalTextureID.isNull()) { normalTexture = getTexture(normalTextureID); normalTexture.isBumpmap = false; - + material.normalTexture = normalTexture; detectDifferentUVs |= (normalTexture.texcoordSet != 0) || (!normalTexture.transform.isIdentity()); } else if (!bumpTextureID.isNull()) { normalTexture = getTexture(bumpTextureID); normalTexture.isBumpmap = true; - + material.normalTexture = normalTexture; detectDifferentUVs |= (normalTexture.texcoordSet != 0) || (!normalTexture.transform.isIdentity()); } @@ -151,7 +148,7 @@ void FBXReader::consolidateFBXMaterials(const QVariantHash& mapping) { if (!specularTextureID.isNull()) { specularTexture = getTexture(specularTextureID); detectDifferentUVs |= (specularTexture.texcoordSet != 0) || (!specularTexture.transform.isIdentity()); - material.specularTexture = specularTexture; + material.specularTexture = specularTexture; } FBXTexture metallicTexture; @@ -222,7 +219,7 @@ void FBXReader::consolidateFBXMaterials(const QVariantHash& mapping) { ambientTextureID = ambientFactorTextures.value(material.materialID); } } - + if (_loadLightmaps && !ambientTextureID.isNull()) { ambientTexture = getTexture(ambientTextureID); detectDifferentUVs |= (ambientTexture.texcoordSet != 0) || (!ambientTexture.transform.isIdentity()); From b3ae6f9aec65917d18bcfc26145b807ca85a1792 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 2 Feb 2017 13:35:40 -0800 Subject: [PATCH 3/6] cap size of textures from FBX files --- libraries/fbx/src/FBXReader.h | 9 ++-- .../src/model-networking/ModelCache.cpp | 2 +- .../src/model-networking/TextureCache.cpp | 53 +++++++++++++------ .../src/model-networking/TextureCache.h | 13 +++-- libraries/networking/src/ResourceCache.h | 4 +- 5 files changed, 54 insertions(+), 27 deletions(-) diff --git a/libraries/fbx/src/FBXReader.h b/libraries/fbx/src/FBXReader.h index cd1dbc5c4f..8b58ad62d1 100644 --- a/libraries/fbx/src/FBXReader.h +++ b/libraries/fbx/src/FBXReader.h @@ -100,22 +100,25 @@ public: /// A single binding to a joint in an FBX document. class FBXCluster { public: - + int jointIndex; glm::mat4 inverseBindMatrix; }; +const int MAX_FBX_TEXTURE_SIZE = 1024 * 1024; + /// A texture map in an FBX document. class FBXTexture { public: QString name; QByteArray filename; QByteArray content; - + Transform transform; + int maxSize { MAX_FBX_TEXTURE_SIZE }; int texcoordSet; QString texcoordSetName; - + bool isBumpmap{ false }; bool isNull() const { return name.isEmpty() && filename.isEmpty() && content.isEmpty(); } diff --git a/libraries/model-networking/src/model-networking/ModelCache.cpp b/libraries/model-networking/src/model-networking/ModelCache.cpp index 2a02540821..946e507d98 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.cpp +++ b/libraries/model-networking/src/model-networking/ModelCache.cpp @@ -472,7 +472,7 @@ QUrl NetworkMaterial::getTextureUrl(const QUrl& baseUrl, const FBXTexture& textu model::TextureMapPointer NetworkMaterial::fetchTextureMap(const QUrl& baseUrl, const FBXTexture& fbxTexture, TextureType type, MapChannel channel) { const auto url = getTextureUrl(baseUrl, fbxTexture); - const auto texture = DependencyManager::get()->getTexture(url, type, fbxTexture.content); + const auto texture = DependencyManager::get()->getTexture(url, type, fbxTexture.content, fbxTexture.maxSize); _textures[channel] = Texture { fbxTexture.name, texture }; auto map = std::make_shared(); diff --git a/libraries/model-networking/src/model-networking/TextureCache.cpp b/libraries/model-networking/src/model-networking/TextureCache.cpp index 6a4edd60ed..e108e69aa1 100644 --- a/libraries/model-networking/src/model-networking/TextureCache.cpp +++ b/libraries/model-networking/src/model-networking/TextureCache.cpp @@ -167,16 +167,17 @@ class TextureExtra { public: NetworkTexture::Type type; const QByteArray& content; + int maxSize; }; -ScriptableResource* TextureCache::prefetch(const QUrl& url, int type) { +ScriptableResource* TextureCache::prefetch(const QUrl& url, int type, int maxSize) { auto byteArray = QByteArray(); - TextureExtra extra = { (Type)type, byteArray }; + TextureExtra extra = { (Type)type, byteArray, maxSize }; return ResourceCache::prefetch(url, &extra); } -NetworkTexturePointer TextureCache::getTexture(const QUrl& url, Type type, const QByteArray& content) { - TextureExtra extra = { type, content }; +NetworkTexturePointer TextureCache::getTexture(const QUrl& url, Type type, const QByteArray& content, int maxSize) { + TextureExtra extra = { type, content, maxSize }; return ResourceCache::getResource(url, QUrl(), &extra).staticCast(); } @@ -251,13 +252,15 @@ QSharedPointer TextureCache::createResource(const QUrl& url, const QSh const TextureExtra* textureExtra = static_cast(extra); auto type = textureExtra ? textureExtra->type : Type::DEFAULT_TEXTURE; auto content = textureExtra ? textureExtra->content : QByteArray(); - return QSharedPointer(new NetworkTexture(url, type, content), + auto maxSize = textureExtra ? textureExtra->maxSize : ABSOLUTE_MAX_TEXTURE_SIZE; + return QSharedPointer(new NetworkTexture(url, type, content, maxSize), &Resource::deleter); } -NetworkTexture::NetworkTexture(const QUrl& url, Type type, const QByteArray& content) : +NetworkTexture::NetworkTexture(const QUrl& url, Type type, const QByteArray& content, int maxSize) : Resource(url), - _type(type) + _type(type), + _maxSize(maxSize) { _textureSource = std::make_shared(); @@ -274,7 +277,7 @@ NetworkTexture::NetworkTexture(const QUrl& url, Type type, const QByteArray& con } NetworkTexture::NetworkTexture(const QUrl& url, const TextureLoaderFunc& textureLoader, const QByteArray& content) : - NetworkTexture(url, CUSTOM_TEXTURE, content) + NetworkTexture(url, CUSTOM_TEXTURE, content, ABSOLUTE_MAX_TEXTURE_SIZE) { _textureLoader = textureLoader; } @@ -290,7 +293,8 @@ NetworkTexture::TextureLoaderFunc NetworkTexture::getTextureLoader() const { class ImageReader : public QRunnable { public: - ImageReader(const QWeakPointer& resource, const QByteArray& data, const QUrl& url = QUrl()); + ImageReader(const QWeakPointer& resource, const QByteArray& data, + const QUrl& url = QUrl(), int maxSize = ABSOLUTE_MAX_TEXTURE_SIZE); virtual void run() override; @@ -300,6 +304,7 @@ private: QWeakPointer _resource; QUrl _url; QByteArray _content; + int _maxSize; }; void NetworkTexture::downloadFinished(const QByteArray& data) { @@ -308,14 +313,15 @@ void NetworkTexture::downloadFinished(const QByteArray& data) { } void NetworkTexture::loadContent(const QByteArray& content) { - QThreadPool::globalInstance()->start(new ImageReader(_self, content, _url)); + QThreadPool::globalInstance()->start(new ImageReader(_self, content, _url, _maxSize)); } ImageReader::ImageReader(const QWeakPointer& resource, const QByteArray& data, - const QUrl& url) : + const QUrl& url, int maxSize) : _resource(resource), _url(url), - _content(data) + _content(data), + _maxSize(maxSize) { #if DEBUG_DUMP_TEXTURE_LOADS static auto start = usecTimestampNow() / USECS_PER_MSEC; @@ -375,10 +381,10 @@ void ImageReader::run() { // Note that QImage.format is the pixel format which is different from the "format" of the image file... auto imageFormat = image.format(); - int originalWidth = image.width(); - int originalHeight = image.height(); + int imageWidth = image.width(); + int imageHeight = image.height(); - if (originalWidth == 0 || originalHeight == 0 || imageFormat == QImage::Format_Invalid) { + if (imageWidth == 0 || imageHeight == 0 || imageFormat == QImage::Format_Invalid) { if (filenameExtension.empty()) { qCDebug(modelnetworking) << "QImage failed to create from content, no file extension:" << _url; } else { @@ -386,6 +392,21 @@ void ImageReader::run() { } return; } + + if (imageWidth * imageHeight > _maxSize) { + float scaleFactor = sqrtf(_maxSize / (float)(imageWidth * imageHeight)); + int originalWidth = imageWidth; + int originalHeight = imageHeight; + imageWidth = (int)(scaleFactor * (float)imageWidth + 0.5f); + imageHeight = (int)(scaleFactor * (float)imageHeight + 0.5f); + //QSize newSize(imageWidth, imageHeight); + QImage newImage = image.scaled(QSize(imageWidth, imageHeight), Qt::IgnoreAspectRatio); + image.swap(newImage); + qCDebug(modelnetworking) << "Downscale image" << _url + << "from" << originalWidth << "x" << originalHeight + << "to" << imageWidth << "x" << imageHeight; + } + gpu::TexturePointer texture = nullptr; { // Double-check the resource still exists between long operations. @@ -408,7 +429,7 @@ void ImageReader::run() { } else { QMetaObject::invokeMethod(resource.data(), "setImage", Q_ARG(gpu::TexturePointer, texture), - Q_ARG(int, originalWidth), Q_ARG(int, originalHeight)); + Q_ARG(int, imageWidth), Q_ARG(int, imageHeight)); } } diff --git a/libraries/model-networking/src/model-networking/TextureCache.h b/libraries/model-networking/src/model-networking/TextureCache.h index 8ccfe5364c..9ad06eddfb 100644 --- a/libraries/model-networking/src/model-networking/TextureCache.h +++ b/libraries/model-networking/src/model-networking/TextureCache.h @@ -23,6 +23,8 @@ #include #include +const int ABSOLUTE_MAX_TEXTURE_SIZE = 8192 * 8192; + namespace gpu { class Batch; } @@ -60,7 +62,7 @@ public: typedef gpu::Texture* TextureLoader(const QImage& image, const std::string& srcImageName); using TextureLoaderFunc = std::function; - NetworkTexture(const QUrl& url, Type type, const QByteArray& content); + NetworkTexture(const QUrl& url, Type type, const QByteArray& content, int maxSize); NetworkTexture(const QUrl& url, const TextureLoaderFunc& textureLoader, const QByteArray& content); QString getType() const override { return "NetworkTexture"; } @@ -70,7 +72,7 @@ public: int getWidth() const { return _width; } int getHeight() const { return _height; } Type getTextureType() const { return _type; } - + TextureLoaderFunc getTextureLoader() const; signals: @@ -81,7 +83,7 @@ protected: virtual bool isCacheable() const override { return _loaded; } virtual void downloadFinished(const QByteArray& data) override; - + Q_INVOKABLE void loadContent(const QByteArray& content); Q_INVOKABLE void setImage(gpu::TexturePointer texture, int originalWidth, int originalHeight); @@ -92,6 +94,7 @@ private: int _originalHeight { 0 }; int _width { 0 }; int _height { 0 }; + int _maxSize { ABSOLUTE_MAX_TEXTURE_SIZE }; }; using NetworkTexturePointer = QSharedPointer; @@ -129,11 +132,11 @@ public: /// Loads a texture from the specified URL. NetworkTexturePointer getTexture(const QUrl& url, Type type = Type::DEFAULT_TEXTURE, - const QByteArray& content = QByteArray()); + const QByteArray& content = QByteArray(), int maxSize = ABSOLUTE_MAX_TEXTURE_SIZE); protected: // Overload ResourceCache::prefetch to allow specifying texture type for loads - Q_INVOKABLE ScriptableResource* prefetch(const QUrl& url, int type); + Q_INVOKABLE ScriptableResource* prefetch(const QUrl& url, int type, int maxSize = ABSOLUTE_MAX_TEXTURE_SIZE); virtual QSharedPointer createResource(const QUrl& url, const QSharedPointer& fallback, const void* extra) override; diff --git a/libraries/networking/src/ResourceCache.h b/libraries/networking/src/ResourceCache.h index 03d37bc9ac..a369416ebe 100644 --- a/libraries/networking/src/ResourceCache.h +++ b/libraries/networking/src/ResourceCache.h @@ -86,7 +86,7 @@ private: /// Wrapper to expose resources to JS/QML class ScriptableResource : public QObject { Q_OBJECT - Q_PROPERTY(QUrl url READ getUrl) + Q_PROPERTY(QUrl url READ getURL) Q_PROPERTY(int state READ getState NOTIFY stateChanged) /**jsdoc @@ -125,7 +125,7 @@ public: */ Q_INVOKABLE void release(); - const QUrl& getUrl() const { return _url; } + const QUrl& getURL() const { return _url; } int getState() const { return (int)_state; } const QSharedPointer& getResource() const { return _resource; } From d65cbbb455cab8a1994be4db65c6a6e1e3ba9ab1 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 2 Feb 2017 14:09:47 -0800 Subject: [PATCH 4/6] name change: maxSize to maxNumPixels --- libraries/fbx/src/FBXReader.h | 4 +-- .../src/model-networking/ModelCache.cpp | 2 +- .../src/model-networking/TextureCache.cpp | 35 +++++++++---------- .../src/model-networking/TextureCache.h | 10 +++--- 4 files changed, 25 insertions(+), 26 deletions(-) diff --git a/libraries/fbx/src/FBXReader.h b/libraries/fbx/src/FBXReader.h index 8b58ad62d1..5b4d3ec3bf 100644 --- a/libraries/fbx/src/FBXReader.h +++ b/libraries/fbx/src/FBXReader.h @@ -105,7 +105,7 @@ public: glm::mat4 inverseBindMatrix; }; -const int MAX_FBX_TEXTURE_SIZE = 1024 * 1024; +const int MAX_FBX_TEXTURE_NUM_PIXELS = 1024 * 1024; /// A texture map in an FBX document. class FBXTexture { @@ -115,7 +115,7 @@ public: QByteArray content; Transform transform; - int maxSize { MAX_FBX_TEXTURE_SIZE }; + int maxNumPixels { MAX_FBX_TEXTURE_NUM_PIXELS }; int texcoordSet; QString texcoordSetName; diff --git a/libraries/model-networking/src/model-networking/ModelCache.cpp b/libraries/model-networking/src/model-networking/ModelCache.cpp index 946e507d98..dd3193073d 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.cpp +++ b/libraries/model-networking/src/model-networking/ModelCache.cpp @@ -472,7 +472,7 @@ QUrl NetworkMaterial::getTextureUrl(const QUrl& baseUrl, const FBXTexture& textu model::TextureMapPointer NetworkMaterial::fetchTextureMap(const QUrl& baseUrl, const FBXTexture& fbxTexture, TextureType type, MapChannel channel) { const auto url = getTextureUrl(baseUrl, fbxTexture); - const auto texture = DependencyManager::get()->getTexture(url, type, fbxTexture.content, fbxTexture.maxSize); + const auto texture = DependencyManager::get()->getTexture(url, type, fbxTexture.content, fbxTexture.maxNumPixels); _textures[channel] = Texture { fbxTexture.name, texture }; auto map = std::make_shared(); diff --git a/libraries/model-networking/src/model-networking/TextureCache.cpp b/libraries/model-networking/src/model-networking/TextureCache.cpp index e108e69aa1..447a1b93c8 100644 --- a/libraries/model-networking/src/model-networking/TextureCache.cpp +++ b/libraries/model-networking/src/model-networking/TextureCache.cpp @@ -167,17 +167,17 @@ class TextureExtra { public: NetworkTexture::Type type; const QByteArray& content; - int maxSize; + int maxNumPixels; }; -ScriptableResource* TextureCache::prefetch(const QUrl& url, int type, int maxSize) { +ScriptableResource* TextureCache::prefetch(const QUrl& url, int type, int maxNumPixels) { auto byteArray = QByteArray(); - TextureExtra extra = { (Type)type, byteArray, maxSize }; + TextureExtra extra = { (Type)type, byteArray, maxNumPixels }; return ResourceCache::prefetch(url, &extra); } -NetworkTexturePointer TextureCache::getTexture(const QUrl& url, Type type, const QByteArray& content, int maxSize) { - TextureExtra extra = { type, content, maxSize }; +NetworkTexturePointer TextureCache::getTexture(const QUrl& url, Type type, const QByteArray& content, int maxNumPixels) { + TextureExtra extra = { type, content, maxNumPixels }; return ResourceCache::getResource(url, QUrl(), &extra).staticCast(); } @@ -252,15 +252,15 @@ QSharedPointer TextureCache::createResource(const QUrl& url, const QSh const TextureExtra* textureExtra = static_cast(extra); auto type = textureExtra ? textureExtra->type : Type::DEFAULT_TEXTURE; auto content = textureExtra ? textureExtra->content : QByteArray(); - auto maxSize = textureExtra ? textureExtra->maxSize : ABSOLUTE_MAX_TEXTURE_SIZE; - return QSharedPointer(new NetworkTexture(url, type, content, maxSize), + auto maxNumPixels = textureExtra ? textureExtra->maxNumPixels : ABSOLUTE_MAX_TEXTURE_NUM_PIXELS; + return QSharedPointer(new NetworkTexture(url, type, content, maxNumPixels), &Resource::deleter); } -NetworkTexture::NetworkTexture(const QUrl& url, Type type, const QByteArray& content, int maxSize) : +NetworkTexture::NetworkTexture(const QUrl& url, Type type, const QByteArray& content, int maxNumPixels) : Resource(url), _type(type), - _maxSize(maxSize) + _maxNumPixels(maxNumPixels) { _textureSource = std::make_shared(); @@ -277,7 +277,7 @@ NetworkTexture::NetworkTexture(const QUrl& url, Type type, const QByteArray& con } NetworkTexture::NetworkTexture(const QUrl& url, const TextureLoaderFunc& textureLoader, const QByteArray& content) : - NetworkTexture(url, CUSTOM_TEXTURE, content, ABSOLUTE_MAX_TEXTURE_SIZE) + NetworkTexture(url, CUSTOM_TEXTURE, content, ABSOLUTE_MAX_TEXTURE_NUM_PIXELS) { _textureLoader = textureLoader; } @@ -294,7 +294,7 @@ class ImageReader : public QRunnable { public: ImageReader(const QWeakPointer& resource, const QByteArray& data, - const QUrl& url = QUrl(), int maxSize = ABSOLUTE_MAX_TEXTURE_SIZE); + const QUrl& url = QUrl(), int maxNumPixels = ABSOLUTE_MAX_TEXTURE_NUM_PIXELS); virtual void run() override; @@ -304,7 +304,7 @@ private: QWeakPointer _resource; QUrl _url; QByteArray _content; - int _maxSize; + int _maxNumPixels; }; void NetworkTexture::downloadFinished(const QByteArray& data) { @@ -313,15 +313,15 @@ void NetworkTexture::downloadFinished(const QByteArray& data) { } void NetworkTexture::loadContent(const QByteArray& content) { - QThreadPool::globalInstance()->start(new ImageReader(_self, content, _url, _maxSize)); + QThreadPool::globalInstance()->start(new ImageReader(_self, content, _url, _maxNumPixels)); } ImageReader::ImageReader(const QWeakPointer& resource, const QByteArray& data, - const QUrl& url, int maxSize) : + const QUrl& url, int maxNumPixels) : _resource(resource), _url(url), _content(data), - _maxSize(maxSize) + _maxNumPixels(maxNumPixels) { #if DEBUG_DUMP_TEXTURE_LOADS static auto start = usecTimestampNow() / USECS_PER_MSEC; @@ -393,13 +393,12 @@ void ImageReader::run() { return; } - if (imageWidth * imageHeight > _maxSize) { - float scaleFactor = sqrtf(_maxSize / (float)(imageWidth * imageHeight)); + if (imageWidth * imageHeight > _maxNumPixels) { + float scaleFactor = sqrtf(_maxNumPixels / (float)(imageWidth * imageHeight)); int originalWidth = imageWidth; int originalHeight = imageHeight; imageWidth = (int)(scaleFactor * (float)imageWidth + 0.5f); imageHeight = (int)(scaleFactor * (float)imageHeight + 0.5f); - //QSize newSize(imageWidth, imageHeight); QImage newImage = image.scaled(QSize(imageWidth, imageHeight), Qt::IgnoreAspectRatio); image.swap(newImage); qCDebug(modelnetworking) << "Downscale image" << _url diff --git a/libraries/model-networking/src/model-networking/TextureCache.h b/libraries/model-networking/src/model-networking/TextureCache.h index 9ad06eddfb..cb509490c6 100644 --- a/libraries/model-networking/src/model-networking/TextureCache.h +++ b/libraries/model-networking/src/model-networking/TextureCache.h @@ -23,7 +23,7 @@ #include #include -const int ABSOLUTE_MAX_TEXTURE_SIZE = 8192 * 8192; +const int ABSOLUTE_MAX_TEXTURE_NUM_PIXELS = 8192 * 8192; namespace gpu { class Batch; @@ -62,7 +62,7 @@ public: typedef gpu::Texture* TextureLoader(const QImage& image, const std::string& srcImageName); using TextureLoaderFunc = std::function; - NetworkTexture(const QUrl& url, Type type, const QByteArray& content, int maxSize); + NetworkTexture(const QUrl& url, Type type, const QByteArray& content, int maxNumPixels); NetworkTexture(const QUrl& url, const TextureLoaderFunc& textureLoader, const QByteArray& content); QString getType() const override { return "NetworkTexture"; } @@ -94,7 +94,7 @@ private: int _originalHeight { 0 }; int _width { 0 }; int _height { 0 }; - int _maxSize { ABSOLUTE_MAX_TEXTURE_SIZE }; + int _maxNumPixels { ABSOLUTE_MAX_TEXTURE_NUM_PIXELS }; }; using NetworkTexturePointer = QSharedPointer; @@ -132,11 +132,11 @@ public: /// Loads a texture from the specified URL. NetworkTexturePointer getTexture(const QUrl& url, Type type = Type::DEFAULT_TEXTURE, - const QByteArray& content = QByteArray(), int maxSize = ABSOLUTE_MAX_TEXTURE_SIZE); + const QByteArray& content = QByteArray(), int maxNumPixels = ABSOLUTE_MAX_TEXTURE_NUM_PIXELS); protected: // Overload ResourceCache::prefetch to allow specifying texture type for loads - Q_INVOKABLE ScriptableResource* prefetch(const QUrl& url, int type, int maxSize = ABSOLUTE_MAX_TEXTURE_SIZE); + Q_INVOKABLE ScriptableResource* prefetch(const QUrl& url, int type, int maxNumPixels = ABSOLUTE_MAX_TEXTURE_NUM_PIXELS); virtual QSharedPointer createResource(const QUrl& url, const QSharedPointer& fallback, const void* extra) override; From 8b2c720e2994c89c6dfe2f3202047e0f8b971f21 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 3 Feb 2017 11:14:40 -0800 Subject: [PATCH 5/6] sliding texture caps for models --- libraries/fbx/src/FBXReader.cpp | 27 +++++++++++++ libraries/fbx/src/FBXReader.h | 8 +++- libraries/fbx/src/FBXReader_Material.cpp | 50 ++++++++++++++++++++++++ 3 files changed, 83 insertions(+), 2 deletions(-) diff --git a/libraries/fbx/src/FBXReader.cpp b/libraries/fbx/src/FBXReader.cpp index 42922ce226..917009956e 100644 --- a/libraries/fbx/src/FBXReader.cpp +++ b/libraries/fbx/src/FBXReader.cpp @@ -1465,6 +1465,33 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS // Create the Material Library consolidateFBXMaterials(mapping); + + // HACK: until we get proper LOD management we're going to cap model textures + // according to how many unique textures the model uses: + // 1 - 7 textures --> 2048 + // 8 - 31 textures --> 1024 + // 32 - 127 textures --> 512 + // etc... + QSet uniqueTextures; + for (auto& material : _fbxMaterials) { + material.getTextureNames(uniqueTextures); + } + int numTextures = uniqueTextures.size(); + const int MAX_NUM_TEXTURES_AT_MAX_RESOLUTION = 7; + if (numTextures > MAX_NUM_TEXTURES_AT_MAX_RESOLUTION) { + int maxWidth = sqrt(MAX_NUM_PIXELS_FOR_FBX_TEXTURE + 1); + int t = numTextures; + t /= MAX_NUM_TEXTURES_AT_MAX_RESOLUTION; + while (t > 0) { + maxWidth /= 2; + t /= 4; + } + qCDebug(modelformat) << "max square texture width =" << maxWidth << " for model" << url; + for (auto& material : _fbxMaterials) { + material.setMaxNumPixelsPerTexture(maxWidth * maxWidth); + } + } + geometry.materials = _fbxMaterials; // see if any materials have texture children diff --git a/libraries/fbx/src/FBXReader.h b/libraries/fbx/src/FBXReader.h index 5b4d3ec3bf..b0e34dd674 100644 --- a/libraries/fbx/src/FBXReader.h +++ b/libraries/fbx/src/FBXReader.h @@ -13,6 +13,7 @@ #define hifi_FBXReader_h #include +#include #include #include #include @@ -105,7 +106,7 @@ public: glm::mat4 inverseBindMatrix; }; -const int MAX_FBX_TEXTURE_NUM_PIXELS = 1024 * 1024; +const int MAX_NUM_PIXELS_FOR_FBX_TEXTURE = 2048 * 2048; /// A texture map in an FBX document. class FBXTexture { @@ -115,7 +116,7 @@ public: QByteArray content; Transform transform; - int maxNumPixels { MAX_FBX_TEXTURE_NUM_PIXELS }; + int maxNumPixels { MAX_NUM_PIXELS_FOR_FBX_TEXTURE }; int texcoordSet; QString texcoordSetName; @@ -146,6 +147,9 @@ public: shininess(shininess), opacity(opacity) {} + void getTextureNames(QSet& textureList) const; + void setMaxNumPixelsPerTexture(int maxNumPixels); + glm::vec3 diffuseColor{ 1.0f }; float diffuseFactor{ 1.0f }; glm::vec3 specularColor{ 0.02f }; diff --git a/libraries/fbx/src/FBXReader_Material.cpp b/libraries/fbx/src/FBXReader_Material.cpp index f3d0c30a41..ca2ec557b4 100644 --- a/libraries/fbx/src/FBXReader_Material.cpp +++ b/libraries/fbx/src/FBXReader_Material.cpp @@ -27,6 +27,56 @@ #include "ModelFormatLogging.h" +void FBXMaterial::getTextureNames(QSet& textureList) const { + if (!normalTexture.isNull()) { + textureList.insert(normalTexture.name); + } + if (!albedoTexture.isNull()) { + textureList.insert(albedoTexture.name); + } + if (!opacityTexture.isNull()) { + textureList.insert(opacityTexture.name); + } + if (!glossTexture.isNull()) { + textureList.insert(glossTexture.name); + } + if (!roughnessTexture.isNull()) { + textureList.insert(roughnessTexture.name); + } + if (!specularTexture.isNull()) { + textureList.insert(specularTexture.name); + } + if (!metallicTexture.isNull()) { + textureList.insert(metallicTexture.name); + } + if (!emissiveTexture.isNull()) { + textureList.insert(emissiveTexture.name); + } + if (!occlusionTexture.isNull()) { + textureList.insert(occlusionTexture.name); + } + if (!scatteringTexture.isNull()) { + textureList.insert(scatteringTexture.name); + } + if (!lightmapTexture.isNull()) { + textureList.insert(lightmapTexture.name); + } +} + +void FBXMaterial::setMaxNumPixelsPerTexture(int maxNumPixels) { + normalTexture.maxNumPixels = maxNumPixels; + albedoTexture.maxNumPixels = maxNumPixels; + opacityTexture.maxNumPixels = maxNumPixels; + glossTexture.maxNumPixels = maxNumPixels; + roughnessTexture.maxNumPixels = maxNumPixels; + specularTexture.maxNumPixels = maxNumPixels; + metallicTexture.maxNumPixels = maxNumPixels; + emissiveTexture.maxNumPixels = maxNumPixels; + occlusionTexture.maxNumPixels = maxNumPixels; + scatteringTexture.maxNumPixels = maxNumPixels; + lightmapTexture.maxNumPixels = maxNumPixels; +} + bool FBXMaterial::needTangentSpace() const { return !normalTexture.isNull(); } From 8b1f569132852cb61ffae0fe70ab1bea68460d78 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 6 Feb 2017 12:13:31 -0800 Subject: [PATCH 6/6] tweak max texture resolution thresholds --- libraries/fbx/src/FBXReader.cpp | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/libraries/fbx/src/FBXReader.cpp b/libraries/fbx/src/FBXReader.cpp index 917009956e..2e6544fbdb 100644 --- a/libraries/fbx/src/FBXReader.cpp +++ b/libraries/fbx/src/FBXReader.cpp @@ -1468,25 +1468,26 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS // HACK: until we get proper LOD management we're going to cap model textures // according to how many unique textures the model uses: - // 1 - 7 textures --> 2048 - // 8 - 31 textures --> 1024 - // 32 - 127 textures --> 512 + // 1 - 8 textures --> 2048 + // 8 - 32 textures --> 1024 + // 33 - 128 textures --> 512 // etc... QSet uniqueTextures; for (auto& material : _fbxMaterials) { material.getTextureNames(uniqueTextures); } int numTextures = uniqueTextures.size(); - const int MAX_NUM_TEXTURES_AT_MAX_RESOLUTION = 7; + const int MAX_NUM_TEXTURES_AT_MAX_RESOLUTION = 8; + int maxWidth = sqrt(MAX_NUM_PIXELS_FOR_FBX_TEXTURE); if (numTextures > MAX_NUM_TEXTURES_AT_MAX_RESOLUTION) { - int maxWidth = sqrt(MAX_NUM_PIXELS_FOR_FBX_TEXTURE + 1); - int t = numTextures; - t /= MAX_NUM_TEXTURES_AT_MAX_RESOLUTION; - while (t > 0) { + int numTextureThreshold = MAX_NUM_TEXTURES_AT_MAX_RESOLUTION; + const int MIN_MIP_TEXTURE_WIDTH = 64; + do { maxWidth /= 2; - t /= 4; - } - qCDebug(modelformat) << "max square texture width =" << maxWidth << " for model" << url; + numTextureThreshold *= 4; + } while (numTextureThreshold < numTextures && maxWidth > MIN_MIP_TEXTURE_WIDTH); + + qCDebug(modelformat) << "Capped square texture width =" << maxWidth << "for model" << url << "with" << numTextures << "textures"; for (auto& material : _fbxMaterials) { material.setMaxNumPixelsPerTexture(maxWidth * maxWidth); }