Esempio n. 1
0
        public static GameObject CreateDclPrimitive(DclPrimitiveType type, bool withCollider = true,
                                                    bool putOnFocusPosition = true)
        {
            GameObject gameObject = new GameObject(type.ToString());

            gameObject.AddComponent <MeshFilter>();
            if (putOnFocusPosition)
            {
                gameObject.transform.position = SceneView.lastActiveSceneView.pivot;
                Selection.objects             = new Object[] { gameObject };
                EditorUtility.SetDirty(gameObject);
                EditorSceneManager.MarkSceneDirty(gameObject.scene);
            }

            var meshRenderer = gameObject.AddComponent <MeshRenderer>();

            meshRenderer.sharedMaterial = PrimitiveHelper.GetDefaultMaterial();

            var dclObj = gameObject.AddComponent <DclObject>();

            dclObj.withCollision    = withCollider;
            dclObj.dclPrimitiveType = type;


            SetDclPrimitiveMesh(dclObj, dclObj.dclPrimitiveType);

            return(gameObject);
        }
 private void Awake()
 {
     sceneToGlTFWiz = GetComponent <SceneToGlTFWiz>();
     if (!sceneToGlTFWiz)
     {
         sceneToGlTFWiz = gameObject.AddComponent <SceneToGlTFWiz>();
     }
     m_GroundMaterial       = new Material(PrimitiveHelper.GetDefaultMaterial().shader);
     m_GroundMaterial.color = Color.gray;
 }
Esempio n. 3
0
        static void ConvertSelectionToDclPrimitives()
        {
            if (EditorUtility.DisplayDialog("Convert To DCL Primitives",
                                            "This operation will traverse all your selected objects and convert Unity Primitives to DCL Primitives. Are you sure to continue?",
                                            "Confirm", "Abort"))
            {
                foreach (var gameObject in Selection.gameObjects)
                {
                    var meshFilter = gameObject.GetComponent <MeshFilter>();
                    if (meshFilter)
                    {
                        var           converted     = false;
                        PrimitiveType primitiveType = PrimitiveType.Cube;
                        if (meshFilter.sharedMesh == PrimitiveHelper.GetPrimitiveMesh(PrimitiveType.Cube))
                        {
                            primitiveType = PrimitiveType.Cube;
                            converted     = true;
                        }
                        else if (meshFilter.sharedMesh == PrimitiveHelper.GetPrimitiveMesh(PrimitiveType.Sphere))
                        {
                            primitiveType = PrimitiveType.Sphere;
                            converted     = true;
                        }
                        else if (meshFilter.sharedMesh == PrimitiveHelper.GetPrimitiveMesh(PrimitiveType.Quad))
                        {
                            primitiveType = PrimitiveType.Quad;
                            converted     = true;
                        }
                        else if (meshFilter.sharedMesh == PrimitiveHelper.GetPrimitiveMesh(PrimitiveType.Cylinder))
                        {
                            primitiveType = PrimitiveType.Cylinder;
                            converted     = true;
                        }

                        if (converted)
                        {
                            var dclObj = gameObject.GetComponent <DclObject>();
                            if (!dclObj)
                            {
                                dclObj = gameObject.AddComponent <DclObject>();
                            }
                            DclPrimitiveHelper.ConvertToDclPrimitive(dclObj, primitiveType);
                            dclObj.withCollision = gameObject.GetComponent <Collider>() != null;
                            EditorSceneManager.MarkSceneDirty(gameObject.scene);
                        }
                    }
                }
                //TODO:注册撤销功能
            }
        }
 void Update()// OnDrawGizmos()
 {
     if (parcels.Count > 0)
     {
         var baseParcel = parcels[0];
         var mtr        = new Matrix4x4();
         foreach (var parcel in parcels)
         {
             var pos = new Vector3((parcel.x - baseParcel.x) * 16, -0.1f, (parcel.y - baseParcel.y) * 16);
             pos += parcelPosOffset;
             mtr.SetTRS(pos, Quaternion.identity, new Vector3(1.6f, 1f, 1.6f));
             Graphics.DrawMesh(PrimitiveHelper.GetPrimitiveMesh(PrimitiveType.Plane), mtr, m_GroundMaterial, 0);
         }
     }
 }
 void Update()// OnDrawGizmos()
 {
     if (parcels.Count > 0)
     {
         var baseParcel = parcels[0];
         //            Gizmos.color = new Color(0.7, 0);
         foreach (var parcel in parcels)
         {
             var pos = new Vector3((parcel.x - baseParcel.x) * 10, 0, (parcel.y - baseParcel.y) * 10);
             //Gizmos.DrawWireCube(pos, new Vector3(10, 0f, 10));
             //Gizmos.DrawCube(pos, new Vector3(10, 0f, 10));
             //Gizmos.DrawMesh(PrimitiveHelper.GetPrimitiveMesh(PrimitiveType.Plane), pos);
             Graphics.DrawMesh(PrimitiveHelper.GetPrimitiveMesh(PrimitiveType.Plane), pos, Quaternion.identity, m_GroundMaterial, 0);
         }
     }
 }
