Your comments

Hi Andrew,

this new code for CADLink.cs should fix your issue. Please check and give me feedback.

Thanks

Thomas

// Game4Automation (R) Framework for Automation Concept Design, Virtual Commissioning and 3D-HMI
// (c) 2019 in2Sight GmbH - Usage of this source code only allowed based on License conditions see https://game4automation.com/lizenz  

using System.IO;
using System.Linq;
using UnityEngine;
using NaughtyAttributes;
using ThreeMf;
using UnityEditor;
using System.Collections.Generic;
using UnityEngine.Analytics;
using UnityScript.Steps;

namespace game4automation
{
    public class CADLink : MonoBehaviour
    {
        [BoxGroup("Import CAD")] public string File;
        [BoxGroup("Import CAD")] public bool DeleteBeforeImporting;

        [BoxGroup("Import CAD")] public bool RemoveTopAssemblyNode = false;
        [BoxGroup("Import CAD")] public bool NameClonesIdentical;
        [BoxGroup("Import CAD")] public float ImportScaleFactor = 0.001f;

        [BoxGroup("Import CAD")] [ReadOnly] public string Status = "";

        [BoxGroup("Advanced")] public bool ImportDistinctVertices = true;
        [BoxGroup("Advanced")] public bool UnityRecalculateNormals = false;
        [BoxGroup("Advanced")] public bool AdvancedRecalculateNormals = true;

        [BoxGroup("Advanced")] [EnableIf("AdvancedRecalculateNormals")]
        public float AdvancedRecalcluateNormalsAngle = 30;

        [BoxGroup("Advanced")] [InfoBox("UV Mapping takes long - just use if needed")]
        public bool CalculateUVS = false;

        [EnableIf("CalculateUVS")] [BoxGroup("Advanced")]
        public float UVScalfactor = 1.0f;

        [BoxGroup("Materials")] public bool SetAndCreateMaterials = true;

        [BoxGroup("Materials")] [EnableIf("SetAndCreateMaterials")]
        public bool OverwriteExistingMaterials = false;

        [BoxGroup("Materials")] [EnableIf("SetAndCreateMaterials")]
        public string NewMaterialPath;

        [BoxGroup("Materials")] [EnableIf("SetAndCreateMaterials")]
        public MaterialMapping MaterialMapping;


        private bool SetPositions = true;

        private float Progress = 0;
        private bool cancel = false;

        private List<Material> newmaterials = new List<Material>();
        private List<CADPart> nosubcomponent = new List<CADPart>();

        [Button("Create New Material Mapping")]
        private void CreateMeaterialMapping()
        {
#if UNITY_EDITOR
            var mapping = CreateAsset<MaterialMapping>();

            MaterialMapping = (MaterialMapping) mapping;
#endif
        }

        [Button("Update Materials")]
        private void SetMaterials()
        {
            newmaterials.Clear();
            // Go through all CAD parts with meshes and check if material is assigned
            // if not assign next material of upper levels
            CADPart[] cadparts = GetComponentsInChildren<CADPart>(this);
            foreach (CADPart cadpart in cadparts)
            {
                MeshFilter meshfilter = cadpart.GetComponent<MeshFilter>();
                Renderer meshrenderer = cadpart.GetComponent<Renderer>();

                if (meshrenderer != null)
                {
                    // Part with Mesh has material assigned
                    if (cadpart.Color != "" || cadpart.Material != "")
                    {
                        meshrenderer.sharedMaterial = Get3mfMaterial(cadpart.Color, cadpart.Material);
                    }
                    else
                        // if not find next CADpart upwards with Material
                    {
                        Component[] uppercadparts = cadpart.GetComponentsInParent(typeof(CADPart), true);
                        foreach (CADPart uppercadpart in uppercadparts)
                        {
                            if (uppercadpart.Color != "")
                            {
                                meshrenderer.sharedMaterial = Get3mfMaterial(uppercadpart.Color, uppercadpart.Material);
                                break;
                            }
                        }
                    }
                }
            }
        }


        [Button("Select CAD Import File")]
        void SelectFile()
        {
#if UNITY_EDITOR
            File = EditorUtility.OpenFilePanel("Select file to import", File, "3mf");
#endif
        }


