public void PopulatePrefabRowsFromTextureBaker(MB3_BatchPrefabBaker prefabBaker)
    {
        Undo.RecordObject(prefabBaker, "Populate prefab rows");
        MB3_TextureBaker  texBaker = prefabBaker.GetComponent <MB3_TextureBaker>();
        List <GameObject> prefabs  = new List <GameObject>();
        List <GameObject> gos      = texBaker.GetObjectsToCombine();

        for (int i = 0; i < gos.Count; i++)
        {
            GameObject         go  = (GameObject)PrefabUtility.FindPrefabRoot(gos[i]);
            UnityEngine.Object obj = MBVersionEditor.PrefabUtility_GetCorrespondingObjectFromSource(go);

            if (obj != null && obj is GameObject)
            {
                if (!prefabs.Contains((GameObject)obj))
                {
                    prefabs.Add((GameObject)obj);
                }
            }
            else
            {
                Debug.LogWarning(String.Format("Object {0} did not have a prefab", gos[i]));
            }
        }
        List <MB3_BatchPrefabBaker.MB3_PrefabBakerRow> newRows = new List <MB3_BatchPrefabBaker.MB3_PrefabBakerRow>();

        for (int i = 0; i < prefabs.Count; i++)
        {
            MB3_BatchPrefabBaker.MB3_PrefabBakerRow row = new MB3_BatchPrefabBaker.MB3_PrefabBakerRow();
            row.sourcePrefab = prefabs[i];
            newRows.Add(row);
        }
        prefabBaker.prefabRows = newRows.ToArray();
    }
    public override void OnInspectorGUI()
    {
        prefabBaker.Update();

        EditorGUILayout.HelpBox(
            "This tool speeds up the process of preparing prefabs " +
            " for static and dynamic batching. It creates duplicate prefab assets and meshes " +
            "that share a combined material. Source assets are not touched.\n\n" +
            "1) bake the textures to be used by prefabs using the MB3_TextureBaker attached to this game object\n" +
            "2) enter the number of prefabs to bake in the 'Prefab Rows Size' field\n" +
            "3) drag source prefab assets to the 'Source Prefab' slots. These should be project assets not scene objects. Renderers" +
            " do not need to be in the root of the prefab. There can be more than one" +
            " renderer in each prefab.\n" +
            "4) choose a folder where the result prefabs will be stored and click 'Create Empty Result Prefabs'\n" +
            "5) click 'Batch Bake Prefabs'\n" +
            "6) Check the console for messages and errors", MessageType.Info);
        EditorGUILayout.PropertyField(logLevel, GUIContentLogLevelContent);

        EditorGUILayout.PropertyField(prefabRows, true);

        EditorGUILayout.LabelField("Output Folder", EditorStyles.boldLabel);
        EditorGUILayout.LabelField(outputFolder.stringValue);

        if (GUILayout.Button("Browse For Output Folder"))
        {
            string path = EditorUtility.OpenFolderPanel("Browse For Output Folder", "", "");
            outputFolder.stringValue = path;
        }

        if (GUILayout.Button("Create Empty Result Prefabs"))
        {
            CreateEmptyOutputPrefabs();
        }

        Color oldColor = GUI.backgroundColor;

        GUI.backgroundColor = buttonColor;
        if (GUILayout.Button(GUIContentBatchBakePrefabReplacePrefab))
        {
            MB3_BatchPrefabBaker pb = (MB3_BatchPrefabBaker)target;
            BakePrefabs(pb, true);
        }
        if (GUILayout.Button(GUIContentBatchBakePrefabOnlyMeshesAndMats))
        {
            MB3_BatchPrefabBaker pb = (MB3_BatchPrefabBaker)target;
            BakePrefabs(pb, false);
        }
        GUI.backgroundColor = oldColor;

        if (GUILayout.Button("Poplate Prefab Rows From Texture Baker"))
        {
            PopulatePrefabRowsFromTextureBaker((MB3_BatchPrefabBaker)prefabBaker.targetObject);
        }
        prefabBaker.ApplyModifiedProperties();
        prefabBaker.SetIsDifferentCacheDirty();
    }
    void _createEmptyOutputPrefabs()
    {
        if (outputFolder.stringValue == null)
        {
            Debug.LogError("Output folder must be set");
            return;
        }
        if (outputFolder.stringValue.StartsWith(Application.dataPath))
        {
            string relativePath = "Assets" + outputFolder.stringValue.Substring(Application.dataPath.Length);
            string gid          = AssetDatabase.AssetPathToGUID(relativePath);
            if (gid == null)
            {
                Debug.LogError("Output folder must be a folder in the Unity project Asset folder");
                return;
            }
        }
        else
        {
            Debug.LogError("Output folder must be a folder in the Unity project Asset folder");
            return;
        }

        int numCreated                   = 0;
        int numSkippedSrcNull            = 0;
        int numSkippedAlreadyExisted     = 0;
        MB3_BatchPrefabBaker prefabBaker = (MB3_BatchPrefabBaker)target;

        for (int i = 0; i < prefabBaker.prefabRows.Length; i++)
        {
            if (prefabBaker.prefabRows[i].sourcePrefab != null)
            {
                if (prefabBaker.prefabRows[i].resultPrefab == null)
                {
                    string outName = outputFolder.stringValue + "/" + prefabBaker.prefabRows[i].sourcePrefab.name + ".prefab";
                    outName = outName.Replace(Application.dataPath, "");
                    outName = "Assets" + outName;
                    //GameObject go = PrefabUtility.CreatePrefab(outputFolder.stringValue + "/" + outName + ".prefab", new GameObject(outName));
                    GameObject go = new GameObject(prefabBaker.prefabRows[i].sourcePrefab.name);
                    prefabBaker.prefabRows[i].resultPrefab = PrefabUtility.CreatePrefab(outName, go);
                    DestroyImmediate(go);
                    numCreated++;
                }
                else
                {
                    numSkippedAlreadyExisted++;
                }
            }
            else
            {
                numSkippedSrcNull++;
            }
        }
        Debug.Log(String.Format("Created {0} prefabs. Skipped {1} because source prefab was null. Skipped {2} because the result prefab was already assigned", numCreated, numSkippedSrcNull, numSkippedAlreadyExisted));
    }
