first commit

This commit is contained in:
Nick Fisher
2021-09-15 20:07:11 +08:00
commit a0f877be48
292 changed files with 100157 additions and 0 deletions

View File

@@ -0,0 +1,88 @@
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef GLTFIO_ANIMATOR_H
#define GLTFIO_ANIMATOR_H
#include <gltfio/FilamentAsset.h>
#include <gltfio/FilamentInstance.h>
namespace gltfio {
struct FFilamentAsset;
struct FFilamentInstance;
struct AnimatorImpl;
/**
* \class Animator Animator.h gltfio/Animator.h
* \brief Updates matrices according to glTF \c animation and \c skin definitions.
*
* Animator can be used for two things:
* - Updating matrices in filament::TransformManager components according to glTF \c animation definitions.
* - Updating bone matrices in filament::RenderableManager components according to glTF \c skin definitions.
*
* For a usage example, see the documentation for AssetLoader.
*/
class UTILS_PUBLIC Animator {
public:
/**
* Applies rotation, translation, and scale to entities that have been targeted by the given
* animation definition. Uses filament::TransformManager.
*
* @param animationIndex Zero-based index for the \c animation of interest.
* @param time Elapsed time of interest in seconds.
*/
void applyAnimation(size_t animationIndex, float time) const;
/**
* Computes root-to-node transforms for all bone nodes, then passes
* the results into filament::RenderableManager::setBones.
* Uses filament::TransformManager and filament::RenderableManager.
*
* NOTE: this operation is independent of \c animation.
*/
void updateBoneMatrices();
/** Returns the number of \c animation definitions in the glTF asset. */
size_t getAnimationCount() const;
/** Returns the duration of the specified glTF \c animation in seconds. */
float getAnimationDuration(size_t animationIndex) const;
/**
* Returns a weak reference to the string name of the specified \c animation, or an
* empty string if none was specified.
*/
const char* getAnimationName(size_t animationIndex) const;
// For internal use only.
void addInstance(FFilamentInstance* instance);
private:
/*! \cond PRIVATE */
friend struct FFilamentAsset;
friend struct FFilamentInstance;
/*! \endcond */
Animator(FFilamentAsset* asset, FFilamentInstance* instance);
~Animator();
AnimatorImpl* mImpl;
};
} // namespace gltfio
#endif // GLTFIO_ANIMATOR_H

View File