        [Button("Delete Import")]
        public void DeleteAll()
        {
            CADPart[] children = transform.GetComponentsInChildren<CADPart>();
            foreach (var child in children.ToArray())
            {
                if (child != null)
                    DestroyImmediate(child.gameObject);
            }
        }

        public void Log(string message)
        {
            Debug.Log("Game4Automation CAD Import: " + message);
#if UNITY_EDITOR
            cancel = EditorUtility.DisplayCancelableProgressBar(
                "CAD Livelink - Import",
                message,
                Progress);
#endif
            Status = message;
        }


        [Button("Import CAD File")]
        public void ImportCad()
        {
            cancel = false;
            if (!System.IO.File.Exists(File))
            {
#if UNITY_EDITOR
                EditorUtility.DisplayDialog("ERROR", "3MF File at defined path [" + File + "] not existing.", "OK", "");
                return;
#endif
                Debug.LogError("3MF File at defined path [" + File + "] not existing.");
            }

            if (!Directory.Exists(NewMaterialPath) && SetAndCreateMaterials)
            {
#if UNITY_EDITOR
                EditorUtility.DisplayDialog("ERROR", "New material path [" + NewMaterialPath + "] not existing.", "OK",
                    "");
                return;
#endif
                Debug.LogError("3MF File at defined path [" + File + "] not existing.");
            }

            if (DeleteBeforeImporting)
                DeleteAll();
            Progress = 0.05f;
            var num = 0;
            nosubcomponent.Clear();
            Log("Load 3MF File");

            var test = ThreeMfFile.Load(File, 1);
            Debug.Log("Import 3MF");
            // Import Positions and Meshes for all Ressources
            foreach (var model in test.Models)
            {
                foreach (var resource in model.Resources)
                {
                    num++;
                    Progress = (float) num / (float) model.Resources.Count;
                    if (cancel)
                    {
                        Debug.Log("Import Canceled by User");
                        #if UNITY_EDITOR
                            EditorUtility.ClearProgressBar();
                        #endif
                        return;
                    }

                    if (resource.GetType() == typeof(ThreeMfObject))
                    {
                        var obj = (ThreeMfObject) resource;
                        Log("Import Part " + obj.Name + " " + obj.Id.ToString());

                        var part = CreateCadPart(this.gameObject, obj.Name, obj.Id.ToString(), obj);
                        part.File = File;
                        part.LastUpdate = System.DateTime.Now.ToString();
                        // Mesh at Part
                        if (obj.Mesh != null)
                        {
                            CreateMesh(part, obj.Mesh);
                        }
                        
                        // Get Porpertyindex

                        var propindex = obj.PropertyIndex;
                        
                        // Properties at Part
                        if (obj.PropertyResource != null)
                        {
                            if (obj.PropertyResource.PropertyItems != null)
                            {

                                var currindex = 0;
                               foreach (var propertyItem in obj.PropertyResource.PropertyItems)
                                {
                                    if (currindex == propindex)
                                    {
                                        Material material = null;
                                        if (propertyItem.GetType() == typeof(ThreeMfColor))
                                        {
                                            var color = (ThreeMfColor) propertyItem;
                                            part.Color = color.Color.ToString();
                                            part.Material = "";
                                        }

                                        if (propertyItem.GetType() == typeof(ThreeMfBase))
                                        {
                                            var color = (ThreeMfBase) propertyItem;
                                            part.Color = color.Color.ToString();
                                            part.Material = color.Name;
                                        }
                                    }

                                    currindex = currindex + 1;
                                }
                            }
                        }

                        foreach (var component in obj.Components)
                        {
                            MakeAsSubComponent(obj.Id.ToString(), component.Object.Id.ToString(), component);
                        }
                    }
                }

                // Set Positions for Build information
                foreach (var item in model.Items)
                {
                   SetBuildPosition(item);
                }
                

            }
            
       

            if (SetAndCreateMaterials)
                SetMaterials();

            if (RemoveTopAssemblyNode)
                RemoveTopAssembly();

            #if UNITY_EDITOR
                 EditorUtility.ClearProgressBar();
            #endif
        }