示例#4
0
        public static void CreateNewBatchPrefabBaker()
        {
            //if (MB3_MeshCombiner.EVAL_VERSION)
            //{
            //    Debug.LogError("The prefab baker is only available in the full version of MeshBaker.");
            //    return;
            //}

            MB3_TextureBaker[] mbs = (MB3_TextureBaker[])Editor.FindObjectsOfType(typeof(MB3_TextureBaker));
            // Generate unique name
            int largest = 0;
            {
                Regex regex = new Regex(@"\((\d+)\)$", RegexOptions.Compiled | RegexOptions.CultureInvariant);
                try
                {
                    for (int i = 0; i < mbs.Length; i++)
                    {
                        Match match = regex.Match(mbs[i].name);
                        if (match.Success)
                        {
                            int val = Convert.ToInt32(match.Groups[1].Value);
                            if (val >= largest)
                            {
                                largest = val + 1;
                            }
                        }
                    }
                }
                catch (Exception e)
                {
                    if (e == null)
                    {
                        e = null;            //Do nothing supress compiler warning
                    }
                }
            }

            GameObject nmb = new GameObject("BatchPrefabBaker (" + largest + ")");

            nmb.transform.position = Vector3.zero;

            MB3_BatchPrefabBaker bpb = nmb.AddComponent <MB3_BatchPrefabBaker>();

            nmb.AddComponent <MB3_TextureBaker>();
            nmb.AddComponent <MB3_MeshBaker>();
            bpb.prefabRows         = new MB3_BatchPrefabBaker.MB3_PrefabBakerRow[0];
            bpb.outputPrefabFolder = "";
        }