@@ -0,0 +1,244 @@
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef GLTFIO_ASSETLOADER_H
#define GLTFIO_ASSETLOADER_H
#include <filament/Engine.h>
#include <filament/Material.h>
#include <gltfio/FilamentAsset.h>
#include <gltfio/FilamentInstance.h>
#include <gltfio/MaterialProvider.h>
#include <utils/compiler.h>
namespace utils {
class EntityManager;
class NameComponentManager;
}
/**
* Loader and pipeline for glTF 2.0 assets.
*/
namespace gltfio {
/**
* \struct AssetConfiguration AssetLoader.h gltfio/AssetLoader.h
* \brief Construction parameters for AssetLoader.
*/
struct AssetConfiguration {
//! The engine that the loader should pass to builder objects (e.g.
//! filament::VertexBuffer::Builder).
class filament::Engine* engine;
//! Controls whether the loader uses filamat to generate materials on the fly, or loads a small
//! set of precompiled ubershader materials. Deleting the MaterialProvider is the client's
//! responsibility. See createMaterialGenerator() and createUbershaderLoader().
MaterialProvider* materials;
//! Optional manager for associating string names with entities in the transform hierarchy.
utils::NameComponentManager* names = nullptr;
//! Overrides the factory used for creating entities in the transform hierarchy. If this is not
//! specified, AssetLoader will use the singleton EntityManager associated with the current
//! process.
utils::EntityManager* entities = nullptr;
//! Optional default node name for anonymous nodes
char* defaultNodeName = nullptr;
};
/**
* \class AssetLoader AssetLoader.h gltfio/AssetLoader.h
* \brief Consumes glTF content and produces FilamentAsset objects.
*
* AssetLoader consumes a blob of glTF 2.0 content (either JSON or GLB) and produces a FilamentAsset
* object, which is a bundle of Filament entities, material instances, textures, vertex buffers,
* and index buffers.
*
* Clients must use AssetLoader to create and destroy FilamentAsset objects.
*
* AssetLoader does not fetch external buffer data or create textures on its own. Clients can use
* ResourceLoader for this, which obtains the URI list from the asset. This is demonstrated in the
* code snippet below.
*
* AssetLoader also owns a cache of filament::Material objects that may be re-used across multiple
* loads.
*
* Example usage:
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* auto engine = Engine::create();
* auto materials = createMaterialGenerator(engine);
* auto loader = AssetLoader::create({engine, materials});
*
* // Parse the glTF content and create Filament entities.
* std::vector<uint8_t> content(...);
* FilamentAsset* asset = loader->createAssetFromJson(content.data(), content.size());
* content.clear();
*
* // Load buffers and textures from disk.
* ResourceLoader({engine, ".", true}).loadResources(asset);
*
* // Obtain the simple animation interface.
* Animator* animator = asset->getAnimator();
*
* // Free the glTF hierarchy as it is no longer needed.
* asset->releaseSourceData();
*
* // Add renderables to the scene.
* scene->addEntities(asset->getEntities(), asset->getEntityCount());
*
* // Execute the render loop and play the first animation.
* do {
* animator->applyAnimation(0, time);
* animator->updateBoneMatrices();
* if (renderer->beginFrame(swapChain)) {
* renderer->render(view);
* renderer->endFrame();
* }
* } while (!quit);
*
* scene->removeEntities(asset->getEntities(), asset->getEntityCount());
* loader->destroyAsset(asset);
* materials->destroyMaterials();
* delete materials;
* AssetLoader::destroy(&loader);
* Engine::destroy(&engine);
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
class UTILS_PUBLIC AssetLoader {
public:
/**
* Creates an asset loader for the given configuration, which specifies the Filament engine.
*
* The engine is held weakly, used only for the creation and destruction of Filament objects.
* The optional name component manager can be used to assign names to renderables.
* The material source specifies whether to use filamat to generate materials on the fly, or to
* load a small set of precompiled ubershader materials.
*/
static AssetLoader* create(const AssetConfiguration& config);
/**
* Frees the loader.
*
* This does not not automatically free the cache of materials, nor
* does it free the entities for created assets (see destroyAsset).
*/
static void destroy(AssetLoader** loader);
/**
* Takes a pointer to the contents of a JSON-based glTF 2.0 file and returns a bundle
* of Filament objects. Returns null on failure.
*/
FilamentAsset* createAssetFromJson(const uint8_t* bytes, uint32_t nbytes);
/**
* Takes a pointer to the contents of a GLB glTF 2.0 file and returns a bundle
* of Filament objects. Returns null on failure.
*/
FilamentAsset* createAssetFromBinary(const uint8_t* bytes, uint32_t nbytes);
/**
* Consumes the contents of a glTF 2.0 file and produces a primary asset with one or more
* instances. The primary asset has ownership over the instances.
*
* The returned instances share their textures, material instances, and vertex buffers with the
* primary asset. However each instance has its own unique set of entities, transform
* components, and renderable components. Instances are freed when the primary asset is freed.
*
* Light components are not instanced, they belong only to the primary asset.
*
* Clients must use ResourceLoader to load resources on the primary asset.
*
* The entity accessor and renderable stack API in the primary asset can be used to control the
* union of all instances. The individual FilamentInstance objects can be used to access each
* instance's partition of entities. Similarly, the Animator in the primary asset controls all
* instances. To animate instances individually, use FilamentInstance::getAnimator().
*
* @param bytes the contents of a glTF 2.0 file (JSON or GLB)
* @param numBytes the number of bytes in "bytes"
* @param instances destination pointer, to be populated by the requested number of instances
* @param numInstances requested number of instances
* @return the primary asset that has ownership over all instances
*/
FilamentAsset* createInstancedAsset(const uint8_t* bytes, uint32_t numBytes,
FilamentInstance** instances, size_t numInstances);
/**
* Adds a new instance to an instanced asset.
*
* Use this with caution. It is more efficient to pre-allocate a max number of instances, and
* gradually add them to the scene as needed. Instances can also be "recycled" by removing and
* re-adding them to the scene.
*
* NOTE: destroyInstance() does not exist because gltfio favors flat arrays for storage of
* entity lists and instance lists, which would be slow to shift. We also wish to discourage
* create/destroy churn, as noted above.
*
* This cannot be called after FilamentAsset::releaseSourceData().
* This cannot be called on a non-instanced asset.
* See also AssetLoader::createInstancedAsset().
*/
FilamentInstance* createInstance(FilamentAsset* primary);
/**
* Allows clients to enable diagnostic shading on newly-loaded assets.
*/
void enableDiagnostics(bool enable = true);
/**
* Destroys the given asset and all of its associated Filament objects.
*
* This destroys entities, components, material instances, vertex buffers, index buffers,
* and textures. This does not necessarily immediately free all source data, since
* texture decoding or GPU uploading might be underway.
*/
void destroyAsset(const FilamentAsset* asset);
/**
* Gets a weak reference to an array of cached materials, used internally to create material
* instances for assets.
*/
const filament::Material* const* getMaterials() const noexcept;
/**
* Gets the number of cached materials.
*/
size_t getMaterialsCount() const noexcept;
utils::NameComponentManager* getNames() const noexcept;
MaterialProvider* getMaterialProvider() const noexcept;
/*! \cond PRIVATE */
protected:
AssetLoader() noexcept = default;
~AssetLoader() = default;
public:
AssetLoader(AssetLoader const&) = delete;
AssetLoader(AssetLoader&&) = delete;
AssetLoader& operator=(AssetLoader const&) = delete;
AssetLoader& operator=(AssetLoader&&) = delete;
/*! \endcond */
};
} // namespace gltfio
#endif // GLTFIO_ASSETLOADER_H

