/// <summary> /// Extract vertex maps for all MCS conten, or only selected folders if useSelection == true. /// </summary> public static void ExtractVertexMaps(bool useSelection) { List <GameObject> content = GetContent(useSelection); if (content.Count == 0) { return; } _activeProcess = new ContentProcessor("Extract", content, true); _activeProcess.Process = delegate() { GameObject obj = _activeProcess.GetObject(); if (obj == null) { return; } CoreMesh[] meshes = obj.GetComponentsInChildren <CoreMesh>(); foreach (CoreMesh mesh in meshes) { string collection = GetCollectionName(mesh.runtimeMorphPath); //_activeProcess.status = collection + ":" + mesh.name; SkinnedMeshRenderer smr = mesh.GetComponent <SkinnedMeshRenderer>(); if (smr != null) { string collectionConversionMapPath = _conversionMapPath + ((string.IsNullOrEmpty(collection) ? "" : "/" + collection)); Directory.CreateDirectory(collectionConversionMapPath); VertexMap vertexMap = new VertexMap(smr.sharedMesh.vertices); vertexMap.WriteToDisk(collectionConversionMapPath + "/" + mesh.name + ".json"); } } if (_activeProcess.isLast) { if (EditorUtility.DisplayDialog("Complete!", "Extracted vertex maps were saved in Assets/MCS/ConversionMaps.\nYou can copy the files to your new Unity project.", "Show in Explorer", "Close")) { EditorUtility.RevealInFinder(_conversionMapPath); } } }; }
/// <summary> /// Removes morphs from selected assets. Useful in cases like hair moving unnaturally with eye blinks. /// </summary> public static void RemoveMorphsFromSelected(List <string> morphNamesToBeRemoved) { List <GameObject> content = GetContent(true); if (content.Count == 0 || morphNamesToBeRemoved == null || morphNamesToBeRemoved.Count == 0) { return; } if (!EditorUtility.DisplayDialog("Warning", "This process is nonreversible.\nAre you sure?", "Yes", "Cancel")) { return; } // Load common conversion tools and data _conversionData = new ConversionData(); _activeProcess = new ContentProcessor("Edit", content, true); _activeProcess.Process = delegate() { GameObject obj = _activeProcess.GetObject(); if (obj == null) { return; } CoreMesh[] meshes = obj.GetComponentsInChildren <CoreMesh>(); foreach (CoreMesh mesh in meshes) { //_activeProcess.status = mesh.name + " : Checking..."; // Check smr SkinnedMeshRenderer smr = mesh.GetComponent <SkinnedMeshRenderer>(); if (smr == null) { continue; } // Create temp directory for generated .morph files string morphPath = Path.Combine(Application.streamingAssetsPath, mesh.runtimeMorphPath); Directory.CreateDirectory(morphPath); try { // Get manifest var manifest = _conversionData.GetManifestForCoreMesh(mesh, _manifestSelectionMethod); // Process morphs List <string> morphNames = new List <string>(manifest.names); morphNames.Add("base"); // Add "base" morph that's not in the manifest but is required for clothing and hair foreach (string morph in morphNames) { MorphData data = _conversionData.GetMorphData(morphPath, morph); if (data != null) { if (morphNamesToBeRemoved.Contains(morph)) { _activeProcess.status = mesh.name + " : Removed Morph " + morph; } else { // Save .morph file for keeping MCS_Utilities.MorphExtraction.MorphExtraction.WriteMorphDataToFile(data, morphPath + "/" + data.name + ".morph", false, false); } } } // Repack morphs into .morph.mr file //_activeProcess.status = mesh.name + " : Rebuilding MR..."; RepackMorphs(morphPath); //_activeProcess.status = mesh.name + " : Success!"; } catch { _activeProcess.status = mesh.name + " : FAILED"; } finally { MCS_Utilities.Paths.TryDirectoryDelete(morphPath); } } }; }
/// <summary> /// Remaps morph data for all MCS content, or only selected folders if useSelection == true. /// </summary> public static void ConvertMorphData(bool useSelection) { if (!useSelection) { if (!EditorUtility.DisplayDialog("Warning", "This will attempt to convert all MCS morph data in your project. This process is nonreversible.\nAre you sure?", "Yes", "Cancel")) { return; } } List <GameObject> content = GetContent(useSelection); if (content.Count == 0) { return; } // Load common conversion tools and data _conversionData = new ConversionData(); _activeProcess = new ContentProcessor("Convert", content, true); _activeProcess.Process = delegate() { GameObject obj = _activeProcess.GetObject(); if (obj == null) { return; } CoreMesh[] meshes = obj.GetComponentsInChildren <CoreMesh>(); foreach (CoreMesh mesh in meshes) { //_activeProcess.status = mesh.name + " : Checking..."; _conversionData.CreateReport(mesh.name); // Check if already converted if (_conversionData.GetMorphData(mesh.runtimeMorphPath, "_2019compatible") != null) { _conversionData.CloseReport("Skipped (already converted)"); continue; } // Check smr SkinnedMeshRenderer smr = mesh.GetComponent <SkinnedMeshRenderer>(); if (smr == null) { _conversionData.CloseReport("Skipped (no SkinnedMeshRenderer found)"); continue; } // Check for original vertex map string vmPath = ""; foreach (string path in _conversionData.vertexMaps) { if (path.Contains(mesh.name + ".json")) { vmPath = path; break; } } if (vmPath == "") { _conversionData.CloseReport("Skipped (no vertex map found)"); continue; } // Create temp directory for generated .morph files string morphPath = Path.Combine(Application.streamingAssetsPath, mesh.runtimeMorphPath); Directory.CreateDirectory(morphPath); // Run process try { // Read vertex map string mapData = File.ReadAllText(vmPath); VertexMap vertexMap = JsonUtility.FromJson <VertexMap>(mapData); // Generate retarget map //_activeProcess.status = mesh.name + " : Generating Target Map..."; Dictionary <int, int> ttsMap = _conversionData.projectionMeshMap.GenerateTargetToSourceMap(vertexMap.vertices, smr.sharedMesh.vertices); // Get manifest var manifest = _conversionData.GetManifestForCoreMesh(mesh, _manifestSelectionMethod); // Process morphs int n = 0; int total = manifest.names.Length; List <string> morphNames = new List <string>(manifest.names); morphNames.Add("base"); // Add "base" morph that's not in the manifest but is required for clothing and hair foreach (string morph in morphNames) { //_activeProcess.status = string.Format("{0} : Processing Morph {1}/{2}", mesh.name, n, total); n++; MorphData source = _conversionData.GetMorphData(morphPath, morph); // Not all assets will have all morphs if (source != null) { // Retarget morphs MorphData target = RemapMorphData(smr, source, ttsMap); // Save new .morph file MCS_Utilities.MorphExtraction.MorphExtraction.WriteMorphDataToFile(target, morphPath + "/" + target.name + ".morph", false, false); } } // Inject evidence of conversion so we don't accidentally remap again. MorphData note = new MorphData(); note.name = "_2019compatible"; MCS_Utilities.MorphExtraction.MorphExtraction.WriteMorphDataToFile(note, morphPath + "/" + note.name + ".morph", false, false); // Repack morphs into .morph.mr file _activeProcess.status = mesh.name + " : Repacking Morphs..."; RepackMorphs(morphPath); _conversionData.CloseReport("Success"); } catch { _conversionData.CloseReport("Failed"); } finally { MCS_Utilities.Paths.TryDirectoryDelete(morphPath); } } if (_activeProcess.isLast) { _conversionData.PrintSummary(); } }; }