示例#5
0
        public static void CreateEmptyOutputPrefabs(string outputFolder, MB3_BatchPrefabBaker target)
        {
            if (!ValidateFolderIsInProject("Output Folder", outputFolder))
            {
                return;
            }

            if (outputFolder.StartsWith("Assets"))
            {
                outputFolder = ConvertProjectRelativePathToFullPath(outputFolder);
            }
            int numCreated                   = 0;
            int numSkippedSrcNull            = 0;
            int numSkippedAlreadyExisted     = 0;
            MB3_BatchPrefabBaker prefabBaker = (MB3_BatchPrefabBaker)target;

            for (int i = 0; i < prefabBaker.prefabRows.Length; i++)
            {
                if (prefabBaker.prefabRows[i].sourcePrefab != null)
                {
                    if (prefabBaker.prefabRows[i].resultPrefab == null)
                    {
                        string outName = outputFolder + "/" + prefabBaker.prefabRows[i].sourcePrefab.name + ".prefab";
                        outName = outName.Replace(Application.dataPath, "");
                        outName = "Assets" + outName;
                        GameObject go = new GameObject(prefabBaker.prefabRows[i].sourcePrefab.name);
                        prefabBaker.prefabRows[i].resultPrefab = PrefabUtility.CreatePrefab(outName, go);
                        GameObject.DestroyImmediate(go);
                        numCreated++;
                    }
                    else
                    {
                        numSkippedAlreadyExisted++;
                    }
                }
                else
                {
                    numSkippedSrcNull++;
                }
            }
            Debug.Log(String.Format("Created {0} prefabs. Skipped {1} because source prefab was null. Skipped {2} because the result prefab was already assigned", numCreated, numSkippedSrcNull, numSkippedAlreadyExisted));
        }
    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();
        //--------------------------
    }
    public static void BakePrefabs(MB3_BatchPrefabBaker pb, bool doReplaceTargetPrefab)
    {
        if (pb.LOG_LEVEL >= MB2_LogLevel.info)
        {
            Debug.Log("Batch baking prefabs");
        }
        if (Application.isPlaying)
        {
            Debug.LogError("The BatchPrefabBaker cannot be run in play mode.");
            return;
        }

        MB3_MeshBaker mb = pb.GetComponent <MB3_MeshBaker>();

        if (mb == null)
        {
            Debug.LogError("Prefab baker needs to be attached to a Game Object with a MB3_MeshBaker component.");
            return;
        }

        if (mb.textureBakeResults == null)
        {
            Debug.LogError("Texture Bake Results is not set");
            return;
        }

        if (mb.meshCombiner.outputOption != MB2_OutputOptions.bakeMeshAssetsInPlace)
        {
            mb.meshCombiner.outputOption = MB2_OutputOptions.bakeMeshAssetsInPlace;
        }

        MB2_TextureBakeResults tbr = mb.textureBakeResults;

        HashSet <Mesh> sourceMeshes    = new HashSet <Mesh>();
        HashSet <Mesh> allResultMeshes = new HashSet <Mesh>();

        //validate prefabs
        for (int i = 0; i < pb.prefabRows.Length; i++)
        {
            if (pb.prefabRows[i] == null || pb.prefabRows[i].sourcePrefab == null)
            {
                Debug.LogError("Source Prefab on row " + i + " is not set.");
                return;
            }
            if (pb.prefabRows[i].resultPrefab == null)
            {
                Debug.LogError("Result Prefab on row " + i + " is not set.");
                return;
            }
            for (int j = i + 1; j < pb.prefabRows.Length; j++)
            {
                if (pb.prefabRows[i].sourcePrefab == pb.prefabRows[j].sourcePrefab)
                {
                    Debug.LogError("Rows " + i + " and " + j + " contain the same source prefab");
                    return;
                }
            }
            for (int j = 0; j < pb.prefabRows.Length; j++)
            {
                if (pb.prefabRows[i].sourcePrefab == pb.prefabRows[j].resultPrefab)
                {
                    Debug.LogError("Row " + i + " source prefab is the same as row " + j + " result prefab");
                    return;
                }
            }
            if (MBVersionEditor.GetPrefabType(pb.prefabRows[i].sourcePrefab) != MB_PrefabType.modelPrefab &&
                MBVersionEditor.GetPrefabType(pb.prefabRows[i].sourcePrefab) != MB_PrefabType.prefab)
            {
                Debug.LogError("Row " + i + " source prefab is not a prefab asset ");
                return;
            }
            if (MBVersionEditor.GetPrefabType(pb.prefabRows[i].resultPrefab) != MB_PrefabType.modelPrefab &&
                MBVersionEditor.GetPrefabType(pb.prefabRows[i].resultPrefab) != MB_PrefabType.prefab)
            {
                Debug.LogError("Row " + i + " result prefab is not a prefab asset");
                return;
            }

            GameObject so = (GameObject)Instantiate(pb.prefabRows[i].sourcePrefab);
            GameObject ro = (GameObject)Instantiate(pb.prefabRows[i].resultPrefab);
            Renderer[] rs = (Renderer[])so.GetComponentsInChildren <Renderer>();

            for (int j = 0; j < rs.Length; j++)
            {
                if (IsGoodToBake(rs[j], tbr))
                {
                    sourceMeshes.Add(MB_Utility.GetMesh(rs[j].gameObject));
                }
            }
            rs = (Renderer[])ro.GetComponentsInChildren <Renderer>();

            for (int j = 0; j < rs.Length; j++)
            {
                Renderer r = rs[j];
                if (r is MeshRenderer || r is SkinnedMeshRenderer)
                {
                    Mesh m = MB_Utility.GetMesh(r.gameObject);
                    if (m != null)
                    {
                        allResultMeshes.Add(m);
                    }
                }
            }
            DestroyImmediate(so); //todo should cache these and have a proper cleanup at end
            DestroyImmediate(ro);
        }

        sourceMeshes.IntersectWith(allResultMeshes);
        HashSet <Mesh> sourceMeshesThatAreUsedByResult = sourceMeshes;

        if (sourceMeshesThatAreUsedByResult.Count > 0)
        {
            foreach (Mesh m in sourceMeshesThatAreUsedByResult)
            {
                Debug.LogWarning("Mesh " + m + " is used by both the source and result prefabs. New meshes will be created.");
            }
            //return;
        }

        List <UnityTransform> unityTransforms = new List <UnityTransform>();

        // Bake the meshes using the meshBaker component one prefab at a time
        for (int prefabIdx = 0; prefabIdx < pb.prefabRows.Length; prefabIdx++)
        {
            if (doReplaceTargetPrefab)
            {
                ProcessPrefabRowReplaceTargetPrefab(pb, pb.prefabRows[prefabIdx], tbr, unityTransforms, mb);
            }
            else
            {
                ProcessPrefabRowOnlyMeshesAndMaterials(pb, pb.prefabRows[prefabIdx], tbr, unityTransforms, mb);
            }
        }
        AssetDatabase.Refresh();
        mb.ClearMesh();
    }