View File

@@ -0,0 +1,251 @@
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef GLTFIO_FILAMENTASSET_H
#define GLTFIO_FILAMENTASSET_H
#include <filament/Box.h>
#include <filament/TextureSampler.h>
#include <utils/compiler.h>
#include <utils/Entity.h>
namespace filament {
class Camera;
class Engine;
class MaterialInstance;
}
namespace gltfio {
class Animator;
class FilamentInstance;
/**
* \class FilamentAsset FilamentAsset.h gltfio/FilamentAsset.h
* \brief Owns a bundle of Filament objects that have been created by AssetLoader.
*
* For usage instructions, see the documentation for AssetLoader.
*
* This class owns a hierarchy of entities that have been loaded from a glTF asset. Every entity has
* a filament::TransformManager component, and some entities also have \c Name, \c Renderable,
* \c Light, or \c Camera components.
*
* In addition to the aforementioned entities, an asset has strong ownership over a list of
* filament::VertexBuffer, filament::IndexBuffer, filament::MaterialInstance, filament::Texture,
* and, optionally, a simple animation engine (gltfio::Animator).
*
* Clients must use ResourceLoader to create filament::Texture objects, compute tangent quaternions,
* and upload data into vertex buffers and index buffers.
*
* \todo Only the default glTF scene is loaded, other glTF scenes are ignored.
*/
class UTILS_PUBLIC FilamentAsset {
public:
/**
* Gets the list of entities, one for each glTF node. All of these have a Transform component.
* Some of the returned entities may also have a Renderable component and/or a Light component.
*/
const utils::Entity* getEntities() const noexcept;
/**
* Gets the number of entities returned by getEntities().
*/
size_t getEntityCount() const noexcept;
/**
* Gets the list of entities in the scene representing lights. All of these have a Light component.
*/
const utils::Entity* getLightEntities() const noexcept;
/**
* Gets the number of entities returned by getLightEntities().
*/
size_t getLightEntityCount() const noexcept;
/**
* Gets the list of entities in the scene representing cameras. All of these have a \c Camera
* component.
*
* Note about aspect ratios:
* gltfio always uses an aspect ratio of 1.0 when setting the projection matrix for perspective
* cameras. gltfio then sets the camera's scaling matrix with the aspect ratio specified in the
* glTF file (if present).
*
* The camera's scaling matrix allows clients to adjust the aspect ratio independently from the
* camera's projection.
*
* To change the aspect ratio of the glTF camera:
*
* camera->setScaling(double4 {1.0 / newAspectRatio, 1.0, 1.0, 1.0});
*
* @see filament::Camera::setScaling
*/
const utils::Entity* getCameraEntities() const noexcept;
/**
* Gets the number of entities returned by getCameraEntities().
*/
size_t getCameraEntityCount() const noexcept;
/**
* Gets the transform root for the asset, which has no matching glTF node.
*
* This node exists for convenience, allowing users to transform the entire asset. For instanced
* assets, this is a "super root" where each of its children is a root in a particular instance.
* This allows users to transform all instances en masse if they wish to do so.
*/
utils::Entity getRoot() const noexcept;
/**
* Pops a ready renderable off the queue, or returns 0 if no renderables have become ready.
*
* NOTE: To determine the progress percentage or completion status, please use
* ResourceLoader#asyncGetLoadProgress. To get the number of ready renderables,
* please use popRenderables().
*
* This method allows clients to progressively add the asset's renderables to the scene as
* textures gradually become ready through asynchronous loading. For example, on every frame
* progressive applications can do something like this:
*
* while (utils::Entity e = popRenderable()) { scene.addEntity(e); }
*
* \see ResourceLoader#asyncBeginLoad
* \see popRenderables()
*/
utils::Entity popRenderable() noexcept;
/**
* Pops up to "count" ready renderables off the queue, or returns the available number.
*
* The given pointer should either be null or point to memory that can hold up to count
* entities. If the pointer is null, returns the number of available renderables. Otherwise
* returns the number of entities that have been written.
*
* \see ResourceLoader#asyncBeginLoad
*/
size_t popRenderables(utils::Entity* entities, size_t count) noexcept;
/** Gets all material instances. These are already bound to renderables. */
const filament::MaterialInstance* const* getMaterialInstances() const noexcept;
/** Gets all material instances (non-const). These are already bound to renderables. */
filament::MaterialInstance* const* getMaterialInstances() noexcept;
/** Gets the number of materials returned by getMaterialInstances(). */
size_t getMaterialInstanceCount() const noexcept;
/** Gets resource URIs for all externally-referenced buffers. */
const char* const* getResourceUris() const noexcept;
/** Gets the number of resource URIs returned by getResourceUris(). */
size_t getResourceUriCount() const noexcept;
/** Gets the bounding box computed from the supplied min / max values in glTF accessors. */
filament::Aabb getBoundingBox() const noexcept;
/** Gets the NameComponentManager label for the given entity, if it exists. */
const char* getName(utils::Entity) const noexcept;
/** Returns the first entity with the given name, or 0 if none exist. */
utils::Entity getFirstEntityByName(const char* name) noexcept;
/**
* Gets a list of entities with the given name.
*
* @param name Null-terminated string to match.
* @param entities Pointer to an array to populate.
* @param maxCount Maximum number of entities to retrieve.
*
* @return If entities is non-null, the number of entities written to the entity pointer.
* Otherwise this returns the number of entities with the given name.
*/
size_t getEntitiesByName(const char* name, utils::Entity* entities,
size_t maxCount) const noexcept;
/**
* Gets a list of entities whose names start with the given prefix.
*
* @param prefix Null-terminated prefix string to match.
* @param entities Pointer to an array to populate.
* @param maxCount Maximum number of entities to retrieve.
*
* @return If entities is non-null, the number of entities written to the entity pointer.
* Otherwise this returns the number of entities with the given prefix.
*/
size_t getEntitiesByPrefix(const char* prefix, utils::Entity* entities,
size_t maxCount) const noexcept;
/** Gets the glTF extras string for a specific node, or for the asset, if it exists. */
const char* getExtras(utils::Entity entity = {}) const noexcept;
/**
* Lazily creates the animation engine or returns it from the cache.
*
* The animator is owned by the asset and should not be manually deleted.
* The first time this is called, it must be called before FilamentAsset::releaseSourceData().
* If the asset is instanced, this returns a "primary" animator that controls all instances.
* To animate each instance individually, use \see FilamentInstance.
*/
Animator* getAnimator() noexcept;
/**
* Lazily creates a single LINES renderable that draws the transformed bounding-box hierarchy
* for diagnostic purposes. The wireframe is owned by the asset so clients should not delete it.
*/
utils::Entity getWireframe() noexcept;
/**
* Returns the Filament engine associated with the AssetLoader that created this asset.
*/
filament::Engine* getEngine() const noexcept;
/**
* Reclaims CPU-side memory for URI strings, binding lists, and raw animation data.
*
* This should only be called after ResourceLoader::loadResources().
* If using Animator, this should be called after getAnimator().
* If this is an instanced asset, this prevents creation of new instances.
*/
void releaseSourceData() noexcept;
/**
* Returns a weak reference to the underlying cgltf hierarchy. This becomes invalid after
* calling releaseSourceData().
*/
const void* getSourceAsset() noexcept;
/*! \cond PRIVATE */
FilamentInstance** getAssetInstances() noexcept;
size_t getAssetInstanceCount() const noexcept;
protected:
FilamentAsset() noexcept = default;
~FilamentAsset() = default;
public:
FilamentAsset(FilamentAsset const&) = delete;
FilamentAsset(FilamentAsset&&) = delete;
FilamentAsset& operator=(FilamentAsset const&) = delete;
FilamentAsset& operator=(FilamentAsset&&) = delete;
/*! \endcond */
};
} // namespace gltfio
#endif // GLTFIO_FILAMENTASSET_H

