Search Unity

  1. Good news ✨ We have more Unite Now videos available for you to watch on-demand! Come check them out and ask our experts any questions!
    Dismiss Notice

Blend Shapes Changing Vertex Normals

Discussion in 'Animation' started by JordyJS, Feb 20, 2019.

  1. JordyJS

    JordyJS

    Joined:
    Jun 8, 2014
    Posts:
    13
    Unless I'm misunderstanding, the new blend shape normal calculation options don't have a way to retain the mesh's base normals. This is particularly problematic when animating meshes with custom vertex normals (for things like toon shading, etc.). The editor tooltip says:

    "If Import is selected and the blend shape has no normals, they will be calculated instead"

    But could there not be an option for the blend shapes to retain the normals of the mesh in its default state, so that the normals don't change at all when animating blend shapes? The way it is now, no matter what my setup is, so long as I have custom normals the blend shapes will change the normals to the calculated versions.

    For reference, I'm using 3ds Max and the Morpher modifier, and I've turned off Smoothing Groups when exporting my FBX because it will average out the vertex normals I've set manually, which is undesirable.

    Edit: I just checked 2018.2, and this seems to be the behaviour I'm talking about. Another option in the importer for having the blend shapes interpolate normals like this would be greatly appreciated. Something like a Legacy option would be ideal.
     
    Last edited: Feb 20, 2019
    JeremyJackson likes this.
  2. thomh_unity

    thomh_unity

    Unity Technologies

    Joined:
    Feb 19, 2019
    Posts:
    10
    We are currently tracking a bug related to the FBX importer calculating normals for blend shapes even when the 'Blend Shape Normals' setting is set to 'None'. You can follow that bug here. However, the 'None' setting should be used when the object requires no normal information, no lighting.

    Regarding smoothing groups. Although this didn't seem to have any impact on my test files, our documentation does say that smoothing groups are required for importing blendshape normals:

    "Note Importing blendshape normals requires smoothing groups in the FBX file." - https://docs.unity3d.com/Manual/FBXImporter-Model.html
    Regarding your edit: Are you saying that 2018.2 has the behaviour you need or exhibits the issue?
     
    Alverik likes this.
  3. JordyJS

    JordyJS

    Joined:
    Jun 8, 2014
    Posts:
    13
    Hey Thomh, thanks for the reply.

    2018.2 has the behaviour I need. When I change the blendshape values in 2018.2, the normals/smoothing groups retain those of the base mesh. When I try to do the same in 2018.3, they will progressively change to the recalculated normals/smoothing groups.

    Basically I want to preserve my custom normals/smoothing group information when my blendshapes are active, but all of the current options always end up recalculating them.

    I've attached a quick GIF to show the problem. 2018.2 is the desired effect; 2018.3 is undesired.
     

    Attached Files:

  4. thomh_unity

    thomh_unity

    Unity Technologies

    Joined:
    Feb 19, 2019
    Posts:
    10
    In 2018.3 I was only able to get this kind of behaviour from an FBX exported from blender in ascii mode. I was unable to get this behaviour from any FBX exported from MAX.

    Are you using ascii or binary FBX files?
     
  5. JordyJS

    JordyJS

    Joined:
    Jun 8, 2014
    Posts:
    13
    Both have the same effect.

    In order to preserve custom normals in MAX while exporting morph targets (blendshapes), I actually have to not export the Smoothing Groups (I've shown my export settings in the attached image). Otherwise, MAX will recalculate the normals due to how the Morpher modifier works.

    This trick seems to work fine in 2018.2, preserving my custom normals/smoothing groups and retaining them in the blendshapes. Could it be because of the bug you mentioned? I basically want the functionality that was default in 2018.2 (blendshapes not calculating normals at all), and perhaps that's what the None option is supposed to do, it just doesn't due to the bug?
     

    Attached Files:

  6. thomh_unity

    thomh_unity

    Unity Technologies

    Joined:
    Feb 19, 2019
    Posts:
    10
    There seems to be an issue with some FBX files ending up with calculated blend shape normals when they should be imported. I've logged some bugs against these problems but if you're having trouble right now with blend shape normals getting recalculated (when you don't want them to be) please take a look at this script editor script for creating a new mesh asset based on any other mesh asset (but with normals copied from the base mesh). Use it like this:

    1) Put this script into your project.
    2) Find the FBX that contains the incorrectly imported blend shape.
    3) Expand the asset to show the mesh, right click on it.
    4) Select 'Generate Mesh With Fixed Normals'.

    Use your fbx model as the basis for your character and then simply drop the exported '_fixed' mesh onto the skinned mesh renderer's mesh reference. Everything should be preserved apart from the blend shape normals which will be changed.

    I hope this helps!

    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEditor;
    3.  
    4. public class FixNormals
    5. {
    6.     /*
    7.      * Set the normals for each blend shape frame to the
    8.      * same normals as the base mesh and export a new mesh
    9.      * asset with a sensible name. Select a mesh, right
    10.      * click and choose 'Generate Mesh With Fixed Normals'.
    11.      */
    12.     [MenuItem("Assets/Generate Mesh With Fixed Normals")]
    13.     private static void FixBlendShapeNormals()
    14.     {
    15.  
    16.         if(Selection.activeObject.GetType() != typeof(Mesh))
    17.         {
    18.             Debug.LogError("This isn't a mesh.");
    19.             return;
    20.         }
    21.  
    22.         Debug.Log("let's fix these blendshape normals!");
    23.  
    24.         Mesh selected = Selection.activeObject as Mesh;
    25.      
    26.         Vector3[] deltaVertices = new Vector3[selected.vertexCount];
    27.         Vector3[] deltaNormals = new Vector3[selected.vertexCount];
    28.         Vector3[] deltaTangents = new Vector3[selected.vertexCount];
    29.  
    30.         int bsc = selected.blendShapeCount;
    31.  
    32.         Mesh newMesh = new Mesh();
    33.         newMesh.vertices = selected.vertices;
    34.         newMesh.uv = selected.uv;
    35.         newMesh.normals = selected.normals;
    36.         newMesh.colors = selected.colors;
    37.         newMesh.tangents = selected.tangents;
    38.         newMesh.subMeshCount = selected.subMeshCount;
    39.         //newMesh.triangles = selected.triangles;
    40.  
    41.         int subMeshes = selected.subMeshCount;
    42.         for (int i = 0; i < subMeshes; i++) {
    43.             int[] tris = selected.GetTriangles(i);
    44.             newMesh.SetIndices(tris, MeshTopology.Triangles, i);
    45.         }
    46.  
    47.         newMesh.name = selected.name + "_fixed";
    48.         newMesh.boneWeights = selected.boneWeights;
    49.         newMesh.bindposes = selected.bindposes;
    50.  
    51.         for (int i = 0; i< bsc; i++)
    52.         {
    53.             string name = selected.GetBlendShapeName(i);
    54.             int weightCount = selected.GetBlendShapeFrameCount(i);
    55.             for (int j = 0; j < weightCount; j++)
    56.             {
    57.                 float weight = selected.GetBlendShapeFrameWeight(i, j);
    58.                 selected.GetBlendShapeFrameVertices(i, j, deltaVertices, deltaNormals, deltaTangents);
    59.                 newMesh.AddBlendShapeFrame(name, weight, deltaVertices, selected.normals, deltaTangents);
    60.             }
    61.         }
    62.  
    63.         string savePath = AssetDatabase.GetAssetPath(selected);
    64.         savePath = savePath.Substring(0, savePath.LastIndexOf('/') + 1);
    65.      
    66.         string newAssetName = savePath + selected.name + "_fixed.asset";
    67.  
    68.         AssetDatabase.CreateAsset(newMesh, newAssetName);
    69.  
    70.         AssetDatabase.SaveAssets();
    71.  
    72.         Debug.Log("Done!");
    73.     }
    74. }
     
    Last edited: Mar 22, 2019
  7. ZoeZoePixel

    ZoeZoePixel

    Joined:
    Feb 4, 2015
    Posts:
    16
    just used this script and it WORKS!!! kinda....
    the eye pupils of my 3d model get distored see pic

    edit: nvm fixed the issue by setting the submeshcount to the num
    ber of submeshes my mesh had
     

    Attached Files:

    Last edited: Mar 21, 2019
  8. thomh_unity

    thomh_unity

    Unity Technologies

    Joined:
    Feb 19, 2019
    Posts:
    10
    Line 38 should read:
    Code (CSharp):
    1. newMesh.subMeshCount = selected.subMeshCount;
    Then it will work for all submesh counts.
     
    Last edited: Mar 22, 2019
  9. dreamerflyer

    dreamerflyer

    Joined:
    Jun 11, 2011
    Posts:
    927
    blendshapeNormal.jpg blendShapeNormal2.jpg
    it seems still has problem,the vertex normal change with blender weight...
     
  10. thomh_unity

    thomh_unity

    Unity Technologies

    Joined:
    Feb 19, 2019
    Posts:
    10
    Hi dreamerflyer,

    Try this version:

    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEditor;
    3.  
    4. public class FixNormals
    5. {
    6.     /*
    7.      * Set the normals for each blend shape frame to the
    8.      * same normals as the base mesh and export a new mesh
    9.      * asset with a sensible name. Select a mesh, right
    10.      * click and choose 'Generate Mesh With Fixed Normals'.
    11.      */
    12.     [MenuItem("Assets/Generate Mesh With Fixed Normals")]
    13.     private static void FixBlendShapeNormals()
    14.     {
    15.  
    16.         if(Selection.activeObject.GetType() != typeof(Mesh))
    17.         {
    18.             Debug.LogError("This isn't a mesh.");
    19.             return;
    20.         }
    21.  
    22.         Debug.Log("let's fix these blendshape normals!");
    23.  
    24.         Mesh selected = Selection.activeObject as Mesh;
    25.      
    26.         Vector3[] deltaVertices = new Vector3[selected.vertexCount];
    27.         Vector3[] deltaNormals = new Vector3[selected.vertexCount];
    28.         Vector3[] deltaTangents = new Vector3[selected.vertexCount];
    29.  
    30.         int bsc = selected.blendShapeCount;
    31.  
    32.         Mesh newMesh = new Mesh();
    33.         newMesh.vertices = selected.vertices;
    34.         newMesh.uv = selected.uv;
    35.         newMesh.normals = selected.normals;
    36.         newMesh.colors = selected.colors;
    37.         newMesh.tangents = selected.tangents;
    38.         newMesh.subMeshCount = selected.subMeshCount;
    39.         //newMesh.triangles = selected.triangles;
    40.  
    41.         int subMeshes = selected.subMeshCount;
    42.         for (int i = 0; i < subMeshes; i++) {
    43.             int[] tris = selected.GetTriangles(i);
    44.             newMesh.SetIndices(tris, MeshTopology.Triangles, i);
    45.         }
    46.  
    47.         newMesh.name = selected.name + "_fixed";
    48.         newMesh.boneWeights = selected.boneWeights;
    49.         newMesh.bindposes = selected.bindposes;
    50.  
    51.         Vector3[] zero = new Vector3[selected.vertexCount];
    52.         for (int i = 0; i < zero.Length; i++)
    53.             zero[i] = Vector3.zero;
    54.  
    55.         for (int i = 0; i< bsc; i++)
    56.         {
    57.             string name = selected.GetBlendShapeName(i);
    58.             int weightCount = selected.GetBlendShapeFrameCount(i);
    59.             for (int j = 0; j < weightCount; j++)
    60.             {
    61.                 float weight = selected.GetBlendShapeFrameWeight(i, j);
    62.                 selected.GetBlendShapeFrameVertices(i, j, deltaVertices, deltaNormals, deltaTangents);
    63.                 newMesh.AddBlendShapeFrame(name, weight, deltaVertices, zero, deltaTangents);
    64.             }
    65.         }
    66.  
    67.         string savePath = AssetDatabase.GetAssetPath(selected);
    68.         savePath = savePath.Substring(0, savePath.LastIndexOf('/') + 1);
    69.      
    70.         string newAssetName = savePath + selected.name + "_fixed.asset";
    71.  
    72.         AssetDatabase.CreateAsset(newMesh, newAssetName);
    73.  
    74.         AssetDatabase.SaveAssets();
    75.  
    76.         Debug.Log("Done!");
    77.     }
    78. }
     
    dreamerflyer likes this.
  11. AcidArrow

    AcidArrow

    Joined:
    May 20, 2010
    Posts:
    7,033
    Hi @thomh_unity is there going to be a built in way to get the old behaviour back? Or do we have to use this script in order to have the blendshape normals be the same as the base normals?

    Also, does that mean that now normals get blended regardless and therefore the whole operation is more expensive?
     
  12. thomh_unity

    thomh_unity

    Unity Technologies

    Joined:
    Feb 19, 2019
    Posts:
    10
    Hi AcidArrow,

    I'm fairly sure the current behaviour is not correct. I've logged a bug relating to this. It should get looked at in the near future.
     
  13. 13524656829

    13524656829

    Joined:
    Jun 20, 2017
    Posts:
    2
    Hi thomh, I just wanted to say that the script you provided has literally saved my day!! Thank you so much!! Our project has encountered the exact same problem and this will be our temporary solution. Hopefully it will be fixed soon in 2018.3x since we will not be able to migrate our entire project to 2019.x...
     
    thomh_unity likes this.
  14. JordyJS

    JordyJS

    Joined:
    Jun 8, 2014
    Posts:
    13
    This appears to be fixed in 2019.1.4f1 by setting the "Blend Shape Normals" option in the model importer settings to "None". Thanks a ton for all your help @thomh_unity!

    EDIT: Looks like they also added a "Legacy Blend Shapes" option that arguably works even better! Great work guys, thank you so much.
     
    Last edited: Jun 3, 2019
    thomh_unity and ZoeZoePixel like this.
  15. rcabot

    rcabot

    Joined:
    Oct 24, 2014
    Posts:
    5
    I stumbled upon this by accident after all our blend shapes broke in the update. Thanks for verifying!
     
  16. Rickey72

    Rickey72

    Joined:
    Sep 9, 2018
    Posts:
    2
    I am unsure if this is the same issue I am having but when I import my mesh into Unity and look at the animation preview I get strange smoothing or normal issues happening to my mesh. I check in Max and my mesh isn't showing this. Is it something with my blend shapes or is there a export or import setting I am doing wrong?
     

    Attached Files:

  17. joshcamas

    joshcamas

    Joined:
    Jun 16, 2017
    Posts:
    1,059
    For me, using the "import" option as opposed to "calculate" worked for me! :D
     
  18. pigglet

    pigglet

    Joined:
    Aug 13, 2014
    Posts:
    113
    Hello. I'm sorry to up this topic, but I'm using unity 2019.2 with Maya 2019 and still can't import blend shape normals from Maya to Unity.
    Here you can see Maya's source before export and unity's import :(

     
    BlankMauser likes this.
  19. FlightyFelon

    FlightyFelon

    Joined:
    Jan 3, 2016
    Posts:
    3
    Thank you so much for this!
    It's been a huge help!
     
    thomh_unity likes this.
  20. skinwalker

    skinwalker

    Joined:
    Apr 10, 2015
    Posts:
    422
    I set my blendshape normals to None and it fixed the issue, my model still has shadows. You said "However, the 'None' setting should be used when the object requires no normal information, no lighting" but I havent seen any issues so far.

    Do you know how to make this script update the current mesh instead of making a new one?
     
  21. mcmount

    mcmount

    Joined:
    Nov 15, 2015
    Posts:
    58
    With the Unity 2019.3.0f6 you can forget this script. I have tons of characters with blendshapes and blendshape normal issue is fixed.
    My settings:
    mesh compression off
    optimize mesh, yes
    normals calculate
    normals mode area & angle weighted
    smoothing angle 180 (you might want to give few tests with this)
     
    ikermozos likes this.
  22. ColonelJCD

    ColonelJCD

    Joined:
    Aug 16, 2017
    Posts:
    3
    Dude ur a life saver! Problem fixed mesh looking great!

    Also for other people struggling with this I got the normals to look better by setting Smoothness Source to From Angle and Smoothing Angle to 180. But this script cleaned everything up perfectly for me.
     
    Dave_3Dln likes this.
  23. ColonelJCD

    ColonelJCD

    Joined:
    Aug 16, 2017
    Posts:
    3
    I tried that version yesterday, problem still exists for my situation. The script in this thread fixed my problems.
     
  24. kite3h

    kite3h

    Joined:
    Aug 27, 2012
    Posts:
    97
    FBX does not apply lock normal mode if mesh has blendshapes.
     
  25. acnestis

    acnestis

    Joined:
    Sep 11, 2019
    Posts:
    1
    None of the options in 【Blend Shape Normals】makes my model in blend-shape look better.
    So I go back to Blender, interchange the blend-shape and the default-state (let the blend-shape be the default-state, let the default-state be the blend-shape), and reverse the animation.
    This new model gives a good look in Unity. Hope it can be helpful.

    upload_2020-6-5_17-24-8.png 2020-06-05-17-33-36.gif
     
  26. franck_Extriple

    franck_Extriple

    Joined:
    Oct 27, 2017
    Posts:
    11
    Hi. @thomh_unity

    Got the same issue with FBX from Modo with Blendshape and VertexNormal map saved at exported.
    and even with the 2 CS Script i can't solved it in 2017.4 Unity release.

    i hope we can switch to 2019.4.0 (where it works well). Developer will tell me, if we can migrate the project.

    hope we can solve that.
     
unityunity