示例#8
0
        public override void OnInspectorGUI()
        {
            prefabBaker.Update();

            EditorGUILayout.HelpBox(
                "This tool speeds up the process of preparing prefabs" +
                " for static and dynamic batching. It creates duplicate prefab assets and meshes" +
                " that share a combined material. Source assets are not touched.\n\n" +
                "1) Create instances of source prefabs to this scene.\n" +
                "2) Add these instances to the TextureBaker on this GameObject and bake the textures used by the prefabs.\n" +
                "2) Using the BatchPrefabBaker component, click 'Populate Prefab Rows From Texture Baker' or manually set up Prefab Rows by dragging to the Prefab Rows list.\n" +
                "4) Choose a folder where the result prefabs will be stored and click 'Create Empty Result Prefabs'\n" +
                "5) click 'Batch Bake Prefabs'\n" +
                "6) Check the console for messages and errors\n" +
                "7) (Optional) If you want to compare the source objects to the result objects use the BatchPrefabBaker '...' menu command 'Create Instances For Prefab Rows'. This will create aligned instances of the prefabs in the scene so that it is easy to see any differences.\n", MessageType.Info);
            EditorGUILayout.PropertyField(logLevel, GUIContentLogLevelContent);

            EditorGUILayout.PropertyField(prefabRows, true);

            EditorGUILayout.LabelField("Output Folder", EditorStyles.boldLabel);
            EditorGUILayout.LabelField(outputFolder.stringValue);

            if (GUILayout.Button("Browse For Output Folder"))
            {
                string path = EditorUtility.OpenFolderPanel("Browse For Output Folder", "", "");
                path = MB_BatchPrefabBakerEditorFunctions.ConvertFullPathToProjectRelativePath(path);
                outputFolder.stringValue = path;
            }

            if (GUILayout.Button("Create Empty Result Prefabs"))
            {
                MB_BatchPrefabBakerEditorFunctions.CreateEmptyOutputPrefabs(outputFolder.stringValue, (MB3_BatchPrefabBaker)target);
            }

            Color oldColor = GUI.backgroundColor;

            GUI.backgroundColor = buttonColor;
            if (GUILayout.Button(GUIContentBatchBakePrefabReplacePrefab))
            {
                MB3_BatchPrefabBaker pb = (MB3_BatchPrefabBaker)target;
                MB_BatchPrefabBakerEditorFunctions.BakePrefabs(pb, true);
            }
            if (GUILayout.Button(GUIContentBatchBakePrefabOnlyMeshesAndMats))
            {
                MB3_BatchPrefabBaker pb = (MB3_BatchPrefabBaker)target;
                MB_BatchPrefabBakerEditorFunctions.BakePrefabs(pb, false);
            }
            GUI.backgroundColor = oldColor;

            if (GUILayout.Button("Poplate Prefab Rows From Texture Baker"))
            {
                PopulatePrefabRowsFromTextureBaker((MB3_BatchPrefabBaker)prefabBaker.targetObject);
            }

            if (GUILayout.Button("Open Replace Prefabs In Scene Window"))
            {
                MB3_BatchPrefabBaker pb = (MB3_BatchPrefabBaker)target;
                MB_ReplacePrefabsInSceneEditorWindow.ShowWindow(pb.prefabRows);
            }


            prefabBaker.ApplyModifiedProperties();
            prefabBaker.SetIsDifferentCacheDirty();
        }
示例#9
0
        public void PopulatePrefabRowsFromTextureBaker(MB3_BatchPrefabBaker prefabBaker)
        {
            MB3_TextureBaker  texBaker   = prefabBaker.GetComponent <MB3_TextureBaker>();
            List <GameObject> newPrefabs = new List <GameObject>();
            List <GameObject> gos        = texBaker.GetObjectsToCombine();

            for (int i = 0; i < gos.Count; i++)
            {
                GameObject         go  = (GameObject)MBVersionEditor.PrefabUtility_FindPrefabRoot(gos[i]);
                UnityEngine.Object obj = MBVersionEditor.PrefabUtility_GetCorrespondingObjectFromSource(go);

                if (obj != null && obj is GameObject)
                {
                    if (!newPrefabs.Contains((GameObject)obj))
                    {
                        newPrefabs.Add((GameObject)obj);
                    }
                }
                else
                {
                    Debug.LogWarning(String.Format("Object {0} did not have a prefab", gos[i]));
                }
            }

            // Remove prefabs that are already in the list of batch prefab baker's prefabs.
            {
                List <GameObject> tmpNewPrefabs = new List <GameObject>();
                for (int i = 0; i < newPrefabs.Count; i++)
                {
                    bool found = false;
                    for (int j = 0; j < prefabBaker.prefabRows.Length; j++)
                    {
                        if (prefabBaker.prefabRows[j].sourcePrefab == newPrefabs[i])
                        {
                            found = true;
                            break;
                        }
                    }

                    if (!found)
                    {
                        tmpNewPrefabs.Add(newPrefabs[i]);
                    }
                }

                newPrefabs = tmpNewPrefabs;
            }

            if (MB3_MeshCombiner.EVAL_VERSION)
            {
                int numPrefabsLimit = MB_BatchPrefabBakerEditorFunctions.EvalVersionPrefabLimit;
                int numNew          = numPrefabsLimit - prefabBaker.prefabRows.Length;
                if (newPrefabs.Count + prefabBaker.prefabRows.Length > numPrefabsLimit)
                {
                    Debug.LogError("The free version of Mesh Baker is limited to batch baking " + numPrefabsLimit +
                                   " prefabs. The full version has no limit on the number of prefabs that can be baked. " + (newPrefabs.Count - numNew) + " prefabs were not added.");
                }


                for (int i = newPrefabs.Count - 1; i >= numNew; i--)
                {
                    newPrefabs.RemoveAt(i);
                }
            }

            List <MB3_BatchPrefabBaker.MB3_PrefabBakerRow> newRows = new List <MB3_BatchPrefabBaker.MB3_PrefabBakerRow>();

            if (prefabBaker.prefabRows == null)
            {
                prefabBaker.prefabRows = new MB3_BatchPrefabBaker.MB3_PrefabBakerRow[0];
            }
            newRows.AddRange(prefabBaker.prefabRows);
            for (int i = 0; i < newPrefabs.Count; i++)
            {
                MB3_BatchPrefabBaker.MB3_PrefabBakerRow row = new MB3_BatchPrefabBaker.MB3_PrefabBakerRow();
                row.sourcePrefab = newPrefabs[i];
                newRows.Add(row);
            }


            Undo.RecordObject(prefabBaker, "Populate prefab rows");
            prefabBaker.prefabRows = newRows.ToArray();
        }
    public void _bakePrefabs()
    {
        Debug.Log("Batch baking prefabs");
        if (Application.isPlaying)
        {
            Debug.LogError("The BatchPrefabBaker cannot be run in play mode.");
            return;
        }
        MB3_BatchPrefabBaker pb = (MB3_BatchPrefabBaker)target;
        MB3_MeshBaker        mb = pb.GetComponent <MB3_MeshBaker>();

        if (mb == null)
        {
            Debug.LogError("Prefab baker needs to be attached to a Game Object with a MB3_MeshBaker component.");
            return;
        }

        if (mb.textureBakeResults == null)
        {
            Debug.LogError("Texture Bake Results is not set");
            return;
        }

        if (mb.meshCombiner.outputOption != MB2_OutputOptions.bakeMeshAssetsInPlace)
        {
            mb.meshCombiner.outputOption = MB2_OutputOptions.bakeMeshAssetsInPlace;
        }

        MB2_TextureBakeResults tbr = mb.textureBakeResults;

        HashSet <Mesh> sourceMeshes    = new HashSet <Mesh>();
        HashSet <Mesh> allResultMeshes = new HashSet <Mesh>();

        //validate prefabs
        for (int i = 0; i < pb.prefabRows.Length; i++)
        {
            if (pb.prefabRows[i] == null || pb.prefabRows[i].sourcePrefab == null)
            {
                Debug.LogError("Source Prefab on row " + i + " is not set.");
                return;
            }
            if (pb.prefabRows[i].resultPrefab == null)
            {
                Debug.LogError("Result Prefab on row " + i + " is not set.");
                return;
            }
            for (int j = i + 1; j < pb.prefabRows.Length; j++)
            {
                if (pb.prefabRows[i].sourcePrefab == pb.prefabRows[j].sourcePrefab)
                {
                    Debug.LogError("Rows " + i + " and " + j + " contain the same source prefab");
                    return;
                }
            }
            for (int j = 0; j < pb.prefabRows.Length; j++)
            {
                if (pb.prefabRows[i].sourcePrefab == pb.prefabRows[j].resultPrefab)
                {
                    Debug.LogError("Row " + i + " source prefab is the same as row " + j + " result prefab");
                    return;
                }
            }
            if (PrefabUtility.GetPrefabType(pb.prefabRows[i].sourcePrefab) != PrefabType.ModelPrefab &&
                PrefabUtility.GetPrefabType(pb.prefabRows[i].sourcePrefab) != PrefabType.Prefab)
            {
                Debug.LogError("Row " + i + " source prefab is not a prefab asset");
                return;
            }
            if (PrefabUtility.GetPrefabType(pb.prefabRows[i].resultPrefab) != PrefabType.ModelPrefab &&
                PrefabUtility.GetPrefabType(pb.prefabRows[i].resultPrefab) != PrefabType.Prefab)
            {
                Debug.LogError("Row " + i + " result prefab is not a prefab asset");
                return;
            }

            GameObject so = (GameObject)Instantiate(pb.prefabRows[i].sourcePrefab);
            GameObject ro = (GameObject)Instantiate(pb.prefabRows[i].resultPrefab);
            Renderer[] rs = (Renderer[])so.GetComponentsInChildren <Renderer>();

            for (int j = 0; j < rs.Length; j++)
            {
                if (IsGoodToBake(rs[j], tbr))
                {
                    sourceMeshes.Add(MB_Utility.GetMesh(rs[j].gameObject));
                }
            }
            rs = (Renderer[])ro.GetComponentsInChildren <Renderer>();

            for (int j = 0; j < rs.Length; j++)
            {
                Renderer r = rs[j];
                if (r is MeshRenderer || r is SkinnedMeshRenderer)
                {
                    Mesh m = MB_Utility.GetMesh(r.gameObject);
                    if (m != null)
                    {
                        allResultMeshes.Add(m);
                    }
                }
            }
            DestroyImmediate(so);             //todo should cache these and have a proper cleanup at end
            DestroyImmediate(ro);
        }

        sourceMeshes.IntersectWith(allResultMeshes);
        HashSet <Mesh> sourceMeshesThatAreUsedByResult = sourceMeshes;

        if (sourceMeshesThatAreUsedByResult.Count > 0)
        {
            foreach (Mesh m in sourceMeshesThatAreUsedByResult)
            {
                Debug.LogWarning("Mesh " + m + " is used by both the source and result prefabs. New meshes will be created.");
            }
            //return;
        }

        Dictionary <string, string> createdMeshPaths = new Dictionary <string, string>();

        // Bake the meshes using the meshBaker component one prefab at a time
        for (int prefabIdx = 0; prefabIdx < pb.prefabRows.Length; prefabIdx++)
        {
            Debug.Log("==== Processing Source Prefab " + pb.prefabRows[prefabIdx].sourcePrefab);
            GameObject sceneObj     = (GameObject)Instantiate(pb.prefabRows[prefabIdx].sourcePrefab);
            GameObject resultPrefab = (GameObject)Instantiate(pb.prefabRows[prefabIdx].resultPrefab);

            Renderer[] rs = sceneObj.GetComponentsInChildren <Renderer>();
            if (rs.Length < 1)
            {
                Debug.LogWarning("Prefab " + prefabIdx + " does not have a renderer");
                DestroyImmediate(sceneObj);
                DestroyImmediate(resultPrefab);
                continue;
            }

            List <Mesh>           usedMeshes      = new List <Mesh>();
            List <UnityTransform> unityTransforms = new List <UnityTransform>();
            for (int j = 0; j < rs.Length; j++)
            {
                unityTransforms.Clear();
                Renderer r = rs[j];

                if (!IsGoodToBake(r, tbr))
                {
                    continue;
                }

                //find the corresponding mesh in the result prefab
                string resultFolderPath = AssetDatabase.GetAssetPath(pb.prefabRows[prefabIdx].resultPrefab);
                resultFolderPath = Path.GetDirectoryName(resultFolderPath);

                Mesh      m    = null;
                Transform tRes = FindCorrespondingTransform(sceneObj.transform, r.transform, resultPrefab.transform);
                if (tRes != null)
                {
                    m = MB_Utility.GetMesh(tRes.gameObject);
                }

                //if the meshes on source and result are the same we want to remove mesh so will create a new one
                if (sourceMeshesThatAreUsedByResult.Contains(m))
                {
                    Debug.LogWarning("Source and result prefabs share a mesh. Creating a new mesh for " + m);
                    MB_Utility.SetMesh(tRes.gameObject, null);
                    m = null;
                }


                string meshPath;
                //check that the mesh is an asset and that we have not used it already
                if (m != null && AssetDatabase.IsMainAsset(m.GetInstanceID()) && !usedMeshes.Contains(m))
                {
                    meshPath = AssetDatabase.GetAssetPath(m);
                    if (createdMeshPaths.ContainsKey(meshPath))
                    {
                        Debug.LogWarning("Different result prefabs share a mesh." + meshPath);
                    }
                }
                else                     //create a new mesh asset with a unique name
                {
                    string resultPrefabFilename = AssetDatabase.GetAssetPath(pb.prefabRows[prefabIdx].resultPrefab);
                    resultPrefabFilename = resultPrefabFilename.Substring(0, resultPrefabFilename.Length - ".prefab".Length) + ".asset";
                    meshPath             = AssetDatabase.GenerateUniqueAssetPath(resultPrefabFilename);
                    m = new Mesh();
                    AssetDatabase.CreateAsset(m, meshPath);
                    m = (Mesh)AssetDatabase.LoadAssetAtPath(meshPath, typeof(Mesh));
                }
                Debug.Log("  creating new mesh asset at path " + meshPath);
                if (!createdMeshPaths.ContainsKey(meshPath))
                {
                    createdMeshPaths.Add(meshPath, meshPath);
                }

                // position rotation and scale are baked into combined mesh.
                // Remember all the transforms settings then
                // record transform values to root of hierarchy
                Transform t = r.transform;
                if (t != t.root)
                {
                    do
                    {
                        unityTransforms.Add(new UnityTransform(t));
                        t = t.parent;
                    } while (t != null && t != t.root);
                }
                //add the root
                unityTransforms.Add(new UnityTransform(t.root));

                //position at identity
                for (int k = 0; k < unityTransforms.Count; k++)
                {
                    unityTransforms[k].t.localPosition = Vector3.zero;
                    unityTransforms[k].t.localRotation = Quaternion.identity;
                    unityTransforms[k].t.localScale    = Vector3.one;
                }

                //throw new Exception("");
                //bake the mesh
                mb.ClearMesh();
                MB3_MeshCombiner mc = mb.meshCombiner;
                m = MB3_BakeInPlace.BakeOneMesh((MB3_MeshCombinerSingle)mc, meshPath, r.gameObject);

                //replace the mesh
                if (r is MeshRenderer)
                {
                    MeshFilter mf = r.gameObject.GetComponent <MeshFilter>();
                    mf.sharedMesh = m;
                }
                else                     //skinned mesh
                {
                    SkinnedMeshRenderer smr = r.gameObject.GetComponent <SkinnedMeshRenderer>();
                    smr.sharedMesh = m;
                    smr.bones      = ((SkinnedMeshRenderer)mc.targetRenderer).bones;
                }

                //replace the result material(s)
                if (mb.textureBakeResults.doMultiMaterial)
                {
                    Material[] rss = new Material[mb.textureBakeResults.resultMaterials.Length];
                    for (int k = 0; k < rss.Length; k++)
                    {
                        rss[k] = mb.textureBakeResults.resultMaterials[k].combinedMaterial;
                    }
                    r.sharedMaterials = rss;
                }
                else
                {
                    Material[] originalMats = r.sharedMaterials;
                    Material[] rss          = new Material[originalMats.Length];
                    for (int k = 0; k < originalMats.Length; k++)
                    {
                        if (tbr.ContainsMaterial(originalMats[k]))
                        {
                            rss[k] = mb.textureBakeResults.resultMaterial;
                        }
                        else
                        {
                            rss[k] = originalMats[k];
                        }
                    }

                    r.sharedMaterials = rss;
                }

                //restore the transforms
                for (int k = 0; k < unityTransforms.Count; k++)
                {
                    unityTransforms[k].t.localPosition = unityTransforms[k].p;
                    unityTransforms[k].t.localRotation = unityTransforms[k].q;
                    unityTransforms[k].t.localScale    = unityTransforms[k].s;
                }
            }

            //replace the result prefab with the source object
            //duplicate the sceneObj so we can replace the clone into the prefab, not the source
            GameObject clone = (GameObject)Instantiate(sceneObj);
            PrefabUtility.ReplacePrefab(clone, pb.prefabRows[prefabIdx].resultPrefab, ReplacePrefabOptions.ReplaceNameBased);
            DestroyImmediate(clone);
            DestroyImmediate(sceneObj);
            DestroyImmediate(resultPrefab);
        }
        AssetDatabase.Refresh();
        mb.ClearMesh();
    }
示例#11
0
        public static void PopulatePrefabRowsFromTextureBaker(MB3_BatchPrefabBaker prefabBaker)
        {
            MB3_TextureBaker  texBaker   = prefabBaker.GetComponent <MB3_TextureBaker>();
            List <GameObject> newPrefabs = new List <GameObject>();
            List <GameObject> gos        = texBaker.GetObjectsToCombine();

            for (int i = 0; i < gos.Count; i++)
            {
                GameObject         go  = (GameObject)PrefabUtility.FindPrefabRoot(gos[i]);
                UnityEngine.Object obj = MBVersionEditor.PrefabUtility_GetCorrespondingObjectFromSource(go);

                if (obj != null && obj is GameObject)
                {
                    if (!newPrefabs.Contains((GameObject)obj))
                    {
                        newPrefabs.Add((GameObject)obj);
                    }
                }
                else
                {
                    Debug.LogWarning(String.Format("Object {0} did not have a prefab", gos[i]));
                }
            }

            // Remove prefabs that are already in the list of batch prefab baker's prefabs.
            {
                List <GameObject> tmpNewPrefabs = new List <GameObject>();
                for (int i = 0; i < newPrefabs.Count; i++)
                {
                    bool found = false;
                    for (int j = 0; j < prefabBaker.prefabRows.Length; j++)
                    {
                        if (prefabBaker.prefabRows[j].sourcePrefab == newPrefabs[i])
                        {
                            found = true;
                            break;
                        }
                    }

                    if (!found)
                    {
                        tmpNewPrefabs.Add(newPrefabs[i]);
                    }
                }

                newPrefabs = tmpNewPrefabs;
            }

            List <MB3_BatchPrefabBaker.MB3_PrefabBakerRow> newRows = new List <MB3_BatchPrefabBaker.MB3_PrefabBakerRow>();

            if (prefabBaker.prefabRows == null)
            {
                prefabBaker.prefabRows = new MB3_BatchPrefabBaker.MB3_PrefabBakerRow[0];
            }
            newRows.AddRange(prefabBaker.prefabRows);
            for (int i = 0; i < newPrefabs.Count; i++)
            {
                MB3_BatchPrefabBaker.MB3_PrefabBakerRow row = new MB3_BatchPrefabBaker.MB3_PrefabBakerRow();
                row.sourcePrefab = newPrefabs[i];
                newRows.Add(row);
            }


            Undo.RecordObject(prefabBaker, "Populate prefab rows");
            prefabBaker.prefabRows = newRows.ToArray();
        }