Esempio n. 6
0
        public static void ProcessMaterial(Transform tra, bool isOnOrUnderGLTF, string entityName, List <Material> materialsToExport, StringBuilder exportStr, SceneStatistics statistics)
        {
            var rdrr = tra.GetComponent <MeshRenderer>();

            if (rdrr && tra.GetComponent <MeshFilter>())
            {
                List <Material> materialList;
                if (isOnOrUnderGLTF)
                {
                    materialList = rdrr.sharedMaterials.ToList();
                }
                else
                {
                    materialList = new List <Material>();
                    if (rdrr.sharedMaterial)
                    {
                        materialList.Add(rdrr.sharedMaterial);
                    }
                }
                foreach (var material in materialList)
                {
                    if (material && material != PrimitiveHelper.GetDefaultMaterial())
                    {
                        string materialName = "material" + Mathf.Abs(material.GetInstanceID());
                        if (!materialsToExport.Contains(material))
                        {
                            materialsToExport.Add(material);

                            if (exportStr != null)
                            {
                                exportStr.AppendFormat(NewMaterial, materialName);
                                exportStr.AppendFormat(SetMaterialAlbedoColor, materialName,
                                                       ToJsColorCtor(material.color));
                                exportStr.AppendFormat(SetMaterialMetallic, materialName,
                                                       material.GetFloat("_Metallic"));
                                exportStr.AppendFormat(SetMaterialRoughness, materialName,
                                                       1 - material.GetFloat("_Glossiness"));
                            }

                            var albedoTex = material.HasProperty("_MainTex") ? material.GetTexture("_MainTex") : null;
                            if (exportStr != null && albedoTex)
                            {
                                exportStr.AppendFormat(SetMaterialAlbedoTexture, materialName,
                                                       GetTextureRelativePath(albedoTex));
                            }

                            bool b = material.IsKeywordEnabled("_ALPHATEST_ON") ||
                                     material.IsKeywordEnabled("_ALPHABLEND_ON") ||
                                     material.IsKeywordEnabled("_ALPHAPREMULTIPLY_ON");
                            if (exportStr != null && b)
                            {
                                exportStr.AppendFormat(SetMaterialAlbedoTextureHasAlpha, materialName);
                                exportStr.AppendFormat(SetMaterialAlpha, materialName, material.color.a);
                            }

                            var bumpTexture = material.HasProperty("_BumpMap") ? material.GetTexture("_BumpMap") : null;
                            if (exportStr != null && bumpTexture)
                            {
                                exportStr.AppendFormat(SetMaterialBumptexture, materialName,
                                                       GetTextureRelativePath(bumpTexture));
                            }

                            var refractionTexture = material.HasProperty("_MetallicGlossMap")
                                ? material.GetTexture("_MetallicGlossMap")
                                : null;
                            if (exportStr != null && refractionTexture)
                            {
                                exportStr.AppendFormat(SetMaterialRefractionTexture, materialName,
                                                       GetTextureRelativePath(refractionTexture));
                            }

                            Texture emissiveTexture = null;
                            if (material.IsKeywordEnabled("_EMISSION"))
                            {
                                if (exportStr != null)
                                {
                                    exportStr.AppendFormat(SetMaterialEmissiveColor, materialName, ToJsColorCtor(material.GetColor("_EmissionColor")));
                                    //					        exportStr.AppendFormat(SetMaterialEmissiveIntensity, materialName, material.GetColor("_EmissionColor")); TODO:
                                }

                                emissiveTexture = material.HasProperty("_EmissionMap") ? material.GetTexture("_EmissionMap") : null;
                                if (exportStr != null && emissiveTexture)
                                {
                                    exportStr.AppendFormat(SetMaterialEmissiveTexture, materialName,
                                                           GetTextureRelativePath(emissiveTexture));
                                }
                            }

                            var textureList = isOnOrUnderGLTF ? resourceRecorder.gltfTextures : resourceRecorder.primitiveTexturesToExport;
                            if (albedoTex)
                            {
                                if (!textureList.Contains(albedoTex))
                                {
                                    textureList.Add(albedoTex);
                                }
                            }

                            if (refractionTexture)
                            {
                                if (!textureList.Contains(refractionTexture))
                                {
                                    textureList.Add(refractionTexture);
                                }
                            }

                            if (bumpTexture)
                            {
                                if (!textureList.Contains(bumpTexture))
                                {
                                    textureList.Add(bumpTexture);
                                }
                            }

                            if (emissiveTexture)
                            {
                                if (!textureList.Contains(emissiveTexture))
                                {
                                    textureList.Add(emissiveTexture);
                                }
                            }

                            if (!isOnOrUnderGLTF)
                            {
                                if (statistics != null)
                                {
                                    statistics.materialCount += 1;
                                }
                            }
                        }
                        if (exportStr != null)
                        {
                            exportStr.AppendFormat(SetMaterial, entityName, materialName);
                        }
                    }
                }
            }
            //const myMaterial = new Material()
            //myMaterial.albedoColor = "#FF0000"
            //myMaterial.metallic = 0.9
            //myMaterial.roughness = 0.1
            //myEntity.addComponent(myMaterial)
            //myMaterial.albedoTexture = new Texture("materials/wood.png")
            //myMaterial.bumpTexture = new Texture"materials/woodBump.png")
            //myMaterial.hasAlpha = true
        }
        public static void RecursivelyTraverseTransform(Transform tra, StringBuilder xmlBuilder, List <GameObject> meshesToExport, int indentLevel, SceneStatistics statistics, SceneWarningRecorder warningRecorder, Dictionary <GameObject, EDclNodeType> gameObjectToNodeTypeDict)
        {
            if (!tra.gameObject.activeInHierarchy)
            {
                return;
            }

            //TODO: Hide empty

            if (statistics != null)
            {
                statistics.entityCount += 1;
            }

            string nodeName        = null;
            var    nodeType        = EDclNodeType._none;
            var    position        = tra.localPosition;
            var    scale           = tra.localScale;
            var    eulerAngles     = tra.localEulerAngles;
            string pColor          = null;                //<...  color="#4A4A4A" ...>
            string pMaterial       = null;                //<... material="#mat01" ...>
            var    extraProperties = new StringBuilder(); //TODO: can be omitted if xmlBuilder == null

            var dclObject = tra.GetComponent <DclObject>();

            if (tra.GetComponent <DclCustomNode>())
            {
                var customNode = tra.GetComponent <DclCustomNode>();
                nodeName = customNode.nodeName;
                nodeType = EDclNodeType.CustomNode;
                if (customNode.position)
                {
                    extraProperties.AppendFormat(" position={{{0}}}", Vector3ToJSONString(tra.localPosition));
                }
                if (customNode.rotation)
                {
                    extraProperties.AppendFormat(" rotation={{{0}}}", Vector3ToJSONString(tra.eulerAngles));
                }
                if (customNode.scale)
                {
                    extraProperties.AppendFormat(" scale={{{0}}}", Vector3ToJSONString(tra.localScale));
                }

                if (customNode.propertyPairs != null)
                {
                    foreach (var propertyPair in customNode.propertyPairs)
                    {
                        extraProperties.AppendFormat(" {0}={1}", propertyPair.name, propertyPair.value);
                    }
                }
            }
            else
            {
                if (tra.GetComponent <MeshFilter>() && tra.GetComponent <MeshRenderer>())               //Primitives & glTF
                {
                    if (dclObject)
                    {
                        switch (dclObject.dclPrimitiveType)
                        {
                        case DclPrimitiveType.box:
                            nodeName = "box";
                            nodeType = EDclNodeType.box;
                            break;

                        case DclPrimitiveType.sphere:
                            nodeName = "sphere";
                            nodeType = EDclNodeType.sphere;
                            break;

                        case DclPrimitiveType.plane:
                            nodeName = "plane";
                            nodeType = EDclNodeType.plane;
                            break;

                        case DclPrimitiveType.cylinder:
                            nodeName = "cylinder";
                            nodeType = EDclNodeType.cylinder;
                            break;

                        case DclPrimitiveType.cone:
                            nodeName = "cone";
                            nodeType = EDclNodeType.cone;
                            break;
                        }
                    }
                    var meshFilter = tra.GetComponent <MeshFilter>();

                    if (nodeName != null)
                    {
                        //Primitive

                        //read color/mat
                        var rdrr = tra.GetComponent <MeshRenderer>();
                        if (rdrr && rdrr.sharedMaterial)
                        {
                            var material = rdrr.sharedMaterial;
                            if (material == PrimitiveHelper.GetDefaultMaterial())
                            {
                                //not use material
                                //                                var matColor = rdrr.sharedMaterial.color;
                                //                                pColor = ToHexString(matColor);
                            }
                            else
                            {
                                //need to export this material
                                if (primitiveMaterialsToExport != null && !primitiveMaterialsToExport.Exists(m => m == material))
                                {
                                    primitiveMaterialsToExport.Add(material);
                                }

                                pMaterial = string.Format("#{0}", material.name);
                            }
                        }

                        //withCollisions
                        if (dclObject)
                        {
                            if (dclObject.dclPrimitiveType != DclPrimitiveType.other)
                            {
                                if (dclObject.withCollision == true)
                                {
                                    extraProperties.Append(" withCollisions={true}");
                                }
                            }
                        }

                        //Statistics
                        if (statistics != null)
                        {
                            switch (dclObject.dclPrimitiveType)
                            {
                            case DclPrimitiveType.box:
                                statistics.triangleCount += 12;
                                break;

                            case DclPrimitiveType.sphere:
                                statistics.triangleCount += 4624;
                                break;

                            case DclPrimitiveType.plane:
                                statistics.triangleCount += 4;
                                break;

                            case DclPrimitiveType.cylinder:
                                statistics.triangleCount += 144;
                                break;

                            case DclPrimitiveType.cone:
                                statistics.triangleCount += 108;
                                break;
                            }

                            statistics.bodyCount += 1;
                        }
                    }
                    else
                    {
                        //GLTF

                        //export as a glTF model
                        if (meshesToExport != null)
                        {
                            meshesToExport.Add(tra.gameObject);
                        }

                        nodeName = "gltf-model";
                        nodeType = EDclNodeType.gltf;
                        // TODO: delete postion info (by alking)
                        // position = Vector3.zero;
                        // eulerAngles = Vector3.zero;
                        // scale = Vector3.zero;

                        //if tra is a prefab and do not get any change. use the prefab's name

                        //extraProperties.AppendFormat(" src=\"./unity_assets/{0}.gltf\"", tra.name);
                        extraProperties.AppendFormat(" src=\"./unity_assets/{0}.gltf\"", CalcName(tra.gameObject));

                        //Statistics
                        if (statistics != null)
                        {
                            statistics.triangleCount += meshFilter.sharedMesh.triangles.LongLength / 3;
                            statistics.bodyCount     += 1;
                        }

                        if (statistics != null)
                        {
                            Mesh m = meshFilter.sharedMesh;

                            Renderer mr = tra.GetComponent <MeshRenderer> ();
                            if (mr == null)
                            {
                                mr = tra.GetComponent <SkinnedMeshRenderer> ();
                            }

                            var sm = mr.sharedMaterials;
                            for (int i = 0; i < sm.Length; ++i)
                            {
                                Material ma = sm [i];
                                if (ma != null)
                                {
                                    statistics.materialCount += 1;
                                    Shader shader = ma.shader;
                                    for (int j = 0; j < ShaderUtil.GetPropertyCount(shader); j++)
                                    {
                                        if (ShaderUtil.GetPropertyType(shader, j) == ShaderUtil.ShaderPropertyType.TexEnv)
                                        {
                                            Texture texture = ma.GetTexture(ShaderUtil.GetPropertyName(shader, j));
                                            if (texture != null)
                                            {
                                                statistics.textureCount += 1;
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
                else if (tra.GetComponent <TextMesh>() && tra.GetComponent <MeshRenderer>()) //TextMesh
                {
                    nodeName = "text";
                    nodeType = EDclNodeType.text;
                    var tm = tra.GetComponent <TextMesh>();
                    extraProperties.AppendFormat(" value=\"{0}\"", tm.text);
                    //scale *= tm.fontSize * 0.5f;
                    //extraProperties.AppendFormat(" fontS=\"{0}\"", 100);
                    pColor = ToHexString(tm.color);
                    var rdrr = tra.GetComponent <MeshRenderer>();
                    if (rdrr)
                    {
                        var width  = rdrr.bounds.size.x * 2 / tra.lossyScale.x;                     //rdrr.bounds.extents.x*2;
                        var height = rdrr.bounds.size.y * 2 / tra.lossyScale.y;                     //rdrr.bounds.extents.y * 2;

                        extraProperties.AppendFormat(" width={{{0}}}", width);
                        extraProperties.AppendFormat(" height={{{0}}}", height);
                    }
                    extraProperties.AppendFormat(" fontSize={{{0}}}", tm.fontSize == 0 ? 13f * 38f : tm.fontSize * 38f);

                    switch (tm.anchor)
                    {
                    case TextAnchor.UpperLeft:
                        extraProperties.AppendFormat(" hAlign=\"right\"");
                        extraProperties.AppendFormat(" vAlign=\"bottom\"");
                        break;

                    case TextAnchor.UpperCenter:
                        extraProperties.AppendFormat(" vAlign=\"bottom\"");
                        break;

                    case TextAnchor.UpperRight:
                        extraProperties.AppendFormat(" hAlign=\"left\"");
                        extraProperties.AppendFormat(" vAlign=\"bottom\"");
                        break;

                    case TextAnchor.MiddleLeft:
                        extraProperties.AppendFormat(" hAlign=\"right\"");
                        break;

                    case TextAnchor.MiddleCenter:

                        break;

                    case TextAnchor.MiddleRight:
                        extraProperties.AppendFormat(" hAlign=\"left\"");
                        break;

                    case TextAnchor.LowerLeft:
                        extraProperties.AppendFormat(" hAlign=\"right\"");
                        extraProperties.AppendFormat(" vAlign=\"top\"");
                        break;

                    case TextAnchor.LowerCenter:
                        extraProperties.AppendFormat(" vAlign=\"top\"");
                        break;

                    case TextAnchor.LowerRight:
                        extraProperties.AppendFormat(" hAlign=\"left\"");
                        extraProperties.AppendFormat(" vAlign=\"top\"");
                        break;
                    }
                }

                if (tra.GetComponent <MeshRenderer>())
                {
                    var meshRenderer = tra.GetComponent <MeshRenderer>();

                    //Statistics
                    if (statistics != null)
                    {
                        var curHeight = meshRenderer.bounds.max.y;
                        if (curHeight > statistics.maxHeight)
                        {
                            statistics.maxHeight = curHeight;
                        }
                    }

                    //Warnings
                    if (warningRecorder != null)
                    {
                        //OutOfLand
                        if (_sceneMeta)
                        {
                            var isOutOfLand = false;
                            var startParcel = SceneUtil.GetParcelCoordinates(meshRenderer.bounds.min);
                            var endParcel   = SceneUtil.GetParcelCoordinates(meshRenderer.bounds.max);
                            for (int x = startParcel.x; x <= endParcel.x; x++)
                            {
                                for (int y = startParcel.y; y <= endParcel.y; y++)
                                {
                                    if (!_sceneMeta.parcels.Exists(parcel => parcel == new ParcelCoordinates(x, y)))
                                    {
                                        warningRecorder.OutOfLandWarnings.Add(
                                            new SceneWarningRecorder.OutOfLand(meshRenderer));
                                        isOutOfLand = true;
                                        break;
                                    }
                                }

                                if (isOutOfLand)
                                {
                                    break;
                                }
                            }
                        }
                    }
                }

                if (nodeName == null)
                {
                    nodeName = "entity";
                    nodeType = EDclNodeType.entity;
                }

                if (pColor != null)
                {
                    extraProperties.AppendFormat(" color=\"{0}\"", pColor);
                }

                if (pMaterial != null)
                {
                    extraProperties.AppendFormat(" material=\"{0}\"", pMaterial);
                }

                if (dclObject)
                {
                    if (dclObject.visible != true)
                    {
                        extraProperties.Append(" visible={false}");
                    }
                }
            }

            StringBuilder xmlNode            = null;
            StringBuilder xmlNodeTail        = null;
            StringBuilder childrenXmlBuilder = null;

            if (xmlBuilder != null)
            {
                xmlNode = new StringBuilder();
                xmlNode.AppendIndent(indentUnit, indentLevel);
                if (nodeType == EDclNodeType.CustomNode)
                {
                    xmlNode.AppendFormat("<{0}{1}>", nodeName, extraProperties);
                }
                else
                {
                    xmlNode.AppendFormat("<{0} position={{{1}}} scale={{{2}}} rotation={{{3}}}{4}>", nodeName,
                                         Vector3ToJSONString(position), Vector3ToJSONString(scale), Vector3ToJSONString(eulerAngles),
                                         extraProperties);
                }

                xmlNodeTail        = new StringBuilder().AppendFormat("</{0}>\n", nodeName);
                childrenXmlBuilder = new StringBuilder();
            }

            if (gameObjectToNodeTypeDict != null)
            {
                gameObjectToNodeTypeDict.Add(tra.gameObject, nodeType);
            }

            if (nodeType != EDclNodeType.gltf) //gltf node will force to pack all its children, so should not traverse into it again.
            {
                foreach (Transform child in tra)
                {
                    RecursivelyTraverseTransform(child, childrenXmlBuilder, meshesToExport, indentLevel + 1, statistics,
                                                 warningRecorder, gameObjectToNodeTypeDict);
                }
            }

            if (xmlBuilder != null)
            {
                if (childrenXmlBuilder.Length > 0)
                {
                    xmlNode.Append("\n");
                    xmlNode.Append(childrenXmlBuilder);
                    xmlNode.AppendIndent(indentUnit, indentLevel);
                }
                xmlNode.Append(xmlNodeTail);
                xmlBuilder.Append(xmlNode);
            }
        }
Esempio n. 8
0
        static void RecursivelyTraverseTransform(Transform tra, StringBuilder xmlBuilder, List <GameObject> meshesToExport, int indentLevel, SceneStatistics statistics)
        {
            if (!tra.gameObject.activeInHierarchy)
            {
                return;
            }

            //TODO: Hide empty

            statistics.entityCount += 1;

            var    components      = tra.GetComponents <Component>();
            string nodeName        = null;
            var    position        = tra.localPosition;
            var    scale           = tra.localScale;
            var    eulerAngles     = tra.localEulerAngles;
            string pColor          = null;
            var    extraProperties = new StringBuilder();

            foreach (var component in components)
            {
                if (component is Transform)
                {
                    continue;
                }

                //Primitive
                if (component is MeshFilter)
                {
                    var meshFilter = component as MeshFilter;
                    if (meshFilter.sharedMesh == PrimitiveHelper.GetPrimitiveMesh(PrimitiveType.Cube))
                    {
                        nodeName = "box";
                    }
                    else if (meshFilter.sharedMesh == PrimitiveHelper.GetPrimitiveMesh(PrimitiveType.Sphere))
                    {
                        nodeName = "sphere";
                    }
                    else if (meshFilter.sharedMesh == PrimitiveHelper.GetPrimitiveMesh(PrimitiveType.Quad))
                    {
                        nodeName = "plane";
                    }
                    else if (meshFilter.sharedMesh == PrimitiveHelper.GetPrimitiveMesh(PrimitiveType.Cylinder))
                    {
                        nodeName = "cylinder";
                        extraProperties.Append(" radius={0.5}");
                    }
                    if (nodeName != null)
                    {
                        //read color
                        var rdrr = tra.GetComponent <MeshRenderer>();
                        if (rdrr)
                        {
                            var matColor = rdrr.sharedMaterial.color;
                            pColor = ToHexString(matColor);
                        }
                        //Statistics
                        statistics.triangleCount += meshFilter.sharedMesh.triangles.LongLength / 3;
                    }
                }

                //Other Model
                if (nodeName == null)
                {
                    if (component is MeshFilter)
                    {
                        var meshFilter = component as MeshFilter;
                        //export as a glTF model
                        if (meshesToExport != null)
                        {
                            meshesToExport.Add(tra.gameObject);
                        }
                        nodeName    = "gltf-model";
                        position    = Vector3.zero;
                        eulerAngles = Vector3.zero;
                        scale       = Vector3.zero;
                        extraProperties.AppendFormat(" src=\"./unity_assets/{0}.gltf\"", tra.name);

                        //Statistics
                        statistics.triangleCount += meshFilter.sharedMesh.triangles.LongLength / 3;
                        statistics.bodyCount     += 1;
                    }
                }

                //TextMesh
                if (component is TextMesh)
                {
                    nodeName = "text";
                    var tm = component as TextMesh;
                    extraProperties.AppendFormat(" value=\"{0}\"", tm.text);
                    scale *= tm.fontSize * 0.5f;
                    //extraProperties.AppendFormat(" fontS=\"{0}\"", 100);
                    pColor = ToHexString(tm.color);
                    var rdrr = tra.GetComponent <MeshRenderer>();
                    if (rdrr)
                    {
                        var width = rdrr.bounds.extents.x * 2;
                        extraProperties.AppendFormat(" width={{{0}}}", width);
                    }
                }

                if (component is MeshRenderer)
                {
                    var meshRenderer = component as MeshRenderer;
                    //Statistics
                    var curHeight = meshRenderer.bounds.max.y;
                    if (curHeight > statistics.maxHeight)
                    {
                        statistics.maxHeight = curHeight;
                    }
                }
            }
            if (nodeName == null)
            {
                nodeName = "entity";
            }
            if (pColor != null)
            {
                extraProperties.AppendFormat(" color=\"{0}\"", pColor);
            }

            StringBuilder xmlNode            = null;
            StringBuilder xmlNodeTail        = null;
            StringBuilder childrenXmlBuilder = null;

            if (xmlBuilder != null)
            {
                xmlNode = new StringBuilder();
                xmlNode.AppendIndent(indentUnit, indentLevel);
                xmlNode.AppendFormat("<{0} position={{{1}}} scale={{{2}}} rotation={{{3}}}{4}>", nodeName, Vector3ToJSONString(position), Vector3ToJSONString(scale), Vector3ToJSONString(eulerAngles), extraProperties);
                xmlNodeTail        = new StringBuilder().AppendFormat("</{0}>\n", nodeName);
                childrenXmlBuilder = new StringBuilder();
            }

            Debug.Log(tra.name);

            foreach (Transform child in tra)
            {
                RecursivelyTraverseTransform(child, childrenXmlBuilder, meshesToExport, indentLevel + 1, statistics);
            }

            if (xmlBuilder != null)
            {
                if (childrenXmlBuilder.Length > 0)
                {
                    xmlNode.Append("\n");
                    xmlNode.Append(childrenXmlBuilder);
                    xmlNode.AppendIndent(indentUnit, indentLevel);
                }
                xmlNode.Append(xmlNodeTail);
                xmlBuilder.Append(xmlNode);
            }
        }