예제 #1
0
        public static void WriteAnimationWithSampleCurves(glTF gltf, AnimationWithSampleCurves animationWithCurve, string animationName, int bufferIndex)
        {
            foreach (var kv in animationWithCurve.SamplerMap)
            {
                var sampler = animationWithCurve.Animation.samplers[kv.Key];

                float min = float.PositiveInfinity;
                float max = float.NegativeInfinity;
                foreach (float value in kv.Value.Input)
                {
                    if (value < min)
                    {
                        min = value;
                    }
                    if (value > max)
                    {
                        max = value;
                    }
                }

                var inputAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(
                    bufferIndex,
                    kv.Value.Input,
                    glBufferTarget.NONE,
                    new float[] { min },
                    new float[] { max });
                sampler.input = inputAccessorIndex;


                var outputAccessorIndex =
                    gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, kv.Value.Output);
                sampler.output = outputAccessorIndex;

                // modify accessors
                var outputAccessor = gltf.accessors[outputAccessorIndex];
                var channel        = animationWithCurve.Animation.channels.First(x => x.sampler == kv.Key);
                switch (glTFAnimationTarget.GetElementCount(channel.target.path))
                {
                case 1:
                    outputAccessor.type = "SCALAR";
                    //outputAccessor.count = ;
                    break;

                case 3:
                    outputAccessor.type   = "VEC3";
                    outputAccessor.count /= 3;
                    break;

                case 4:
                    outputAccessor.type   = "VEC4";
                    outputAccessor.count /= 4;
                    break;

                default:
                    throw new NotImplementedException();
                }
            }

            animationWithCurve.Animation.name = animationName;
            gltf.animations.Add(animationWithCurve.Animation);
        }