        private void RemoveTopAssembly()
        {
            var top = nosubcomponent[0];
            List<GameObject> children = new List<GameObject>();
            if (top != null)
            {
                for (int i = 0; i < top.transform.childCount; i++)
                {
                    children.Add(top.transform.GetChild(i).gameObject);
                }
            }

            foreach (var child in children)
            {
                child.transform.parent = this.transform;
            }

            DestroyImmediate(top.gameObject);
        }


        private Material Get3mfMaterial(string colorname, string materialname)
        {
            
            Material newmaterial = null;


            //    colorname.Replace("#", "Hex");
            var tempMaterial = new Material(Shader.Find("Standard"));

            // check if material assignment in material mapping
            // 1st check if color and material combination are defined
            if (MaterialMapping != null)
            {
                foreach (var mapping in MaterialMapping.Mappings)
                {
                    if (mapping.Colorname == colorname && mapping.Materialname == materialname)
                        return mapping.Material;
                }
            }

            // 2nd check if material is defined 
            if (MaterialMapping != null)
            {
                foreach (var mapping in MaterialMapping.Mappings)
                {
                    if (mapping.Materialname == materialname && mapping.Materialname != "")
                        return mapping.Material;
                }
            }

            // 3rd check if color is defined 
            if (MaterialMapping != null)
            {
                foreach (var mapping in MaterialMapping.Mappings)
                {
                    if (mapping.Colorname == colorname && mapping.Colorname != "")
                        return mapping.Material;
                }
            }

            #if UNITY_EDITOR         
            // create new material if not existing
            string[] assets = AssetDatabase.FindAssets(colorname + " t:material");

            bool createnewmaterial = true;

            if (assets.Length != 0 && OverwriteExistingMaterials == false)
            {
                createnewmaterial = false;
            }

            if (assets.Length != 0 && OverwriteExistingMaterials == true)
            {
                newmaterial = AssetDatabase.LoadAssetAtPath<Material>(AssetDatabase.GUIDToAssetPath(assets[0]));

                if (newmaterials.Contains(newmaterial))
                {
                    createnewmaterial = false;
                }
                else
                {
                    createnewmaterial = true;
                    AssetDatabase.DeleteAsset(AssetDatabase.GUIDToAssetPath(assets[0]));
                }
            }

            if (createnewmaterial)
            {
                var path = Path.Combine(NewMaterialPath, colorname + ".mat");
                AssetDatabase.CreateAsset(tempMaterial, path);
                newmaterial = AssetDatabase.LoadAssetAtPath<Material>(path);
                newmaterials.Add(newmaterial);
                var col = new Color();
                ColorUtility.TryParseHtmlString(colorname, out col);
                newmaterial.color = col;
            }
            else
            {
                newmaterial = AssetDatabase.LoadAssetAtPath<Material>(AssetDatabase.GUIDToAssetPath(assets[0]));
            }
            #else
                newmaterial =  new Material(Shader.Find("Standard"));   
                var col = new Color();
                ColorUtility.TryParseHtmlString(colorname, out col);
                newmaterial.color = col;
            #endif
            
            

            return newmaterial;
        }

        private void CreateMesh(CADPart part, ThreeMfMesh mesh)
        {
            MeshFilter meshfilter = part.transform.GetComponent<MeshFilter>();
            if (meshfilter == null)
            {
                meshfilter = part.transform.gameObject.AddComponent<MeshFilter>();
            }

            MeshRenderer meshrenderer = part.transform.GetComponent<MeshRenderer>();
            if (meshrenderer == null)
            {
                meshrenderer = part.transform.gameObject.AddComponent<MeshRenderer>();
            }

            Mesh umesh = new Mesh();

            umesh.name = part.gameObject.name;
            umesh.vertices = mesh.uVertices.ToArray();
            umesh.triangles = mesh.uTriangles.ToArray();

            if (ImportDistinctVertices)
                CADMeshTools.DistinctVertices(ref umesh);
            if (UnityRecalculateNormals)
                umesh.RecalculateNormals();
            if (AdvancedRecalculateNormals)
                CADMeshTools.RecalculateNormals(umesh, AdvancedRecalcluateNormalsAngle);
            if (CalculateUVS)
                CADMeshTools.CalculateUVS(ref umesh, UVScalfactor);
            if (ImportScaleFactor != 1)
                CADMeshTools.ScaleMesh(ref umesh, ImportScaleFactor);


            meshfilter.mesh = umesh;
        }


