Example #1
0
        /// <summary>
        /// コピー元のアバターのBlendShapeBindingを基に、コピー先のアバターのBlendShapeBindingを生成します。
        /// </summary>
        /// <param name="sourceBinding"></param>
        /// <param name="source"></param>
        /// <param name="destination"></param>
        /// <returns></returns>
        private static BlendShapeBinding CopyBlendShapeBinding(
            BlendShapeBinding binding,
            GameObject source,
            GameObject destination
            )
        {
            var sourceMesh = CopyVRMBlendShapes.GetMesh(binding, source);

            if (!sourceMesh)
            {
                return(binding);
            }

            var shapeKeyName = sourceMesh.GetBlendShapeName(binding.Index);

            var destinationMesh = CopyVRMBlendShapes.GetMesh(binding.RelativePath, destination);

            if (destinationMesh)
            {
                var index = destinationMesh.GetBlendShapeIndex(shapeKeyName);
                if (index != -1)
                {
                    binding.Index = index;
                    return(binding);
                }
            }

            return(CopyVRMBlendShapes.FindShapeKey(binding, shapeKeyName, destination));
        }
Example #2
0
        /// <summary>
        /// BlendShapeBindingに対応するメッシュを返します。
        /// </summary>
        /// <param name="binding"></param>
        /// <param name="avatar"></param>
        /// <returns></returns>
        private static Mesh GetMesh(BlendShapeBinding binding, GameObject avatar)
        {
            var mesh = CopyVRMBlendShapes.GetMesh(binding.RelativePath, avatar);

            if (!mesh || binding.Index > mesh.blendShapeCount)
            {
                return(null);
            }

            return(mesh);
        }
Example #3
0
        /// <summary>
        /// 指定されたシェイプキー名を持つメッシュを探し、見つからなければ後方一致するものを探し、BlendShapeBindingを書き替えて返します。
        /// </summary>
        /// <param name="binding"></param>
        /// <param name="shapeKeyName"></param>
        /// <param name="avatar"></param>
        /// <returns>見つからなかった場合は <c>binding</c> をそのまま返します。</returns>
        private static BlendShapeBinding FindShapeKey(BlendShapeBinding binding, string shapeKeyName, GameObject avatar)
        {
            var renderers = avatar.GetComponentsInChildren <SkinnedMeshRenderer>();

            foreach (var renderer in renderers)
            {
                Mesh mesh = renderer.sharedMesh;
                if (!mesh)
                {
                    continue;
                }

                var index = mesh.GetBlendShapeIndex(shapeKeyName);
                if (index == -1)
                {
                    continue;
                }

                binding.RelativePath = renderer.transform.RelativePathFrom(avatar.transform);
                binding.Index        = index;
                return(binding);
            }

            foreach (var renderer in renderers)
            {
                var mesh = renderer.sharedMesh;
                if (!mesh)
                {
                    continue;
                }

                for (var i = 0; i < mesh.blendShapeCount; i++)
                {
                    var name = mesh.GetBlendShapeName(i);
                    if (!name.EndsWith(shapeKeyName) && !shapeKeyName.EndsWith(name))
                    {
                        continue;
                    }

                    binding.RelativePath = renderer.transform.RelativePathFrom(avatar.transform);
                    binding.Index        = i;
                    return(binding);
                }
            }

            return(binding);
        }
Example #4
0
    /// <summary>
    /// 表示中のUIから表情プリセットを設定
    /// </summary>
    void SetClip(int index)
    {
        var clips  = Proxy.BlendShapeAvatar.Clips;
        var clip   = clips[index];
        var values = new List <BlendShapeBinding>();

        foreach (Transform child in Content.transform)
        {
            // IsBinaryは最初の一回だけ(気持ち悪いけど我慢する)
            var toggle = child.transform.Find("Toggle");
            if (toggle != null)
            {
                clip.IsBinary = toggle.GetComponent <Toggle>().isOn;
            }

            // ブレンドシェイプ
            var text   = child.transform.Find("Text");
            var slider = child.transform.Find("Slider");
            var input  = child.transform.Find("InputField");
            if (text != null && slider != null && input != null)
            {
                var value = slider.GetComponent <Slider>().value;
                if (value != 0)
                {
                    // UIに0でない値が設定されていた場合だけ表情プリセットに追加
                    var s2i   = slider.GetComponent <SliderToInput>();
                    var shape = new BlendShapeBinding();
                    shape.RelativePath = s2i.Mesh.transform.RelativePathFrom(Proxy.transform);
                    shape.Index        = s2i.Index;
                    shape.Weight       = value;
                    values.Add(shape);
                }
            }
        }

        clip.Values = values.ToArray();
        Proxy.BlendShapeAvatar.Clips[index] = clip;
    }
