gltfio: use BitmaskFlags for sRGB
This PR also contains a small change in ResourceLoader::createTextures that will permit zero-instance assets (an upcoming gltfio feature).
This commit is contained in:
@@ -21,6 +21,7 @@
|
||||
#include <stdint.h>
|
||||
|
||||
#include <utils/compiler.h>
|
||||
#include <utils/BitmaskEnum.h>
|
||||
|
||||
namespace filament {
|
||||
class Engine;
|
||||
@@ -71,9 +72,9 @@ namespace filament::gltfio {
|
||||
class UTILS_PUBLIC TextureProvider {
|
||||
public:
|
||||
using Texture = filament::Texture;
|
||||
using FlagBits = uint64_t;
|
||||
|
||||
enum class Flags {
|
||||
enum class TextureFlags : uint64_t {
|
||||
NONE = 0,
|
||||
sRGB = 1 << 0,
|
||||
};
|
||||
|
||||
@@ -86,7 +87,7 @@ public:
|
||||
* Texture object, but it is only safe to do so after it has been popped from the queue.
|
||||
*/
|
||||
virtual Texture* pushTexture(const uint8_t* data, size_t byteCount,
|
||||
const char* mimeType, FlagBits flags) = 0;
|
||||
const char* mimeType, TextureFlags flags) = 0;
|
||||
|
||||
/**
|
||||
* Checks if any texture is ready to be removed from the asynchronous decoding queue, and if so
|
||||
@@ -177,4 +178,7 @@ TextureProvider* createKtx2Provider(filament::Engine* engine);
|
||||
|
||||
} // namespace filament::gltfio
|
||||
|
||||
template<> struct utils::EnableBitMaskOperators<filament::gltfio::TextureProvider::TextureFlags>
|
||||
: public std::true_type {};
|
||||
|
||||
#endif // GLTFIO_TEXTUREPROVIDER_H
|
||||
|
||||
@@ -1317,8 +1317,11 @@ MaterialInstance* FAssetLoader::createMaterialInstance(const cgltf_data* srcAsse
|
||||
mi->setParameter("glossinessFactor", sgConfig.glossiness_factor);
|
||||
}
|
||||
|
||||
const TextureProvider::TextureFlags sRGB = TextureProvider::TextureFlags::sRGB;
|
||||
const TextureProvider::TextureFlags LINEAR = TextureProvider::TextureFlags::NONE;
|
||||
|
||||
if (matkey.hasBaseColorTexture) {
|
||||
mAsset->addTextureBinding(mi, "baseColorMap", baseColorTexture.texture, true);
|
||||
mAsset->addTextureBinding(mi, "baseColorMap", baseColorTexture.texture, sRGB);
|
||||
if (matkey.hasTextureTransforms) {
|
||||
const cgltf_texture_transform& uvt = baseColorTexture.transform;
|
||||
auto uvmat = matrixFromUvTransform(uvt.offset, uvt.rotation, uvt.scale);
|
||||
@@ -1331,7 +1334,7 @@ MaterialInstance* FAssetLoader::createMaterialInstance(const cgltf_data* srcAsse
|
||||
// enabled. Note that KHR_materials_pbrSpecularGlossiness specifies that diffuseTexture and
|
||||
// specularGlossinessTexture are both sRGB, whereas the core glTF spec stipulates that
|
||||
// metallicRoughness is not sRGB.
|
||||
bool srgb = inputMat->has_pbr_specular_glossiness;
|
||||
TextureProvider::TextureFlags srgb = inputMat->has_pbr_specular_glossiness ? sRGB : LINEAR;
|
||||
mAsset->addTextureBinding(mi, "metallicRoughnessMap", metallicRoughnessTexture.texture, srgb);
|
||||
if (matkey.hasTextureTransforms) {
|
||||
const cgltf_texture_transform& uvt = metallicRoughnessTexture.transform;
|
||||
@@ -1341,7 +1344,7 @@ MaterialInstance* FAssetLoader::createMaterialInstance(const cgltf_data* srcAsse
|
||||
}
|
||||
|
||||
if (matkey.hasNormalTexture) {
|
||||
mAsset->addTextureBinding(mi, "normalMap", inputMat->normal_texture.texture, false);
|
||||
mAsset->addTextureBinding(mi, "normalMap", inputMat->normal_texture.texture, LINEAR);
|
||||
if (matkey.hasTextureTransforms) {
|
||||
const cgltf_texture_transform& uvt = inputMat->normal_texture.transform;
|
||||
auto uvmat = matrixFromUvTransform(uvt.offset, uvt.rotation, uvt.scale);
|
||||
@@ -1353,7 +1356,7 @@ MaterialInstance* FAssetLoader::createMaterialInstance(const cgltf_data* srcAsse
|
||||
}
|
||||
|
||||
if (matkey.hasOcclusionTexture) {
|
||||
mAsset->addTextureBinding(mi, "occlusionMap", inputMat->occlusion_texture.texture, false);
|
||||
mAsset->addTextureBinding(mi, "occlusionMap", inputMat->occlusion_texture.texture, LINEAR);
|
||||
if (matkey.hasTextureTransforms) {
|
||||
const cgltf_texture_transform& uvt = inputMat->occlusion_texture.transform;
|
||||
auto uvmat = matrixFromUvTransform(uvt.offset, uvt.rotation, uvt.scale);
|
||||
@@ -1365,7 +1368,7 @@ MaterialInstance* FAssetLoader::createMaterialInstance(const cgltf_data* srcAsse
|
||||
}
|
||||
|
||||
if (matkey.hasEmissiveTexture) {
|
||||
mAsset->addTextureBinding(mi, "emissiveMap", inputMat->emissive_texture.texture, true);
|
||||
mAsset->addTextureBinding(mi, "emissiveMap", inputMat->emissive_texture.texture, sRGB);
|
||||
if (matkey.hasTextureTransforms) {
|
||||
const cgltf_texture_transform& uvt = inputMat->emissive_texture.transform;
|
||||
auto uvmat = matrixFromUvTransform(uvt.offset, uvt.rotation, uvt.scale);
|
||||
@@ -1379,7 +1382,7 @@ MaterialInstance* FAssetLoader::createMaterialInstance(const cgltf_data* srcAsse
|
||||
|
||||
if (matkey.hasClearCoatTexture) {
|
||||
mAsset->addTextureBinding(mi, "clearCoatMap", ccConfig.clearcoat_texture.texture,
|
||||
false);
|
||||
LINEAR);
|
||||
if (matkey.hasTextureTransforms) {
|
||||
const cgltf_texture_transform& uvt = ccConfig.clearcoat_texture.transform;
|
||||
auto uvmat = matrixFromUvTransform(uvt.offset, uvt.rotation, uvt.scale);
|
||||
@@ -1388,7 +1391,7 @@ MaterialInstance* FAssetLoader::createMaterialInstance(const cgltf_data* srcAsse
|
||||
}
|
||||
if (matkey.hasClearCoatRoughnessTexture) {
|
||||
mAsset->addTextureBinding(mi, "clearCoatRoughnessMap",
|
||||
ccConfig.clearcoat_roughness_texture.texture, false);
|
||||
ccConfig.clearcoat_roughness_texture.texture, LINEAR);
|
||||
if (matkey.hasTextureTransforms) {
|
||||
const cgltf_texture_transform& uvt = ccConfig.clearcoat_roughness_texture.transform;
|
||||
auto uvmat = matrixFromUvTransform(uvt.offset, uvt.rotation, uvt.scale);
|
||||
@@ -1397,7 +1400,7 @@ MaterialInstance* FAssetLoader::createMaterialInstance(const cgltf_data* srcAsse
|
||||
}
|
||||
if (matkey.hasClearCoatNormalTexture) {
|
||||
mAsset->addTextureBinding(mi, "clearCoatNormalMap",
|
||||
ccConfig.clearcoat_normal_texture.texture, false);
|
||||
ccConfig.clearcoat_normal_texture.texture, LINEAR);
|
||||
if (matkey.hasTextureTransforms) {
|
||||
const cgltf_texture_transform& uvt = ccConfig.clearcoat_normal_texture.transform;
|
||||
auto uvmat = matrixFromUvTransform(uvt.offset, uvt.rotation, uvt.scale);
|
||||
@@ -1414,7 +1417,7 @@ MaterialInstance* FAssetLoader::createMaterialInstance(const cgltf_data* srcAsse
|
||||
|
||||
if (matkey.hasSheenColorTexture) {
|
||||
mAsset->addTextureBinding(mi, "sheenColorMap", shConfig.sheen_color_texture.texture,
|
||||
true);
|
||||
sRGB);
|
||||
if (matkey.hasTextureTransforms) {
|
||||
const cgltf_texture_transform& uvt = shConfig.sheen_color_texture.transform;
|
||||
auto uvmat = matrixFromUvTransform(uvt.offset, uvt.rotation, uvt.scale);
|
||||
@@ -1423,7 +1426,7 @@ MaterialInstance* FAssetLoader::createMaterialInstance(const cgltf_data* srcAsse
|
||||
}
|
||||
if (matkey.hasSheenRoughnessTexture) {
|
||||
mAsset->addTextureBinding(mi, "sheenRoughnessMap",
|
||||
shConfig.sheen_roughness_texture.texture, false);
|
||||
shConfig.sheen_roughness_texture.texture, LINEAR);
|
||||
if (matkey.hasTextureTransforms) {
|
||||
const cgltf_texture_transform& uvt = shConfig.sheen_roughness_texture.transform;
|
||||
auto uvmat = matrixFromUvTransform(uvt.offset, uvt.rotation, uvt.scale);
|
||||
@@ -1444,7 +1447,7 @@ MaterialInstance* FAssetLoader::createMaterialInstance(const cgltf_data* srcAsse
|
||||
|
||||
if (matkey.hasVolumeThicknessTexture) {
|
||||
mAsset->addTextureBinding(mi, "volumeThicknessMap", vlConfig.thickness_texture.texture,
|
||||
false);
|
||||
LINEAR);
|
||||
if (matkey.hasTextureTransforms) {
|
||||
const cgltf_texture_transform& uvt = vlConfig.thickness_texture.transform;
|
||||
auto uvmat = matrixFromUvTransform(uvt.offset, uvt.rotation, uvt.scale);
|
||||
@@ -1457,7 +1460,7 @@ MaterialInstance* FAssetLoader::createMaterialInstance(const cgltf_data* srcAsse
|
||||
mi->setParameter("transmissionFactor", trConfig.transmission_factor);
|
||||
if (matkey.hasTransmissionTexture) {
|
||||
mAsset->addTextureBinding(mi, "transmissionMap", trConfig.transmission_texture.texture,
|
||||
false);
|
||||
LINEAR);
|
||||
if (matkey.hasTextureTransforms) {
|
||||
const cgltf_texture_transform& uvt = trConfig.transmission_texture.transform;
|
||||
auto uvmat = matrixFromUvTransform(uvt.offset, uvt.rotation, uvt.scale);
|
||||
|
||||
@@ -79,12 +79,6 @@ public:
|
||||
// Marks the given texture as being fully decoded, with all miplevels initialized.
|
||||
void markAsReady(Texture* texture);
|
||||
|
||||
// Marks the material as ready, but due to an error.
|
||||
//
|
||||
// This should be called when it known that at least one of the material's texture
|
||||
// dependencies will never become available.
|
||||
void markAsError(Material* material) { markAsReady(material); }
|
||||
|
||||
private:
|
||||
struct TextureNode {
|
||||
Texture* texture;
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include <filament/VertexBuffer.h>
|
||||
|
||||
#include <gltfio/MaterialProvider.h>
|
||||
#include <gltfio/TextureProvider.h>
|
||||
|
||||
#include <math/mat4.h>
|
||||
|
||||
@@ -249,7 +250,7 @@ struct FFilamentAsset : public FilamentAsset {
|
||||
// If a Filament Texture for the given args already exists, calls setParameter() and returns
|
||||
// early. If the Texture doesn't exist yet, stashes binding information for later.
|
||||
void addTextureBinding(MaterialInstance* materialInstance, const char* parameterName,
|
||||
const cgltf_texture* srcTexture, bool srgb);
|
||||
const cgltf_texture* srcTexture, TextureProvider::TextureFlags flags);
|
||||
|
||||
// Calls mi->setParameter() for the given texture slot and optionally adds an edge
|
||||
// to the dependency graph used for gradual reveal of entities.
|
||||
@@ -315,7 +316,7 @@ struct FFilamentAsset : public FilamentAsset {
|
||||
struct TextureInfo {
|
||||
std::vector<TextureSlot> bindings;
|
||||
Texture* texture;
|
||||
bool srgb;
|
||||
TextureProvider::TextureFlags flags;
|
||||
};
|
||||
|
||||
// Mapping from cgltf_texture to Texture* is required when creating new instances.
|
||||
|
||||
@@ -99,7 +99,8 @@ const char* FFilamentAsset::getExtras(utils::Entity entity) const noexcept {
|
||||
}
|
||||
|
||||
void FFilamentAsset::addTextureBinding(MaterialInstance* materialInstance,
|
||||
const char* parameterName, const cgltf_texture* srcTexture, bool srgb) {
|
||||
const char* parameterName, const cgltf_texture* srcTexture,
|
||||
TextureProvider::TextureFlags flags) {
|
||||
if (!srcTexture->image && !srcTexture->basisu_image) {
|
||||
#ifndef NDEBUG
|
||||
slog.w << "Texture is missing image (" << srcTexture->name << ")." << io::endl;
|
||||
@@ -111,8 +112,8 @@ void FFilamentAsset::addTextureBinding(MaterialInstance* materialInstance,
|
||||
TextureInfo& info = mTextures[textureIndex];
|
||||
|
||||
// All bindings for a particular glTF texture must have the same transform function.
|
||||
assert_invariant(info.bindings.size() == 0 || info.srgb == srgb);
|
||||
info.srgb = srgb;
|
||||
assert_invariant(info.bindings.size() == 0 || info.flags == flags);
|
||||
info.flags = flags;
|
||||
|
||||
const TextureSlot slot = { materialInstance, parameterName };
|
||||
if (info.texture) {
|
||||
|
||||
@@ -41,7 +41,7 @@ public:
|
||||
~Ktx2Provider();
|
||||
|
||||
Texture* pushTexture(const uint8_t* data, size_t byteCount,
|
||||
const char* mimeType, uint64_t flags) final;
|
||||
const char* mimeType, TextureFlags flags) final;
|
||||
|
||||
Texture* popTexture() final;
|
||||
void updateQueue() final;
|
||||
@@ -87,12 +87,12 @@ private:
|
||||
};
|
||||
|
||||
Texture* Ktx2Provider::pushTexture(const uint8_t* data, size_t byteCount,
|
||||
const char* mimeType, FlagBits flags) {
|
||||
const char* mimeType, TextureProvider::TextureFlags flags) {
|
||||
using TransferFunction = ktxreader::Ktx2Reader::TransferFunction;
|
||||
const FlagBits sRGB = FlagBits(Flags::sRGB);
|
||||
|
||||
auto async = mKtxReader->asyncCreate(data, byteCount,
|
||||
(flags & sRGB) ? TransferFunction::sRGB : TransferFunction::LINEAR);
|
||||
any(flags & TextureProvider::TextureFlags::sRGB) ?
|
||||
TransferFunction::sRGB : TransferFunction::LINEAR);
|
||||
|
||||
if (async == nullptr) {
|
||||
mRecentPushMessage = "Unable to build Texture object.";
|
||||
|
||||
@@ -91,7 +91,8 @@ struct ResourceLoader::Impl {
|
||||
void computeTangents(FFilamentAsset* asset);
|
||||
void createTextures(FFilamentAsset* asset, bool async);
|
||||
void cancelTextureDecoding();
|
||||
Texture* getOrCreateTexture(FFilamentAsset* asset, size_t textureIndex, const TextureSlot& tb);
|
||||
Texture* getOrCreateTexture(FFilamentAsset* asset, size_t textureIndex,
|
||||
TextureProvider::TextureFlags flags);
|
||||
~Impl();
|
||||
};
|
||||
|
||||
@@ -555,18 +556,14 @@ void ResourceLoader::asyncUpdateLoad() {
|
||||
}
|
||||
|
||||
Texture* ResourceLoader::Impl::getOrCreateTexture(FFilamentAsset* asset, size_t textureIndex,
|
||||
const TextureSlot& tb) {
|
||||
TextureProvider::TextureFlags flags) {
|
||||
const cgltf_texture& srcTexture = asset->mSourceAsset->hierarchy->textures[textureIndex];
|
||||
const cgltf_image* image = srcTexture.basisu_image ?
|
||||
srcTexture.basisu_image : srcTexture.image;
|
||||
const cgltf_buffer_view* bv = image->buffer_view;
|
||||
const char* uri = image->uri;
|
||||
|
||||
TextureProvider::FlagBits flags = {};
|
||||
FFilamentAsset::TextureInfo& info = asset->mTextures[textureIndex];
|
||||
if (info.srgb) {
|
||||
flags |= int(TextureProvider::Flags::sRGB);
|
||||
}
|
||||
|
||||
std::string mime = image->mime_type ? image->mime_type : "";
|
||||
size_t dataUriSize;
|
||||
@@ -581,7 +578,6 @@ Texture* ResourceLoader::Impl::getOrCreateTexture(FFilamentAsset* asset, size_t
|
||||
TextureProvider* provider = mTextureProviders[mime];
|
||||
if (!provider) {
|
||||
slog.e << "Missing texture provider for " << mime << io::endl;
|
||||
asset->mDependencyGraph.markAsError(tb.materialInstance);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -634,7 +630,6 @@ Texture* ResourceLoader::Impl::getOrCreateTexture(FFilamentAsset* asset, size_t
|
||||
Path fullpath = Path(mGltfPath).getParent() + uri;
|
||||
if (!fullpath.exists()) {
|
||||
slog.e << "Unable to open " << fullpath << io::endl;
|
||||
asset->mDependencyGraph.markAsError(tb.materialInstance);
|
||||
return nullptr;
|
||||
}
|
||||
using namespace std;
|
||||
@@ -659,7 +654,6 @@ Texture* ResourceLoader::Impl::getOrCreateTexture(FFilamentAsset* asset, size_t
|
||||
const char* name = srcTexture.name ? srcTexture.name : uri;
|
||||
slog.e << "Unable to create texture " << name << ": "
|
||||
<< provider->getPushMessage() << io::endl;
|
||||
asset->mDependencyGraph.markAsError(tb.materialInstance);
|
||||
} else {
|
||||
info.texture = texture;
|
||||
}
|
||||
@@ -679,10 +673,14 @@ void ResourceLoader::Impl::createTextures(FFilamentAsset* asset, bool async) {
|
||||
mRemainingTextureDownloads = 0;
|
||||
size_t textureIndex = 0;
|
||||
for (FFilamentAsset::TextureInfo& info : asset->mTextures) {
|
||||
for (const TextureSlot& slot : info.bindings) {
|
||||
// There might be no bindings yet (e.g. if the user is preloading a zero-instance asset)
|
||||
// in which case we still need to trigger texture creation.
|
||||
getOrCreateTexture(asset, textureIndex, info.flags);
|
||||
|
||||
// Returns null if the user has not yet called addResourceData for the texture.
|
||||
if (Texture* texture = getOrCreateTexture(asset, textureIndex, slot)) {
|
||||
// For each binding to a material instance, check if the texture exists yet; if so,
|
||||
// call setParameter(...) on the material.
|
||||
for (const TextureSlot& slot : info.bindings) {
|
||||
if (Texture* texture = getOrCreateTexture(asset, textureIndex, info.flags)) {
|
||||
asset->applyTextureBinding(textureIndex, slot);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ public:
|
||||
~StbProvider();
|
||||
|
||||
Texture* pushTexture(const uint8_t* data, size_t byteCount,
|
||||
const char* mimeType, uint64_t flags) final;
|
||||
const char* mimeType, TextureFlags flags) final;
|
||||
|
||||
Texture* popTexture() final;
|
||||
void updateQueue() final;
|
||||
@@ -87,7 +87,7 @@ private:
|
||||
};
|
||||
|
||||
Texture* StbProvider::pushTexture(const uint8_t* data, size_t byteCount,
|
||||
const char* mimeType, FlagBits flags) {
|
||||
const char* mimeType, TextureFlags flags) {
|
||||
int width, height, numComponents;
|
||||
if (!stbi_info_from_memory(data, byteCount, &width, &height, &numComponents)) {
|
||||
mRecentPushMessage = std::string("Unable to parse texture: ") + stbi_failure_reason();
|
||||
@@ -95,13 +95,12 @@ Texture* StbProvider::pushTexture(const uint8_t* data, size_t byteCount,
|
||||
}
|
||||
|
||||
using InternalFormat = Texture::InternalFormat;
|
||||
const FlagBits sRGB = FlagBits(Flags::sRGB);
|
||||
|
||||
Texture* texture = Texture::Builder()
|
||||
.width(width)
|
||||
.height(height)
|
||||
.levels(0xff)
|
||||
.format((flags & sRGB) ? InternalFormat::SRGB8_A8 : InternalFormat::RGBA8)
|
||||
.format(any(flags & TextureFlags::sRGB) ? InternalFormat::SRGB8_A8 : InternalFormat::RGBA8)
|
||||
.build(*mEngine);
|
||||
|
||||
if (texture == nullptr) {
|
||||
|
||||
Reference in New Issue
Block a user