        private CADPart CreateCadPart(GameObject parent, string name, string Id, ThreeMfObject threemfobject)
        {
            var part = GetCADPart(Id);

            if (part == null)
            {
                // Create new part
                var newobj = new GameObject(name);
                part = newobj.AddComponent<CADPart>();
                newobj.transform.parent = parent.transform;
                newobj.transform.localPosition = new Vector3(0, 0, 0);
                newobj.transform.localEulerAngles = new Vector3(0, 0, 0);
            }

            part.Id = Id;
            part.Name = name;
            part.LastUpdate = System.DateTime.Now.ToString();
            part.Set3MFfObject(threemfobject);
            nosubcomponent.Add(part);
            return part;
        }


        public void SetBuildPosition(ThreeMfModelItem item)
        {
            var id = item.Object.Id.ToString();
            var comp = GetCADPart(id);
            
            comp.ImportPos = item.Transform.GetPosition() * ImportScaleFactor;
            comp.ImportRotOriginal = item.Transform.Get3mfAngles();
            comp.ImportScale = item.Transform.GetScale();
            if (SetPositions)
            {
                comp.transform.localPosition = comp.ImportPos;
                comp.transform.localRotation = item.Transform.GetRotationQuaternion();
            }

            comp.ImportRot = comp.transform.localRotation.eulerAngles;    
        }
        
        
        public void MakeAsSubComponent(string idparent, string idchild, ThreeMfComponent component)
        {
            var parent = GetCADPart(idparent);
            var child = GetCADPart(idchild);
            nosubcomponent.Remove(child);
            CADPart comp;

            if (child.AssembledInto == null)
            {
                child.MakeAsSubCompponent(parent);
                comp = child;
            }
            else
            {
                // Is Allready assembled into another component - make copy
                var copy = child.CreateClone(NameClonesIdentical);
                copy.MakeAsSubCompponent(parent);
                comp = copy;
            }

            comp.ImportPos = component.Transform.GetPosition() * ImportScaleFactor;
            comp.ImportRotOriginal = component.Transform.Get3mfAngles();
            comp.ImportScale = component.Transform.GetScale();
            if (SetPositions)
            {
                comp.transform.localPosition = comp.ImportPos;
                comp.transform.localRotation = component.Transform.GetRotationQuaternion();
            }

            comp.ImportRot = comp.transform.localRotation.eulerAngles;
        }

        private CADPart GetCADPart(string id)
        {
            CADPart[] children = transform.GetComponentsInChildren<CADPart>();
            foreach (var child in children)
            {
                if (child.Id == id && child.IsClone == false)
                {
                    return child;
                }
            }

            return null;
        }

        public static object CreateAsset<T>() where T : ScriptableObject
        {
            T asset = ScriptableObject.CreateInstance<T>();
#if UNITY_EDITOR
            var find = AssetDatabase.FindAssets(
                "StandardMaterialMapping t:ScriptableObject");

            string path = AssetDatabase.GUIDToAssetPath(find[0]);
            var theasset = AssetDatabase.LoadAssetAtPath<ScriptableObject>(path);
            if (path == "")
            {
                path = "Assets";
            }
            else if (Path.GetExtension(path) != "")
            {
                path = path.Replace(Path.GetFileName(AssetDatabase.GetAssetPath(theasset)), "");
            }

            string assetPathAndName =
                AssetDatabase.GenerateUniqueAssetPath(path + "/New " + typeof(T).ToString() + ".asset");

            AssetDatabase.CreateAsset(asset, assetPathAndName);

            AssetDatabase.SaveAssets();
            AssetDatabase.Refresh();
#endif
            return asset;
        }
    }
}

I can't open the Solidedge file - can you please send it as a Step file.

OK thanks for the files. We received it. We will check it. Because we are nearly starting the weekend now it might take until Monday evening.

OK thanks. I am happy that at least the color problem is solved. We will also get solved the rest.  You could delete everything in the parts and just leave some primitives which show me how it should be positioned. You could also additionally send me the Solidedge file - this will allow me to compare both.