예제 #2
0
        static gltfMorphTarget ExportMorphTarget(glTF gltf, int bufferIndex,
                                                 Mesh mesh, int j,
                                                 bool useSparseAccessorForMorphTarget,
                                                 bool exportOnlyBlendShapePosition)
        {
            var blendShapeVertices = mesh.vertices;
            var usePosition        = blendShapeVertices != null && blendShapeVertices.Length > 0;

            var blendShapeNormals = mesh.normals;
            var useNormal         = usePosition && blendShapeNormals != null && blendShapeNormals.Length == blendShapeVertices.Length;
            // var useNormal = usePosition && blendShapeNormals != null && blendShapeNormals.Length == blendShapeVertices.Length && !exportOnlyBlendShapePosition;

            var blendShapeTangents = mesh.tangents.Select(y => (Vector3)y).ToArray();
            //var useTangent = usePosition && blendShapeTangents != null && blendShapeTangents.Length == blendShapeVertices.Length;
            var useTangent = false;

            var frameCount = mesh.GetBlendShapeFrameCount(j);

            mesh.GetBlendShapeFrameVertices(j, frameCount - 1, blendShapeVertices, blendShapeNormals, null);

            var blendShapePositionAccessorIndex = -1;
            var blendShapeNormalAccessorIndex   = -1;
            var blendShapeTangentAccessorIndex  = -1;

            if (useSparseAccessorForMorphTarget)
            {
                var accessorCount = blendShapeVertices.Length;
                var sparseIndices = Enumerable.Range(0, blendShapeVertices.Length)
                                    .Where(x => UseSparse(
                                               usePosition, blendShapeVertices[x],
                                               useNormal, blendShapeNormals[x],
                                               useTangent, blendShapeTangents[x]))
                                    .ToArray()
                ;

                if (sparseIndices.Length == 0)
                {
                    usePosition = false;
                    useNormal   = false;
                    useTangent  = false;
                }
                else
                {
                    Debug.LogFormat("Sparse {0}/{1}", sparseIndices.Length, mesh.vertexCount);
                }

                /*
                 * var vertexSize = 12;
                 * if (useNormal) vertexSize += 12;
                 * if (useTangent) vertexSize += 24;
                 * var sparseBytes = (4 + vertexSize) * sparseIndices.Length;
                 * var fullBytes = (vertexSize) * blendShapeVertices.Length;
                 * Debug.LogFormat("Export sparse: {0}/{1}bytes({2}%)",
                 *  sparseBytes, fullBytes, (int)((float)sparseBytes / fullBytes)
                 *  );
                 */

                var sparseIndicesViewIndex = -1;
                if (usePosition)
                {
                    sparseIndicesViewIndex = gltf.ExtendBufferAndGetViewIndex(bufferIndex, sparseIndices);

                    blendShapeVertices = sparseIndices.Select(x => blendShapeVertices[x].ReverseZ()).ToArray();
                    blendShapePositionAccessorIndex = gltf.ExtendSparseBufferAndGetAccessorIndex(bufferIndex, accessorCount,
                                                                                                 blendShapeVertices,
                                                                                                 sparseIndices, sparseIndicesViewIndex,
                                                                                                 glBufferTarget.ARRAY_BUFFER);
                }

                if (useNormal)
                {
                    blendShapeNormals             = sparseIndices.Select(x => blendShapeNormals[x].ReverseZ()).ToArray();
                    blendShapeNormalAccessorIndex = gltf.ExtendSparseBufferAndGetAccessorIndex(bufferIndex, accessorCount,
                                                                                               blendShapeNormals,
                                                                                               sparseIndices, sparseIndicesViewIndex,
                                                                                               glBufferTarget.ARRAY_BUFFER);
                }

                if (useTangent)
                {
                    blendShapeTangents             = sparseIndices.Select(x => blendShapeTangents[x].ReverseZ()).ToArray();
                    blendShapeTangentAccessorIndex = gltf.ExtendSparseBufferAndGetAccessorIndex(bufferIndex, accessorCount,
                                                                                                blendShapeTangents, sparseIndices, sparseIndicesViewIndex,
                                                                                                glBufferTarget.ARRAY_BUFFER);
                }
            }
            else
            {
                for (int i = 0; i < blendShapeVertices.Length; ++i)
                {
                    blendShapeVertices[i] = blendShapeVertices[i].ReverseZ();
                }
                if (usePosition)
                {
                    blendShapePositionAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex,
                                                                                           blendShapeVertices,
                                                                                           glBufferTarget.ARRAY_BUFFER);
                }

                if (useNormal)
                {
                    for (int i = 0; i < blendShapeNormals.Length; ++i)
                    {
                        blendShapeNormals[i] = blendShapeNormals[i].ReverseZ();
                    }
                    blendShapeNormalAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex,
                                                                                         blendShapeNormals,
                                                                                         glBufferTarget.ARRAY_BUFFER);
                }

                if (useTangent)
                {
                    for (int i = 0; i < blendShapeTangents.Length; ++i)
                    {
                        blendShapeTangents[i] = blendShapeTangents[i].ReverseZ();
                    }
                    blendShapeTangentAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex,
                                                                                          blendShapeTangents,
                                                                                          glBufferTarget.ARRAY_BUFFER);
                }
            }

            if (blendShapePositionAccessorIndex != -1)
            {
                gltf.accessors[blendShapePositionAccessorIndex].min = blendShapeVertices.Aggregate(blendShapeVertices[0], (a, b) => new Vector3(Mathf.Min(a.x, b.x), Math.Min(a.y, b.y), Mathf.Min(a.z, b.z))).ToArray();
                gltf.accessors[blendShapePositionAccessorIndex].max = blendShapeVertices.Aggregate(blendShapeVertices[0], (a, b) => new Vector3(Mathf.Max(a.x, b.x), Math.Max(a.y, b.y), Mathf.Max(a.z, b.z))).ToArray();
            }

            return(new gltfMorphTarget
            {
                POSITION = blendShapePositionAccessorIndex,
                NORMAL = blendShapeNormalAccessorIndex,
                TANGENT = blendShapeTangentAccessorIndex,
            });
        }
