gltfio: support material extras
This commit is contained in:
committed by
Philip Rideout
parent
785f7de25d
commit
45054eece9
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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()) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user