Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Using data-driven conversion to automatically convert entities from modeling tool to Unity entities

Discussion in 'Entity Component System' started by florianhanke, Aug 11, 2019.

  1. florianhanke

    florianhanke

    Joined:
    Jun 8, 2018
    Posts:
    426
    Hi all,

    I am working on a WW2 game where armor is important, and where various pieces on vehicles have different types of material (rolled steel, rubber) and a thickness.

    I was looking for a way to elegantly convert a blender 2.8 model into an entity with the various vehicle pieces as child entities with appropriate colliders. The following is a simple prototype. I'm hoping some of you find it helpful (or shockingly silly :D).

    I had multiple requirements:
    1. I want it to be data driven, i.e. changes in blender will change the entity information.
    2. I don't want to have to add a GO component on every piece on the vehicle, but just a single one at the root vehicle GO.

    To do so, I am using a simple (currently unpolished) naming scheme on the blender objects. "sdkfz222-vision-l-rha-5" means right vision port (on the turret) with 5mm of rolled armor:

    Screenshot 2019-08-11 10.31.10.png

    Unity automatically updates the model via import.

    To convert prefab instances in a scene, I attach the Authoring.Armor MonoBehaviour described below:

    Code (CSharp):
    1. using Unity.Entities;
    2. using UnityEngine;
    3.  
    4. // A container for simple component types.
    5. namespace BUD.Components
    6. {
    7.  
    8.     public struct Armor : IComponentData
    9.     {
    10.         public Managers.Armors.Type type;
    11.         public float thickness;
    12.     }
    13.  
    14.     namespace Authoring
    15.     {
    16.         [RequiresEntityConversion]
    17.         public class Armor : MonoBehaviour, IConvertGameObjectToEntity
    18.         {
    19.             public void Convert(Entity entity, EntityManager entityManager, GameObjectConversionSystem conversionSystem)
    20.             {
    21.                 // Extract data from game object.
    22.                 var namePieces = name.Split('-');
    23.                 if (namePieces.Length == 5)
    24.                 {
    25.                     // We have an Armor game object. Extract the data.
    26.                     var typeString = namePieces[3];
    27.                     var thicknessString = namePieces[4];
    28.  
    29.                     // Map to enum / float.
    30.                     var type = (Managers.Armors.Type) Managers.Armors.Type.Parse(typeof(Managers.Armors.Type), typeString.ToUpper());
    31.                     var thickness = float.Parse(thicknessString);
    32.  
    33.                     // Create component.
    34.                     entityManager.AddComponentData(entity, new Components.Armor
    35.                     {
    36.                         type = type,
    37.                         thickness = thickness,
    38.                     });
    39.                 }
    40.  
    41.                 for (int i = 0; i < transform.childCount; i++)
    42.                 {
    43.                     var child = transform.GetChild(i);
    44.                     // Add this Armor component here so I can add it only to the topmost component in the hierarchy.
    45.                     child.gameObject.AddComponent(typeof(Authoring.Armor));
    46.                 }
    47.             }
    48.         }
    49.     }
    50. }
    For completeness:

    Screenshot 2019-08-11 10.34.21.png

    This is converted into:

    Screenshot 2019-08-11 10.35.44.png

    The pieces of Armor are still in the correct hierarchy relationship with their parent, are correctly names, and have an Armor component with the correctly mapped type and thickness (see right in image).

    For most entities, I use an archetype based instantiation (since I rarely need authoring), but for specifically this case, using a custom conversion script is quite powerful.

    This works well so far. One bigger issue of this script is that it depends on a strict parent-first conversion order, since to fulfil requirement #2 ("I don't want to have to add a GO component on every piece on the vehicle, but just a single one at the root vehicle GO.") I add Armor GO components, applying it to children as I go. And I am not sure if I can depend on this order.

    This is quite unpolished (Armor is applied to all children, for example and colliders are not optimized yet), but what do you guys think: Is this the way to go or is there a much more appropriate way to do this?
     
  2. DreamingImLatios

    DreamingImLatios

    Joined:
    Jun 3, 2017
    Posts:
    4,222
  3. florianhanke

    florianhanke

    Joined:
    Jun 8, 2018
    Posts:
    426
    Thanks so much for your helpful comment! Calling it "alternative" is mildly put – I think it's far superior.

    I'm doing what you suggested, with the modification that I create a GO component for each blender object that is marked as having armor. Then, entity conversion is straightforward:

    Code (CSharp):
    1.     public struct Armor : IComponentData
    2.     {
    3.         public Armors.Type type;
    4.         public float thickness; // In mm.
    5.     }
    6.  
    7.     namespace Authoring
    8.     {
    9.         [RequiresEntityConversion]
    10.         public class Armor : MonoBehaviour, IConvertGameObjectToEntity
    11.         {
    12.             public Armors.Type type;
    13.             public float thickness;
    14.             public void Convert(Entity entity, EntityManager entityManager, GameObjectConversionSystem conversionSystem)
    15.             {
    16.                 entityManager.AddComponentData(entity, new Components.Armor
    17.                 {
    18.                     type = type,
    19.                     thickness = thickness,
    20.                 });
    21.             }
    22.         }
    23.     }
    This allows me to directly see armor types/values in Unity on all GOs and child GOs that have it and only (mainly) performs work when I save the blender file, and not in the entity conversion.

    Thanks again, much appreciated!
     
    Last edited: Aug 12, 2019
    DreamingImLatios likes this.