예제 #3
0
        static glTFMesh ExportPrimitives(glTF gltf, int bufferIndex,
                                         string rendererName,
                                         Mesh mesh, Material[] materials,
                                         List <Material> unityMaterials)
        {
            var positions             = mesh.vertices.Select(y => y.ReverseZ()).ToArray();
            var positionAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, positions, glBufferTarget.ARRAY_BUFFER);

            gltf.accessors[positionAccessorIndex].min = positions.Aggregate(positions[0], (a, b) => new Vector3(Mathf.Min(a.x, b.x), Math.Min(a.y, b.y), Mathf.Min(a.z, b.z))).ToArray();
            gltf.accessors[positionAccessorIndex].max = positions.Aggregate(positions[0], (a, b) => new Vector3(Mathf.Max(a.x, b.x), Math.Max(a.y, b.y), Mathf.Max(a.z, b.z))).ToArray();

            var normalAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, mesh.normals.Select(y => y.normalized.ReverseZ()).ToArray(), glBufferTarget.ARRAY_BUFFER);

#if GLTF_EXPORT_TANGENTS
            var tangentAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, mesh.tangents.Select(y => y.ReverseZ()).ToArray(), glBufferTarget.ARRAY_BUFFER);
#endif
            var uvAccessorIndex    = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, mesh.uv.Select(y => y.ReverseUV()).ToArray(), glBufferTarget.ARRAY_BUFFER);
            var colorAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, mesh.colors, glBufferTarget.ARRAY_BUFFER);

            var boneweights         = mesh.boneWeights;
            var weightAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, boneweights.Select(y => new Vector4(y.weight0, y.weight1, y.weight2, y.weight3)).ToArray(), glBufferTarget.ARRAY_BUFFER);
            var jointsAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, boneweights.Select(y => new UShort4((ushort)y.boneIndex0, (ushort)y.boneIndex1, (ushort)y.boneIndex2, (ushort)y.boneIndex3)).ToArray(), glBufferTarget.ARRAY_BUFFER);

            var attributes = new glTFAttributes
            {
                POSITION = positionAccessorIndex,
            };
            if (normalAccessorIndex != -1)
            {
                attributes.NORMAL = normalAccessorIndex;
            }
#if GLTF_EXPORT_TANGENTS
            if (tangentAccessorIndex != -1)
            {
                attributes.TANGENT = tangentAccessorIndex;
            }
#endif
            if (uvAccessorIndex != -1)
            {
                attributes.TEXCOORD_0 = uvAccessorIndex;
            }
            if (colorAccessorIndex != -1)
            {
                attributes.COLOR_0 = colorAccessorIndex;
            }
            if (weightAccessorIndex != -1)
            {
                attributes.WEIGHTS_0 = weightAccessorIndex;
            }
            if (jointsAccessorIndex != -1)
            {
                attributes.JOINTS_0 = jointsAccessorIndex;
            }

            var gltfMesh = new glTFMesh(mesh.name);
            for (int j = 0; j < mesh.subMeshCount; ++j)
            {
                var indices = TriangleUtil.FlipTriangle(mesh.GetIndices(j)).Select(y => (uint)y).ToArray();
                var indicesAccessorIndex = gltf.ExtendBufferAndGetAccessorIndex(bufferIndex, indices, glBufferTarget.ELEMENT_ARRAY_BUFFER);

                if (j >= materials.Length)
                {
                    Debug.LogWarningFormat("{0}.materials is not enough", rendererName);
                    break;
                }

                gltfMesh.primitives.Add(new glTFPrimitives
                {
                    attributes = attributes,
                    indices    = indicesAccessorIndex,
                    mode       = 4, // triangles ?
                    material   = unityMaterials.IndexOf(materials[j])
                });
            }
            return(gltfMesh);
        }
예제 #4
0
 public IEnumerator ProcessCoroutine(glTF gltf, IStorage storage)
 {
     ProcessOnAnyThread(gltf, storage);
     yield return(ProcessOnMainThreadCoroutine(gltf));
 }
예제 #5
0
 public void ProcessOnAnyThread(glTF gltf, IStorage storage)
 {
     m_textureLoader.ProcessOnAnyThread(gltf, storage);
 }