View File

@@ -0,0 +1,75 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef GLTFIO_FILAMENTINSTANCE_H
#define GLTFIO_FILAMENTINSTANCE_H
#include <utils/compiler.h>
#include <utils/Entity.h>
namespace gltfio {
class Animator;
class FilamentAsset;
/**
* \class FilamentInstance FilamentInstance.h gltfio/FilamentInstance.h
* \brief Provides access to a hierarchy of entities that have been instanced from a glTF asset.
*
* Every entity has a filament::TransformManager component, and some entities also have \c Name or
* \c Renderable components.
*
* \see AssetLoader::createInstancedAsset()
*/
class UTILS_PUBLIC FilamentInstance {
public:
/**
* Gets the owner of this instance.
*/
FilamentAsset* getAsset() const noexcept;
/**
* Gets the list of entities in this instance, one for each glTF node. All of these have a
* Transform component. Some of the returned entities may also have a Renderable component or
* Name component.
*/
const utils::Entity* getEntities() const noexcept;
/**
* Gets the number of entities returned by getEntities().
*/
size_t getEntityCount() const noexcept;
/** Gets the transform root for the instance, which has no matching glTF node. */
utils::Entity getRoot() const noexcept;
/**
* Lazily creates the animation engine for the instance, or returns it from the cache.
*
* Note that an animator can be obtained either from an individual instance, or from the
* originating FilamentAsset. In the latter case, the animation frame is shared amongst all
* instances. If individual control is desired, users must obtain the animator from the
* individual instances.
*
* The animator is owned by the asset and should not be manually deleted.
* The first time this is called, it must be called before FilamentAsset::releaseSourceData().
*/
Animator* getAnimator() noexcept;
};
} // namespace gltfio
#endif // GLTFIO_FILAMENTINSTANCE_H

