//public static readonly Dictionary<GameObject, EDclNodeType> GameObjectToNodeTypeDict = new Dictionary<GameObject, EDclNodeType>(); public static ResourceRecorder TraverseAllScene(StringBuilder exportStr, SceneStatistics statistics, SceneWarningRecorder warningRecorder) { var rootGameObjects = new List <GameObject>(); for (int i = 0; i < SceneManager.sceneCount; i++) { var roots = SceneManager.GetSceneAt(i).GetRootGameObjects(); rootGameObjects.AddRange(roots); } _sceneMeta = Object.FindObjectOfType <DclSceneMeta>(); _resourceRecorder = new ResourceRecorder(); //GameObjectToNodeTypeDict.Clear(); //====== Start Traversing ====== foreach (var rootGO in rootGameObjects) { RecursivelyTraverseTransform(rootGO.transform, exportStr, _resourceRecorder, 4, statistics, warningRecorder); } //Append PlayAudio functions if (exportStr != null) { if (_resourceRecorder.audioSourceAddFunctions.Count > 0) { exportStr.AppendLine(); exportStr.AppendLine( @"export class AutoPlayUnityAudio implements ISystem { activate() {"); foreach (var functionName in _resourceRecorder.audioSourceAddFunctions) { exportStr.AppendIndent(indentUnit, 2).AppendFormat("{0}()\n", functionName); } exportStr.AppendLine( @" } } engine.addSystem(new AutoPlayUnityAudio()) "); } } if (statistics != null) { statistics.textureCount = _resourceRecorder.primitiveTexturesToExport.Count + _resourceRecorder.gltfTextures.Count; } return(_resourceRecorder); }
void InfoGUI() { EditorGUILayout.BeginHorizontal(); GUILayout.Label("Statistics", EditorStyles.boldLabel, GUILayout.Width(100)); if (GUILayout.Button("Refresh")) { sceneStatistics = new SceneStatistics(); SceneTraverser.TraverseAllScene(null, null, sceneStatistics); } EditorGUILayout.EndHorizontal(); GUILayout.Label("Keep these numbers smaller than the right", EditorStyles.centeredGreyMiniLabel); var n = sceneMeta.parcels.Count; EditorGUILayout.LabelField("Triangles", string.Format("{0} / {1}", sceneStatistics.triangleCount, LimitationConfigs.GetMaxTriangles(n))); EditorGUILayout.LabelField("Entities", string.Format("{0} / {1}", sceneStatistics.entityCount, LimitationConfigs.GetMaxTriangles(n))); EditorGUILayout.LabelField("Bodies", string.Format("{0} / {1}", sceneStatistics.bodyCount, LimitationConfigs.GetMaxBodies(n))); EditorGUILayout.LabelField("Height", string.Format("{0} / {1}", sceneStatistics.maxHeight, LimitationConfigs.GetMaxHeight(n))); }
//public static readonly Dictionary<GameObject, EDclNodeType> GameObjectToNodeTypeDict = new Dictionary<GameObject, EDclNodeType>(); public static ResourceRecorder TraverseAllScene(StringBuilder exportStr, SceneStatistics statistics, SceneWarningRecorder warningRecorder) { var rootGameObjects = new List <GameObject>(); for (int i = 0; i < SceneManager.sceneCount; i++) { var roots = SceneManager.GetSceneAt(i).GetRootGameObjects(); rootGameObjects.AddRange(roots); } _sceneMeta = Object.FindObjectOfType <DclSceneMeta>(); resourceRecorder = new ResourceRecorder(); //GameObjectToNodeTypeDict.Clear(); //====== Start Traversing ====== foreach (var rootGO in rootGameObjects) { RecursivelyTraverseTransform(rootGO.transform, exportStr, resourceRecorder, 4, statistics, warningRecorder); } //Append PlayAudio functions if (exportStr != null) { if (resourceRecorder.audioSourceAddFunctions.Count > 0) { exportStr.AppendLine(); exportStr.AppendLine("Input.instance.subscribe(\"BUTTON_UP\", e => {"); foreach (var functionName in resourceRecorder.audioSourceAddFunctions) { exportStr.AppendIndent(indentUnit, 1).AppendFormat("{0}()\n", functionName); } exportStr.AppendLine("})\n"); } } if (statistics != null) { statistics.textureCount = resourceRecorder.primitiveTexturesToExport.Count + resourceRecorder.gltfTextures.Count; } return(resourceRecorder); }
/// <summary> /// Export scene.tsx, scene.json, unity_assets/ /// </summary> void Export() { if (string.IsNullOrEmpty(exportPath)) { EditorUtility.DisplayDialog("NO Path!", "You must assign the export path!", null, "OK"); return; } if (!Directory.Exists(exportPath)) { Directory.CreateDirectory("exportPath"); } //delete all files in exportPath/unity_assets/ var unityAssetsFolderPath = Path.Combine(exportPath, "unity_assets/"); if (Directory.Exists(unityAssetsFolderPath)) { //ClearFolder(unityAssetsFolderPath); UnityEditor.FileUtil.DeleteFileOrDirectory(unityAssetsFolderPath); } Directory.CreateDirectory(unityAssetsFolderPath);//TODO:当DCLSDK运行时,文件操作会冲突。可能可以用异步等待删除完毕。 if (!Directory.Exists(Path.Combine(exportPath, "src"))) { Directory.CreateDirectory(Path.Combine(exportPath, "src")); } var statistics = new SceneStatistics(); StringBuilder exportStr = new StringBuilder(); var resourceRecorder = SceneTraverser.TraverseAllScene(exportStr, statistics, null); File.WriteAllText(Path.Combine(exportPath, "src/game.ts"), exportStr.ToString()); //glTF in unity_asset foreach (var go in resourceRecorder.meshesToExport) { string tempPath = Path.Combine(unityAssetsFolderPath, SceneTraverser.GetIdentityName(go) + ".gltf"); sceneMeta.sceneToGlTFWiz.ExportGameObjectAndChildren(go, tempPath, null, false, true, false, false); } //textures foreach (var texture in resourceRecorder.primitiveTexturesToExport) { var relPath = AssetDatabase.GetAssetPath(texture); if (string.IsNullOrEmpty(relPath) || relPath.StartsWith("Library/")) { //built-in asset var bytes = ((Texture2D)texture).EncodeToPNG(); string str = Path.Combine(unityAssetsFolderPath, texture.name + ".png"); File.WriteAllBytes(str.Replace(" ", string.Empty), bytes); } else { var path = Application.dataPath; //<path to project folder>/Assets path = path.Remove(path.Length - 6, 6) + relPath; var toPath = unityAssetsFolderPath + relPath; //replace space by zcy //toPath = toPath.Replace (" ", string.Empty); var directoryPath = Path.GetDirectoryName(toPath); if (!Directory.Exists(directoryPath)) { Directory.CreateDirectory(directoryPath); } File.Copy(path, toPath, true); } Debug.Log("Texture out " + relPath); } //audioClips foreach (var audioClip in resourceRecorder.audioClipsToExport) { var relPath = AssetDatabase.GetAssetPath(audioClip); if (string.IsNullOrEmpty(relPath) || relPath.StartsWith("Library/")) { Debug.LogError("AudioClip should not be built-in assets."); } else { var path = Application.dataPath; //<path to project folder>/Assets path = path.Remove(path.Length - 6, 6) + relPath; var toPath = unityAssetsFolderPath + relPath; var directoryPath = Path.GetDirectoryName(toPath); if (!Directory.Exists(directoryPath)) { Directory.CreateDirectory(directoryPath); } File.Copy(path, toPath, true); } Debug.Log("Audio out " + relPath); } //scene.json { var fileTxt = GetSceneJsonFileTemplate(); fileTxt = fileTxt.Replace("{ETH_ADDRESS}", sceneMeta.ethAddress); fileTxt = fileTxt.Replace("{CONTACT_NAME}", sceneMeta.contactName); fileTxt = fileTxt.Replace("{CONTACT_EMAIL}", sceneMeta.email); var parcelsString = GetParcelsString(); fileTxt = fileTxt.Replace("{PARCELS}", parcelsString); if (sceneMeta.parcels.Count > 0) { fileTxt = fileTxt.Replace("{BASE}", ParcelToString(sceneMeta.parcels[0])); } var filePath = Path.Combine(exportPath, "scene.json"); File.WriteAllText(filePath, fileTxt); } Debug.Log("===Export Complete==="); }
public static void ProcessText(Transform tra, string entityName, StringBuilder exportStr, SceneStatistics statistics) { if (!(tra.GetComponent <TextMesh>() && tra.GetComponent <MeshRenderer>())) { return; } if (exportStr != null) { exportStr.AppendFormat("{0}.addComponent(new TextShape())\n", entityName); var tm = tra.GetComponent <TextMesh>(); var str = System.Text.RegularExpressions.Regex.Escape(tm.text); exportStr.AppendFormat("{0}.getComponent(TextShape).value = \"{1}\"\n", entityName, str); //scale *= tm.fontSize * 0.5f; //exportStr.AppendFormat(" fontS=\"{0}\"", 100); var color = ToJsColorCtor(tm.color); exportStr.AppendFormat("{0}.getComponent(TextShape).color = {1}\n", entityName, color); var rdrr = tra.GetComponent <MeshRenderer>(); if (rdrr) { var width = Math.Min(32, rdrr.bounds.size.x * 2 / tra.lossyScale.x); //rdrr.bounds.extents.x*2; var height = Math.Min(32, rdrr.bounds.size.y * 2 / tra.lossyScale.y); //rdrr.bounds.extents.y * 2; exportStr.AppendFormat("{0}.getComponent(TextShape).width = {1}\n", entityName, width); exportStr.AppendFormat("{0}.getComponent(TextShape).height = {1}\n", entityName, height); } var fontSize = tm.fontSize == 0 ? 13f * 38f : tm.fontSize * 38f; exportStr.AppendFormat("{0}.getComponent(TextShape).fontSize = {1}\n", entityName, fontSize); switch (tm.anchor) { case TextAnchor.UpperLeft: exportStr.AppendFormat("{0}.getComponent(TextShape).hAlign = \"{1}\"\n", entityName, "\"right\""); exportStr.AppendFormat("{0}.getComponent(TextShape).vAlign = \"{1}\"\n", entityName, "\"bottom\""); break; case TextAnchor.UpperCenter: exportStr.AppendFormat("{0}.getComponent(TextShape).vAlign = \"{1}\"\n", entityName, "\"bottom\""); break; case TextAnchor.UpperRight: exportStr.AppendFormat("{0}.getComponent(TextShape).hAlign = \"{1}\"\n", entityName, "\"left\""); exportStr.AppendFormat("{0}.getComponent(TextShape).vAlign = \"{1}\"\n", entityName, "\"bottom\""); break; case TextAnchor.MiddleLeft: exportStr.AppendFormat("{0}.getComponent(TextShape).hAlign = \"{1}\"\n", entityName, "\"right\""); break; case TextAnchor.MiddleCenter: break; case TextAnchor.MiddleRight: exportStr.AppendFormat("{0}.getComponent(TextShape).hAlign = \"{1}\"\n", entityName, "\"left\""); break; case TextAnchor.LowerLeft: exportStr.AppendFormat("{0}.getComponent(TextShape).hAlign = \"{1}\"\n", entityName, "\"right\""); exportStr.AppendFormat("{0}.getComponent(TextShape).vAlign = \"{1}\"\n", entityName, "\"top\""); break; case TextAnchor.LowerCenter: exportStr.AppendFormat("{0}.getComponent(TextShape).vAlign = \"{1}\"\n", entityName, "\"top\""); break; case TextAnchor.LowerRight: exportStr.AppendFormat("{0}.getComponent(TextShape).hAlign = \"{1}\"\n", entityName, "\"left\""); exportStr.AppendFormat("{0}.getComponent(TextShape).vAlign = \"{1}\"\n", entityName, "\"top\""); break; } } if (statistics != null) { statistics.triangleCount += 4; statistics.bodyCount += 2; } }
public static void ProcessShape(Transform tra, string entityName, StringBuilder exportStr, ResourceRecorder resourceRecorder, SceneStatistics statistics) { var meshFilter = tra.GetComponent <MeshFilter>(); if (!(meshFilter && tra.GetComponent <MeshRenderer>())) { return; } var dclObject = tra.GetComponent <DclObject>(); string shapeName = null; if (dclObject) { switch (dclObject.dclPrimitiveType) { case DclPrimitiveType.box: dclObject.dclNodeType = EDclNodeType.box; shapeName = "BoxShape"; break; case DclPrimitiveType.sphere: dclObject.dclNodeType = EDclNodeType.sphere; shapeName = "SphereShape"; break; case DclPrimitiveType.plane: dclObject.dclNodeType = EDclNodeType.plane; shapeName = "PlaneShape"; break; case DclPrimitiveType.cylinder: dclObject.dclNodeType = EDclNodeType.cylinder; shapeName = "CylinderShape"; break; case DclPrimitiveType.cone: dclObject.dclNodeType = EDclNodeType.cone; shapeName = "ConeShape"; break; } } if (shapeName != null) { //Primitive if (exportStr != null) { exportStr.AppendFormat(SetShape, entityName, shapeName); } } else { //gltf - root dclObject.dclNodeType = EDclNodeType.gltf; if (exportStr != null) { string gltfPath = string.Format("./unity_assets/{0}.gltf", GetIdentityName(tra.gameObject)); exportStr.AppendFormat(SetGLTFshape, entityName, gltfPath); } //export as a glTF model if (resourceRecorder != null) { resourceRecorder.meshesToExport.Add(tra.gameObject); } } if (exportStr != null) { if (dclObject && dclObject.withCollision) { exportStr.AppendFormat("{0}.getComponent({1}).withCollisions = true\n", entityName, shapeName); } if (dclObject && !dclObject.visible) { exportStr.AppendFormat("{0}.getComponent(Shape).visible = false\n", entityName); } } }
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 RecursivelyTraverseIntoGLTF(Transform tra, int layerUnderGLTFRoot, SceneStatistics statistics, SceneWarningRecorder warningRecorder) { if (!tra.gameObject.activeInHierarchy) { return; } if (tra.gameObject.GetComponent <DclSceneMeta>()) { return; //skip .dcl } var dclObject = tra.GetComponent <DclObject>() ?? tra.gameObject.AddComponent <DclObject>(); if (layerUnderGLTFRoot > 0) { dclObject.dclNodeType = EDclNodeType.ChildOfGLTF; } var position = tra.localPosition; var scale = tra.localScale; var rotation = tra.localRotation; if (tra.GetComponent <MeshRenderer>()) { var meshFilter = tra.GetComponent <MeshFilter>(); var meshRenderer = tra.GetComponent <MeshRenderer>(); //Statistics if (statistics != null) { if (meshFilter && meshFilter.sharedMesh) { statistics.triangleCount += meshFilter.sharedMesh.triangles.LongLength / 3; statistics.bodyCount += 1; } 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; } } } } } ProcessMaterial(tra, true, null, statistics.gltfMaterials, null, statistics); foreach (Transform child in tra) { RecursivelyTraverseIntoGLTF(child, layerUnderGLTFRoot + 1, statistics, warningRecorder); } }
public static void RecursivelyTraverseTransform(Transform tra, StringBuilder exportStr, ResourceRecorder resourceRecorder, int indentLevel, SceneStatistics statistics, SceneWarningRecorder warningRecorder) { if (!tra.gameObject.activeInHierarchy) { return; } if (tra.gameObject.GetComponent <DclSceneMeta>()) { return; //skip .dcl } var dclObject = tra.GetComponent <DclObject>() ?? tra.gameObject.AddComponent <DclObject>(); dclObject.dclNodeType = EDclNodeType.entity; var entityName = GetIdentityName(tra.gameObject); if (statistics != null) { statistics.entityCount += 1; } var position = tra.localPosition; var scale = tra.localScale; var rotation = tra.localRotation; if (exportStr != null) { exportStr.AppendFormat(NewEntityWithName, entityName, tra.name); if (tra.parent) { //Set Parent exportStr.AppendFormat(SetParent, entityName, GetIdentityName(tra.parent.gameObject)); } else { //Entity exportStr.AppendFormat(AddEntity, entityName); } //Transform exportStr.AppendFormat(SetTransform, entityName, position.x, position.y, position.z); exportStr.AppendFormat(SetRotation, entityName, rotation.x, rotation.y, rotation.z, rotation.w); exportStr.AppendFormat(SetScale, entityName, scale.x, scale.y, scale.z); } ProcessShape(tra, entityName, exportStr, resourceRecorder, statistics); if (exportStr != null && dclObject.dclNodeType == EDclNodeType.gltf) //reverse 180° along local y-axis because of DCL's special purpose. { rotation = Quaternion.AngleAxis(180, tra.up) * rotation; exportStr.AppendFormat(SetRotation, entityName, rotation.x, rotation.y, rotation.z, rotation.w); } if (dclObject.dclNodeType != EDclNodeType.gltf) { ProcessText(tra, entityName, exportStr, statistics); } if (dclObject.dclNodeType != EDclNodeType.gltf) { ProcessMaterial(tra, false, entityName, resourceRecorder.primitiveMaterialsToExport, exportStr, statistics); if (tra.GetComponent <MeshRenderer>()) { var meshFilter = tra.GetComponent <MeshFilter>(); var meshRenderer = tra.GetComponent <MeshRenderer>(); //Statistics if (statistics != null) { if (meshFilter && meshFilter.sharedMesh) { statistics.triangleCount += meshFilter.sharedMesh.triangles.LongLength / 3; statistics.bodyCount += 1; } 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 (exportStr != null) { exportStr.Append('\n'); } // if (tra.GetComponent<DclCustomNode>()) // { // var customNode = tra.GetComponent<DclCustomNode>(); // nodeName = customNode.nodeName; // nodeType = EDclNodeType.CustomNode; //if(customNode.propertyPairs!=null){ // foreach (var propertyPair in customNode.propertyPairs) // { // extraProperties.AppendFormat(" {0}={1}", propertyPair.name, propertyPair.value); // } //} // } // else // { if (dclObject) { //TODO: if (dclObject.visible != true) extraProperties.Append(" visible={false}"); } //GameObjectToNodeTypeDict.Add(tra.gameObject, nodeType); foreach (Transform child in tra) { RecursivelyTraverseTransform(child, exportStr, resourceRecorder, indentLevel + 1, statistics, warningRecorder); } } else { if (statistics != null) { statistics.gltfMaterials.Clear(); } RecursivelyTraverseIntoGLTF(tra, 0, statistics, warningRecorder); if (statistics != null) { statistics.materialCount += statistics.gltfMaterials.Count; } } ProcessAudio(tra, entityName, exportStr); }
void Export() { var exportPath = sceneMeta.exportPath; if (string.IsNullOrEmpty(exportPath)) { EditorUtility.DisplayDialog("NO Path!", "You must assign the export path!", null, "OK"); return; } if (!Directory.Exists(exportPath)) { Directory.CreateDirectory("exportPath"); } //delete all files in exportPath/unity_assets/ var unityAssetsFolderPath = Path.Combine(exportPath, "unity_assets/"); if (Directory.Exists(unityAssetsFolderPath)) { Directory.GetFiles(unityAssetsFolderPath, "*", SearchOption.AllDirectories).ToList().ForEach(File.Delete); Directory.GetDirectories(unityAssetsFolderPath).ToList().ForEach(f => Directory.Delete(f, true)); } else { Directory.CreateDirectory(unityAssetsFolderPath); } var meshesToExport = new List <GameObject>(); var sceneXmlBuilder = new StringBuilder(); var statistics = new SceneStatistics(); SceneTraverser.TraverseAllScene(sceneXmlBuilder, meshesToExport, statistics); var sceneXml = sceneXmlBuilder.ToString(); //scene.tsx var fileTxt = GetSceneTsxFileTemplate(); fileTxt = fileTxt.Replace("{XML}", sceneXml); var filePath = Path.Combine(exportPath, "scene.tsx"); File.WriteAllText(filePath, fileTxt); //glTF in unity_asset foreach (var go in meshesToExport) { sceneMeta.sceneToGlTFWiz.ExportGameObject(go, Path.Combine(unityAssetsFolderPath, go.name + ".gltf"), null, false, true, false, false); } //scene.json fileTxt = GetSceneJsonFileTemplate(); fileTxt = fileTxt.Replace("{ETH_ADDRESS}", sceneMeta.ethAddress); fileTxt = fileTxt.Replace("{CONTACT_NAME}", sceneMeta.contactName); fileTxt = fileTxt.Replace("{CONTACT_EMAIL}", sceneMeta.email); var parcelsString = GetParcelsString(); fileTxt = fileTxt.Replace("{PARCELS}", parcelsString); if (sceneMeta.parcels.Count > 0) { fileTxt = fileTxt.Replace("{BASE}", ParcelToString(sceneMeta.parcels[0])); } filePath = Path.Combine(exportPath, "scene.json"); File.WriteAllText(filePath, fileTxt); Debug.Log("===Export Complete==="); }
public static void TraverseAllScene(StringBuilder xmlBuilder, List <GameObject> meshesToExport, SceneStatistics statistics, SceneWarningRecorder warningRecorder) { var rootGameObjects = new List <GameObject>(); for (int i = 0; i < SceneManager.sceneCount; i++) { var roots = SceneManager.GetSceneAt(i).GetRootGameObjects(); rootGameObjects.AddRange(roots); } if (xmlBuilder != null) { xmlBuilder.AppendIndent(indentUnit, 3); xmlBuilder.AppendFormat("<scene position={{{0}}}>\n", Vector3ToJSONString(new Vector3(5, 0, 5))); } _sceneMeta = Object.FindObjectOfType <DclSceneMeta>(); primitiveMaterialsToExport = new List <Material>(); primitiveTexturesToExport = new List <Texture>(); GameObjectToNodeTypeDict.Clear(); //====== Start Traversing ====== foreach (var rootGO in rootGameObjects) { RecursivelyTraverseTransform(rootGO.transform, xmlBuilder, meshesToExport, 4, statistics, warningRecorder, GameObjectToNodeTypeDict); } foreach (var material in primitiveMaterialsToExport) { var materialXml = xmlBuilder != null ? new StringBuilder() : null; TraverseMaterial(material, materialXml, warningRecorder); //Append materials if (xmlBuilder != null) { xmlBuilder.AppendIndent(indentUnit, 4); xmlBuilder.Append(materialXml).Append("\n"); } } //Check textures if (warningRecorder != null) { foreach (var texture in primitiveTexturesToExport) { CheckTextureValidity(texture, warningRecorder); } } statistics.materialCount += primitiveMaterialsToExport.Count; //TODO: include glTF's materials statistics.textureCount += primitiveTexturesToExport.Count; //TODO: include glTF's textures if (xmlBuilder != null) { xmlBuilder.AppendIndent(indentUnit, 3); xmlBuilder.Append("</scene>"); } }
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); } }
public void RefreshStatistics() { sceneStatistics = new SceneStatistics(); sceneWarningRecorder = new SceneWarningRecorder(); SceneTraverser.TraverseAllScene(null, sceneStatistics, sceneWarningRecorder); }
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); } }
public static void TraverseAllScene(StringBuilder xmlBuilder, List <GameObject> meshesToExport, SceneStatistics statistics) { var rootGameObjects = new List <GameObject>(); for (int i = 0; i < SceneManager.sceneCount; i++) { var roots = SceneManager.GetSceneAt(i).GetRootGameObjects(); rootGameObjects.AddRange(roots); } if (xmlBuilder != null) { xmlBuilder.AppendIndent(indentUnit, 3); xmlBuilder.AppendFormat("<scene position={{{0}}}>\n", Vector3ToJSONString(new Vector3(5, 0, 5))); } foreach (var rootGO in rootGameObjects) { RecursivelyTraverseTransform(rootGO.transform, xmlBuilder, meshesToExport, 4, statistics); } if (xmlBuilder != null) { xmlBuilder.AppendIndent(indentUnit, 3); xmlBuilder.Append("</scene>"); } }
/// <summary> /// Export scene.tsx, scene.json, unity_assets/ /// </summary> void Export() { if (string.IsNullOrEmpty(exportPath)) { EditorUtility.DisplayDialog("NO Path!", "You must assign the export path!", null, "OK"); return; } if (!Directory.Exists(exportPath)) { Directory.CreateDirectory("exportPath"); } //delete all files in exportPath/unity_assets/ var unityAssetsFolderPath = Path.Combine(exportPath, "unity_assets/"); if (Directory.Exists(unityAssetsFolderPath)) { //ClearFolder(unityAssetsFolderPath); UnityEditor.FileUtil.DeleteFileOrDirectory(unityAssetsFolderPath); } Directory.CreateDirectory(unityAssetsFolderPath); var meshesToExport = new List <GameObject>(); var sceneXmlBuilder = new StringBuilder(); var statistics = new SceneStatistics(); SceneTraverser.TraverseAllScene(sceneXmlBuilder, meshesToExport, statistics, null); var sceneXml = sceneXmlBuilder.ToString(); //scene.tsx var fileTxt = GetSceneTsxFileTemplate(); fileTxt = fileTxt.Replace("{XML}", sceneXml); var filePath = Path.Combine(exportPath, "scene.tsx"); File.WriteAllText(filePath, fileTxt); //glTF in unity_asset foreach (var go in meshesToExport) { string tempPath = Path.Combine(unityAssetsFolderPath, SceneTraverser.CalcName(go) + ".gltf"); if (!File.Exists(tempPath)) { sceneMeta.sceneToGlTFWiz.ExportGameObjectAndChildren(go, tempPath, null, false, true, false, false); } } //textures var primitiveTexturesToExport = SceneTraverser.primitiveTexturesToExport; foreach (var texture in primitiveTexturesToExport) { var relPath = AssetDatabase.GetAssetPath(texture); if (string.IsNullOrEmpty(relPath)) { //built-in asset var bytes = ((Texture2D)texture).EncodeToPNG(); File.WriteAllBytes(Path.Combine(unityAssetsFolderPath, texture.name + ".png"), bytes); } else { var path = Application.dataPath; //<path to project folder>/Assets path = path.Remove(path.Length - 6, 6) + relPath; var toPath = unityAssetsFolderPath + relPath; var directoryPath = Path.GetDirectoryName(toPath); if (!Directory.Exists(directoryPath)) { Directory.CreateDirectory(directoryPath); } File.Copy(path, toPath, true); } } //scene.json fileTxt = GetSceneJsonFileTemplate(); fileTxt = fileTxt.Replace("{ETH_ADDRESS}", sceneMeta.ethAddress); fileTxt = fileTxt.Replace("{CONTACT_NAME}", sceneMeta.contactName); fileTxt = fileTxt.Replace("{CONTACT_EMAIL}", sceneMeta.email); var parcelsString = GetParcelsString(); fileTxt = fileTxt.Replace("{PARCELS}", parcelsString); if (sceneMeta.parcels.Count > 0) { fileTxt = fileTxt.Replace("{BASE}", ParcelToString(sceneMeta.parcels[0])); } filePath = Path.Combine(exportPath, "scene.json"); File.WriteAllText(filePath, fileTxt); Debug.Log("===Export Complete==="); }