예제 #6
0
파일: UniGLTFTests.cs 프로젝트: notargs/VCI
        public void SameMeshButDifferentMaterialExport()
        {
            var go = new GameObject("same_mesh");

            try
            {
                var shader = Shader.Find("Unlit/Color");

                var cubeA = GameObject.CreatePrimitive(PrimitiveType.Cube);
                {
                    cubeA.transform.SetParent(go.transform);
                    var material = new Material(shader);
                    material.name  = "red";
                    material.color = Color.red;
                    cubeA.GetComponent <Renderer>().sharedMaterial = material;
                }

                {
                    var cubeB = GameObject.Instantiate(cubeA);
                    cubeB.transform.SetParent(go.transform);
                    var material = new Material(shader);
                    material.color = Color.blue;
                    material.name  = "blue";
                    cubeB.GetComponent <Renderer>().sharedMaterial = material;

                    Assert.AreEqual(cubeB.GetComponent <MeshFilter>().sharedMesh, cubeA.GetComponent <MeshFilter>().sharedMesh);
                }

                // export
                var gltf = new glTF();
                var json = default(string);
                using (var exporter = new gltfExporter(gltf))
                {
                    exporter.Prepare(go);
                    exporter.Export();

                    json = gltf.ToJson();
                }

                Assert.AreEqual(2, gltf.meshes.Count);

                var red = gltf.materials[gltf.meshes[0].primitives[0].material];
                Assert.AreEqual(new float[] { 1, 0, 0, 1 }, red.pbrMetallicRoughness.baseColorFactor);

                var blue = gltf.materials[gltf.meshes[1].primitives[0].material];
                Assert.AreEqual(new float[] { 0, 0, 1, 1 }, blue.pbrMetallicRoughness.baseColorFactor);

                Assert.AreEqual(2, gltf.nodes.Count);

                Assert.AreNotEqual(gltf.nodes[0].mesh, gltf.nodes[1].mesh);

                // import
                {
                    var context = new ImporterContext();
                    context.ParseJson(json, new SimpleStorage(new ArraySegment <byte>(new byte[1024 * 1024])));
                    //Debug.LogFormat("{0}", context.Json);
                    context.Load();

                    var importedRed         = context.Root.transform.GetChild(0);
                    var importedRedMaterial = importedRed.GetComponent <Renderer>().sharedMaterial;
                    Assert.AreEqual("red", importedRedMaterial.name);
                    Assert.AreEqual(Color.red, importedRedMaterial.color);

                    var importedBlue         = context.Root.transform.GetChild(1);
                    var importedBlueMaterial = importedBlue.GetComponent <Renderer>().sharedMaterial;
                    Assert.AreEqual("blue", importedBlueMaterial.name);
                    Assert.AreEqual(Color.blue, importedBlueMaterial.color);
                }

                // import new version
                {
                    var context = new ImporterContext
                    {
                        SerializerType = SerializerTypes.UniJSON
                    };
                    context.ParseJson(json, new SimpleStorage(new ArraySegment <byte>(new byte[1024 * 1024])));
                    //Debug.LogFormat("{0}", context.Json);
                    context.Load();

                    var importedRed         = context.Root.transform.GetChild(0);
                    var importedRedMaterial = importedRed.GetComponent <Renderer>().sharedMaterial;
                    Assert.AreEqual("red", importedRedMaterial.name);
                    Assert.AreEqual(Color.red, importedRedMaterial.color);

                    var importedBlue         = context.Root.transform.GetChild(1);
                    var importedBlueMaterial = importedBlue.GetComponent <Renderer>().sharedMaterial;
                    Assert.AreEqual("blue", importedBlueMaterial.name);
                    Assert.AreEqual(Color.blue, importedBlueMaterial.color);
                }
            }
            finally
            {
                GameObject.DestroyImmediate(go);
            }
        }
예제 #7
0
 public void Process(glTF gltf, IStorage storage)
 {
     ProcessOnAnyThread(gltf, storage);
     ProcessOnMainThreadCoroutine(gltf).CoroutinetoEnd();
 }
