private static void AddToDictionary(Mesh sourceMesh, ProcessedMeshInfo pmi, Dictionary <Mesh, List <ProcessedMeshInfo> > dict) { List <ProcessedMeshInfo> lpmi; if (!dict.ContainsKey(sourceMesh)) { lpmi = new List <ProcessedMeshInfo>(); dict[sourceMesh] = lpmi; } else { lpmi = dict[sourceMesh]; } lpmi.Add(pmi); }
private static void ProcessPrefabRowReplaceTargetPrefab(MB3_BatchPrefabBaker pb, MB3_BatchPrefabBaker.MB3_PrefabBakerRow pr, MB2_TextureBakeResults tbr, List <UnityTransform> unityTransforms, MB3_MeshBaker mb) { if (pb.LOG_LEVEL >= MB2_LogLevel.info) { Debug.Log("==== Processing Source Prefab " + pr.sourcePrefab); } GameObject srcPrefab = pr.sourcePrefab; GameObject targetPrefab = pr.resultPrefab; string targetPrefabName = AssetDatabase.GetAssetPath(targetPrefab); GameObject prefabInstance = GameObject.Instantiate(srcPrefab); Renderer[] rs = prefabInstance.GetComponentsInChildren <Renderer>(); if (rs.Length < 1) { Debug.LogWarning("Prefab " + pr.sourcePrefab + " does not have a renderer"); DestroyImmediate(prefabInstance); return; } Renderer[] sourceRenderers = prefabInstance.GetComponentsInChildren <Renderer>(); Dictionary <Mesh, List <ProcessedMeshInfo> > processedMeshesSrcToTargetMap = new Dictionary <Mesh, List <ProcessedMeshInfo> >(); for (int i = 0; i < sourceRenderers.Length; i++) { if (!IsGoodToBake(sourceRenderers[i], tbr)) { continue; } Mesh sourceMesh = MB_Utility.GetMesh(sourceRenderers[i].gameObject); if (pb.LOG_LEVEL >= MB2_LogLevel.debug) { Debug.Log("== Visiting renderer: " + sourceRenderers[i]); } // Try to find an existing mesh in the target that we can re-use Mesh targetMeshAsset = null; Transform tr = FindCorrespondingTransform(prefabInstance.transform, sourceRenderers[i].transform, targetPrefab.transform); if (tr != null) { Mesh targMesh = MB_Utility.GetMesh(tr.gameObject); // Only replace target meshes if they are part of the target prefab. if (AssetDatabase.GetAssetPath(targMesh) == AssetDatabase.GetAssetPath(targetPrefab)) { targetMeshAsset = MB_Utility.GetMesh(tr.gameObject); if (pb.LOG_LEVEL >= MB2_LogLevel.trace) { Debug.Log("Found correspoinding transform in target prefab: " + tr + " mesh: " + targetMeshAsset); } } } // Check that we haven't processed this mesh already. List <ProcessedMeshInfo> lpmi; if (processedMeshesSrcToTargetMap.TryGetValue(sourceMesh, out lpmi)) { Material[] srcMats = MB_Utility.GetGOMaterials(sourceRenderers[i].gameObject); for (int j = 0; j < lpmi.Count; j++) { if (ComapreMaterials(srcMats, lpmi[j].srcMaterials)) { if (pb.LOG_LEVEL >= MB2_LogLevel.trace) { Debug.Log("Found already processed mesh that uses the same mats"); } targetMeshAsset = lpmi[j].targetMesh; break; } } } Material[] sourceMaterials = MB_Utility.GetGOMaterials(sourceRenderers[i].gameObject); TargetMeshTreatment targetMeshTreatment = TargetMeshTreatment.createNewMesh; string newMeshName = sourceMesh.name; if (targetMeshAsset != null) { // check if this mesh has already been processed processedMeshesSrcToTargetMap.TryGetValue(sourceMesh, out lpmi); if (lpmi != null) { // check if this mesh uses the same materials as one of the processed meshs bool foundMatch = false; bool targetMeshHasBeenUsed = false; Material[] foundMatchMaterials = null; for (int j = 0; j < lpmi.Count; j++) { if (lpmi[j].targetMesh == targetMeshAsset) { targetMeshHasBeenUsed = true; } if (ComapreMaterials(sourceMaterials, lpmi[j].srcMaterials)) { foundMatchMaterials = lpmi[j].targMaterials; foundMatch = true; break; } } if (foundMatch) { // If materials match then we can re-use this processed mesh don't process. if (pb.LOG_LEVEL >= MB2_LogLevel.trace) { Debug.Log(" we can re-use this processed mesh don't process. " + targetMeshAsset); } targetMeshTreatment = TargetMeshTreatment.reuseMesh; MB_Utility.SetMesh(sourceRenderers[i].gameObject, targetMeshAsset); SetMaterials(foundMatchMaterials, sourceRenderers[i]); continue; } else { if (targetMeshHasBeenUsed) { // we need a new target mesh with a safe different name if (pb.LOG_LEVEL >= MB2_LogLevel.trace) { Debug.Log(" we can't re-use this processed mesh create new with different name. " + targetMeshAsset); } newMeshName = GetNameForNewMesh(AssetDatabase.GetAssetPath(targetPrefab), newMeshName); targetMeshTreatment = TargetMeshTreatment.createNewMesh; targetMeshAsset = null; } else { // is it safe to reuse the target mesh // we need a new target mesh with a safe different name if (pb.LOG_LEVEL >= MB2_LogLevel.trace) { Debug.Log(" we can replace this processed mesh. " + targetMeshAsset); } targetMeshTreatment = TargetMeshTreatment.replaceMesh; } } } else { // source mesh has not been processed can reuse the target mesh targetMeshTreatment = TargetMeshTreatment.replaceMesh; } } if (targetMeshTreatment == TargetMeshTreatment.replaceMesh) { if (pb.LOG_LEVEL >= MB2_LogLevel.debug) { Debug.Log("Replace mesh " + targetMeshAsset); } EditorUtility.CopySerialized(sourceMesh, targetMeshAsset); AssetDatabase.SaveAssets(); AssetDatabase.ImportAsset(targetPrefabName); } else if (targetMeshTreatment == TargetMeshTreatment.createNewMesh) { if (pb.LOG_LEVEL >= MB2_LogLevel.debug) { Debug.Log("Create new mesh " + newMeshName); } targetMeshAsset = GameObject.Instantiate <Mesh>(sourceMesh); targetMeshAsset.name = newMeshName; AssetDatabase.AddObjectToAsset(targetMeshAsset, targetPrefab); #if UNITY_2018_3_OR_NEWER PrefabUtility.SavePrefabAsset(targetPrefab); #endif Debug.Assert(targetMeshAsset != null); // need a new mesh } if (targetMeshTreatment == TargetMeshTreatment.createNewMesh || targetMeshTreatment == TargetMeshTreatment.replaceMesh) { if (ProcessMesh(sourceRenderers[i], targetMeshAsset, unityTransforms, mb)) { if (pb.LOG_LEVEL >= MB2_LogLevel.debug) { Debug.Log("Done processing mesh " + targetMeshAsset + " verts " + targetMeshAsset.vertexCount); } ProcessedMeshInfo pmi = new ProcessedMeshInfo(); pmi.targetMesh = targetMeshAsset; pmi.srcMaterials = sourceMaterials; pmi.targMaterials = sourceRenderers[i].sharedMaterials; AddToDictionary(sourceMesh, pmi, processedMeshesSrcToTargetMap); } else { Debug.LogError("Error processing mesh " + targetMeshAsset); } } MB_Utility.SetMesh(sourceRenderers[i].gameObject, targetMeshAsset); } // TODO replace this with MBVersionEditor.ReplacePrefab I tried to do this, but when I did, // ProcessedMeshInfo.targetMesh becomes null, not sure what is going on there. GameObject obj = (GameObject)AssetDatabase.LoadAssetAtPath(targetPrefabName, typeof(GameObject)); PrefabUtility.ReplacePrefab(prefabInstance, obj, ReplacePrefabOptions.ReplaceNameBased); GameObject.DestroyImmediate(prefabInstance); // Destroy obsolete meshes UnityEngine.Object[] allAssets = AssetDatabase.LoadAllAssetsAtPath(targetPrefabName); HashSet <Mesh> usedByTarget = new HashSet <Mesh>(); foreach (List <ProcessedMeshInfo> ll in processedMeshesSrcToTargetMap.Values) { for (int i = 0; i < ll.Count; i++) { usedByTarget.Add(ll[i].targetMesh); } } int numDestroyed = 0; for (int i = 0; i < allAssets.Length; i++) { if (allAssets[i] is Mesh) { if (!usedByTarget.Contains((Mesh)allAssets[i]) && AssetDatabase.GetAssetPath(allAssets[i]) == AssetDatabase.GetAssetPath(targetPrefab)) { numDestroyed++; GameObject.DestroyImmediate(allAssets[i], true); } } } if (pb.LOG_LEVEL >= MB2_LogLevel.debug) { Debug.Log("Destroyed " + numDestroyed + " meshes"); } AssetDatabase.SaveAssets(); //-------------------------- }