Hi Andrew,

for the color problem (Solidedge has another way to use the ColorGroups) we will release an update soon. You can already replace CADLINK.cs with this file - this should help.

For the Assembly Positions I will need to check. Can you please send me an example exported 3mf from solidworks to info@game4automation.com.

Thanks

// Game4Automation (R) Framework for Automation Concept Design, Virtual Commissioning and 3D-HMI
// (c) 2019 in2Sight GmbH - Usage of this source code only allowed based on License conditions see https://game4automation.com/lizenz  

using System.IO;
using System.Linq;
using UnityEngine;
using NaughtyAttributes;
using ThreeMf;
using UnityEditor;
using System.Collections.Generic;

namespace game4automation
{
    public class CADLink : MonoBehaviour
    {
        [BoxGroup("Import CAD")] public string File;
        [BoxGroup("Import CAD")] public bool DeleteBeforeImporting;

        [BoxGroup("Import CAD")] public bool RemoveTopAssemblyNode = false;
        [BoxGroup("Import CAD")] public bool NameClonesIdentical;
        [BoxGroup("Import CAD")] public float ImportScaleFactor = 0.001f;

        [BoxGroup("Import CAD")] [ReadOnly] public string Status = "";

        [BoxGroup("Advanced")] public bool ImportDistinctVertices = true;
        [BoxGroup("Advanced")] public bool UnityRecalculateNormals = false;
        [BoxGroup("Advanced")] public bool AdvancedRecalculateNormals = true;

        [BoxGroup("Advanced")] [EnableIf("AdvancedRecalculateNormals")]
        public float AdvancedRecalcluateNormalsAngle = 30;

        [BoxGroup("Advanced")] [InfoBox("UV Mapping takes long - just use if needed")]
        public bool CalculateUVS = false;

        [EnableIf("CalculateUVS")] [BoxGroup("Advanced")]
        public float UVScalfactor = 1.0f;

        [BoxGroup("Materials")] public bool SetAndCreateMaterials = true;

        [BoxGroup("Materials")] [EnableIf("SetAndCreateMaterials")]
        public bool OverwriteExistingMaterials = false;

        [BoxGroup("Materials")] [EnableIf("SetAndCreateMaterials")]
        public string NewMaterialPath;

        [BoxGroup("Materials")] [EnableIf("SetAndCreateMaterials")]
        public MaterialMapping MaterialMapping;


        private bool SetPositions = true;

        private float Progress = 0;
        private bool cancel = false;

        private List<Material> newmaterials = new List<Material>();
        private List<CADPart> nosubcomponent = new List<CADPart>();

        [Button("Create New Material Mapping")]
        private void CreateMeaterialMapping()
        {
#if UNITY_EDITOR
            var mapping = CreateAsset<MaterialMapping>();

            MaterialMapping = (MaterialMapping) mapping;
#endif
        }

        [Button("Update Materials")]
        private void SetMaterials()
        {
            newmaterials.Clear();
            // Go through all CAD parts with meshes and check if material is assigned
            // if not assign next material of upper levels
            CADPart[] cadparts = GetComponentsInChildren<CADPart>(this);
            foreach (CADPart cadpart in cadparts)
            {
                MeshFilter meshfilter = cadpart.GetComponent<MeshFilter>();
                Renderer meshrenderer = cadpart.GetComponent<Renderer>();

                if (meshrenderer != null)
                {
                    // Part with Mesh has material assigned
                    if (cadpart.Color != "" || cadpart.Material != "")
                    {
                        meshrenderer.sharedMaterial = Get3mfMaterial(cadpart.Color, cadpart.Material);
                    }
                    else
                        // if not find next CADpart upwards with Material
                    {
                        Component[] uppercadparts = cadpart.GetComponentsInParent(typeof(CADPart), true);
                        foreach (CADPart uppercadpart in uppercadparts)
                        {
                            if (uppercadpart.Color != "")
                            {
                                meshrenderer.sharedMaterial = Get3mfMaterial(uppercadpart.Color, uppercadpart.Material);
                                break;
                            }
                        }
                    }
                }
            }
        }