예제 #8
0
파일: UniGLTFTests.cs 프로젝트: notargs/VCI
        public void GlTFToJsonTest()
        {
            var gltf = new glTF();

            using (var exporter = new gltfExporter(gltf))
            {
                exporter.Prepare(CreateSimpleScene());
                exporter.Export();
            }

            var expected = gltf.ToJson().ParseAsJson();

            expected.AddKey(Utf8String.From("meshes"));
            expected.AddValue(default(ArraySegment <byte>), ValueNodeType.Array);
            expected["meshes"].AddValue(default(ArraySegment <byte>), ValueNodeType.Object);

            var mesh = expected["meshes"][0];

            mesh.AddKey(Utf8String.From("name"));
            mesh.AddValue(Utf8String.From(JsonString.Quote("test")).Bytes, ValueNodeType.String);
            mesh.AddKey(Utf8String.From("primitives"));
            mesh.AddValue(default(ArraySegment <byte>), ValueNodeType.Array);
            mesh["primitives"].AddValue(default(ArraySegment <byte>), ValueNodeType.Object);

            var primitive = mesh["primitives"][0];

            primitive.AddKey(Utf8String.From("mode"));
            primitive.AddValue(Utf8String.From("0").Bytes, ValueNodeType.Integer);
            primitive.AddKey(Utf8String.From("indices"));
            primitive.AddValue(Utf8String.From("0").Bytes, ValueNodeType.Integer);
            primitive.AddKey(Utf8String.From("material"));
            primitive.AddValue(Utf8String.From("0").Bytes, ValueNodeType.Integer);
            primitive.AddKey(Utf8String.From("attributes"));
            primitive.AddValue(default(ArraySegment <byte>), ValueNodeType.Object);
            primitive["attributes"].AddKey(Utf8String.From("POSITION"));
            primitive["attributes"].AddValue(Utf8String.From("0").Bytes, ValueNodeType.Integer);
            primitive.AddKey(Utf8String.From("targets"));
            primitive.AddValue(default(ArraySegment <byte>), ValueNodeType.Array);
            primitive["targets"].AddValue(default(ArraySegment <byte>), ValueNodeType.Object);
            primitive["targets"][0].AddKey(Utf8String.From("POSITION"));
            primitive["targets"][0].AddValue(Utf8String.From("1").Bytes, ValueNodeType.Integer);
            primitive["targets"].AddValue(default(ArraySegment <byte>), ValueNodeType.Object);
            primitive["targets"][1].AddKey(Utf8String.From("POSITION"));
            primitive["targets"][1].AddValue(Utf8String.From("2").Bytes, ValueNodeType.Integer);
            primitive["targets"][1].AddKey(Utf8String.From("TANGENT"));
            primitive["targets"][1].AddValue(Utf8String.From("0").Bytes, ValueNodeType.Integer);

            gltf.meshes.Add(new glTFMesh("test")
            {
                primitives = new List <glTFPrimitives>
                {
                    new glTFPrimitives
                    {
                        indices    = 0,
                        attributes = new glTFAttributes
                        {
                            POSITION = 0,
                            TANGENT  = -1 // should be removed
                        },
                        targets = new List <gltfMorphTarget>
                        {
                            new gltfMorphTarget
                            {
                                POSITION = 1,
                                TANGENT  = -1 // should be removed
                            },
                            new gltfMorphTarget
                            {
                                POSITION = 2,
                                TANGENT  = 0
                            }
                        }
                    }
                }
            });
            var actual = gltf.ToJson().ParseAsJson();

            Assert.AreEqual(expected, actual);
        }
예제 #9
0
 public static int ExtendBufferAndGetViewIndex <T>(this glTF gltf, int bufferIndex,
                                                   T[] array,
                                                   glBufferTarget target = glBufferTarget.NONE) where T : struct
 {
     return(ExtendBufferAndGetViewIndex(gltf, bufferIndex, new ArraySegment <T>(array), target));
 }
예제 #10
0
 public void ProcessOnAnyThread(glTF gltf, IStorage storage)
 {
 }
예제 #11
0
        public void ProcessOnAnyThread(glTF gltf, IStorage storage)
        {
            var imageIndex = gltf.GetImageIndexFromTextureIndex(m_textureIndex);

            m_segments = gltf.GetImageBytes(storage, imageIndex, out m_textureName);
        }