View File

@@ -0,0 +1,32 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// gltfio supports PNG and JPEG, disable all other formats.
#define STBI_NO_BMP
#define STBI_NO_PSD
#define STBI_NO_TGA
#define STBI_NO_GIF
#define STBI_NO_HDR
#define STBI_NO_PIC
#define STBI_NO_PNM
// For emscripten and Android builds, we never load from the file
// system, so we-opt out of the stdio functionality in stb.
#if defined(__EMSCRIPTEN__) || defined(ANDROID)
#define STBI_NO_STDIO
#endif
#include <stb_image.h>

View File

@@ -0,0 +1,199 @@
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef GLTFIO_MATERIALPROVIDER_H
#define GLTFIO_MATERIALPROVIDER_H
#include <filament/Engine.h>
#include <filament/Material.h>
#include <filament/MaterialInstance.h>
#include <utils/compiler.h>
#include <array>
#include <string>
namespace gltfio {
enum class AlphaMode : uint8_t {
OPAQUE,
MASK,
BLEND
};
/**
* \struct MaterialKey MaterialProvider.h gltfio/MaterialProvider.h
* \brief Small POD structure that specifies the requirements for a glTF material.
* \note This key is processed by MurmurHashFn so please make padding explicit.
*/
struct alignas(4) MaterialKey {
// -- 32 bit boundary --
bool doubleSided : 1;
bool unlit : 1;
bool hasVertexColors : 1;
bool hasBaseColorTexture : 1;
bool hasNormalTexture : 1;
bool hasOcclusionTexture : 1;
bool hasEmissiveTexture : 1;
bool useSpecularGlossiness : 1;
AlphaMode alphaMode : 4;
bool enableDiagnostics : 4;
union {
struct {
bool hasMetallicRoughnessTexture : 1;
uint8_t metallicRoughnessUV : 7;
};
struct {
bool hasSpecularGlossinessTexture : 1;
uint8_t specularGlossinessUV : 7;
};
};
uint8_t baseColorUV;
// -- 32 bit boundary --
bool hasClearCoatTexture : 1;
uint8_t clearCoatUV : 7;
bool hasClearCoatRoughnessTexture : 1;
uint8_t clearCoatRoughnessUV : 7;
bool hasClearCoatNormalTexture : 1;
uint8_t clearCoatNormalUV : 7;
bool hasClearCoat : 1;
bool hasTransmission : 1;
bool hasTextureTransforms : 6;
// -- 32 bit boundary --
uint8_t emissiveUV;
uint8_t aoUV;
uint8_t normalUV;
bool hasTransmissionTexture : 1;
uint8_t transmissionUV : 7;
// -- 32 bit boundary --
bool hasSheenColorTexture : 1;
uint8_t sheenColorUV : 7;
bool hasSheenRoughnessTexture : 1;
uint8_t sheenRoughnessUV : 7;
bool hasVolumeThicknessTexture : 1;
uint8_t volumeThicknessUV : 7;
bool hasSheen : 1;
bool hasIOR : 1;
bool hasVolume : 1;
};
static_assert(sizeof(MaterialKey) == 16, "MaterialKey has unexpected padding.");
bool operator==(const MaterialKey& k1, const MaterialKey& k2);
// Define a mapping from a uv set index in the source asset to one of Filament's uv sets.
enum UvSet : uint8_t { UNUSED, UV0, UV1 };
constexpr int UvMapSize = 8;
using UvMap = std::array<UvSet, UvMapSize>;
inline uint8_t getNumUvSets(const UvMap& uvmap) {
return std::max({
uvmap[0], uvmap[1], uvmap[2], uvmap[3],
uvmap[4], uvmap[5], uvmap[6], uvmap[7],
});
};
/**
* \class MaterialProvider MaterialProvider.h gltfio/MaterialProvider.h
* \brief Interface to a provider of glTF materials (has two implementations).
*
* - The \c MaterialGenerator implementation generates materials at run time (which can be slow) and
* requires the filamat library, but produces streamlined shaders. See createMaterialGenerator().
*
* - The \c UbershaderLoader implementation uses a small number of pre-built materials with complex
* fragment shaders, but does not require any run time work or usage of filamat. See
* createUbershaderLoader().
*
* Both implementations of MaterialProvider maintain a small cache of materials which must be
* explicitly freed using destroyMaterials(). These materials are not freed automatically when the
* MaterialProvider is destroyed, which allows clients to take ownership if desired.
*
*/
class UTILS_PUBLIC MaterialProvider {
public:
virtual ~MaterialProvider() {}
/**
* Creates or fetches a compiled Filament material, then creates an instance from it.
*
* @param config Specifies requirements; might be mutated due to resource constraints.
* @param uvmap Output argument that gets populated with a small table that maps from a glTF uv
* index to a Filament uv index.
* @param label Optional tag that is not a part of the cache key.
*/
virtual filament::MaterialInstance* createMaterialInstance(MaterialKey* config, UvMap* uvmap,
const char* label = "material") = 0;
/**
* Gets a weak reference to the array of cached materials.
*/
virtual const filament::Material* const* getMaterials() const noexcept = 0;
/**
* Gets the number of cached materials.
*/
virtual size_t getMaterialsCount() const noexcept = 0;
/**
* Destroys all cached materials.
*
* This is not called automatically when MaterialProvider is destroyed, which allows
* clients to take ownership of the cache if desired.
*/
virtual void destroyMaterials() = 0;
/**
* Returns true if the presence of the given vertex attribute is required.
*
* Some types of providers (e.g. ubershader) require dummy attribute values
* if the glTF model does not provide them.
*/
virtual bool needsDummyData(filament::VertexAttribute attrib) const noexcept = 0;
};
void constrainMaterial(MaterialKey* key, UvMap* uvmap);
void processShaderString(std::string* shader, const UvMap& uvmap,
const MaterialKey& config);
/**
* Creates a material provider that builds materials on the fly, composing GLSL at run time.
*
* @param optimizeShaders Optimizes shaders, but at significant cost to construction time.
* @return New material provider that can build materials at run time.
*
* Requires \c libfilamat to be linked in. Not available in \c libgltfio_core.
*
* @see createUbershaderLoader
*/
UTILS_PUBLIC
MaterialProvider* createMaterialGenerator(filament::Engine* engine, bool optimizeShaders = false);
/**
* Creates a material provider that loads a small set of pre-built materials.
*
* @return New material provider that can quickly load a material from a cache.
*
* Requires \c libgltfio_resources to be linked in.
*
* @see createMaterialGenerator
*/
UTILS_PUBLIC
MaterialProvider* createUbershaderLoader(filament::Engine* engine);
} // namespace gltfio
#endif // GLTFIO_MATERIALPROVIDER_H