        [Button("Select CAD Import File")]
        void SelectFile()
        {
#if UNITY_EDITOR
            File = EditorUtility.OpenFilePanel("Select file to import", File, "3mf");
#endif
        }


        [Button("Delete Import")]
        public void DeleteAll()
        {
            CADPart[] children = transform.GetComponentsInChildren<CADPart>();
            foreach (var child in children.ToArray())
            {
                if (child != null)
                    DestroyImmediate(child.gameObject);
            }
        }

        public void Log(string message)
        {
            Debug.Log("Game4Automation CAD Import: " + message);
#if UNITY_EDITOR
            cancel = EditorUtility.DisplayCancelableProgressBar(
                "CAD Livelink - Import",
                message,
                Progress);
#endif
            Status = message;
        }


        [Button("Import CAD File")]
        public void ImportCad()
        {
            cancel = false;
            if (!System.IO.File.Exists(File))
            {
#if UNITY_EDITOR
                EditorUtility.DisplayDialog("ERROR", "3MF File at defined path [" + File + "] not existing.", "OK", "");
                return;
#endif
                Debug.LogError("3MF File at defined path [" + File + "] not existing.");
            }

            if (!Directory.Exists(NewMaterialPath) && SetAndCreateMaterials)
            {
#if UNITY_EDITOR
                EditorUtility.DisplayDialog("ERROR", "New material path [" + NewMaterialPath + "] not existing.", "OK",
                    "");
                return;
#endif
                Debug.LogError("3MF File at defined path [" + File + "] not existing.");
            }

            if (DeleteBeforeImporting)
                DeleteAll();
            Progress = 0.05f;
            var num = 0;
            nosubcomponent.Clear();
            Log("Load 3MF File");

            var test = ThreeMfFile.Load(File, 1);
            Debug.Log("Import 3MF");
            foreach (var model in test.Models)
            {
                foreach (var resource in model.Resources)
                {
                    num++;
                    Progress = (float) num / (float) model.Resources.Count;
                    if (cancel)
                    {
                        Debug.Log("Import Canceled by User");
                        #if UNITY_EDITOR
                            EditorUtility.ClearProgressBar();
                        #endif
                        return;
                    }

                    if (resource.GetType() == typeof(ThreeMfObject))
                    {
                        var obj = (ThreeMfObject) resource;
                        Log("Import Part " + obj.Name + " " + obj.Id.ToString());

                        var part = CreateCadPart(this.gameObject, obj.Name, obj.Id.ToString(), obj);
                        part.File = File;
                        part.LastUpdate = System.DateTime.Now.ToString();
                        // Mesh at Part
                        if (obj.Mesh != null)
                        {
                            CreateMesh(part, obj.Mesh);
                        }
                        
                        // Get Porpertyindex

                        var propindex = obj.PropertyIndex;
                        
                        // Properties at Part
                        if (obj.PropertyResource != null)
                        {
                            if (obj.PropertyResource.PropertyItems != null)
                            {

                                var currindex = 0;
                               foreach (var propertyItem in obj.PropertyResource.PropertyItems)
                                {
                                    if (currindex == propindex)
                                    {
                                        Material material = null;
                                        if (propertyItem.GetType() == typeof(ThreeMfColor))
                                        {
                                            var color = (ThreeMfColor) propertyItem;
                                            part.Color = color.Color.ToString();
                                            part.Material = "";
                                        }

                                        if (propertyItem.GetType() == typeof(ThreeMfBase))
                                        {
                                            var color = (ThreeMfBase) propertyItem;
                                            part.Color = color.Color.ToString();
                                            part.Material = color.Name;
                                        }
                                    }

                                    currindex = currindex + 1;
                                }
                            }
                        }

                        foreach (var component in obj.Components)
                        {
                            MakeAsSubComponent(obj.Id.ToString(), component.Object.Id.ToString(), component);
                        }
                    }
                }
            }

            if (SetAndCreateMaterials)
                SetMaterials();

            if (RemoveTopAssemblyNode)
                RemoveTopAssembly();

            #if UNITY_EDITOR
                 EditorUtility.ClearProgressBar();
            #endif
        }

