diff --git a/android/gltfio-android/src/main/cpp/AssetLoader.cpp b/android/gltfio-android/src/main/cpp/AssetLoader.cpp index 42f22c35cc..7c4128adc5 100644 --- a/android/gltfio-android/src/main/cpp/AssetLoader.cpp +++ b/android/gltfio-android/src/main/cpp/AssetLoader.cpp @@ -69,7 +69,7 @@ public: jclass providerClass = env->GetObjectClass(provider); mCreateMaterialInstance = env->GetMethodID(providerClass, "createMaterialInstance", - "(L" JAVA_MATERIAL_KEY ";[ILjava/lang/String;)Lcom/google/android/filament/MaterialInstance;"); + "(L" JAVA_MATERIAL_KEY ";[ILjava/lang/String;Ljava/lang/String;)Lcom/google/android/filament/MaterialInstance;"); assert_invariant(mCreateMaterialInstance); mGetMaterials = env->GetMethodID(providerClass, "getMaterials", @@ -89,7 +89,7 @@ public: delete mPreviousMaterials; } - MaterialInstance* createMaterialInstance(MaterialKey* config, UvMap* uvmap, const char* label) override { + MaterialInstance* createMaterialInstance(MaterialKey* config, UvMap* uvmap, const char* label, const char* extras) override { // Create a Java object for the material key and copy the native fields into it. jobject javaKey = mEnv->NewObject(mMaterialKeyClass, mMaterialKeyConstructor); @@ -99,12 +99,15 @@ public: // Convert the optional label into a Java string. jstring stringLabel = label ? mEnv->NewStringUTF(label) : nullptr; + // Convert the optional extras into a Java string. + jstring stringExtras = extras ? mEnv->NewStringUTF(extras) : nullptr; + // Allocate space for the output argument. jintArray uvMapArray = mEnv->NewIntArray(8); // Call the Java-based material provider. jobject materialInstance = mEnv->CallObjectMethod(mJavaProvider, mCreateMaterialInstance, - javaKey, uvMapArray, stringLabel); + javaKey, uvMapArray, stringLabel, stringExtras); // Copy the UvMap results from the JVM array into the native array. if (uvmap) { @@ -125,6 +128,10 @@ public: mEnv->DeleteLocalRef(stringLabel); } + if (stringExtras) { + mEnv->DeleteLocalRef(stringExtras); + } + if (materialInstance == nullptr) { return nullptr; } diff --git a/android/gltfio-android/src/main/java/com/google/android/filament/gltfio/MaterialProvider.java b/android/gltfio-android/src/main/java/com/google/android/filament/gltfio/MaterialProvider.java index 92557a6625..b8feac09a2 100644 --- a/android/gltfio-android/src/main/java/com/google/android/filament/gltfio/MaterialProvider.java +++ b/android/gltfio-android/src/main/java/com/google/android/filament/gltfio/MaterialProvider.java @@ -99,9 +99,10 @@ public interface MaterialProvider { * @param uvmap Output argument that gets populated with a small table that maps from a glTF uv * index to a Filament uv index (0 = UNUSED, 1 = UV0, 2 = UV1). * @param label Optional tag that is not a part of the cache key. + * @param extras Optional extras as stringified JSON (not a part of the cache key). */ public @Nullable MaterialInstance createMaterialInstance(MaterialKey config, - @NonNull @Size(min = 8) int[] uvmap, @Nullable String label); + @NonNull @Size(min = 8) int[] uvmap, @Nullable String label, @Nullable String extras); /** * Creates and returns an array containing all cached materials. diff --git a/android/gltfio-android/src/main/java/com/google/android/filament/gltfio/UbershaderLoader.java b/android/gltfio-android/src/main/java/com/google/android/filament/gltfio/UbershaderLoader.java index 6b2a85979b..917a30171f 100644 --- a/android/gltfio-android/src/main/java/com/google/android/filament/gltfio/UbershaderLoader.java +++ b/android/gltfio-android/src/main/java/com/google/android/filament/gltfio/UbershaderLoader.java @@ -56,7 +56,7 @@ public class UbershaderLoader implements MaterialProvider { } public @Nullable MaterialInstance createMaterialInstance(MaterialKey config, - @NonNull @Size(min = 8) int[] uvmap, @Nullable String label) { + @NonNull @Size(min = 8) int[] uvmap, @Nullable String label, @Nullable String extras) { long nativeMaterialInstance = nCreateMaterialInstance(mNativeObject, config, uvmap, label); return nativeMaterialInstance == 0 ? null : new MaterialInstance(null, nativeMaterialInstance); } diff --git a/libs/gltfio/include/gltfio/MaterialProvider.h b/libs/gltfio/include/gltfio/MaterialProvider.h index fd3cc22404..8f12850f68 100644 --- a/libs/gltfio/include/gltfio/MaterialProvider.h +++ b/libs/gltfio/include/gltfio/MaterialProvider.h @@ -133,9 +133,10 @@ public: * @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. + * @param extras Optional extras as stringified JSON (not a part of the cache key). Don't store the pointer. */ virtual filament::MaterialInstance* createMaterialInstance(MaterialKey* config, UvMap* uvmap, - const char* label = "material") = 0; + const char* label = "material", const char* extras = nullptr) = 0; /** * Gets a weak reference to the array of cached materials. diff --git a/libs/gltfio/src/AssetLoader.cpp b/libs/gltfio/src/AssetLoader.cpp index 6a855aa2b0..67b31ea2cc 100644 --- a/libs/gltfio/src/AssetLoader.cpp +++ b/libs/gltfio/src/AssetLoader.cpp @@ -125,16 +125,18 @@ struct FAssetLoader : public AssetLoader { } void createAsset(const cgltf_data* srcAsset, size_t numInstances); - FFilamentInstance* createInstance(FFilamentAsset* primary, const cgltf_scene* scene); - void createEntity(const cgltf_node* node, Entity parent, bool enableLight, - FFilamentInstance* instance); - void createRenderable(const cgltf_node* node, Entity entity, const char* name); + FFilamentInstance* createInstance(FFilamentAsset* primary, const cgltf_data* srcAsset, + const cgltf_scene* scene); + void createEntity(const cgltf_data* srcAsset, const cgltf_node* node, Entity parent, + bool enableLight, FFilamentInstance* instance); + void createRenderable(const cgltf_data* srcAsset, const cgltf_node* node, Entity entity, + const char* name); bool createPrimitive(const cgltf_primitive* inPrim, Primitive* outPrim, const UvMap& uvmap, const char* name, MaterialInstance* mi); void createLight(const cgltf_light* light, Entity entity); void createCamera(const cgltf_camera* camera, Entity entity); - MaterialInstance* createMaterialInstance(const cgltf_material* inputMat, UvMap* uvmap, - bool vertexColor); + MaterialInstance* createMaterialInstance(const cgltf_data* srcAsset, + const cgltf_material* inputMat, UvMap* uvmap, bool vertexColor); void addTextureBinding(MaterialInstance* materialInstance, const char* parameterName, const cgltf_texture* srcTexture, bool srgb); bool primitiveHasVertexColor(const cgltf_primitive* inPrim) const; @@ -241,7 +243,7 @@ FilamentInstance* FAssetLoader::createInstance(FFilamentAsset* primary) { slog.e << "There is no scene in the asset." << io::endl; return nullptr; } - FFilamentInstance* instance = createInstance(primary, scene); + FFilamentInstance* instance = createInstance(primary, srcAsset, scene); // Import the skin data. This is normally done by ResourceLoader but dynamically created // instances are a bit special. @@ -291,14 +293,14 @@ void FAssetLoader::createAsset(const cgltf_data* srcAsset, size_t numInstances) // For each scene root, recursively create all entities. for (cgltf_size i = 0, len = scene->nodes_count; i < len; ++i) { cgltf_node** nodes = scene->nodes; - createEntity(nodes[i], mResult->mRoot, true, nullptr); + createEntity(srcAsset, nodes[i], mResult->mRoot, true, nullptr); } } else { // Create a separate entity hierarchy for each instance. Note that MeshCache (vertex // buffers and index buffers) and MatInstanceCache (materials and textures) help avoid // needless duplication of resources. for (size_t index = 0; index < numInstances; ++index) { - if (createInstance(mResult, scene) == nullptr) { + if (createInstance(mResult, srcAsset, scene) == nullptr) { mError = true; break; } @@ -331,7 +333,8 @@ void FAssetLoader::createAsset(const cgltf_data* srcAsset, size_t numInstances) } } -FFilamentInstance* FAssetLoader::createInstance(FFilamentAsset* primary, const cgltf_scene* scene) { +FFilamentInstance* FAssetLoader::createInstance(FFilamentAsset* primary, + const cgltf_data* srcAsset, const cgltf_scene* scene) { auto rootTransform = mTransformManager.getInstance(primary->mRoot); Entity instanceRoot = mEntityManager.create(); mTransformManager.create(instanceRoot, rootTransform); @@ -347,13 +350,13 @@ FFilamentInstance* FAssetLoader::createInstance(FFilamentAsset* primary, const c // For each scene root, recursively create all entities. for (cgltf_size i = 0, len = scene->nodes_count; i < len; ++i) { cgltf_node** nodes = scene->nodes; - createEntity(nodes[i], instanceRoot, false, instance); + createEntity(srcAsset, nodes[i], instanceRoot, false, instance); } return instance; } -void FAssetLoader::createEntity(const cgltf_node* node, Entity parent, bool enableLight, - FFilamentInstance* instance) { +void FAssetLoader::createEntity(const cgltf_data* srcAsset, const cgltf_node* node, Entity parent, + bool enableLight, FFilamentInstance* instance) { Entity entity = mEntityManager.create(); // Always create a transform component to reflect the original hierarchy. @@ -402,7 +405,7 @@ void FAssetLoader::createEntity(const cgltf_node* node, Entity parent, bool enab // If the node has a mesh, then create a renderable component. if (node->mesh) { - createRenderable(node, entity, name); + createRenderable(srcAsset, node, entity, name); } if (node->light && enableLight) { @@ -414,11 +417,12 @@ void FAssetLoader::createEntity(const cgltf_node* node, Entity parent, bool enab } for (cgltf_size i = 0, len = node->children_count; i < len; ++i) { - createEntity(node->children[i], entity, enableLight, instance); + createEntity(srcAsset, node->children[i], entity, enableLight, instance); } } -void FAssetLoader::createRenderable(const cgltf_node* node, Entity entity, const char* name) { +void FAssetLoader::createRenderable(const cgltf_data* srcAsset, const cgltf_node* node, + Entity entity, const char* name) { const cgltf_mesh* mesh = node->mesh; // Compute the transform relative to the root. @@ -460,7 +464,8 @@ void FAssetLoader::createRenderable(const cgltf_node* node, Entity entity, const // Create a material instance for this primitive or fetch one from the cache. UvMap uvmap {}; bool hasVertexColor = primitiveHasVertexColor(inputPrim); - MaterialInstance* mi = createMaterialInstance(inputPrim->material, &uvmap, hasVertexColor); + MaterialInstance* mi = createMaterialInstance(srcAsset, inputPrim->material, &uvmap, + hasVertexColor); if (!mi) { mError = true; continue; @@ -878,8 +883,8 @@ void FAssetLoader::createCamera(const cgltf_camera* camera, Entity entity) { mResult->mCameraEntities.push_back(entity); } -MaterialInstance* FAssetLoader::createMaterialInstance(const cgltf_material* inputMat, - UvMap* uvmap, bool vertexColor) { +MaterialInstance* FAssetLoader::createMaterialInstance(const cgltf_data* srcAsset, + const cgltf_material* inputMat, UvMap* uvmap, bool vertexColor) { intptr_t key = ((intptr_t) inputMat) ^ (vertexColor ? 1 : 0); auto iter = mResult->mMatInstanceCache.find(key); if (iter != mResult->mMatInstanceCache.end()) { @@ -995,9 +1000,17 @@ MaterialInstance* FAssetLoader::createMaterialInstance(const cgltf_material* inp break; } + // Check if this material has an extras string. + CString extras; + const cgltf_size extras_size = inputMat->extras.end_offset - inputMat->extras.start_offset; + if (extras_size > 0) { + extras = CString(srcAsset->json + inputMat->extras.start_offset, extras_size); + } + // This not only creates a material instance, it modifies the material key according to our // rendering constraints. For example, Filament only supports 2 sets of texture coordinates. - MaterialInstance* mi = mMaterials->createMaterialInstance(&matkey, uvmap, inputMat->name); + MaterialInstance* mi = mMaterials->createMaterialInstance(&matkey, uvmap, inputMat->name, + extras.c_str()); if (!mi) { slog.e << "No material with the specified requirements exists." << io::endl; return nullptr; diff --git a/libs/gltfio/src/MaterialGenerator.cpp b/libs/gltfio/src/MaterialGenerator.cpp index c832fe3893..8c1967defa 100644 --- a/libs/gltfio/src/MaterialGenerator.cpp +++ b/libs/gltfio/src/MaterialGenerator.cpp @@ -37,7 +37,7 @@ public: ~MaterialGenerator() override; MaterialInstance* createMaterialInstance(MaterialKey* config, UvMap* uvmap, - const char* label) override; + const char* label, const char* extras) override; size_t getMaterialsCount() const noexcept override; const Material* const* getMaterials() const noexcept override; @@ -533,7 +533,7 @@ static Material* createMaterial(Engine* engine, const MaterialKey& config, const } MaterialInstance* MaterialGenerator::createMaterialInstance(MaterialKey* config, UvMap* uvmap, - const char* label) { + const char* label, const char* extras) { constrainMaterial(config, uvmap); auto iter = mCache.find(*config); if (iter == mCache.end()) { diff --git a/libs/gltfio/src/UbershaderLoader.cpp b/libs/gltfio/src/UbershaderLoader.cpp index b9323b2b88..bef9eb53a9 100644 --- a/libs/gltfio/src/UbershaderLoader.cpp +++ b/libs/gltfio/src/UbershaderLoader.cpp @@ -45,7 +45,7 @@ public: ~UbershaderLoader() {} MaterialInstance* createMaterialInstance(MaterialKey* config, UvMap* uvmap, - const char* label) override; + const char* label, const char* extras) override; size_t getMaterialsCount() const noexcept override; const Material* const* getMaterials() const noexcept override; @@ -163,7 +163,7 @@ Material* UbershaderLoader::getMaterial(const MaterialKey& config) const { } MaterialInstance* UbershaderLoader::createMaterialInstance(MaterialKey* config, UvMap* uvmap, - const char* label) { + const char* label, const char* extras) { // Diagnostics are not supported with LOAD_UBERSHADERS, please use GENERATE_SHADERS instead. if (config->enableDiagnostics) { return nullptr;