View File

@@ -0,0 +1,163 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef GLTFIO_RESOURCELOADER_H
#define GLTFIO_RESOURCELOADER_H
#include <gltfio/FilamentAsset.h>
#include <backend/BufferDescriptor.h>
#include <utils/compiler.h>
namespace filament {
class Engine;
}
namespace gltfio {
struct FFilamentAsset;
class AssetPool;
/**
* \struct ResourceConfiguration ResourceLoader.h gltfio/ResourceLoader.h
* \brief Construction parameters for ResourceLoader.
*/
struct ResourceConfiguration {
//! The engine that the loader should pass to builder objects (e.g.
//! filament::Texture::Builder).
class filament::Engine* engine;
//! Optional path or URI that points to the base glTF file. This is used solely
//! to resolve relative paths. The string pointer is not retained.
const char* gltfPath;
//! If true, adjusts skinning weights to sum to 1. Well formed glTF files do not need this,
//! but it is useful for robustness.
bool normalizeSkinningWeights;
//! If true, computes the bounding boxes of all \c POSITION attibutes. Well formed glTF files
//! do not need this, but it is useful for robustness.
bool recomputeBoundingBoxes;
};
/**
* \class ResourceLoader ResourceLoader.h gltfio/ResourceLoader.h
* \brief Prepares and uploads vertex buffers and textures to the GPU.
*
* For a usage example, see the documentation for AssetLoader.
*
* ResourceLoader must be destroyed on the same thread that calls filament::Renderer::render()
* because it listens to filament::backend::BufferDescriptor callbacks in order to determine when to
* free CPU-side data blobs.
*
* \todo If clients persist their ResourceLoader, Filament textures are currently re-created upon
* subsequent re-loads of the same asset. To fix this, we would need to enable shared ownership
* of Texture objects between ResourceLoader and FilamentAsset.
*/
class UTILS_PUBLIC ResourceLoader {
public:
using BufferDescriptor = filament::backend::BufferDescriptor;
ResourceLoader(const ResourceConfiguration& config);
~ResourceLoader();
/**
* Feeds the binary content of an external resource into the loader's URI cache.
*
* On some platforms, `ResourceLoader` does not know how to download external resources on its
* own (external resources might come from a filesystem, a database, or the internet) so this
* method allows clients to download external resources and push them to the loader.
*
* Every resource should be passed in before calling #loadResources or #asyncBeginLoad. See
* also FilamentAsset#getResourceUris.
*
* When loading GLB files (as opposed to JSON-based glTF files), clients typically do not
* need to call this method.
*/
void addResourceData(const char* uri, BufferDescriptor&& buffer);
/**
* Checks if the given resource has already been added to the URI cache.
*/
bool hasResourceData(const char* uri) const;
/**
* Frees memory by evicting the URI cache that was populated via addResourceData.
*
* This can be called only after a model is fully loaded or after loading has been cancelled.
*/
void evictResourceData();
/**
* Loads resources for the given asset from the filesystem or data cache and "finalizes" the
* asset by transforming the vertex data format if necessary, decoding image files, supplying
* tangent data, etc.
*
* Returns false if resources have already been loaded, or if one or more resources could not
* be loaded.
*
* Note: this method is synchronous and blocks until all textures have been decoded.
* For an asynchronous alternative, see #asyncBeginLoad.
*/
bool loadResources(FilamentAsset* asset);
/**
* Starts an asynchronous resource load.
*
* Returns false if the loading process was unable to start.
*
* This is an alternative to #loadResources and requires periodic calls to #asyncUpdateLoad.
* On multi-threaded systems this creates threads for texture decoding.
*/
bool asyncBeginLoad(FilamentAsset* asset);
/**
* Gets the status of an asynchronous resource load as a percentage in [0,1].
*/
float asyncGetLoadProgress() const;
/**
* Updates an asynchronous load by performing any pending work that must take place
* on the main thread.
*
* Clients must periodically call this until #asyncGetLoadProgress returns 100%.
* After progress reaches 100%, calling this is harmless; it just does nothing.
*/
void asyncUpdateLoad();
/**
* Cancels pending decoder jobs, frees all CPU-side texel data, and flushes the Engine.
*
* Calling this is only necessary if the asyncBeginLoad API was used
* and cancellation is required before progress reaches 100%.
*/
void asyncCancelLoad();
private:
bool loadResources(FFilamentAsset* asset, bool async);
void applySparseData(FFilamentAsset* asset) const;
void normalizeSkinningWeights(FFilamentAsset* asset) const;
void updateBoundingBoxes(FFilamentAsset* asset) const;
AssetPool* mPool;
struct Impl;
Impl* pImpl;
};
} // namespace gltfio
#endif // GLTFIO_RESOURCELOADER_H