        private void RemoveTopAssembly()
        {
            var top = nosubcomponent[0];
            List<GameObject> children = new List<GameObject>();
            if (top != null)
            {
                for (int i = 0; i < top.transform.childCount; i++)
                {
                    children.Add(top.transform.GetChild(i).gameObject);
                }
            }

            foreach (var child in children)
            {
                child.transform.parent = this.transform;
            }

            DestroyImmediate(top.gameObject);
        }


        private Material Get3mfMaterial(string colorname, string materialname)
        {
            
            Material newmaterial = null;


            //    colorname.Replace("#", "Hex");
            var tempMaterial = new Material(Shader.Find("Standard"));

            // check if material assignment in material mapping
            // 1st check if color and material combination are defined
            if (MaterialMapping != null)
            {
                foreach (var mapping in MaterialMapping.Mappings)
                {
                    if (mapping.Colorname == colorname && mapping.Materialname == materialname)
                        return mapping.Material;
                }
            }

            // 2nd check if material is defined 
            if (MaterialMapping != null)
            {
                foreach (var mapping in MaterialMapping.Mappings)
                {
                    if (mapping.Materialname == materialname && mapping.Materialname != "")
                        return mapping.Material;
                }
            }

            // 3rd check if color is defined 
            if (MaterialMapping != null)
            {
                foreach (var mapping in MaterialMapping.Mappings)
                {
                    if (mapping.Colorname == colorname && mapping.Colorname != "")
                        return mapping.Material;
                }
            }

            #if UNITY_EDITOR         
            // create new material if not existing
            string[] assets = AssetDatabase.FindAssets(colorname + " t:material");

            bool createnewmaterial = true;

            if (assets.Length != 0 && OverwriteExistingMaterials == false)
            {
                createnewmaterial = false;
            }

            if (assets.Length != 0 && OverwriteExistingMaterials == true)
            {
                newmaterial = AssetDatabase.LoadAssetAtPath<Material>(AssetDatabase.GUIDToAssetPath(assets[0]));

                if (newmaterials.Contains(newmaterial))
                {
                    createnewmaterial = false;
                }
                else
                {
                    createnewmaterial = true;
                    AssetDatabase.DeleteAsset(AssetDatabase.GUIDToAssetPath(assets[0]));
                }
            }

            if (createnewmaterial)
            {
                var path = Path.Combine(NewMaterialPath, colorname + ".mat");
                AssetDatabase.CreateAsset(tempMaterial, path);
                newmaterial = AssetDatabase.LoadAssetAtPath<Material>(path);
                newmaterials.Add(newmaterial);
                var col = new Color();
                ColorUtility.TryParseHtmlString(colorname, out col);
                newmaterial.color = col;
            }
            else
            {
                newmaterial = AssetDatabase.LoadAssetAtPath<Material>(AssetDatabase.GUIDToAssetPath(assets[0]));
            }
            #else
                newmaterial =  new Material(Shader.Find("Standard"));   
                var col = new Color();
                ColorUtility.TryParseHtmlString(colorname, out col);
                newmaterial.color = col;
            #endif
            
            

            return newmaterial;
        }

        private void CreateMesh(CADPart part, ThreeMfMesh mesh)
        {
            MeshFilter meshfilter = part.transform.GetComponent<MeshFilter>();
            if (meshfilter == null)
            {
                meshfilter = part.transform.gameObject.AddComponent<MeshFilter>();
            }

            MeshRenderer meshrenderer = part.transform.GetComponent<MeshRenderer>();
            if (meshrenderer == null)
            {
                meshrenderer = part.transform.gameObject.AddComponent<MeshRenderer>();
            }

            Mesh umesh = new Mesh();

            umesh.name = part.gameObject.name;
            umesh.vertices = mesh.uVertices.ToArray();
            umesh.triangles = mesh.uTriangles.ToArray();

            if (ImportDistinctVertices)
                CADMeshTools.DistinctVertices(ref umesh);
            if (UnityRecalculateNormals)
                umesh.RecalculateNormals();
            if (AdvancedRecalculateNormals)
                CADMeshTools.RecalculateNormals(umesh, AdvancedRecalcluateNormalsAngle);
            if (CalculateUVS)
                CADMeshTools.CalculateUVS(ref umesh, UVScalfactor);
            if (ImportScaleFactor != 1)
                CADMeshTools.ScaleMesh(ref umesh, ImportScaleFactor);


            meshfilter.mesh = umesh;
        }