Example #5
0
        public Mesh BuildMesh(List <BlendShapeClip> blendShapeClips)
        {
            var blendShapeFrames = GetBlendShapeFrames(_srcMesh.blendShapeCount);

            var newMesh = Object.Instantiate(_srcMesh);

            newMesh.name = newMesh.name.Substring(0, newMesh.name.IndexOf('('));
            newMesh.ClearBlendShapes();

            var clipIndex = 0;

            foreach (var blendShapeClip in blendShapeClips)
            {
                // フォームが空の場合は飛ばす
                if (blendShapeClip == null || blendShapeClip.Values == null)
                {
                    continue;
                }

                var vCount   = _srcMesh.vertexCount;
                var vertices = new Vector3[vCount];
                var normals  = new Vector3[vCount];
                var tangents = new Vector3[vCount];

                var blendRatio   = new List <BlendRatio>();
                var baseBindings = new List <BlendShapeBinding>();
                var relativePath = "";
                foreach (var value in blendShapeClip.Values)
                {
                    if (Path.GetFileName(value.RelativePath) != _smr.name)
                    {
                        baseBindings.Add(value);
                        continue;
                    }

                    relativePath = value.RelativePath;
                    blendRatio.Add(new BlendRatio()
                    {
                        Index = value.Index, Weight = value.Weight / 100
                    });
                }
                // 関係するシェイプが無い場合は飛ばす
                if (blendRatio.Count == 0)
                {
                    continue;
                }
                for (int i = 0; i < vCount; i++)
                {
                    var v = Vector3.zero;
                    var n = Vector3.zero;
                    var t = Vector3.zero;
                    foreach (var mix in blendRatio)
                    {
                        v += blendShapeFrames[mix.Index].vertices[i] * mix.Weight;
                        n += blendShapeFrames[mix.Index].normals[i] * mix.Weight;
                        t += blendShapeFrames[mix.Index].tangents[i] * mix.Weight;
                    }

                    vertices[i] = v;
                    normals[i]  = n.normalized;
                    tangents[i] = t.normalized;
                }
                newMesh.AddBlendShapeFrame(blendShapeClip.BlendShapeName, 1.0f, vertices, normals, tangents);
                var mergedBinding = new BlendShapeBinding
                {
                    RelativePath = relativePath, Index = clipIndex, Weight = 100.0f
                };
                baseBindings.Add(mergedBinding);
                blendShapeClip.Values = baseBindings.ToArray();
                clipIndex++;
            }

            return(newMesh);
        }
    /// <summary>
    /// 表情プリセットにcsvから設定を読み込み
    /// </summary>
    public void Load(string path)
    {
        if (Vrm.VRM == null)
        {
            return;
        }

        // csv読み込み
        var list   = new List <List <string> >();
        var reader = new StreamReader(path);

        while (reader.Peek() >= 0)
        {
            list.Add(new List <string>());
            string[] cols = reader.ReadLine().Split(',');
            for (int n = 0; n < cols.Length; n++)
            {
                list[list.Count - 1].Add(cols[n]);
            }
        }
        reader.Close();

        // ブレンドシェイプの一致性確認
        var index  = 2;
        var meshes = Vrm.VRM.GetComponentsInChildren <SkinnedMeshRenderer>();

        foreach (SkinnedMeshRenderer mesh in meshes)
        {
            var meshPath = mesh.transform.RelativePathFrom(Vrm.VRM.transform);
            for (int i = 0; i < mesh.sharedMesh.blendShapeCount; i++)
            {
                var meshName = mesh.sharedMesh.GetBlendShapeName(i);
                if (list[index][CSV_COL_PATH] != meshPath ||
                    list[index][CSV_COL_INDEX] != i.ToString() ||
                    list[index][CSV_COL_NAME] != meshName)
                {
                    Text.text = "メッシュのパス\nブレンドシェイプ名\nが不一致";
                    CsvErrorCheckPlane.SetActive(true);
                    return;
                }
                index++;
            }
        }
        if (list.Count != index)
        {
            Text.text  = "ブレンドシェイプ数が不一致\n";
            Text.text += "CSV = " + (list.Count - 2) + "\n";
            Text.text += "VRM = " + (index - 2) + "\n";
            CsvErrorCheckPlane.SetActive(true);
            return;
        }

        // 表情プリセット設定
        var proxy = Vrm.VRM.GetComponent <VRMBlendShapeProxy>();

        proxy.BlendShapeAvatar.Clips.Clear();
        for (int col = CSV_COL_WEIGHT; col < list[CSV_ROW_LABEL].Count; col++)
        {
            var clip = ScriptableObject.CreateInstance <BlendShapeClip>();
            clip.BlendShapeName = list[CSV_ROW_LABEL][col];
            clip.IsBinary       = bool.Parse(list[CSV_ROW_ISBINARY][col]);

            var values = new List <BlendShapeBinding>();
            for (int row = CSV_ROW_WEIGHT; row < list.Count; row++)
            {
                if (list[row][col] != "0")
                {
                    // 0でない値が設定されていた場合だけ表情プリセットに追加
                    var shape = new BlendShapeBinding();
                    shape.RelativePath = list[row][CSV_COL_PATH];
                    shape.Index        = int.Parse(list[row][CSV_COL_INDEX]);
                    shape.Weight       = float.Parse(list[row][col]);
                    values.Add(shape);
                }
            }

            clip.Values = values.ToArray();
            proxy.BlendShapeAvatar.Clips.Add(clip);
        }

        BlendShape.Get();
    }
    /// <summary>
    /// 表情プリセットにcsvから設定を読み込み
    /// </summary>
    public void Load(string path)
    {
        if (Vrm.VRM == null)
        {
            return;
        }

        // csv読み込み
        var list   = new List <List <string> >();
        var reader = new StreamReader(path);

        while (reader.Peek() >= 0)
        {
            list.Add(new List <string>());
            string[] cols = reader.ReadLine().Split(',');
            for (int n = 0; n < cols.Length; n++)
            {
                list[list.Count - 1].Add(cols[n]);
            }
        }
        reader.Close();

        var index  = CSV_ROW_WEIGHT;
        var meshes = Vrm.VRM.GetComponentsInChildren <SkinnedMeshRenderer>();

        foreach (SkinnedMeshRenderer mesh in meshes)
        {
            var meshPath = mesh.transform.RelativePathFrom(Vrm.VRM.transform);
            for (int i = 0; i < mesh.sharedMesh.blendShapeCount; i++)
            {
                var meshName = mesh.sharedMesh.GetBlendShapeName(i);
                if (list[index][CSV_COL_PATH] != meshPath ||
                    list[index][CSV_COL_INDEX] != i.ToString() ||
                    list[index][CSV_COL_NAME] != meshName)
                {
                    // オブジェクトのパス、インデックス、ブレンドシェイプ名が一致しなければ中断
                    return;
                }
                index++;
            }
        }

        var proxy = Vrm.VRM.GetComponent <VRMBlendShapeProxy>();
        var clips = proxy.BlendShapeAvatar.Clips;

        if (clips.Count != list[CSV_ROW_LABEL].Count - CSV_COL_WEIGHT)
        {
            // 表情プリセットの数が一致しなければ中断
            return;
        }

        // 表情プリセット設定
        for (int col = CSV_COL_WEIGHT; col < list[CSV_ROW_LABEL].Count; col++)
        {
            var clip = clips[col - CSV_COL_WEIGHT];
            clip.IsBinary = bool.Parse(list[CSV_ROW_ISBINARY][col]);

            var values = new List <BlendShapeBinding>();
            for (int row = CSV_ROW_WEIGHT; row < list.Count; row++)
            {
                if (list[row][col] != "0")
                {
                    // 0でない値が設定されていた場合だけ表情プリセットに追加
                    var shape = new BlendShapeBinding();
                    shape.RelativePath = list[row][CSV_COL_PATH];
                    shape.Index        = int.Parse(list[row][CSV_COL_INDEX]);
                    shape.Weight       = float.Parse(list[row][col]);
                    values.Add(shape);
                }
            }

            clip.Values = values.ToArray();
            proxy.BlendShapeAvatar.Clips[col - CSV_COL_WEIGHT] = clip;
        }

        BlendShape.Get();
    }