예제 #12
0
        /// StandardShader vaiables
        ///
        /// _Color
        /// _MainTex
        /// _Cutoff
        /// _Glossiness
        /// _Metallic
        /// _MetallicGlossMap
        /// _BumpScale
        /// _BumpMap
        /// _Parallax
        /// _ParallaxMap
        /// _OcclusionStrength
        /// _OcclusionMap
        /// _EmissionColor
        /// _EmissionMap
        /// _DetailMask
        /// _DetailAlbedoMap
        /// _DetailNormalMapScale
        /// _DetailNormalMap
        /// _UVSec
        /// _EmissionScaleUI
        /// _EmissionColorUI
        /// _Mode
        /// _SrcBlend
        /// _DstBlend
        /// _ZWrite
        public virtual Material CreateMaterial(glTF gltf, int i, glTFMaterial x)
        {
            var shader = m_shaderStore.GetShader(x);
            //Debug.LogFormat("[{0}]{1}", i, shader.name);
            var material = new Material(shader);

#if UNITY_EDITOR
            // textureImporter.SaveAndReimport(); may destory this material
            material.hideFlags = HideFlags.DontUnloadUnusedAsset;
#endif

            material.name = (x == null || string.IsNullOrEmpty(x.name))
                ? string.Format("material_{0:00}", i)
                : x.name
            ;

            if (x == null)
            {
                Debug.LogWarning("glTFMaterial is empty");
                return(material);
            }

            // unlit material
            if (x.extensions != null && x.extensions.KHR_materials_unlit != null)
            {
                // texture
                if (x.pbrMetallicRoughness.baseColorTexture != null)
                {
                    var texture = m_context.GetTexture(x.pbrMetallicRoughness.baseColorTexture.index);
                    if (texture != null)
                    {
                        material.mainTexture = texture.Texture;
                    }
                }

                // color
                if (x.pbrMetallicRoughness.baseColorFactor != null && x.pbrMetallicRoughness.baseColorFactor.Length == 4)
                {
                    var color = x.pbrMetallicRoughness.baseColorFactor;
                    material.color = new Color(color[0], color[1], color[2], color[3]);
                }

                //renderMode
                if (x.alphaMode == "OPAQUE")
                {
                    Utils.SetRenderMode(material, UniUnlitRenderMode.Opaque);
                }
                else if (x.alphaMode == "BLEND")
                {
                    Utils.SetRenderMode(material, UniUnlitRenderMode.Transparent);
                }
                else if (x.alphaMode == "MASK")
                {
                    Utils.SetRenderMode(material, UniUnlitRenderMode.Cutout);
                }
                else
                {
                    // default OPAQUE
                    Utils.SetRenderMode(material, UniUnlitRenderMode.Opaque);
                }

                // culling
                if (x.doubleSided)
                {
                    Utils.SetCullMode(material, UniUnlitCullMode.Off);
                }
                else
                {
                    Utils.SetCullMode(material, UniUnlitCullMode.Back);
                }

                // VColor
                if (gltf != null && gltf.MaterialHasVertexColor(x))
                {
                    Utils.SetVColBlendMode(material, UniUnlitVertexColorBlendOp.Multiply);
                }


                Utils.ValidateProperties(material, true);

                return(material);
            }

            // PBR material
            if (x.pbrMetallicRoughness != null)
            {
                if (x.pbrMetallicRoughness.baseColorFactor != null && x.pbrMetallicRoughness.baseColorFactor.Length == 4)
                {
                    var color = x.pbrMetallicRoughness.baseColorFactor;
                    material.color = new Color(color[0], color[1], color[2], color[3]);
                }

                if (x.pbrMetallicRoughness.baseColorTexture != null && x.pbrMetallicRoughness.baseColorTexture.index != -1)
                {
                    var texture = m_context.GetTexture(x.pbrMetallicRoughness.baseColorTexture.index);
                    if (texture != null)
                    {
                        material.mainTexture = texture.Texture;
                    }
                }

                if (x.pbrMetallicRoughness.metallicRoughnessTexture != null && x.pbrMetallicRoughness.metallicRoughnessTexture.index != -1)
                {
                    material.EnableKeyword("_METALLICGLOSSMAP");
                    var texture = Context.GetTexture(x.pbrMetallicRoughness.metallicRoughnessTexture.index);
                    if (texture != null)
                    {
                        var prop = "_MetallicGlossMap";
                        // Bake roughnessFactor values into a texture.
                        material.SetTexture(prop, texture.ConvertTexture(prop, x.pbrMetallicRoughness.roughnessFactor));
                    }

                    material.SetFloat("_Metallic", 1.0f);
                    // Set 1.0f as hard-coded. See: https://github.com/dwango/UniVRM/issues/212.
                    material.SetFloat("_GlossMapScale", 1.0f);
                }
                else
                {
                    material.SetFloat("_Metallic", x.pbrMetallicRoughness.metallicFactor);
                    material.SetFloat("_Glossiness", 1.0f - x.pbrMetallicRoughness.roughnessFactor);
                }
            }

            if (x.normalTexture != null && x.normalTexture.index != -1)
            {
                material.EnableKeyword("_NORMALMAP");
                var texture = Context.GetTexture(x.normalTexture.index);
                if (texture != null)
                {
                    var prop = "_BumpMap";
                    material.SetTexture(prop, texture.ConvertTexture(prop));
                    material.SetFloat("_BumpScale", x.normalTexture.scale);
                }
            }

            if (x.occlusionTexture != null && x.occlusionTexture.index != -1)
            {
                var texture = Context.GetTexture(x.occlusionTexture.index);
                if (texture != null)
                {
                    var prop = "_OcclusionMap";
                    material.SetTexture(prop, texture.ConvertTexture(prop));
                    material.SetFloat("_OcclusionStrength", x.occlusionTexture.strength);
                }
            }

            if (x.emissiveFactor != null ||
                (x.emissiveTexture != null && x.emissiveTexture.index != -1))
            {
                material.EnableKeyword("_EMISSION");
                material.globalIlluminationFlags &= ~MaterialGlobalIlluminationFlags.EmissiveIsBlack;

                if (x.emissiveFactor != null && x.emissiveFactor.Length == 3)
                {
                    material.SetColor("_EmissionColor", new Color(x.emissiveFactor[0], x.emissiveFactor[1], x.emissiveFactor[2]));
                }

                if (x.emissiveTexture != null && x.emissiveTexture.index != -1)
                {
                    var texture = Context.GetTexture(x.emissiveTexture.index);
                    if (texture != null)
                    {
                        material.SetTexture("_EmissionMap", texture.Texture);
                    }
                }
            }

            BlendMode blendMode = BlendMode.Opaque;
            // https://forum.unity.com/threads/standard-material-shader-ignoring-setfloat-property-_mode.344557/#post-2229980
            switch (x.alphaMode)
            {
            case "BLEND":
                blendMode = BlendMode.Fade;
                material.SetOverrideTag("RenderType", "Transparent");
                material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.SrcAlpha);
                material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
                material.SetInt("_ZWrite", 0);
                material.DisableKeyword("_ALPHATEST_ON");
                material.EnableKeyword("_ALPHABLEND_ON");
                material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
                material.renderQueue = 3000;
                break;

            case "MASK":
                blendMode = BlendMode.Cutout;
                material.SetOverrideTag("RenderType", "TransparentCutout");
                material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One);
                material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.Zero);
                material.SetInt("_ZWrite", 1);
                material.SetFloat("_Cutoff", x.alphaCutoff);
                material.EnableKeyword("_ALPHATEST_ON");
                material.DisableKeyword("_ALPHABLEND_ON");
                material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
                material.renderQueue = 2450;

                break;

            default:     // OPAQUE
                blendMode = BlendMode.Opaque;
                material.SetOverrideTag("RenderType", "");
                material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One);
                material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.Zero);
                material.SetInt("_ZWrite", 1);
                material.DisableKeyword("_ALPHATEST_ON");
                material.DisableKeyword("_ALPHABLEND_ON");
                material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
                material.renderQueue = -1;
                break;
            }

            material.SetFloat("_Mode", (float)blendMode);
            return(material);
        }