        private CADPart CreateCadPart(GameObject parent, string name, string Id, ThreeMfObject threemfobject)
        {
            var part = GetCADPart(Id);

            if (part == null)
            {
                // Create new part
                var newobj = new GameObject(name);
                part = newobj.AddComponent<CADPart>();
                newobj.transform.parent = parent.transform;
                newobj.transform.localPosition = new Vector3(0, 0, 0);
                newobj.transform.localEulerAngles = new Vector3(0, 0, 0);
            }

            part.Id = Id;
            part.Name = name;
            part.LastUpdate = System.DateTime.Now.ToString();
            part.Set3MFfObject(threemfobject);
            nosubcomponent.Add(part);
            return part;
        }


        public void MakeAsSubComponent(string idparent, string idchild, ThreeMfComponent component)
        {
            var parent = GetCADPart(idparent);
            var child = GetCADPart(idchild);
            nosubcomponent.Remove(child);
            CADPart comp;

            if (child.AssembledInto == null)
            {
                child.MakeAsSubCompponent(parent);
                comp = child;
            }
            else
            {
                // Is Allready assembled into another component - make copy
                var copy = child.CreateClone(NameClonesIdentical);
                copy.MakeAsSubCompponent(parent);
                comp = copy;
            }

            comp.ImportPos = component.Transform.GetPosition() * ImportScaleFactor;
            comp.ImportRotOriginal = component.Transform.Get3mfAngles();
            comp.ImportScale = component.Transform.GetScale();
            if (SetPositions)
            {
                comp.transform.localPosition = comp.ImportPos;
                comp.transform.localRotation = component.Transform.GetRotationQuaternion();
            }

            comp.ImportRot = comp.transform.localRotation.eulerAngles;
        }

        private CADPart GetCADPart(string id)
        {
            CADPart[] children = transform.GetComponentsInChildren<CADPart>();
            foreach (var child in children)
            {
                if (child.Id == id && child.IsClone == false)
                {
                    return child;
                }
            }

            return null;
        }

        public static object CreateAsset<T>() where T : ScriptableObject
        {
            T asset = ScriptableObject.CreateInstance<T>();
#if UNITY_EDITOR
            var find = AssetDatabase.FindAssets(
                "StandardMaterialMapping t:ScriptableObject");

            string path = AssetDatabase.GUIDToAssetPath(find[0]);
            var theasset = AssetDatabase.LoadAssetAtPath<ScriptableObject>(path);
            if (path == "")
            {
                path = "Assets";
            }
            else if (Path.GetExtension(path) != "")
            {
                path = path.Replace(Path.GetFileName(AssetDatabase.GetAssetPath(theasset)), "");
            }

            string assetPathAndName =
                AssetDatabase.GenerateUniqueAssetPath(path + "/New " + typeof(T).ToString() + ".asset");

            AssetDatabase.CreateAsset(asset, assetPathAndName);

            AssetDatabase.SaveAssets();
            AssetDatabase.Refresh();
#endif
            return asset;
        }
    }
}

Hi Leon,

1) yes this is the case. In Professional there is the 3MF interface included (since yesterday). You can directly import from all CAD-Systems which are able to export 3MF. Professional will get aditional features fur the 3MF interface like Updating, Mesh reduction .....

2) Yes you only need to buy and use PixYZ if you want to import the mentioned formats. Which CAD System are you using. For Solidworks we will have soon addtional export functions (as Solidworks makro) which will be more than what PIXYZ is able to do (like export kinematics).

3) Yes, 3MF with Game4Automation Professional - the rest is standard unity.

4) Yes it is. The 3MF interface is just a script attached to a GameObject. You can use it also in Runtime (during simulation).

Best regards

Thomas

Yes, there is a bidirectional communication between the PLC and the Digital Twin in Unity. You can read PLC Outputs and write PLC Inputs.

Difference between Starter and Professional Version are the Interfaces - in Starter only TCP-IP with S7 in Professional additional Shared Memory (Simit), OPC-UA and PLCSimAdvanced. Professional also includes CAD interface. Starter not.


Cheers

Thomas