Search Unity

Blend Shapes Preset Tool [Released]

Discussion in 'Assets and Asset Store' started by kalagaan, Nov 8, 2017.

  1. kalagaan

    kalagaan

    Joined:
    May 27, 2012
    Posts:
    1,503
    Hello,
    thank you for the feedback,
    the blendshapePresetController overrides all the blendshapes included in the preset list, so it could interfere with other tools.
    I'll push a new version that will modify the blendshapes only if the weight has been modified by the API, and I'll add a Refresh() function to force the refresh if needed.
     
    vibedev and wetcircuit like this.
  2. HamFar

    HamFar

    Joined:
    Nov 16, 2014
    Posts:
    89
    I have a face model with 12 blendshapes and thanks to this amazing tool, I can manipulate the blendshapes! :cool:

    I am, however, starting off with only the first 2 blendshapes; i.e. only two lists for now, say smile and skeptic looks.

    My intention is to go through all the possible combinations of all the items in these two lists and make a footage (movie clip) of the facial movements, to display how all the possible combinations of blendshape values/weights look like.

    So, I wrote the following (code snippets from the tool are extremely helpful) to facilitate this scenario for only two blendshapes for now, and I save them to file as soon as the application closes:

    Code (CSharp):
    1.  
    2. public class BlendShapesVAL : MonoBehaviour
    3. {
    4.     private List<float> _weightValues_Preset1_smile   = new List<float>();
    5.     private List<float> _weightValues_Preset2_skeptic = new List<float>();
    6.  
    7.     public bool _TransitionAnimation = true;
    8.     public float _TransitionAnimationSpeed = 2f;
    9.  
    10.     public BlendShapesPresetController _BSPC;
    11.  
    12.     private List<float> _weightsList = new List<float>();
    13.  
    14.     public List<bool> _ActivationsList = new List<bool>();
    15.     public List<string> _PresetsNamesList = new List<string>();
    16.    
    17.  
    18.     private void Awake()
    19.     {      
    20.         _weightsList.Clear();
    21.         _ActivationsList.Clear();
    22.         for (int i = 0; i < _PresetsNamesList.Count; ++i)
    23.         {
    24.             _ActivationsList.Add(false);
    25.             _weightsList.Add(0);
    26.         }
    27.      }
    28.  
    29.  
    30.     private void Start()
    31.     {
    32.         if (_BSPC != null)
    33.         {
    34.            //
    35.         }
    36.         else
    37.         {
    38.             _BSPC = GetComponent<BlendShapesPresetController>();
    39.         }
    40.  
    41.         StartCoroutine("Interpolate");
    42.     }
    43.  
    44.  
    45.     /// <summary>
    46.     /// Writes (i.e. saves) blendshape values to file when the application quits.
    47.     /// </summary>
    48.     ///
    49.     private void OnApplicationQuit()
    50.     {
    51.         SaveBlendShapesValues(_weightValues_Preset1_smile);
    52.         SaveBlendShapesValues(_weightValues_Preset2_skeptic);
    53.  
    54.         PlayerPrefs.DeleteAll();
    55.     }
    56.  
    57.  
    58.     /// <summary>
    59.     /// Goes thorugh all the possible combinations of blendshape weights.
    60.     /// For now, only the first two though!
    61.     /// </summary>
    62.     ///
    63.     private IEnumerator Interpolate()
    64.     {
    65.         for (int i = 0; i <= 100; i++)
    66.         {
    67.             float weightValuesmile = (float)i / 100.0f;
    68.             _BSPC.SetWeight("Preset1_smile", weightValuesmile);
    69.             _weightValues_Preset1_smile.Add(weightValuesmile);
    70.  
    71.             for (int j = 0; j <= 100; j++)
    72.             {
    73.                 float weightValueSkeptic = (float)j / 100.0f;
    74.                 _BSPC.SetWeight("Preset2_skeptic", weightValueSkeptic);
    75.                 _weightValues_Preset2_skeptic.Add(weightValueSkeptic);
    76.             }
    77.  
    78.             yield return null;
    79.         }
    80.     }
    81.  
    82.  
    83.     /// <summary>
    84.     /// Writes (i.e. saves) blendshape values to file.
    85.     /// <param name="blendShapesValuesFilePath">
    86.     /// The path to the file that will store the list of float values;
    87.     /// i.e. "Application.dataPath" plus the name of the CSV file.
    88.     /// </param>
    89.     /// <param name="values">
    90.     /// The float values that are the blendshape weights.
    91.     /// </param>
    92.     /// </summary>
    93.     ///
    94.     private static void SaveBlendShapesValues(List<float> values)
    95.     {
    96.         List<string> lines = new List<string>
    97.         {
    98.             /// Add a header row for the labels.
    99.             "TimeStamp,Preset1_smile,Preset2_skeptic"
    100.         };
    101.  
    102.         foreach (var value in values)
    103.         {
    104.             /// Iterate through all the elements.
    105.             lines.Add(DateTime.Now + "," + value);
    106.         }
    107.  
    108.         /// Load the old counter.
    109.         int counter = PlayerPrefs.GetInt("_counter_", 0);
    110.  
    111.         /// Concatenate the file name constituents and combine it with the application data path.
    112.         string fileName = string.Format("BlendShapesValues_{0}.csv", counter.ToString() );
    113.         string tempPath = Path.Combine(Application.dataPath, fileName);
    114.  
    115.         try
    116.         {          
    117.             File.WriteAllLines(tempPath, lines.ToArray() );
    118.             Debug.Log("Saved blendshape weight values to: " + tempPath);
    119.  
    120.             /// Increment the counter.
    121.             counter++;
    122.  
    123.             /// Save the current counter.
    124.             PlayerPrefs.SetInt("_counter_", counter);
    125.             PlayerPrefs.Save();
    126.         }
    127.         catch (Exception e)
    128.         {
    129.             Debug.LogWarning("Failed to save to PlayerPrefs: " + tempPath);
    130.             Debug.LogWarning("Error: " + e.Message);
    131.         }      
    132.     }
    133. }
    134.  
    In the Unity Editor, the blendshapes are displayed with values from 0 to 100, hence my conversion in the code, as seen in this screenshot:

    blendshapes.png

    The first file has 101 values (0...100 plus a top row for column labels) a snippet can be seen in this screenshot:

    weights.png

    The second file has 10201 values. My first question is whether this method of saving the iterated values to file after the app stops is a good solution, given the large growth in the values as I add more lists (i.e. blendshapes)?

    My second question is how I can slow down the iterations, because (in the first screenshot) the smile values start counting up from 0 to 100 and I can see them (the face moves slowly in a visible manner) but as that is happening, I notice that the second list (skeptic) apparently jumps to 100 immediately, so it is done so quickly that it cannot be recorded by the Win screen recorder...

    Thank you
     
  3. kalagaan

    kalagaan

    Joined:
    May 27, 2012
    Posts:
    1,503
    1. It's a tool for a specific so you can do it by generating big lists, but you could also use a StreamWriter to push the result in the file each frame. sample here and here

    2. the Skeptic weights are set to 100 before 'yield return null;' is called.
    The first 'for' loop (i) breaks each step because the yield return is inside the loop, so each frame 1 step of the loop is executed.
    But the second loop (j) is completed (0->100) inside the first loop and before the yield return.
    So you could try this :

    Code (CSharp):
    1. private IEnumerator Interpolate()
    2.     {
    3.         for (int i = 0; i <= 100; i++)
    4.         {
    5.             float weightValuesmile = (float)i / 100.0f;
    6.             _BSPC.SetWeight("Preset1_smile", weightValuesmile);
    7.             _weightValues_Preset1_smile.Add(weightValuesmile);
    8.  
    9.             for (int j = 0; j <= 100; j++)
    10.             {
    11.                 float weightValueSkeptic = (float)j / 100.0f;
    12.                 _BSPC.SetWeight("Preset2_skeptic", weightValueSkeptic);
    13.                 _weightValues_Preset2_skeptic.Add(weightValueSkeptic);
    14.  
    15.                  yield return null;
    16.             }        
    17.         }
    18.     }
     
    HamFar likes this.
  4. RadioactiveXP

    RadioactiveXP

    Joined:
    Nov 6, 2013
    Posts:
    69
    Does this work with the Daz3d Models (genesis?)
     
  5. kalagaan

    kalagaan

    Joined:
    May 27, 2012
    Posts:
    1,503
    If your character has blenshapes it will work :)
     
  6. Volkerku

    Volkerku

    Joined:
    Nov 23, 2016
    Posts:
    114
    Is it possible to drive blendshape sets through Unity timeline? Is there a limit how many blendshapes I can combine with various values? Can I save sets and reuse?
    Thnaks, V
     
  7. kalagaan

    kalagaan

    Joined:
    May 27, 2012
    Posts:
    1,503
    Yes, you can use BSPT with unity timeline.
    You have to add the 'BlendShapesPresetAnimator' component.
    The default script can control 20 presets, but you can easily modify it to add more animated presets.

    There's no limitation, each preset can modify all the existing blendshapes of the SkinnedMeshRenderer, and all the presets can be mixed.

    You can create different presets files and switch them at runtime or use them on different characters.
     
    Last edited: Jun 25, 2019
  8. Volkerku

    Volkerku

    Joined:
    Nov 23, 2016
    Posts:
    114
    Thanks
    I tried to do that on my own character, which I added to the demo scene.
    As in the screengrab below, I added the the BlendshapeControllerBase component to my skinnedMesh renderer game object, set a preset, and then the BlendshapePresetAnimator component. This one is empty, and won't accept the gameObject as reference. If I click select (BlendshapePresetController) only the male and female demo heads are listed as options.
    Can you help please.

    Capture.JPG

     
  9. Volkerku

    Volkerku

    Joined:
    Nov 23, 2016
    Posts:
    114
    Actually figured it out. Not the base controller script, but the regular. Works like a charm.
     
  10. kalagaan

    kalagaan

    Joined:
    May 27, 2012
    Posts:
    1,503
    I'm glad that it works as expected :)
    Thank you for the feedback, I'll add a fix to prevent this behavior.
     
  11. Dorumeka

    Dorumeka

    Joined:
    Aug 19, 2017
    Posts:
    18
    Is there a way to change the Preset Template in code? The API in the documentation doesn't include a reference to that.
     
  12. kalagaan

    kalagaan

    Joined:
    May 27, 2012
    Posts:
    1,503
    Yes, you have to set the new template to the m_blendShapePreset parameter.
    Have a look to the demo script, you can change the preset at runtime.

    Code (CSharp):
    1.  
    2. public void SwitchPresets(Dropdown dpd)
    3. {
    4.        m_female.m_blendShapePreset = m_presets[dpd.value];
    5.        m_male.m_blendShapePreset = m_presets[dpd.value];
    6.        InitPresetSliders();
    7. }
    8.  
     
  13. xinxiangjo

    xinxiangjo

    Joined:
    Aug 2, 2017
    Posts:
    2
    Add the 'Blend Shape Preset Controller' component

    !!! "SkinnedMeshRenderer has no blendshape"

    How to operate it?
     

    Attached Files:

  14. kalagaan

    kalagaan

    Joined:
    May 27, 2012
    Posts:
    1,503
    Blend Shapes Preset Tool requires some blendshapes for creating presets.
    If the mesh doesn't have initial blendshapes to mix it won't work.

    You could try to create blendshapes in a 3D software, like Blender.
     
  15. milenaps

    milenaps

    Joined:
    Jul 8, 2020
    Posts:
    2
    Hi!

    Just purchased the asset, but I got some warnings during import. I am using Unity 2019.3.0a5
    upload_2020-7-10_16-19-8.png

    It cannot find the mesh and I cannot set up the example in the package. Any suggestions?

    Thanks!
     
  16. kalagaan

    kalagaan

    Joined:
    May 27, 2012
    Posts:
    1,503
    This warning is not important, the character of the demo was imported with an older version of Unity without normals for the blendshapes.
    You can generate the normals for the blendshapes in the fbx import settings if you want :

    - Select the model in the project folder : "BlendShapePrestTool/Demo/Models/"
    - Select the 'Model' tab
    - Disable 'Legacy Blend Shapes'
    - Set the normal mode to 'Unweighted' (not 'Unweighted (legacy)' )

    The mesh warning will be fixed and the normals will be enabled.
    This is not a problem for the tool, the demo will work fine without these modifications.

    The demo scene is in the folder :
    "BlendShapePresetTool/Demo/Demo"

    It works with Unity 2019.3 and later, maybe you should update to a final version, you're using an alpha version of unity. ;)

    You have to add the POFX component on the gameobject with the SkinnedMeshRenderer of your character.
     
    Last edited: Jul 10, 2020
  17. milenaps

    milenaps

    Joined:
    Jul 8, 2020
    Posts:
    2
    Hi!
    Thanks for the reply, I was able to play the demo and it seems exactly what I need for my prototype!
    Still, I am struggling a bit. I want to get a model from Adobe Fuse and then animation from Mixamo to Unity. On top of this, to add the facial expression from this asset. But it seems the model from Mixamo misses some bones and when I try to use the BSPT component to the avatar, it gives me error "Requires skinnedmesh renderer". I see that it is because of the model itself.
    Do you think what I am trying to achieve is possible? (I know I am messing up something, but as long as it is possible, it is a question of more struggle to figure it out how:) ).

    Thanks!
     
  18. kalagaan

    kalagaan

    Joined:
    May 27, 2012
    Posts:
    1,503
    You have to add the BSPT component on the gameobject with the skinnedMeshRenderer, sometimes this gameobject is a child of the character gameObject.
     
  19. spikezart

    spikezart

    Joined:
    Oct 28, 2021
    Posts:
    72
    Hi, I see a purchaser review saying they had used Blend Shapes to manage morphs from iClone so I was wondering if Blend Shapes can do the same with morphs imported with a character from Daz ?
     
  20. kalagaan

    kalagaan

    Joined:
    May 27, 2012
    Posts:
    1,503
    Blend Shapes Preset tool can manage all the morph shapes exported in a skinnedmeshRenderer.
    So if you can see the morph targets in the component, it will work.
     
    spikezart likes this.
  21. spikezart

    spikezart

    Joined:
    Oct 28, 2021
    Posts:
    72
    Thank you.