/// <summary> /// Converts the given GLTF 2 material to a Unity Material. /// This is "best effort": we only interpret SOME, but not all GLTF material parameters. /// We try to be robust, and will always try to return *some* material rather than fail, /// even if crucial fields are missing or can't be parsed. /// </summary> /// <param name="gltfMat">The GLTF 2 material to convert.</param> /// <returns>The result of the conversion</returns> private UnityMaterial?ConvertGltf2Material(Gltf2Material gltfMat) { Material baseMaterial; { string alphaMode = gltfMat.alphaMode == null ? null : gltfMat.alphaMode.ToUpperInvariant(); switch (alphaMode) { case Gltf2Material.kAlphaModeOpaque: baseMaterial = gltfMat.doubleSided ? TbtSettings.Instance.m_BasePbrOpaqueDoubleSidedMaterial : TbtSettings.Instance.m_BasePbrOpaqueSingleSidedMaterial; break; case Gltf2Material.kAlphaModeBlend: baseMaterial = gltfMat.doubleSided ? TbtSettings.Instance.m_BasePbrBlendDoubleSidedMaterial : TbtSettings.Instance.m_BasePbrBlendSingleSidedMaterial; break; default: Debug.LogWarning($"Not yet supported: alphaMode={alphaMode}"); goto case Gltf2Material.kAlphaModeOpaque; } } if (gltfMat.pbrMetallicRoughness == null) { Debug.LogWarningFormat("Material #{0} has no PBR info.", gltfMat.gltfIndex); return(null); } return(CreateNewPbrMaterial(baseMaterial, gltfMat.name, gltfMat.pbrMetallicRoughness)); }
/// <summary> /// Converts the given GLTF 2 material to a Unity Material. /// This is "best effort": we only interpret SOME, but not all GLTF material parameters. /// We try to be robust, and will always try to return *some* material rather than fail, /// even if crucial fields are missing or can't be parsed. /// </summary> /// <param name="gltfMat">The GLTF 2 material to convert.</param> /// <returns>The result of the conversion</returns> private UnityMaterial?ConvertGltf2Material(Gltf2Material gltfMat) { TbtSettings.PbrMaterialInfo pbrInfo; string alphaMode = gltfMat.alphaMode == null ? null : gltfMat.alphaMode.ToUpperInvariant(); switch (alphaMode) { case null: case "": case Gltf2Material.kAlphaModeOpaque: pbrInfo = gltfMat.doubleSided ? TbtSettings.Instance.m_PbrOpaqueDoubleSided : TbtSettings.Instance.m_PbrOpaqueSingleSided; break; case Gltf2Material.kAlphaModeBlend: pbrInfo = gltfMat.doubleSided ? TbtSettings.Instance.m_PbrBlendDoubleSided : TbtSettings.Instance.m_PbrBlendSingleSided; break; default: Debug.LogWarning($"Not yet supported: alphaMode={alphaMode}"); goto case Gltf2Material.kAlphaModeOpaque; } if (gltfMat.pbrMetallicRoughness == null) { var specGloss = gltfMat.extensions?.KHR_materials_pbrSpecularGlossiness; if (specGloss != null) { // Try and make the best of pbrSpecularGlossiness. // Maybe it would be better to support "extensionsRequired" and raise an error // if the asset requires pbrSpecularGlossiness. gltfMat.pbrMetallicRoughness = new Gltf2Material.PbrMetallicRoughness { baseColorFactor = specGloss.diffuseFactor, baseColorTexture = specGloss.diffuseTexture, roughnessFactor = 1f - specGloss.glossinessFactor }; } else { Debug.LogWarningFormat("Material #{0} has no PBR info.", gltfMat.gltfIndex); return(null); } } return(CreateNewPbrMaterial(pbrInfo, gltfMat.name, gltfMat.pbrMetallicRoughness)); }
/// <summary> /// Converts the given GLTF 2 material to a Unity Material. /// This is "best effort": we only interpret SOME, but not all GLTF material parameters. /// We try to be robust, and will always try to return *some* material rather than fail, /// even if crucial fields are missing or can't be parsed. /// </summary> /// <param name="gltfMat">The GLTF 2 material to convert.</param> /// <returns>The result of the conversion</returns> private UnityMaterial?ConvertGltf2Material(Gltf2Material gltfMat) { TbtSettings.PbrMaterialInfo pbrInfo; #if TILT_BRUSH if (!gltfMat.doubleSided) { // TBT supports importing single-sided materials, forcing TB to try. // TB will import them but can't export single-sided because it lacks single-sided BD. // Single-sided BD // TB's copy of TbtSettings uses our double-sided BrushDescriptor for these single-sided // materials, so they'll export as double-sided. // TODO: create single-sided BrushDescriptors, push out to TBT, PT, Poly, ... Debug.LogWarning($"Not fully supported: single-sided"); } #endif string alphaMode = gltfMat.alphaMode == null ? null : gltfMat.alphaMode.ToUpperInvariant(); switch (alphaMode) { case null: case "": case Gltf2Material.kAlphaModeOpaque: pbrInfo = gltfMat.doubleSided ? TbtSettings.Instance.m_PbrOpaqueDoubleSided : TbtSettings.Instance.m_PbrOpaqueSingleSided; break; case Gltf2Material.kAlphaModeBlend: pbrInfo = gltfMat.doubleSided ? TbtSettings.Instance.m_PbrBlendDoubleSided : TbtSettings.Instance.m_PbrBlendSingleSided; break; default: Debug.LogWarning($"Not yet supported: alphaMode={alphaMode}"); goto case Gltf2Material.kAlphaModeOpaque; } if (gltfMat.pbrMetallicRoughness == null) { var specGloss = gltfMat.extensions?.KHR_materials_pbrSpecularGlossiness; if (specGloss != null) { // Try and make the best of pbrSpecularGlossiness. // Maybe it would be better to support "extensionsRequired" and raise an error // if the asset requires pbrSpecularGlossiness. gltfMat.pbrMetallicRoughness = new Gltf2Material.PbrMetallicRoughness { baseColorFactor = specGloss.diffuseFactor, baseColorTexture = specGloss.diffuseTexture, roughnessFactor = 1f - specGloss.glossinessFactor }; } else { Debug.LogWarningFormat("Material #{0} has no PBR info.", gltfMat.gltfIndex); return(null); } } return(CreateNewPbrMaterial(pbrInfo, gltfMat.name, gltfMat.pbrMetallicRoughness)); }
/// <summary> /// Looks up a built-in global material that corresponds to the given GLTF material. /// This will NOT create new materials; it will only look up global ones. /// </summary> /// <param name="gltfMaterial">The material to look up.</param> /// <param name="materialGuid">The guid parsed from the material name, or Guid.None</param> /// <returns>The global material that corresponds to the given GLTF material, /// if found. If not found, null.</returns> private static UnityMaterial?LookUpGlobalMaterial(GltfMaterialBase gltfMaterial) { #if TILT_BRUSH // Is this a Gltf1 blocks material? if (gltfMaterial.TechniqueExtras != null) { string surfaceShader = null; gltfMaterial.TechniqueExtras.TryGetValue("gvrss", out surfaceShader); if (surfaceShader != null) { // Blocks material. Look up the mapping in TbtSettings. if (TbtSettings.Instance.LookupSurfaceShaderMaterial(surfaceShader) is UnityMaterial um) { return(um); } else { Debug.LogWarningFormat("Unknown gvrss surface shader {0}", surfaceShader); } } } // This method of building Guid from a name is flimsy, and proven so by b/109698832. // As a patch fix, look specifically for Blocks material names. // Is this a Gltf2 Blocks material? Gltf2Material gltf2 = gltfMaterial as Gltf2Material; if (gltf2 != null) { if (gltfMaterial.name != null) { string url = "https://vr.google.com/shaders/w/gvrss/"; if (gltfMaterial.name.Equals("BlocksGem")) { return(TbtSettings.Instance.LookupSurfaceShaderMaterial(url + "gem.json")); } if (gltfMaterial.name.Equals("BlocksGlass")) { return(TbtSettings.Instance.LookupSurfaceShaderMaterial(url + "glass.json")); } if (gltfMaterial.name.Equals("BlocksPaper")) { return(TbtSettings.Instance.LookupSurfaceShaderMaterial(url + "paper.json")); } } } #endif // Check if it's a Tilt Brush material. Guid guid = ParseGuidFromMaterial(gltfMaterial); if (guid != Guid.Empty) { // Tilt Brush global material. PBR materials will use unrecognized guids; // these will be handled by the caller. BrushDescriptor desc; if (TbtSettings.Instance.TryGetBrush(guid, out desc)) { return(new UnityMaterial { material = desc.Material, #if TILT_BRUSH exportableMaterial = desc, #endif template = desc.Material }); } } return(null); }
/// Map gltfIndex values (ie, int indices) names to the objects they refer to public override void Dereference(IUriLoader uriLoader = null, PolyFormat gltfFormat = null) { // "dereference" all the indices scenePtr = scenes[scene]; for (int i = 0; i < buffers.Count; i++) { Gltf2Buffer buffer = buffers[i]; buffer.gltfIndex = i; if (uriLoader != null) { // Only id 0 may lack a URI; this indicates that it is the binary chunk. Debug.Assert(!(i != 0 && buffer.uri == null)); buffer.data = uriLoader.Load(buffer.uri); } else if (gltfFormat != null) { // Runtime import case; the uris refer to resource files in the PolyFormat. foreach (PolyFile resource in gltfFormat.resources) { if (resource.relativePath == buffer.uri) { buffer.data = new Reader(resource.contents); break; } } } } for (int i = 0; i < accessors.Count; i++) { accessors[i].gltfIndex = i; accessors[i].bufferViewPtr = bufferViews[accessors[i].bufferView]; } for (int i = 0; i < bufferViews.Count; i++) { bufferViews[i].gltfIndex = i; bufferViews[i].bufferPtr = buffers[bufferViews[i].buffer]; } for (int i = 0; i < meshes.Count; i++) { meshes[i].gltfIndex = i; foreach (var prim in meshes[i].primitives) { prim.attributePtrs = prim.attributes.ToDictionary( elt => elt.Key, elt => accessors[elt.Value]); prim.indicesPtr = accessors[prim.indices]; prim.materialPtr = materials[prim.material]; } } if (images != null) { for (int i = 0; i < images.Count; i++) { images[i].gltfIndex = i; } } if (textures != null) { for (int i = 0; i < textures.Count; i++) { textures[i].gltfIndex = i; textures[i].sourcePtr = images[textures[i].source]; } } for (int i = 0; i < materials.Count; i++) { Gltf2Material mat = materials[i]; mat.gltfIndex = i; DereferenceTextureInfo(mat.emissiveTexture); DereferenceTextureInfo(mat.normalTexture); if (mat.pbrMetallicRoughness != null) { DereferenceTextureInfo(mat.pbrMetallicRoughness.baseColorTexture); DereferenceTextureInfo(mat.pbrMetallicRoughness.metallicRoughnessTexture); } } for (int i = 0; i < nodes.Count; i++) { nodes[i].gltfIndex = i; Gltf2Node node = nodes[i]; if (node.mesh >= 0) { node.meshPtr = meshes[node.mesh]; } if (node.children != null) { node.childPtrs = node.children.Select(id => nodes[id]).ToList(); } } for (int i = 0; i < scenes.Count; i++) { scenes[i].gltfIndex = i; var thisScene = scenes[i]; if (thisScene.nodes != null) { thisScene.nodePtrs = thisScene.nodes.Select(index => nodes[index]).ToList(); } } }
/// Map gltfIndex values (ie, int indices) names to the objects they refer to public override void Dereference(bool isGlb, IUriLoader uriLoader = null) { // "dereference" all the indices scenePtr = scenes[scene]; for (int i = 0; i < buffers.Count; i++) { Gltf2Buffer buffer = buffers[i]; buffer.gltfIndex = i; if (buffer.uri == null && !(i == 0 && isGlb)) { Debug.LogErrorFormat("Buffer {0} isGlb {1} has null uri", i, isGlb); // leave the data buffer null return; } if (uriLoader != null) { buffer.data = uriLoader.Load(buffer.uri); } } for (int i = 0; i < accessors.Count; i++) { accessors[i].gltfIndex = i; accessors[i].bufferViewPtr = bufferViews[accessors[i].bufferView]; } for (int i = 0; i < bufferViews.Count; i++) { bufferViews[i].gltfIndex = i; bufferViews[i].bufferPtr = buffers[bufferViews[i].buffer]; } for (int i = 0; i < meshes.Count; i++) { meshes[i].gltfIndex = i; foreach (var prim in meshes[i].primitives) { prim.attributePtrs = prim.attributes.ToDictionary( elt => elt.Key, elt => accessors[elt.Value]); prim.indicesPtr = accessors[prim.indices]; prim.materialPtr = materials[prim.material]; } } if (images != null) { for (int i = 0; i < images.Count; i++) { images[i].gltfIndex = i; } } if (textures != null) { for (int i = 0; i < textures.Count; i++) { textures[i].gltfIndex = i; textures[i].sourcePtr = images[textures[i].source]; } } for (int i = 0; i < materials.Count; i++) { Gltf2Material mat = materials[i]; mat.gltfIndex = i; DereferenceTextureInfo(mat.emissiveTexture); DereferenceTextureInfo(mat.normalTexture); if (mat.pbrMetallicRoughness != null) { DereferenceTextureInfo(mat.pbrMetallicRoughness.baseColorTexture); DereferenceTextureInfo(mat.pbrMetallicRoughness.metallicRoughnessTexture); } DereferenceTextureInfo(mat.extensions?.KHR_materials_pbrSpecularGlossiness?.diffuseTexture); } for (int i = 0; i < nodes.Count; i++) { nodes[i].gltfIndex = i; Gltf2Node node = nodes[i]; if (node.mesh >= 0) { node.meshPtr = meshes[node.mesh]; } if (node.children != null) { node.childPtrs = node.children.Select(id => nodes[id]).ToList(); } } for (int i = 0; i < scenes.Count; i++) { scenes[i].gltfIndex = i; var thisScene = scenes[i]; if (thisScene.nodes != null) { thisScene.nodePtrs = thisScene.nodes.Select(index => nodes[index]).ToList(); } } }