Search Unity

Mirroring Meshes in MeshInstanceRenderer doesn't work as expected ?

Discussion in 'Entity Component System and C# Job system' started by Held0fTheWelt, Jan 11, 2019.

  1. Held0fTheWelt

    Held0fTheWelt

    Joined:
    Sep 29, 2015
    Posts:
    134
    I have very complex meshes like this cockpit, which i want to make use of.
    I want to switch and click about anything, that is in there in this cockpit.
    Therefore i had to work on the mesh itself, i got it as a whole one mesh, and that is a quite inaccessible approach.
    So i started seperating out all that buttons, switches, knobs and displays and made myself logical pivot points, where i can rotate around things, when i wanted to do this - this is working quite well.
    Also it made me shrinking the meshes sizes from 33mb to 3mb - then reworking everything up to a gameobject with several prefabs for everything i want to have in there.
    The final product looks quite like the original - everything seems to be in place.
    I can use this GameObject regularly and using a hybrid approad works out quite good, but i was thinking about scripting me everything forward to a complete entity approach, so i do this:

    Code (CSharp):
    1. using System.Collections.Generic;
    2. using Unity.Mathematics;
    3. using UnityEngine;
    4.  
    5. /// <summary>
    6. /// ScriptableEntity is a Scriptable Object, that is used, to translate
    7. /// a given GameObject or Prefab to entity component data.
    8. /// It can be read in by spawner classes to spawn related entities
    9. /// with their given information.
    10. /// </summary>
    11. [System.Serializable]
    12. [CreateAssetMenu(fileName = "ScriptableEntity", menuName = "Entites/Scriptable Entity", order = 1)]
    13. public class ScriptableEntity : ScriptableObject
    14. {
    15.     [Header("Name of Entity to identify in List")]
    16.     public string Name;
    17.  
    18.     [Space]
    19.     [Header("Material Information about this entity")]
    20.     public int DefaultMaterialIndex = 0;
    21.     public int DefaultGlassIndex = 0;
    22.     /// <summary>
    23.     /// Material information, used by this scriptable entity in a whole
    24.     /// </summary>
    25.     public MaterialInformation[] MaterialInformation;
    26.  
    27.     //public NodeInstanceInformation NodeInstanceInformation;
    28.  
    29.     [Header("Node Structure for this entity")] // TODO: Keine List, sondern Map !!!!
    30.     public NodeInstanceInformation[] NodeInformation;
    31. }
    32.  
    33. [System.Serializable]
    34. public struct NodeInstanceInformation
    35. {
    36.     /// <summary>
    37.     /// Name of this entity
    38.     /// </summary>
    39.     public string Name;
    40.      
    41.     // Transform information about this entity
    42.     /// <summary>
    43.     /// Position of this entity
    44.     /// </summary>
    45.     public float3 Position;
    46.     /// <summary>
    47.     /// Rotation of this entity
    48.     /// </summary>
    49.     public quaternion Rotation;
    50.     /// <summary>
    51.     /// Scale of this entity
    52.     /// </summary>
    53.     [Tooltip("This is a tooltip")]
    54.     public float3 Scale;
    55.  
    56.     // Presence of this entity
    57.     /// <summary>
    58.     /// Mesh information of this entity
    59.     /// </summary>
    60.     public Mesh Mesh;
    61.     /// <summary>
    62.     /// Material information about this entity
    63.     /// </summary>
    64.     public Material Material;
    65.  
    66.     // Physics of this entity
    67.     /// <summary>
    68.     /// Information, set in the Rigidbody component
    69.     /// </summary>
    70.     public RigidBodyInformation Rigidbody;
    71.     /// <summary>
    72.     /// Collider related settings.
    73.     /// Can be more than one
    74.     /// </summary>
    75.     public ColliderInformation[] ColliderType;
    76.  
    77.     /// <summary>
    78.     /// Index of this Node
    79.     /// </summary>
    80.     public int Index;
    81.     /// <summary>
    82.     /// Child Indices for this node
    83.     /// </summary>
    84.     public int[] Children;
    85. }
    86.  
    Now i can write a Generator for this - i started with some real easy approach:

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using Unity.Mathematics;
    4. using UnityEngine;
    5.  
    6. /// <summary>
    7. /// Calculation and Generation methods for GameObjectToScriptableEntityEditor
    8. /// </summary>
    9. public partial class GameObjectToScriptableEntityEditor
    10. {
    11.     private static int _index = 0;
    12.  
    13.     #region Generate Scriptable Entity
    14.     /// <summary>
    15.     /// Translates information about a Gameobject into a known
    16.     /// scriptable entity.
    17.     /// </summary>
    18.     private void GenerateScriptableEntity()
    19.     {
    20.         // Get our resources
    21.         GameObject parentObject = (GameObject) gameObjectSource.objectReferenceValue;
    22.         ScriptableEntity destinationObject = (ScriptableEntity) scriptableEntityDestination.objectReferenceValue;
    23.  
    24.         GenerateNodeStructure(parentObject, destinationObject);
    25.     }
    26.     #endregion
    27.  
    28.     List<NodeInstanceInformation> nodeList = new List<NodeInstanceInformation>();
    29.     #region Generate Node Structure
    30.     /// <summary>
    31.     /// Generates the inner structure of the gameobject
    32.     /// </summary>
    33.     /// <param name="parent">Source GameObject Resource</param>
    34.     /// <param name="destination">Destination Scriptable Entity to write to</param>
    35.     private void GenerateNodeStructure(GameObject parent, ScriptableEntity destination)
    36.     {
    37.         NodeInstanceInformation parentNode = new NodeInstanceInformation();
    38.         parentNode = GenerateNodeTree(parent, parentNode);
    39.  
    40.         nodeList.Add(parentNode);
    41.         destination.NodeInformation = nodeList.ToArray();
    42.     }
    43.     #endregion
    44.  
    45.     #region Translate Transform
    46.     public static float3 GetPosition(GameObject parent)
    47.     {
    48.         return new float3(parent.transform.localPosition);
    49.     }
    50.     public static quaternion GetRotation(GameObject parent)
    51.     {
    52.         return new quaternion(parent.transform.localRotation.x, parent.transform.localRotation.y, parent.transform.localRotation.z, parent.transform.localRotation.w);
    53.     }
    54.     public static float3 GetScale(GameObject parent)
    55.     {
    56.         return new float3(parent.transform.localScale);
    57.     }
    58.     #endregion
    59.  
    60.     private NodeInstanceInformation GenerateNodeTree(GameObject gameObject, NodeInstanceInformation entityInformation)
    61.     {
    62.         // Setup values
    63.         entityInformation.Index = _index;
    64.         _index++; // TODO should be a oneliner, but have
    65.         //to look, if postincrement is legt or preincrement
    66.         // was the answer
    67.  
    68.         #region Name
    69.         entityInformation.Name = gameObject.name;
    70.         #endregion
    71.    
    72.         #region Transform transform
    73.         entityInformation.Position = GetPosition(gameObject);
    74.         entityInformation.Rotation = GetRotation(gameObject);
    75.         entityInformation.Scale = GetScale(gameObject);
    76.         #endregion
    77.      
    78.         #region Presence / Mesh & Material
    79.         if (gameObject.GetComponent<MeshFilter>() != null)
    80.             entityInformation.Mesh = gameObject.GetComponent<MeshFilter>().sharedMesh;
    81.         if (gameObject.GetComponent<MeshRenderer>() != null)
    82.             entityInformation.Material = gameObject.GetComponent<MeshRenderer>().sharedMaterial;
    83.         #endregion
    84.      
    85.         #region  Physics / RigidBody & colliders
    86.         if (gameObject.GetComponent<Rigidbody>())
    87.         {
    88.             var body = gameObject.GetComponent<Rigidbody>();
    89.          
    90.             entityInformation.Rigidbody = new RigidBodyInformation
    91.             {
    92.                 Mass = body.mass,
    93.                 Drag = body.drag,
    94.                 AngularDrag = body.angularDrag,
    95.                 UseGravity = body.useGravity,
    96.                 IsKinematic = body.isKinematic,
    97.                 Interpolate = body.interpolation,
    98.                 CollisionDetectionMode = body.collisionDetectionMode
    99.  
    100.                 // TODO: Constraints about Freeze Position & Rotation are missing yet
    101.             };
    102.         }
    103.  
    104.  
    105.         //  if (parent.GetComponent<Collider>())
    106.         //        destination.Collider = parent.GetComponent<Collider>();
    107.         #endregion
    108.  
    109.         #region  Child Nodes
    110.         int childCount = gameObject.transform.childCount;
    111.         if(!(childCount == 0))
    112.         {
    113.             List<int> childList = new List<int>();
    114.             for (int i = 0; i < childCount; i++)
    115.             {
    116.                 NodeInstanceInformation child = new NodeInstanceInformation();
    117.                 child = GenerateNodeTree(gameObject.transform.GetChild(i).gameObject, child);
    118.                 childList.Add(child.Index);
    119.                 nodeList.Add(child);
    120.             }
    121.             entityInformation.Children = childList.ToArray();
    122.         }
    123.         #endregion
    124.  
    125.         return entityInformation;
    126.     }
    127. }
    128.  
    This works out really well and gives me a list, that i can now spawn as entity on scene start:

    Code (CSharp):
    1.  
    2. public partial class CockpitWorldManager
    3. {
    4.     public static string PathToCockpit = "Spaceships/Cockpits/HeavyFighterCockpit/HeavyFighterCockpit";
    5.  
    6.     private static System.Collections.Generic.Dictionary<int, NodeInstanceInformation> nodeList;
    7.     static EntityLookupTable table;
    8.     #region InitWithScene
    9.     [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterSceneLoad)]
    10.     public static void InitWithScene()
    11.     {
    12.         GameObject tableObject = GameObject.FindGameObjectWithTag("GameController");
    13.         table = tableObject.GetComponent<EntityLookupTable>();
    14.  
    15.         Debug.Log("Start Spawning");
    16.         var InputResourceFile = Resources.Load<ScriptableEntity>(PathToCockpit);
    17.         Debug.Log("Input Resource File loaded: " + InputResourceFile == null);
    18.         if (InputResourceFile == null) return;
    19.         Debug.Log("Spawning Parent Entity" );
    20.         Entity parent = SpawnParentEntity();
    21.         Debug.Log("Parent Entity Spawned" );
    22.         Debug.Log("Read in Nodes" );
    23.         nodeList = new System.Collections.Generic.Dictionary<int, NodeInstanceInformation>();
    24.         foreach(NodeInstanceInformation info in InputResourceFile.NodeInformation)
    25.         {
    26.             nodeList.Add(info.Index, info);
    27.         }
    28.         Debug.Log("Nodes read in" );
    29.         NodeInstanceInformation start = nodeList[0];
    30.         Debug.Log("Start Spawning" );
    31.         if (start.Mesh != null)
    32.             SpawnMeshRendererInstanceEntity(parent, start);
    33.         else
    34.             SpawnConnectorNode(parent, start);
    35.         Debug.Log("Finish Spawning");
    36.     }
    37.     #endregion
    38.  
    39.     #region Spawn Parent Entity
    40.     /// <summary>
    41.     /// Spawns a new parent entity
    42.     /// </summary>
    43.     /// <returns>Returns the new parent entity</returns>
    44.     private static Entity SpawnParentEntity()
    45.     {
    46.         Entity parentEntity = entityManager.CreateEntity(parentArchetype);
    47.         return parentEntity;
    48.     }
    49.     #endregion
    50.  
    51.     #region Recursive Iteration
    52.     /// <summary>
    53.     /// This is a non-direct recursion which acts as a finisher of setting up entities.
    54.     /// If there are children, all those will be set up too
    55.     /// </summary>
    56.     /// <param name="parent">Parent Entity</param>
    57.     /// <param name="def">Children in definition file</param>
    58.     private static void RecursiveIteration(Entity parent, NodeInstanceInformation def)
    59.     {
    60.        
    61.         if(def.Children.Length != 0)
    62.         {
    63.             foreach (int child in def.Children)
    64.             {
    65.                 if (nodeList[child].Mesh != null)
    66.                     SpawnMeshRendererInstanceEntity(parent, nodeList[child]);
    67.                 else
    68.                     SpawnConnectorNode(parent, nodeList[child]);
    69.                 Debug.Log("Spawning " + def.Name);
    70.             }
    71.         }
    72.        
    73.     }
    74.     #endregion
    75.  
    76.     #region Spawn MeshRendererInstance Entity
    77.     /// <summary>
    78.     /// Spawns a new entity with position, rotation and scale and attaches
    79.     /// a given MeshInstanceRenderer to it.
    80.     /// Last it creates an Entity of AttachType and attaches the new
    81.     /// entity to the objects parent
    82.     /// </summary>
    83.     /// <param name="parent">The parent object of this child</param>
    84.     /// <param name="def">The MeshInstanceRenderer information</param>
    85.     private static void SpawnMeshRendererInstanceEntity(Entity parent, NodeInstanceInformation def)
    86.     {
    87.         table.entities.Add(def);
    88.  
    89.         Entity childEntity = entityManager.CreateEntity(meshInstanceRendererArchetype);
    90.         // Set up Position, Rotation and Scale
    91.         entityManager.SetComponentData(childEntity, new Position { Value = def.Position });
    92.         entityManager.SetComponentData(childEntity, new Rotation { Value = def.Rotation });
    93.         entityManager.SetComponentData(childEntity, new Scale { Value = def.Scale * MeshToEntityScale });        // Add MeshInstanceRenderer
    94.  
    95.         entityManager.AddSharedComponentData(childEntity,
    96.             new MeshInstanceRenderer {  mesh = def.Mesh,
    97.                                         material = def.Material} );
    98.  
    99.         // Attach to parent
    100.         Entity attach = entityManager.CreateEntity(localToParentArchetype);
    101.         /* Just for review purpose
    102.         var attach = entityManager.CreateEntity(typeof(Attach));
    103.         */
    104.         entityManager.SetComponentData(attach, new Attach { Parent = parent, Child = childEntity });
    105.  
    106.         RecursiveIteration(childEntity, def);
    107.     }
    108.     #endregion
    109.  
    110.     #region Spawn Connector Node
    111.     /// <summary>
    112.     /// Sets up an entity, that acts as a connector entity between nodes
    113.     /// </summary>
    114.     /// <param name="parent">parent Node</param>
    115.     /// <param name="def">NodeInstance Information definition</param>
    116.     private static void SpawnConnectorNode(Entity parent, NodeInstanceInformation def)
    117.     {
    118.         table.entities.Add(def);
    119.  
    120.         Entity childEntity = entityManager.CreateEntity(connectorArchetype);
    121.  
    122.         entityManager.SetComponentData(childEntity, new Position { Value = def.Position});
    123.         entityManager.SetComponentData(childEntity, new Rotation { Value = def.Rotation });
    124.         entityManager.SetComponentData(childEntity, new Scale { Value = def.Scale * MeshToEntityScale });
    125.  
    126.         // Attach to parent
    127.         Entity attach = entityManager.CreateEntity(localToParentArchetype);      
    128.         entityManager.SetComponentData(attach, new Attach { Parent = parent, Child = childEntity });
    129.  
    130.         RecursiveIteration(childEntity, def);
    131.     }
    132.     #endregion
    133. }
    134.  
    It's working ! Somehow ....
    But there are Problems left !
    Some of my Meshes are mirrored, as can be seen in my upload.
    When instantiating the entities, the mesh seems to be mirrored another time, and i can't see why.
    Everything is mirrored on an axe, that isn't touched anywhere, and i cannot see the logic, that is causing this.
    Things are translated to the backside, and i cannot say, what is going wrong, or how i can avoid this.

    As anybody can see, this happens on any rescaled thing, buttons, switches - everything.
    In the shown scene, many objects, that needed a rescale are mirrored to the backside - somehow...
     

    Attached Files: