遍历几个列表项的所有可能组合

时间:2019-03-04 12:23:14

标签: c# file unity3d

我有一个具有12个混合形状的面部模型,其中每个混合形状只是 0 (中性面部表情)和 1 (最大激活表情)之间的浮点值列表,但是我从头两个混合形状开始;也就是说,目前只有两个清单,例如微笑和怀疑的表情。

我的目的是浏览这两个列表中所有项目的所有可能组合,并制作面部动作的素材(电影剪辑),以显示blendshape值/权重的所有可能组合。 / p>

因此,我现在编写了以下代码以简化这种情况,仅适用于两个blendshapes,并在应用程序关闭时将它们保存到文件中。

public class BlendShapesVAL : MonoBehaviour
{
    private List<float> _weightValues_Preset1_smile   = new List<float>();
    private List<float> _weightValues_Preset2_skeptic = new List<float>();

    public bool _TransitionAnimation = true;
    public float _TransitionAnimationSpeed = 2f;

    public BlendShapesPresetController _BSPC;

    private List<float> _weightsList = new List<float>();

    public List<bool> _ActivationsList = new List<bool>();
    public List<string> _PresetsNamesList = new List<string>();


    private void Awake()
    {        
        _weightsList.Clear();
        _ActivationsList.Clear();
        for (int i = 0; i < _PresetsNamesList.Count; ++i)
        {
            _ActivationsList.Add(false);
            _weightsList.Add(0);
        }
     }


    private void Start()
    {
        if (_BSPC != null)
        {
            // . . .
        }
        else
        {
            _BSPC = GetComponent<BlendShapesPresetController>();
        }

        StartCoroutine("Interpolate");
    }


    /// <summary>
    /// Writes (i.e. saves) blendshape values to file when the application quits.
    /// </summary>
    /// 
    private void OnApplicationQuit()
    {
        SaveBlendShapesValues(_weightValues_Preset1_smile);
        SaveBlendShapesValues(_weightValues_Preset2_skeptic);

        PlayerPrefs.DeleteAll();
    }


    /// <summary>
    /// Goes thorugh all the possible combinations of blendshape weights.
    /// For now, only the first two though!
    /// </summary>
    /// 
    private IEnumerator Interpolate()
    {
        for (int i = 0; i <= 100; i++)
        {
            float weightValuesmile = (float)i / 100.0f;
            _BSPC.SetWeight("Preset1_smile", weightValuesmile);
            _weightValues_Preset1_smile.Add(weightValuesmile);

            for (int j = 0; j <= 100; j++)
            {
                float weightValueSkeptic = (float)j / 100.0f;
                _BSPC.SetWeight("Preset2_skeptic", weightValueSkeptic);
                _weightValues_Preset2_skeptic.Add(weightValueSkeptic);
            }

            yield return null;
        }
    }


    /// <summary>
    /// Writes (i.e. saves) blendshape values to file.
    /// <param name="blendShapesValuesFilePath">
    /// The path to the file that will store the list of float values;
    /// i.e. "Application.dataPath" plus the name of the CSV file.
    /// </param>
    /// <param name="values">
    /// The float values that are the blendshape weights.
    /// </param>
    /// </summary>
    /// 
    private static void SaveBlendShapesValues(List<float> values)
    {
        List<string> lines = new List<string>
        {
            /// Add a header row for the labels.
            "TimeStamp,Preset1_smile,Preset2_skeptic"
        };

        foreach (var value in values)
        {
            /// Iterate through all the elements.
            lines.Add(DateTime.Now + "," + value);
        }

        /// Load the old counter.
        int counter = PlayerPrefs.GetInt("_counter_", 0);

        /// Concatenate the file name constituents and combine it with the application data path.
        string fileName = string.Format("BlendShapesValues_{0}.csv", counter.ToString() );
        string tempPath = Path.Combine(Application.dataPath, fileName);

        try
        {            
            File.WriteAllLines(tempPath, lines.ToArray() );
            Debug.Log("Saved blendshape weight values to: " + tempPath);

            /// Increment the counter.
            counter++;

            /// Save the current counter.
            PlayerPrefs.SetInt("_counter_", counter);
            PlayerPrefs.Save();
        }
        catch (Exception e)
        {
            Debug.LogWarning("Failed to save to PlayerPrefs: " + tempPath);
            Debug.LogWarning("Error: " + e.Message);
        }        
    }
}

在Unity编辑器中,混合形状显示的值为0到100,因此我在代码中进行了转换,如以下屏幕截图所示:

enter image description here

第一个文件具有 101 个值(0 ... 100以及列标签的第一行),可以在此屏幕截图中看到一个代码段:

enter image description here

第二个文件具有 10201 值。我的第一个问题是:考虑到随着我添加更多列表(即blendshapes)而导致值的大幅增长,这种在应用程序停止后将迭代值保存到文件的方法是否是一个好的解决方案?

我的第二个问题是我如何减慢迭代速度,因为(在第一个屏幕截图中)微笑值从0开始计数到100,并且我可以看到它们(脸部缓慢移动一种可见的方式),但在这种情况下,我注意到第二个列表(怀疑者)显然立即跳到了100个,因此执行起来是如此之快,以至于Win屏幕录像机无法将其记录下来...

1 个答案:

答案 0 :(得分:1)

好吧,我不确定这可能是评论还是答案,所以请让我知道我是否缺少某些东西。

对于您的第一个问题,如果您认为人类无法读取这些保存的文件还可以,我建议您使用BinaryReader。因为保存的文件的大小会更小,并且当您想读回它们以制作剪辑时,它会更快地读取它。另外,考虑到要有12个混合形状及其组合,此文件可能很大。

第二个问题的迭代次数跳到100,因为只有在内循环完成时才屈服。因此,在每个帧中,将对1个微笑表示怀疑的组合添加到列表中。我建议对这种任务使用多线程或Unity作业系统,因为使用12个blendshapes和所有组合可能在计算上成本很高。

让我知道我能否进一步提供帮助。祝好运!