View File

@@ -0,0 +1,46 @@
#ifndef GLTFRESOURCES_H_
#define GLTFRESOURCES_H_
#include <stdint.h>
extern "C" {
extern const uint8_t GLTFRESOURCES_PACKAGE[];
extern int GLTFRESOURCES_LIT_FADE_OFFSET;
extern int GLTFRESOURCES_LIT_FADE_SIZE;
extern int GLTFRESOURCES_LIT_OPAQUE_OFFSET;
extern int GLTFRESOURCES_LIT_OPAQUE_SIZE;
extern int GLTFRESOURCES_LIT_MASKED_OFFSET;
extern int GLTFRESOURCES_LIT_MASKED_SIZE;
extern int GLTFRESOURCES_SPECULARGLOSSINESS_FADE_OFFSET;
extern int GLTFRESOURCES_SPECULARGLOSSINESS_FADE_SIZE;
extern int GLTFRESOURCES_SPECULARGLOSSINESS_OPAQUE_OFFSET;
extern int GLTFRESOURCES_SPECULARGLOSSINESS_OPAQUE_SIZE;
extern int GLTFRESOURCES_SPECULARGLOSSINESS_MASKED_OFFSET;
extern int GLTFRESOURCES_SPECULARGLOSSINESS_MASKED_SIZE;
extern int GLTFRESOURCES_UNLIT_FADE_OFFSET;
extern int GLTFRESOURCES_UNLIT_FADE_SIZE;
extern int GLTFRESOURCES_UNLIT_OPAQUE_OFFSET;
extern int GLTFRESOURCES_UNLIT_OPAQUE_SIZE;
extern int GLTFRESOURCES_UNLIT_MASKED_OFFSET;
extern int GLTFRESOURCES_UNLIT_MASKED_SIZE;
extern int GLTFRESOURCES_LIT_VOLUME_OFFSET;
extern int GLTFRESOURCES_LIT_VOLUME_SIZE;
extern int GLTFRESOURCES_LIT_TRANSMISSION_OFFSET;
extern int GLTFRESOURCES_LIT_TRANSMISSION_SIZE;
extern int GLTFRESOURCES_LIT_SHEEN_OFFSET;
extern int GLTFRESOURCES_LIT_SHEEN_SIZE;
}
#define GLTFRESOURCES_LIT_FADE_DATA (GLTFRESOURCES_PACKAGE + GLTFRESOURCES_LIT_FADE_OFFSET)
#define GLTFRESOURCES_LIT_OPAQUE_DATA (GLTFRESOURCES_PACKAGE + GLTFRESOURCES_LIT_OPAQUE_OFFSET)
#define GLTFRESOURCES_LIT_MASKED_DATA (GLTFRESOURCES_PACKAGE + GLTFRESOURCES_LIT_MASKED_OFFSET)
#define GLTFRESOURCES_SPECULARGLOSSINESS_FADE_DATA (GLTFRESOURCES_PACKAGE + GLTFRESOURCES_SPECULARGLOSSINESS_FADE_OFFSET)
#define GLTFRESOURCES_SPECULARGLOSSINESS_OPAQUE_DATA (GLTFRESOURCES_PACKAGE + GLTFRESOURCES_SPECULARGLOSSINESS_OPAQUE_OFFSET)
#define GLTFRESOURCES_SPECULARGLOSSINESS_MASKED_DATA (GLTFRESOURCES_PACKAGE + GLTFRESOURCES_SPECULARGLOSSINESS_MASKED_OFFSET)
#define GLTFRESOURCES_UNLIT_FADE_DATA (GLTFRESOURCES_PACKAGE + GLTFRESOURCES_UNLIT_FADE_OFFSET)
#define GLTFRESOURCES_UNLIT_OPAQUE_DATA (GLTFRESOURCES_PACKAGE + GLTFRESOURCES_UNLIT_OPAQUE_OFFSET)
#define GLTFRESOURCES_UNLIT_MASKED_DATA (GLTFRESOURCES_PACKAGE + GLTFRESOURCES_UNLIT_MASKED_OFFSET)
#define GLTFRESOURCES_LIT_VOLUME_DATA (GLTFRESOURCES_PACKAGE + GLTFRESOURCES_LIT_VOLUME_OFFSET)
#define GLTFRESOURCES_LIT_TRANSMISSION_DATA (GLTFRESOURCES_PACKAGE + GLTFRESOURCES_LIT_TRANSMISSION_OFFSET)
#define GLTFRESOURCES_LIT_SHEEN_DATA (GLTFRESOURCES_PACKAGE + GLTFRESOURCES_LIT_SHEEN_OFFSET)
#endif

View File

@@ -0,0 +1,16 @@
#ifndef GLTFRESOURCES_LITE_H_
#define GLTFRESOURCES_LITE_H_
#include <stdint.h>
extern "C" {
extern const uint8_t GLTFRESOURCES_LITE_PACKAGE[];
extern int GLTFRESOURCES_LITE_LIT_OPAQUE_OFFSET;
extern int GLTFRESOURCES_LITE_LIT_OPAQUE_SIZE;
extern int GLTFRESOURCES_LITE_LIT_FADE_OFFSET;
extern int GLTFRESOURCES_LITE_LIT_FADE_SIZE;
}
#define GLTFRESOURCES_LITE_LIT_OPAQUE_DATA (GLTFRESOURCES_LITE_PACKAGE + GLTFRESOURCES_LITE_LIT_OPAQUE_OFFSET)
#define GLTFRESOURCES_LITE_LIT_FADE_DATA (GLTFRESOURCES_LITE_PACKAGE + GLTFRESOURCES_LITE_LIT_FADE_OFFSET)
#endif