mirror of
https://github.com/overte-org/overte.git
synced 2025-04-08 02:14:26 +02:00
Add support for GLTF roughness/metallic
This commit is contained in:
parent
9193704173
commit
23806ed67d
8 changed files with 118 additions and 16 deletions
|
@ -1057,8 +1057,10 @@ void GLTFSerializer::setHFMMaterial(HFMMaterial& fbxmat, const GLTFMaterial& mat
|
|||
}
|
||||
if (material.pbrMetallicRoughness.defined["metallicRoughnessTexture"]) {
|
||||
fbxmat.roughnessTexture = getHFMTexture(_file.textures[material.pbrMetallicRoughness.metallicRoughnessTexture]);
|
||||
fbxmat.roughnessTexture.channelMapping = ColorChannelMapping::GREEN;
|
||||
fbxmat.useRoughnessMap = true;
|
||||
fbxmat.metallicTexture = getHFMTexture(_file.textures[material.pbrMetallicRoughness.metallicRoughnessTexture]);
|
||||
fbxmat.metallicTexture.channelMapping = ColorChannelMapping::BLUE;
|
||||
fbxmat.useMetallicMap = true;
|
||||
}
|
||||
if (material.pbrMetallicRoughness.defined["roughnessFactor"]) {
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
|
||||
#include <graphics/Geometry.h>
|
||||
#include <graphics/Material.h>
|
||||
#include <shared/ColorChannelMapping.h>
|
||||
|
||||
#if defined(Q_OS_ANDROID)
|
||||
#define HFM_PACK_NORMALS 0
|
||||
|
@ -125,6 +126,7 @@ public:
|
|||
QString name;
|
||||
QByteArray filename;
|
||||
QByteArray content;
|
||||
ColorChannelMapping channelMapping { ColorChannelMapping::NONE };
|
||||
|
||||
Transform transform;
|
||||
int maxNumPixels { MAX_NUM_PIXELS_FOR_FBX_TEXTURE };
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include <QtCore/QtGlobal>
|
||||
#include <QUrl>
|
||||
#include <QImage>
|
||||
#include <QRgb>
|
||||
#include <QBuffer>
|
||||
#include <QImageReader>
|
||||
|
||||
|
@ -221,7 +222,45 @@ QImage processRawImageData(QIODevice& content, const std::string& filename) {
|
|||
return QImage();
|
||||
}
|
||||
|
||||
gpu::TexturePointer processImage(std::shared_ptr<QIODevice> content, const std::string& filename,
|
||||
void mapToRedChannel(QImage& image, ColorChannelMapping sourceChannel) {
|
||||
// Change format of image so we know exactly how to process it
|
||||
if (image.format() != QImage::Format_ARGB32) {
|
||||
image = image.convertToFormat(QImage::Format_ARGB32);
|
||||
}
|
||||
|
||||
for (int i = 0; i < image.height(); i++) {
|
||||
QRgb* pixel = reinterpret_cast<QRgb*>(image.scanLine(i));
|
||||
// Past end pointer
|
||||
QRgb* lineEnd = pixel + image.width();
|
||||
|
||||
// Transfer channel data from source to target
|
||||
for (; pixel < lineEnd; pixel++) {
|
||||
int colorValue;
|
||||
switch (sourceChannel) {
|
||||
case ColorChannelMapping::RED:
|
||||
colorValue = qRed(*pixel);
|
||||
break;
|
||||
case ColorChannelMapping::GREEN:
|
||||
colorValue = qGreen(*pixel);
|
||||
break;
|
||||
case ColorChannelMapping::BLUE:
|
||||
colorValue = qBlue(*pixel);
|
||||
break;
|
||||
case ColorChannelMapping::ALPHA:
|
||||
colorValue = qAlpha(*pixel);
|
||||
break;
|
||||
default:
|
||||
colorValue = qRed(*pixel);
|
||||
break;
|
||||
}
|
||||
|
||||
// Dump the color in the red channel, ignore the rest
|
||||
*pixel = qRgba(colorValue, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gpu::TexturePointer processImage(std::shared_ptr<QIODevice> content, const std::string& filename, ColorChannelMapping channelMapping,
|
||||
int maxNumPixels, TextureUsage::Type textureType,
|
||||
bool compress, BackendTarget target, const std::atomic<bool>& abortProcessing) {
|
||||
|
||||
|
@ -252,6 +291,11 @@ gpu::TexturePointer processImage(std::shared_ptr<QIODevice> content, const std::
|
|||
QSize(originalWidth, originalHeight) << " to " <<
|
||||
QSize(imageWidth, imageHeight) << ")";
|
||||
}
|
||||
|
||||
// Re-map to image with single red channel texture if requested
|
||||
if (channelMapping != ColorChannelMapping::NONE) {
|
||||
mapToRedChannel(image, channelMapping);
|
||||
}
|
||||
|
||||
auto loader = TextureUsage::getTextureLoaderForType(textureType);
|
||||
auto texture = loader(std::move(image), filename, compress, target, abortProcessing);
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include <QVariant>
|
||||
|
||||
#include <gpu/Texture.h>
|
||||
#include <shared/ColorChannelMapping.h>
|
||||
|
||||
class QByteArray;
|
||||
class QImage;
|
||||
|
@ -81,7 +82,7 @@ gpu::TexturePointer processCubeTextureColorFromImage(QImage&& srcImage, const st
|
|||
|
||||
const QStringList getSupportedFormats();
|
||||
|
||||
gpu::TexturePointer processImage(std::shared_ptr<QIODevice> content, const std::string& url,
|
||||
gpu::TexturePointer processImage(std::shared_ptr<QIODevice> content, const std::string& url, ColorChannelMapping channelMapping,
|
||||
int maxNumPixels, TextureUsage::Type textureType,
|
||||
bool compress, gpu::BackendTarget target, const std::atomic<bool>& abortProcessing = false);
|
||||
|
||||
|
|
|
@ -599,7 +599,7 @@ graphics::TextureMapPointer NetworkMaterial::fetchTextureMap(const QUrl& baseUrl
|
|||
}
|
||||
|
||||
const auto url = getTextureUrl(baseUrl, hfmTexture);
|
||||
const auto texture = DependencyManager::get<TextureCache>()->getTexture(url, type, hfmTexture.content, hfmTexture.maxNumPixels);
|
||||
const auto texture = DependencyManager::get<TextureCache>()->getTexture(url, type, hfmTexture.content, hfmTexture.maxNumPixels, hfmTexture.channelMapping);
|
||||
_textures[channel] = Texture { hfmTexture.name, texture };
|
||||
|
||||
auto map = std::make_shared<graphics::TextureMap>();
|
||||
|
|
|
@ -192,6 +192,7 @@ public:
|
|||
image::TextureUsage::Type type;
|
||||
const QByteArray& content;
|
||||
int maxNumPixels;
|
||||
ColorChannelMapping channelMapping;
|
||||
};
|
||||
|
||||
namespace std {
|
||||
|
@ -206,19 +207,19 @@ namespace std {
|
|||
struct hash<TextureExtra> {
|
||||
size_t operator()(const TextureExtra& a) const {
|
||||
size_t result = 0;
|
||||
hash_combine(result, (int)a.type, a.content, a.maxNumPixels);
|
||||
hash_combine(result, (int)a.type, a.content, a.maxNumPixels, a.channelMapping);
|
||||
return result;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
ScriptableResource* TextureCache::prefetch(const QUrl& url, int type, int maxNumPixels) {
|
||||
ScriptableResource* TextureCache::prefetch(const QUrl& url, int type, int maxNumPixels, ColorChannelMapping channelMapping) {
|
||||
auto byteArray = QByteArray();
|
||||
TextureExtra extra = { (image::TextureUsage::Type)type, byteArray, maxNumPixels };
|
||||
TextureExtra extra = { (image::TextureUsage::Type)type, byteArray, maxNumPixels, channelMapping };
|
||||
return ResourceCache::prefetch(url, &extra, std::hash<TextureExtra>()(extra));
|
||||
}
|
||||
|
||||
NetworkTexturePointer TextureCache::getTexture(const QUrl& url, image::TextureUsage::Type type, const QByteArray& content, int maxNumPixels) {
|
||||
NetworkTexturePointer TextureCache::getTexture(const QUrl& url, image::TextureUsage::Type type, const QByteArray& content, int maxNumPixels, ColorChannelMapping channelMapping) {
|
||||
if (url.scheme() == RESOURCE_SCHEME) {
|
||||
return getResourceTexture(url);
|
||||
}
|
||||
|
@ -228,7 +229,7 @@ NetworkTexturePointer TextureCache::getTexture(const QUrl& url, image::TextureUs
|
|||
query.addQueryItem("skybox", "");
|
||||
modifiedUrl.setQuery(query.toString());
|
||||
}
|
||||
TextureExtra extra = { type, content, maxNumPixels };
|
||||
TextureExtra extra = { type, content, maxNumPixels, channelMapping };
|
||||
return ResourceCache::getResource(modifiedUrl, QUrl(), &extra, std::hash<TextureExtra>()(extra)).staticCast<NetworkTexture>();
|
||||
}
|
||||
|
||||
|
@ -346,6 +347,7 @@ NetworkTexture::NetworkTexture(const QUrl& url) :
|
|||
NetworkTexture::NetworkTexture(const NetworkTexture& other) :
|
||||
Resource(other),
|
||||
_type(other._type),
|
||||
_channelMapping(other._channelMapping),
|
||||
_currentlyLoadingResourceType(other._currentlyLoadingResourceType),
|
||||
_originalWidth(other._originalWidth),
|
||||
_originalHeight(other._originalHeight),
|
||||
|
@ -353,6 +355,11 @@ NetworkTexture::NetworkTexture(const NetworkTexture& other) :
|
|||
_height(other._height),
|
||||
_maxNumPixels(other._maxNumPixels)
|
||||
{
|
||||
if (_width == 0 || _height == 0 ||
|
||||
other._currentlyLoadingResourceType == ResourceType::META ||
|
||||
(other._currentlyLoadingResourceType == ResourceType::KTX && other._ktxResourceState != KTXResourceState::WAITING_FOR_MIP_REQUEST)) {
|
||||
_startedLoading = false;
|
||||
}
|
||||
}
|
||||
|
||||
static bool isLocalUrl(const QUrl& url) {
|
||||
|
@ -364,6 +371,7 @@ void NetworkTexture::setExtra(void* extra) {
|
|||
const TextureExtra* textureExtra = static_cast<const TextureExtra*>(extra);
|
||||
_type = textureExtra ? textureExtra->type : image::TextureUsage::DEFAULT_TEXTURE;
|
||||
_maxNumPixels = textureExtra ? textureExtra->maxNumPixels : ABSOLUTE_MAX_TEXTURE_NUM_PIXELS;
|
||||
_channelMapping = textureExtra ? textureExtra->channelMapping : ColorChannelMapping::NONE;
|
||||
|
||||
_textureSource = std::make_shared<gpu::TextureSource>(_url, (int)_type);
|
||||
_lowestRequestedMipLevel = 0;
|
||||
|
@ -425,7 +433,8 @@ gpu::TexturePointer NetworkTexture::getFallbackTexture() const {
|
|||
class ImageReader : public QRunnable {
|
||||
public:
|
||||
ImageReader(const QWeakPointer<Resource>& resource, const QUrl& url,
|
||||
const QByteArray& data, int maxNumPixels);
|
||||
const QByteArray& data, size_t extraHash, int maxNumPixels,
|
||||
ColorChannelMapping channelMapping);
|
||||
void run() override final;
|
||||
void read();
|
||||
|
||||
|
@ -435,7 +444,9 @@ private:
|
|||
QWeakPointer<Resource> _resource;
|
||||
QUrl _url;
|
||||
QByteArray _content;
|
||||
size_t _extraHash;
|
||||
int _maxNumPixels;
|
||||
ColorChannelMapping _channelMapping;
|
||||
};
|
||||
|
||||
NetworkTexture::~NetworkTexture() {
|
||||
|
@ -1068,7 +1079,7 @@ void NetworkTexture::loadTextureContent(const QByteArray& content) {
|
|||
return;
|
||||
}
|
||||
|
||||
QThreadPool::globalInstance()->start(new ImageReader(_self, _url, content, _maxNumPixels));
|
||||
QThreadPool::globalInstance()->start(new ImageReader(_self, _url, content, _extraHash, _maxNumPixels, _channelMapping));
|
||||
}
|
||||
|
||||
void NetworkTexture::refresh() {
|
||||
|
@ -1093,11 +1104,13 @@ void NetworkTexture::refresh() {
|
|||
Resource::refresh();
|
||||
}
|
||||
|
||||
ImageReader::ImageReader(const QWeakPointer<Resource>& resource, const QUrl& url, const QByteArray& data, int maxNumPixels) :
|
||||
ImageReader::ImageReader(const QWeakPointer<Resource>& resource, const QUrl& url, const QByteArray& data, size_t extraHash, int maxNumPixels, const ColorChannelMapping channelMapping) :
|
||||
_resource(resource),
|
||||
_url(url),
|
||||
_content(data),
|
||||
_maxNumPixels(maxNumPixels)
|
||||
_extraHash(extraHash),
|
||||
_maxNumPixels(maxNumPixels),
|
||||
_channelMapping(channelMapping)
|
||||
{
|
||||
DependencyManager::get<StatTracker>()->incrementStat("PendingProcessing");
|
||||
listSupportedImageFormats();
|
||||
|
@ -1152,11 +1165,12 @@ void ImageReader::read() {
|
|||
}
|
||||
auto networkTexture = resource.staticCast<NetworkTexture>();
|
||||
|
||||
// Hash the source image to for KTX caching
|
||||
// Hash the source image and extra to for KTX caching
|
||||
std::string hash;
|
||||
{
|
||||
QCryptographicHash hasher(QCryptographicHash::Md5);
|
||||
hasher.addData(_content);
|
||||
hasher.addData(std::to_string(_extraHash).c_str());
|
||||
hash = hasher.result().toHex().toStdString();
|
||||
}
|
||||
|
||||
|
@ -1204,7 +1218,7 @@ void ImageReader::read() {
|
|||
constexpr bool shouldCompress = false;
|
||||
#endif
|
||||
auto target = getBackendTarget();
|
||||
texture = image::processImage(std::move(buffer), _url.toString().toStdString(), _maxNumPixels, networkTexture->getTextureType(), shouldCompress, target);
|
||||
texture = image::processImage(std::move(buffer), _url.toString().toStdString(), _channelMapping, _maxNumPixels, networkTexture->getTextureType(), shouldCompress, target);
|
||||
|
||||
if (!texture) {
|
||||
QMetaObject::invokeMethod(resource.data(), "setImage",
|
||||
|
|
|
@ -96,6 +96,7 @@ private:
|
|||
friend class ImageReader;
|
||||
|
||||
image::TextureUsage::Type _type;
|
||||
ColorChannelMapping _channelMapping;
|
||||
|
||||
enum class ResourceType {
|
||||
META,
|
||||
|
@ -178,7 +179,8 @@ public:
|
|||
|
||||
/// Loads a texture from the specified URL.
|
||||
NetworkTexturePointer getTexture(const QUrl& url, image::TextureUsage::Type type = image::TextureUsage::DEFAULT_TEXTURE,
|
||||
const QByteArray& content = QByteArray(), int maxNumPixels = ABSOLUTE_MAX_TEXTURE_NUM_PIXELS);
|
||||
const QByteArray& content = QByteArray(), int maxNumPixels = ABSOLUTE_MAX_TEXTURE_NUM_PIXELS,
|
||||
ColorChannelMapping channelMapping = ColorChannelMapping::NONE);
|
||||
|
||||
gpu::TexturePointer getTextureByHash(const std::string& hash);
|
||||
gpu::TexturePointer cacheTextureByHash(const std::string& hash, const gpu::TexturePointer& texture);
|
||||
|
@ -201,7 +203,7 @@ signals:
|
|||
protected:
|
||||
|
||||
// Overload ResourceCache::prefetch to allow specifying texture type for loads
|
||||
Q_INVOKABLE ScriptableResource* prefetch(const QUrl& url, int type, int maxNumPixels = ABSOLUTE_MAX_TEXTURE_NUM_PIXELS);
|
||||
Q_INVOKABLE ScriptableResource* prefetch(const QUrl& url, int type, int maxNumPixels = ABSOLUTE_MAX_TEXTURE_NUM_PIXELS, ColorChannelMapping channelMapping = ColorChannelMapping::NONE);
|
||||
|
||||
virtual QSharedPointer<Resource> createResource(const QUrl& url) override;
|
||||
QSharedPointer<Resource> createResourceCopy(const QSharedPointer<Resource>& resource) override;
|
||||
|
|
37
libraries/shared/src/shared/ColorChannelMapping.h
Normal file
37
libraries/shared/src/shared/ColorChannelMapping.h
Normal file
|
@ -0,0 +1,37 @@
|
|||
//
|
||||
// ColorChannelMapping.h
|
||||
// libraries/shared/src
|
||||
//
|
||||
// Created by Sabrina Shanman on 2019/02/05.
|
||||
// Copyright 2019 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_ColorChannelMapping_h
|
||||
#define hifi_ColorChannelMapping_h
|
||||
|
||||
#include "../RegisteredMetaTypes.h"
|
||||
|
||||
enum class ColorChannelMapping {
|
||||
NONE,
|
||||
RED,
|
||||
GREEN,
|
||||
BLUE,
|
||||
ALPHA,
|
||||
COUNT
|
||||
};
|
||||
|
||||
namespace std {
|
||||
template <>
|
||||
struct hash<ColorChannelMapping> {
|
||||
size_t operator()(const ColorChannelMapping& a) const {
|
||||
size_t result = 0;
|
||||
hash_combine(result, (int)a);
|
||||
return result;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
#endif // hifi_ColorChannelMapping_h
|
Loading…
Reference in a new issue