コード例 #1
0
    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 void AddTextureFormat(Texture2D tx, bool isNormalMap)
 {
     //pixel values don't copy correctly from one texture to another when isNormal is set so unset it.
     _SetTextureFormat(tx,
                       new TextureFormatInfo(TextureImporterFormat.ARGB32, MBVersionEditor.GetPlatformString(), TextureImporterFormat.AutomaticTruecolor, isNormalMap),
                       true, false);
 }
コード例 #3
0
        public void SaveMeshesToOutputFolderAndAssignToSMRs(Mesh[] targetMeshes, SkinnedMeshRenderer[] targetSMRs)
        {
            //validate meshes
            for (int i = 0; i < targetMeshes.Length; i++)
            {
                if (targetSMRs[i] == null)
                {
                    Debug.LogError(string.Format("Target Mesh {0} is null", i));
                    return;
                }

                if (targetSMRs[i].sharedMesh == null)
                {
                    Debug.LogError(string.Format("Target Mesh {0} does not have a mesh", i));
                    return;
                }
                MB_PrefabType pt = MBVersionEditor.GetPrefabType(targetMeshes[i]);
                if (pt == MB_PrefabType.modelPrefab)
                {
                    Debug.LogError(string.Format("Target Mesh {0} is an imported model prefab. Can't modify these meshes because changes will be overwritten the next time the model is saved or reimported. Try instantiating the prefab and using skinned meshes from the scene instance.", i));
                    return;
                }
            }
            //validate output folder
            if (outputFolderProp.stringValue == null)
            {
                Debug.LogError("Output folder must be set");
                return;
            }
            if (outputFolderProp.stringValue.StartsWith(Application.dataPath))
            {
                string relativePath = "Assets" + outputFolderProp.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;
            }
            for (int i = 0; i < targetMeshes.Length; i++)
            {
                Mesh   m   = targetMeshes[i];
                string pth = ConvertAbsolutePathToUnityPath(outputFolderProp.stringValue + "/" + targetMeshes[i].name + ".Asset");
                if (pth == null)
                {
                    Debug.LogError("The output folder must be a folder in the project Assets folder.");
                    return;
                }
                AssetDatabase.CreateAsset(m, pth);
                targetSMRs[i].sharedMesh = m;
                Debug.Log(string.Format("Created mesh at {0}. Updated Skinned Mesh {1} to use created mesh.", pth, targetSMRs[i].name));
            }
            AssetDatabase.SaveAssets();
        }
コード例 #4
0
    // The serialized object reference is necessary to work around a nasty unity bug.
    public static void RebuildPrefab(MB3_MeshBakerCommon mom, ref SerializedObject so)
    {
        if (MB3_MeshCombiner.EVAL_VERSION)
        {
            return;
        }

        if (mom.meshCombiner.LOG_LEVEL >= MB2_LogLevel.debug)
        {
            Debug.Log("Rebuilding Prefab: " + mom.resultPrefab);
        }
        GameObject prefabRoot = mom.resultPrefab;
        GameObject rootGO     = (GameObject)PrefabUtility.InstantiatePrefab(prefabRoot);

        //remove all renderer childeren of rootGO
        MBVersionEditor.UnpackPrefabInstance(rootGO, ref so);
        Renderer[] rs = rootGO.GetComponentsInChildren <Renderer>();
        for (int i = 0; i < rs.Length; i++)
        {
            if (rs[i] != null && rs[i].transform.parent == rootGO.transform)
            {
                MB_Utility.Destroy(rs[i].gameObject);
            }
        }

        if (mom is MB3_MeshBaker)
        {
            MB3_MeshBaker          mb  = (MB3_MeshBaker)mom;
            MB3_MeshCombinerSingle mbs = (MB3_MeshCombinerSingle)mb.meshCombiner;
            MB3_MeshCombinerSingle.BuildPrefabHierarchy(mbs, rootGO, mbs.GetMesh());
        }
        else if (mom is MB3_MultiMeshBaker)
        {
            MB3_MultiMeshBaker    mmb = (MB3_MultiMeshBaker)mom;
            MB3_MultiMeshCombiner mbs = (MB3_MultiMeshCombiner)mmb.meshCombiner;
            for (int i = 0; i < mbs.meshCombiners.Count; i++)
            {
                MB3_MeshCombinerSingle.BuildPrefabHierarchy(mbs.meshCombiners[i].combinedMesh, rootGO, mbs.meshCombiners[i].combinedMesh.GetMesh(), true);
            }
        }
        else
        {
            Debug.LogError("Argument was not a MB3_MeshBaker or an MB3_MultiMeshBaker.");
        }

        string prefabPth = AssetDatabase.GetAssetPath(prefabRoot);

        MBVersionEditor.ReplacePrefab(rootGO, prefabPth, MB_ReplacePrefabOption.connectToPrefab);
        if (mom.meshCombiner.renderType != MB_RenderType.skinnedMeshRenderer)
        {
            // For Skinned meshes, leave the prefab instance in the scene so source game objects can moved into the prefab.
            Editor.DestroyImmediate(rootGO);
        }
    }
コード例 #5
0
        private static void DoGeneratePrefabsIfNecessary(MB3_MeshBakerGrouper grouper, List <MB3_MeshBakerCommon> newBakers)
        {
            if (!grouper.prefabOptions_autoGeneratePrefabs &&
                !grouper.prefabOptions_mergeOutputIntoSinglePrefab)
            {
                return;
            }
            if (!MB_BatchPrefabBakerEditorFunctions.ValidateFolderIsInProject("Output Folder", grouper.prefabOptions_outputFolder))
            {
                return;
            }

            if (grouper.prefabOptions_autoGeneratePrefabs)
            {
                for (int i = 0; i < newBakers.Count; i++)
                {
                    MB3_MeshBakerCommon baker = newBakers[i];

                    string path = grouper.prefabOptions_outputFolder;
                    // To handle paths with a different root
                    //path = MB_BatchPrefabBakerEditorFunctions.ConvertAnyPathToProjectRelativePath(path);

                    // Generate a new prefab name
                    string prefabName = baker.name.Replace("MeshBaker", "CombinedMesh");
                    prefabName = prefabName.Replace(" ", "_");
                    prefabName = prefabName.Replace(",", "_");
                    prefabName = prefabName.Trim(Path.GetInvalidFileNameChars());
                    prefabName = prefabName.Trim(Path.GetInvalidPathChars());

                    string pathName = AssetDatabase.GenerateUniqueAssetPath(path + "/" + prefabName + ".prefab");
                    if (pathName == null || pathName.Length == 0)
                    {
                        Debug.LogError("Could not generate prefab " + prefabName + " in folder " + path + ". There is something wrong with the path or prefab name.");
                        continue;
                    }

                    // Generate a new prefab
                    GameObject go = new GameObject(baker.name);
                    GameObject pf = MBVersionEditor.PrefabUtility_CreatePrefab(pathName, go);

                    // Configure the baker to bake into the prefab
                    baker.resultPrefab = pf;
                    baker.resultPrefabLeaveInstanceInSceneAfterBake = true;
                    baker.meshCombiner.outputOption = MB2_OutputOptions.bakeIntoPrefab;
                    if (grouper.parentSceneObject != null)
                    {
                        baker.parentSceneObject = grouper.parentSceneObject;
                    }

                    MB_Utility.Destroy(go);
                }
            }
        }
コード例 #6
0
        public void SaveMeshesToOutputFolderAndAssignToSMRs(Mesh[] targetMeshes, SkinnedMeshRenderer[] targetSMRs)
        {
            //validate meshes
            for (int i = 0; i < targetMeshes.Length; i++)
            {
                if (targetSMRs[i] == null)
                {
                    Debug.LogError(string.Format("Target Mesh {0} is null", i));
                    return;
                }

                if (targetSMRs[i].sharedMesh == null)
                {
                    Debug.LogError(string.Format("Target Mesh {0} does not have a mesh", i));
                    return;
                }
                MB_PrefabType pt = MBVersionEditor.PrefabUtility_GetPrefabType(targetMeshes[i]);
                if (pt == MB_PrefabType.modelPrefabAsset)
                {
                    Debug.LogError(string.Format("Target Mesh {0} is an imported model prefab. Can't modify these meshes because changes will be overwritten the next time the model is saved or reimported. Try instantiating the prefab and using skinned meshes from the scene instance.", i));
                    return;
                }
            }
            //validate output folder
            if (outputFolderProp.stringValue == null)
            {
                Debug.LogError("Output folder must be set");
                return;
            }
            else
            {
                if (!MB_BatchPrefabBakerEditorFunctions.ValidateFolderIsInProject("Output Folder", outputFolderProp.stringValue))
                {
                    return;
                }
            }
            for (int i = 0; i < targetMeshes.Length; i++)
            {
                Mesh   m   = targetMeshes[i];
                string pth = MB_BatchPrefabBakerEditorFunctions.ConvertAnyPathToProjectRelativePath(outputFolderProp.stringValue + "/" + targetMeshes[i].name + ".Asset");
                if (pth == null)
                {
                    Debug.LogError("The output folder must be a folder in the project Assets folder.");
                    return;
                }
                AssetDatabase.CreateAsset(m, pth);
                targetSMRs[i].sharedMesh = m;
                Debug.Log(string.Format("Created mesh at {0}. Updated Skinned Mesh {1} to use created mesh.", pth, targetSMRs[i].name));
            }
            AssetDatabase.SaveAssets();
        }
        void addSelectedObjects()
        {
            MB3_MeshBakerRoot mom = (MB3_MeshBakerRoot)target;

            if (mom == null)
            {
                Debug.LogError("Must select a target MeshBaker to add objects to");
                return;
            }

            List <GameObject> newMomObjs = GetFilteredList(addingObjects: true);

            MBVersionEditor.RegisterUndo(mom, "Add Objects");
            List <GameObject> momObjs = mom.GetObjectsToCombine();
            int numAdded         = 0;
            int numAlreadyInList = 0;

            for (int i = 0; i < newMomObjs.Count; i++)
            {
                if (!momObjs.Contains(newMomObjs[i]))
                {
                    momObjs.Add(newMomObjs[i]);
                    numAdded++;
                }
                else
                {
                    numAlreadyInList++;
                }
            }

            SerializedObject so = new SerializedObject(mom);

            so.SetIsDifferentCacheDirty();
            if (numAlreadyInList > 0)
            {
                Debug.Log(String.Format("Skipped adding {0} objects to Target because these objects had already been added to this Target. ", numAlreadyInList));
            }

            if (numAdded == 0)
            {
                Debug.LogWarning("Added 0 objects. Make sure some or all objects are selected in the hierarchy view. Also check ths 'Only Static Objects', 'Using Material' and 'Using Shader' settings");
            }
            else
            {
                Debug.Log(string.Format("Added {0} objects to {1}. ", numAdded, mom.name));
            }

            helpBoxString += String.Format("\nAdded {0} objects to {1}", numAdded, mom.name);
        }
コード例 #8
0
 private static void createEmptyPrefab(MB3_MeshBakerCommon mom, string folder, string prefabNameNoExtension, int idx)
 {
     if (prefabNameNoExtension != null && prefabNameNoExtension.Length > 0)
     {
         string     prefabName = prefabNameNoExtension + idx;
         GameObject go         = new GameObject(prefabName);
         string     fullName   = folder + "/" + prefabName + ".prefab";
         fullName = AssetDatabase.GenerateUniqueAssetPath(fullName);
         Debug.Log(fullName);
         MBVersionEditor.PrefabUtility_CreatePrefab(fullName, go);
         GameObject.DestroyImmediate(go);
         SerializedObject so = new SerializedObject(mom);
         so.FindProperty("resultPrefab").objectReferenceValue = (GameObject)AssetDatabase.LoadAssetAtPath(fullName, typeof(GameObject));
         so.ApplyModifiedProperties();
     }
 }
コード例 #9
0
        void removeSelectedObjects()
        {
            MB3_MeshBakerRoot mom = (MB3_MeshBakerRoot)target;

            if (mom == null)
            {
                Debug.LogError("Must select a target MeshBaker");
                return;
            }
            List <GameObject>    objsToCombine = mom.GetObjectsToCombine();
            HashSet <GameObject> objectsAlreadyIncludedInBakers = new HashSet <GameObject>();
            GameObject           dontAddMe = null;
            Renderer             r         = MB_Utility.GetRenderer(mom.gameObject);

            if (r != null)
            { //make sure that this MeshBaker object is not in list
                dontAddMe = r.gameObject;
            }

            List <GameObject> objsSelectedMatchingFilter = GetFilteredList(addingObjects: false);

            Debug.Log("Matching filter " + objsSelectedMatchingFilter.Count);
            List <GameObject> objsToRemove = new List <GameObject>();

            for (int i = 0; i < objsSelectedMatchingFilter.Count; i++)
            {
                if (objsToCombine.Contains(objsSelectedMatchingFilter[i]))
                {
                    objsToRemove.Add(objsSelectedMatchingFilter[i]);
                }
            }

            MBVersionEditor.RegisterUndo(mom, "Remove Objects");
            for (int i = 0; i < objsToRemove.Count; i++)
            {
                objsToCombine.Remove(objsToRemove[i]);
            }

            SerializedObject so = new SerializedObject(mom);

            so.SetIsDifferentCacheDirty();
            Debug.Log("Removed " + objsToRemove.Count + " objects from " + mom.name);
            helpBoxString += String.Format("\nRemoved {0} objects from {1}", objsToRemove.Count, mom.name);
        }
コード例 #10
0
        private static List <GameObject> FindAllPrefabInstances(UnityEngine.Object myPrefab)
        {
            List <GameObject> result = new List <GameObject>();

            GameObject[] allObjects = (GameObject[])GameObject.FindObjectsOfType(typeof(GameObject));
            foreach (GameObject go in allObjects)
            {
                MB_PrefabType objPrefabType = MBVersionEditor.PrefabUtility_GetPrefabType(go);
                if (objPrefabType == MB_PrefabType.scenePefabInstance)
                {
                    UnityEngine.Object GO_prefab = MBVersionEditor.PrefabUtility_GetCorrespondingObjectFromSource(go);
                    if (myPrefab == GO_prefab)
                    {
                        result.Add(go);
                    }
                }
            }

            return(result);
        }
コード例 #11
0
    void addSelectedObjects()
    {
        MB3_MeshBakerRoot mom = (MB3_MeshBakerRoot)target;

        if (mom == null)
        {
            Debug.LogError("Must select a target MeshBaker to add objects to");
            return;
        }
        List <GameObject> newMomObjs = GetFilteredList();

        MBVersionEditor.RegisterUndo(mom, "Add Objects");
        List <GameObject> momObjs = mom.GetObjectsToCombine();
        int numAdded = 0;

        for (int i = 0; i < newMomObjs.Count; i++)
        {
            if (!momObjs.Contains(newMomObjs[i]))
            {
                momObjs.Add(newMomObjs[i]);
                numAdded++;
            }
        }
        SerializedObject so = new SerializedObject(mom);

        so.SetIsDifferentCacheDirty();

        if (numAdded == 0)
        {
            Debug.LogWarning("Added 0 objects. Make sure some or all objects are selected in the hierarchy view. Also check ths 'Only Static Objects', 'Using Material' and 'Using Shader' settings");
        }
        else
        {
            Debug.Log("Added " + numAdded + " objects to " + mom.name);
        }
    }
コード例 #12
0
        //posibilities
        //  using fixOutOfBoundsUVs or not
        //
        public static void ConfigureMutiMaterialsFromObjsToCombine(MB3_TextureBaker mom, SerializedProperty resultMaterials, SerializedObject textureBaker)
        {
            if (mom.GetObjectsToCombine().Count == 0)
            {
                Debug.LogError("You need to add some objects to combine before building the multi material list.");
                return;
            }
            if (resultMaterials.arraySize > 0)
            {
                Debug.LogError("You already have some source to combined material mappings configured. You must remove these before doing this operation.");
                return;
            }
            if (mom.textureBakeResults == null)
            {
                Debug.LogError("Texture Bake Result asset must be set before using this operation.");
                return;
            }
            Dictionary <MultiMatSubmeshInfo, List <List <Material> > > shader2Material_map = new Dictionary <MultiMatSubmeshInfo, List <List <Material> > >();
            Dictionary <Material, Mesh> obUVobject2mesh_map = new Dictionary <Material, Mesh>();

            //validate that the objects to be combined are valid
            for (int i = 0; i < mom.GetObjectsToCombine().Count; i++)
            {
                GameObject go = mom.GetObjectsToCombine()[i];
                if (go == null)
                {
                    Debug.LogError("Null object in list of objects to combine at position " + i);
                    return;
                }
                Renderer r = go.GetComponent <Renderer>();
                if (r == null || (!(r is MeshRenderer) && !(r is SkinnedMeshRenderer)))
                {
                    Debug.LogError("GameObject at position " + i + " in list of objects to combine did not have a renderer");
                    return;
                }
                if (r.sharedMaterial == null)
                {
                    Debug.LogError("GameObject at position " + i + " in list of objects to combine has a null material");
                    return;
                }
            }

            //first pass put any meshes with obUVs on their own submesh if not fixing OB uvs
            if (mom.doMultiMaterialSplitAtlasesIfOBUVs)
            {
                for (int i = 0; i < mom.GetObjectsToCombine().Count; i++)
                {
                    GameObject go = mom.GetObjectsToCombine()[i];
                    Mesh       m  = MB_Utility.GetMesh(go);
                    MB_Utility.MeshAnalysisResult dummyMar = new MB_Utility.MeshAnalysisResult();
                    Renderer r = go.GetComponent <Renderer>();
                    for (int j = 0; j < r.sharedMaterials.Length; j++)
                    {
                        if (MB_Utility.hasOutOfBoundsUVs(m, ref dummyMar, j))
                        {
                            if (!obUVobject2mesh_map.ContainsKey(r.sharedMaterials[j]))
                            {
                                Debug.LogWarning("Object " + go + " submesh " + j + " uses UVs outside the range 0,0..1,1 to generate tiling. This object has been mapped to its own submesh in the combined mesh. It can share a submesh with other objects that use different materials if you use the fix out of bounds UVs feature which will bake the tiling");
                                obUVobject2mesh_map.Add(r.sharedMaterials[j], m);
                            }
                        }
                    }
                }
            }

            //second pass  put other materials without OB uvs in a shader to material map
            for (int i = 0; i < mom.GetObjectsToCombine().Count; i++)
            {
                Renderer r = mom.GetObjectsToCombine()[i].GetComponent <Renderer>();
                for (int j = 0; j < r.sharedMaterials.Length; j++)
                {
                    if (!obUVobject2mesh_map.ContainsKey(r.sharedMaterials[j]))
                    { //if not already added
                        if (r.sharedMaterials[j] == null)
                        {
                            continue;
                        }
                        List <List <Material> > binsOfMatsThatUseShader = null;
                        MultiMatSubmeshInfo     newKey = new MultiMatSubmeshInfo(r.sharedMaterials[j].shader, r.sharedMaterials[j]);
                        if (!shader2Material_map.TryGetValue(newKey, out binsOfMatsThatUseShader))
                        {
                            binsOfMatsThatUseShader = new List <List <Material> >();
                            binsOfMatsThatUseShader.Add(new List <Material>());
                            shader2Material_map.Add(newKey, binsOfMatsThatUseShader);
                        }
                        if (!binsOfMatsThatUseShader[0].Contains(r.sharedMaterials[j]))
                        {
                            binsOfMatsThatUseShader[0].Add(r.sharedMaterials[j]);
                        }
                    }
                }
            }

            int numResMats = shader2Material_map.Count;

            //third pass for each shader grouping check how big the atlas would be and group into bins that would fit in an atlas
            if (mom.doMultiMaterialSplitAtlasesIfTooBig)
            {
                if (mom.packingAlgorithm == MB2_PackingAlgorithmEnum.UnitysPackTextures)
                {
                    Debug.LogWarning("Unity texture packer does not support splitting atlases if too big. Atlases will not be split.");
                }
                else
                {
                    numResMats = 0;
                    foreach (MultiMatSubmeshInfo sh in shader2Material_map.Keys)
                    {
                        List <List <Material> > binsOfMatsThatUseShader = shader2Material_map[sh];
                        List <Material>         allMatsThatUserShader   = binsOfMatsThatUseShader[0];//at this point everything is in the same list
                        binsOfMatsThatUseShader.RemoveAt(0);
                        MB3_TextureCombiner combiner = mom.CreateAndConfigureTextureCombiner();
                        combiner.saveAtlasesAsAssets = false;
                        if (allMatsThatUserShader.Count > 1)
                        {
                            combiner.fixOutOfBoundsUVs = mom.fixOutOfBoundsUVs;
                        }
                        else
                        {
                            combiner.fixOutOfBoundsUVs = false;
                        }

                        // Do the texture pack
                        List <AtlasPackingResult> packingResults = new List <AtlasPackingResult>();
                        Material tempMat = new Material(sh.shader);
                        combiner.CombineTexturesIntoAtlases(null, null, tempMat, mom.GetObjectsToCombine(), allMatsThatUserShader, null, packingResults, true, true);
                        for (int i = 0; i < packingResults.Count; i++)
                        {
                            List <MatsAndGOs> matsData = (List <MatsAndGOs>)packingResults[i].data;
                            List <Material>   mats     = new List <Material>();
                            for (int j = 0; j < matsData.Count; j++)
                            {
                                for (int kk = 0; kk < matsData[j].mats.Count; kk++)
                                {
                                    if (!mats.Contains(matsData[j].mats[kk].mat))
                                    {
                                        mats.Add(matsData[j].mats[kk].mat);
                                    }
                                }
                            }
                            binsOfMatsThatUseShader.Add(mats);
                        }
                        numResMats += binsOfMatsThatUseShader.Count;
                    }
                }
            }

            //build the result materials
            if (shader2Material_map.Count == 0 && obUVobject2mesh_map.Count == 0)
            {
                Debug.LogError("Found no materials in list of objects to combine");
            }
            mom.resultMaterials = new MB_MultiMaterial[numResMats + obUVobject2mesh_map.Count];
            string pth        = AssetDatabase.GetAssetPath(mom.textureBakeResults);
            string baseName   = Path.GetFileNameWithoutExtension(pth);
            string folderPath = pth.Substring(0, pth.Length - baseName.Length - 6);
            int    k          = 0;

            foreach (MultiMatSubmeshInfo sh in shader2Material_map.Keys)
            {
                foreach (List <Material> matsThatUse in shader2Material_map[sh])
                {
                    MB_MultiMaterial mm = mom.resultMaterials[k] = new MB_MultiMaterial();
                    mm.sourceMaterials = matsThatUse;
                    if (mm.sourceMaterials.Count == 1)
                    {
                        mm.considerMeshUVs = false;
                    }
                    else
                    {
                        mm.considerMeshUVs = mom.fixOutOfBoundsUVs;
                    }
                    string   matName = folderPath + baseName + "-mat" + k + ".mat";
                    Material newMat  = new Material(Shader.Find("Diffuse"));
                    if (matsThatUse.Count > 0 && matsThatUse[0] != null)
                    {
                        MB3_TextureBaker.ConfigureNewMaterialToMatchOld(newMat, matsThatUse[0]);
                    }
                    AssetDatabase.CreateAsset(newMat, matName);
                    mm.combinedMaterial = (Material)AssetDatabase.LoadAssetAtPath(matName, typeof(Material));
                    k++;
                }
            }
            foreach (Material m in obUVobject2mesh_map.Keys)
            {
                MB_MultiMaterial mm = mom.resultMaterials[k] = new MB_MultiMaterial();
                mm.sourceMaterials = new List <Material>();
                mm.sourceMaterials.Add(m);
                mm.considerMeshUVs = false;
                string   matName = folderPath + baseName + "-mat" + k + ".mat";
                Material newMat  = new Material(Shader.Find("Diffuse"));
                MB3_TextureBaker.ConfigureNewMaterialToMatchOld(newMat, m);
                AssetDatabase.CreateAsset(newMat, matName);
                mm.combinedMaterial = (Material)AssetDatabase.LoadAssetAtPath(matName, typeof(Material));
                k++;
            }
            MBVersionEditor.UpdateIfDirtyOrScript(textureBaker);
        }
コード例 #13
0
        public void DrawGUI(SerializedObject meshBaker, MB3_MeshBakerCommon target, UnityEngine.Object[] targets, System.Type editorWindowType)
        {
            if (meshBaker == null)
            {
                return;
            }

            meshBaker.Update();

            showInstructions = EditorGUILayout.Foldout(showInstructions, "Instructions:");
            if (showInstructions)
            {
                EditorGUILayout.HelpBox("1. Bake combined material(s).\n\n" +
                                        "2. If necessary set the 'Texture Bake Results' field.\n\n" +
                                        "3. Add scene objects or prefabs to combine or check 'Same As Texture Baker'. For best results these should use the same shader as result material.\n\n" +
                                        "4. Select options and 'Bake'.\n\n" +
                                        "6. Look at warnings/errors in console. Decide if action needs to be taken.\n\n" +
                                        "7. (optional) Disable renderers in source objects.", UnityEditor.MessageType.None);

                EditorGUILayout.Separator();
            }

            MB3_MeshBakerCommon momm = (MB3_MeshBakerCommon)target;

            EditorGUILayout.PropertyField(logLevel, gc_logLevelContent);
            EditorGUILayout.PropertyField(textureBakeResults, gc_textureBakeResultsGUIContent);
            bool doingTextureArray = false;

            if (textureBakeResults.objectReferenceValue != null)
            {
                doingTextureArray  = ((MB2_TextureBakeResults)textureBakeResults.objectReferenceValue).resultType == MB2_TextureBakeResults.ResultType.textureArray;
                showContainsReport = EditorGUILayout.Foldout(showContainsReport, "Shaders & Materials Contained");
                if (showContainsReport)
                {
                    EditorGUILayout.HelpBox(((MB2_TextureBakeResults)textureBakeResults.objectReferenceValue).GetDescription(), MessageType.Info);
                }
            }

            EditorGUILayout.BeginVertical(editorStyles.editorBoxBackgroundStyle);
            EditorGUILayout.LabelField("Objects To Be Combined", EditorStyles.boldLabel);
            if (momm.GetTextureBaker() != null)
            {
                EditorGUILayout.PropertyField(useObjsToMeshFromTexBaker, gc_useTextureBakerObjsGUIContent);
            }
            else
            {
                useObjsToMeshFromTexBaker.boolValue = false;
                momm.useObjsToMeshFromTexBaker      = false;
                GUI.enabled = false;
                EditorGUILayout.PropertyField(useObjsToMeshFromTexBaker, gc_useTextureBakerObjsGUIContent);
                GUI.enabled = true;
            }

            if (!momm.useObjsToMeshFromTexBaker)
            {
                if (GUILayout.Button(gc_openToolsWindowLabelContent))
                {
                    MB3_MeshBakerEditorWindow mmWin = (MB3_MeshBakerEditorWindow)EditorWindow.GetWindow(editorWindowType);
                    mmWin.SetTarget((MB3_MeshBakerRoot)momm);
                }

                object[] objs = MB3_EditorMethods.DropZone("Drag & Drop Renderers or Parents\n" + "HERE\n" +
                                                           "to add objects to be combined", 300, 50);
                MB3_EditorMethods.AddDroppedObjects(objs, momm);

                EditorGUILayout.PropertyField(objsToMesh, gc_objectsToCombineGUIContent, true);
                EditorGUILayout.Separator();
                EditorGUILayout.BeginHorizontal();
                if (GUILayout.Button("Select Objects In Scene"))
                {
                    List <MB3_MeshBakerCommon> selectedBakers = _getBakersFromTargets(targets);
                    List <GameObject>          obsToCombine   = new List <GameObject>();

                    foreach (MB3_MeshBakerCommon baker in selectedBakers)
                    {
                        obsToCombine.AddRange(baker.GetObjectsToCombine());
                    }
                    Selection.objects = obsToCombine.ToArray();
                    if (momm.GetObjectsToCombine().Count > 0)
                    {
                        SceneView.lastActiveSceneView.pivot = momm.GetObjectsToCombine()[0].transform.position;
                    }
                }
                if (GUILayout.Button(gc_SortAlongAxis))
                {
                    MB3_MeshBakerRoot.ZSortObjects sorter = new MB3_MeshBakerRoot.ZSortObjects();
                    sorter.sortAxis = sortOrderAxis.vector3Value;
                    sorter.SortByDistanceAlongAxis(momm.GetObjectsToCombine());
                }
                EditorGUILayout.PropertyField(sortOrderAxis, GUIContent.none);
                EditorGUILayout.EndHorizontal();
            }
            else
            {
                GUI.enabled = false;
                EditorGUILayout.PropertyField(objsToMesh, gc_objectsToCombineGUIContent, true);
                GUI.enabled = true;
            }
            EditorGUILayout.EndVertical();

            EditorGUILayout.Space();
            EditorGUILayout.LabelField("Output", EditorStyles.boldLabel);
            EditorGUILayout.PropertyField(outputOptions, gc_outputOptoinsGUIContent);
            if (momm.meshCombiner.outputOption == MB2_OutputOptions.bakeIntoSceneObject)
            {
                Transform pgo = (Transform)EditorGUILayout.ObjectField(gc_parentSceneObject, parentSceneObject.objectReferenceValue, typeof(Transform), true);
                if (pgo != null && MB_Utility.IsSceneInstance(pgo.gameObject))
                {
                    parentSceneObject.objectReferenceValue = pgo;
                }
                else
                {
                    parentSceneObject.objectReferenceValue = null;
                }

                //todo switch to renderer
                momm.meshCombiner.resultSceneObject = (GameObject)EditorGUILayout.ObjectField("Combined Mesh Object", momm.meshCombiner.resultSceneObject, typeof(GameObject), true);
                if (momm is MB3_MeshBaker)
                {
                    string l = "Mesh";
                    Mesh   m = (Mesh)mesh.objectReferenceValue;
                    if (m != null)
                    {
                        l += " (" + m.GetInstanceID() + ")";
                    }
                    Mesh nm = (Mesh)EditorGUILayout.ObjectField(gc_combinedMesh, m, typeof(Mesh), true);
                    if (nm != m)
                    {
                        Undo.RecordObject(momm, "Assign Mesh");
                        ((MB3_MeshCombinerSingle)momm.meshCombiner).SetMesh(nm);
                        mesh.objectReferenceValue = nm;
                    }
                }
            }
            else if (momm.meshCombiner.outputOption == MB2_OutputOptions.bakeIntoPrefab)
            {
                if (momm.meshCombiner.settings.renderType == MB_RenderType.skinnedMeshRenderer)
                {
                    EditorGUILayout.HelpBox("The workflow for baking Skinned Meshes into prefabs has changed as of version 29.1. " +
                                            "It is no longer necessary to manually copy bones to the target prefab after baking. This should happen automatically.", MessageType.Info);
                }

                Transform pgo = (Transform)EditorGUILayout.ObjectField(gc_parentSceneObject, parentSceneObject.objectReferenceValue, typeof(Transform), true);
                if (pgo != null && MB_Utility.IsSceneInstance(pgo.gameObject))
                {
                    parentSceneObject.objectReferenceValue = pgo;
                }
                else
                {
                    parentSceneObject.objectReferenceValue = null;
                }

                EditorGUILayout.BeginHorizontal();
                momm.resultPrefab = (GameObject)EditorGUILayout.ObjectField(gc_combinedMeshPrefabGUIContent, momm.resultPrefab, typeof(GameObject), true);
                if (momm.resultPrefab != null)
                {
                    string assetPath = AssetDatabase.GetAssetPath(momm.resultPrefab);
                    if (assetPath == null || assetPath.Length == 0)
                    {
                        Debug.LogError("The " + gc_combinedMeshPrefabGUIContent.text + " must be a prefab asset, not a scene GameObject");
                        momm.resultPrefab = null;
                    }
                    else
                    {
                        MB_PrefabType pt = MBVersionEditor.PrefabUtility_GetPrefabType(momm.resultPrefab);
                        if (pt != MB_PrefabType.prefabAsset)
                        {
                            Debug.LogError("The " + gc_combinedMeshPrefabGUIContent.text + " must be a prefab asset, the prefab type was '" + pt + "'");
                            momm.resultPrefab = null;
                        }
                    }
                }
                else
                {
                    if (GUILayout.Button("Create Empty Prefab"))
                    {
                        if (!Application.isPlaying)
                        {
                            string path          = EditorUtility.SaveFilePanelInProject("Create Empty Prefab", "MyPrefab", "prefab", "Create a prefab containing an empty GameObject");
                            string pathNoFolder  = Path.GetDirectoryName(path);
                            string fileNameNoExt = Path.GetFileNameWithoutExtension(path);
                            List <MB3_MeshBakerCommon> selectedBakers = _getBakersFromTargets(targets);
                            if (selectedBakers.Count > 1)
                            {
                                Debug.Log("About to create prefabs for " + selectedBakers.Count);
                            }
                            int idx = 0;
                            foreach (MB3_MeshBakerCommon baker in selectedBakers)
                            {
                                createEmptyPrefab(baker, pathNoFolder, fileNameNoExt, idx);
                                idx++;
                            }
                        }
                    }
                }
                EditorGUILayout.EndHorizontal();

                EditorGUILayout.PropertyField(resultPrefabLeaveInstanceInSceneAfterBake, gc_resultPrefabLeaveInstanceInSceneAfterBake);
                if (momm is MB3_MeshBaker)
                {
                    string l = "Mesh";
                    Mesh   m = (Mesh)mesh.objectReferenceValue;
                    if (m != null)
                    {
                        l += " (" + m.GetInstanceID() + ")";
                    }
                    Mesh nm = (Mesh)EditorGUILayout.ObjectField(gc_combinedMesh, m, typeof(Mesh), true);
                    if (nm != m)
                    {
                        Undo.RecordObject(momm, "Assign Mesh");
                        ((MB3_MeshCombinerSingle)momm.meshCombiner).SetMesh(nm);
                        mesh.objectReferenceValue = nm;
                    }
                }
            }
            else if (momm.meshCombiner.outputOption == MB2_OutputOptions.bakeMeshAssetsInPlace)
            {
                EditorGUILayout.HelpBox("Try the BatchPrefabBaker component! It makes preparing a batch of prefabs for static/ dynamic batching much easier.", MessageType.Info);
                if (GUILayout.Button("Choose Folder For Bake In Place Meshes"))
                {
                    string newFolder = EditorUtility.SaveFolderPanel("Folder For Bake In Place Meshes", Application.dataPath, "");
                    if (!newFolder.Contains(Application.dataPath))
                    {
                        Debug.LogWarning("The chosen folder must be in your assets folder.");
                    }
                    string folder = "Assets" + newFolder.Replace(Application.dataPath, "");
                    List <MB3_MeshBakerCommon> selectedBakers = _getBakersFromTargets(targets);
                    Undo.RecordObjects(targets, "Undo Set Folder");
                    foreach (MB3_MeshBakerCommon baker in selectedBakers)
                    {
                        baker.bakeAssetsInPlaceFolderPath = folder;
                        EditorUtility.SetDirty(baker);
                    }
                }

                EditorGUILayout.LabelField("Folder For Meshes: " + momm.bakeAssetsInPlaceFolderPath);
            }

            if (momm is MB3_MultiMeshBaker)
            {
                MB3_MultiMeshCombiner mmc = (MB3_MultiMeshCombiner)momm.meshCombiner;
                mmc.maxVertsInMesh = EditorGUILayout.IntField("Max Verts In Mesh", mmc.maxVertsInMesh);
            }

            //-----------------------------------
            EditorGUILayout.Space();
            EditorGUILayout.LabelField("Settings", EditorStyles.boldLabel);
            bool settingsEnabled = true;

            //------------- Mesh Baker Settings is a bit tricky because it is an interface.



            EditorGUILayout.Space();
            UnityEngine.Object obj = settingsHolder.objectReferenceValue;

            // Don't use a PropertyField because we may not be able to use the assigned object. It may not implement requried interface.
            obj = EditorGUILayout.ObjectField(gc_Settings, obj, typeof(UnityEngine.Object), true);

            if (obj == null)
            {
                settingsEnabled = true;
                settingsHolder.objectReferenceValue = null;
                if (meshBakerSettingsExternal != null)
                {
                    meshBakerSettingsExternal.OnDisable();
                    meshBakerSettingsExternal = null;
                }
            }

            else if (obj is GameObject)
            {
                // Check to see if there is a component on this game object that implements MB_IMeshBakerSettingsHolder
                MB_IMeshBakerSettingsHolder itf = (MB_IMeshBakerSettingsHolder)((GameObject)obj).GetComponent(typeof(MB_IMeshBakerSettingsHolder));
                if (itf != null)
                {
                    settingsEnabled = false;
                    Component settingsHolderComponent = (Component)itf;
                    if (settingsHolder.objectReferenceValue != settingsHolderComponent)
                    {
                        settingsHolder.objectReferenceValue = settingsHolderComponent;
                        meshBakerSettingsExternal           = new MB_MeshBakerSettingsEditor();
                        UnityEngine.Object targetObj;
                        string             propertyName;
                        itf.GetMeshBakerSettingsAsSerializedProperty(out propertyName, out targetObj);
                        SerializedProperty meshBakerSettings = new SerializedObject(targetObj).FindProperty(propertyName);
                        meshBakerSettingsExternal.OnEnable(meshBakerSettings);
                    }
                }
                else
                {
                    settingsEnabled = true;
                    settingsHolder  = null;
                    if (meshBakerSettingsExternal != null)
                    {
                        meshBakerSettingsExternal.OnDisable();
                        meshBakerSettingsExternal = null;
                    }
                }
            }
            else if (obj is MB_IMeshBakerSettingsHolder)
            {
                settingsEnabled = false;
                if (settingsHolder.objectReferenceValue != obj)
                {
                    settingsHolder.objectReferenceValue = obj;
                    meshBakerSettingsExternal           = new MB_MeshBakerSettingsEditor();
                    UnityEngine.Object targetObj;
                    string             propertyName;
                    ((MB_IMeshBakerSettingsHolder)obj).GetMeshBakerSettingsAsSerializedProperty(out propertyName, out targetObj);
                    SerializedProperty meshBakerSettings = new SerializedObject(targetObj).FindProperty(propertyName);
                    meshBakerSettingsExternal.OnEnable(meshBakerSettings);
                }
            }
            else
            {
                Debug.LogError("Object was not a Mesh Baker Settings object.");
            }
            EditorGUILayout.Space();

            if (settingsHolder.objectReferenceValue == null)
            {
                // Use the meshCombiner settings
                meshBakerSettingsThis.DrawGUI(momm.meshCombiner, settingsEnabled, doingTextureArray);
            }
            else
            {
                if (meshBakerSettingsExternal == null)
                {
                    meshBakerSettingsExternal = new MB_MeshBakerSettingsEditor();
                    UnityEngine.Object targetObj;
                    string             propertyName;
                    ((MB_IMeshBakerSettingsHolder)obj).GetMeshBakerSettingsAsSerializedProperty(out propertyName, out targetObj);
                    SerializedProperty meshBakerSettings = new SerializedObject(targetObj).FindProperty(propertyName);
                    meshBakerSettingsExternal.OnEnable(meshBakerSettings);
                }
                meshBakerSettingsExternal.DrawGUI(((MB_IMeshBakerSettingsHolder)settingsHolder.objectReferenceValue).GetMeshBakerSettings(), settingsEnabled, doingTextureArray);
            }

            Color oldColor = GUI.backgroundColor;

            GUI.backgroundColor = buttonColor;
            if (GUILayout.Button("Bake"))
            {
                List <MB3_MeshBakerCommon> selectedBakers = _getBakersFromTargets(targets);
                if (selectedBakers.Count > 1)
                {
                    Debug.Log("About to bake " + selectedBakers.Count);
                }
                foreach (MB3_MeshBakerCommon baker in selectedBakers)
                {
                    // Why are we caching and recreating the SerializedObject? Because "bakeIntoPrefab" corrupts the serialized object
                    // and the meshBaker SerializedObject throws an NRE the next time it gets used.
                    MB3_MeshBakerCommon mbr = (MB3_MeshBakerCommon)meshBaker.targetObject;
                    bake(baker);
                    meshBaker = new SerializedObject(mbr);
                }
            }
            GUI.backgroundColor = oldColor;

            string enableRenderersLabel;
            bool   disableRendererInSource = false;

            if (momm.GetObjectsToCombine().Count > 0)
            {
                Renderer r = MB_Utility.GetRenderer(momm.GetObjectsToCombine()[0]);
                if (r != null && r.enabled)
                {
                    disableRendererInSource = true;
                }
            }
            if (disableRendererInSource)
            {
                enableRenderersLabel = "Disable Renderers On Source Objects";
            }
            else
            {
                enableRenderersLabel = "Enable Renderers On Source Objects";
            }
            if (GUILayout.Button(enableRenderersLabel))
            {
                List <MB3_MeshBakerCommon> selectedBakers = _getBakersFromTargets(targets);
                foreach (MB3_MeshBakerCommon baker in selectedBakers)
                {
                    baker.EnableDisableSourceObjectRenderers(!disableRendererInSource);
                }
            }

            meshBaker.ApplyModifiedProperties();
            meshBaker.SetIsDifferentCacheDirty();
        }
コード例 #14
0
    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();
    }
コード例 #15
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();
        }
コード例 #16
0
    public static bool BakeIntoCombined(MB3_MeshBakerCommon mom, out bool createdDummyTextureBakeResults)
    {
        MB2_OutputOptions prefabOrSceneObject = mom.meshCombiner.outputOption;

        createdDummyTextureBakeResults = false;
        if (MB3_MeshCombiner.EVAL_VERSION && prefabOrSceneObject == MB2_OutputOptions.bakeIntoPrefab)
        {
            Debug.LogError("Cannot BakeIntoPrefab with evaluation version.");
            return(false);
        }
        if (prefabOrSceneObject != MB2_OutputOptions.bakeIntoPrefab && prefabOrSceneObject != MB2_OutputOptions.bakeIntoSceneObject)
        {
            Debug.LogError("Paramater prefabOrSceneObject must be bakeIntoPrefab or bakeIntoSceneObject");
            return(false);
        }

        MB3_TextureBaker tb = mom.GetComponentInParent <MB3_TextureBaker>();

        if (mom.textureBakeResults == null && tb != null)
        {
            mom.textureBakeResults = tb.textureBakeResults;
        }
        if (mom.textureBakeResults == null)
        {
            if (_OkToCreateDummyTextureBakeResult(mom))
            {
                createdDummyTextureBakeResults = true;
                List <GameObject> gos = mom.GetObjectsToCombine();
                if (mom.GetNumObjectsInCombined() > 0)
                {
                    if (mom.clearBuffersAfterBake)
                    {
                        mom.ClearMesh();
                    }
                    else
                    {
                        Debug.LogError("'Texture Bake Result' must be set to add more objects to a combined mesh that already contains objects. Try enabling 'clear buffers after bake'");
                        return(false);
                    }
                }
                mom.textureBakeResults = MB2_TextureBakeResults.CreateForMaterialsOnRenderer(gos.ToArray(), mom.meshCombiner.GetMaterialsOnTargetRenderer());
                if (mom.meshCombiner.LOG_LEVEL >= MB2_LogLevel.debug)
                {
                    Debug.Log("'Texture Bake Result' was not set. Creating a temporary one. Each material will be mapped to a separate submesh.");
                }
            }
        }
        MB2_ValidationLevel vl = Application.isPlaying ? MB2_ValidationLevel.quick : MB2_ValidationLevel.robust;

        if (!MB3_MeshBakerRoot.DoCombinedValidate(mom, MB_ObjsToCombineTypes.sceneObjOnly, new MB3_EditorMethods(), vl))
        {
            return(false);
        }
        if (prefabOrSceneObject == MB2_OutputOptions.bakeIntoPrefab &&
            mom.resultPrefab == null)
        {
            Debug.LogError("Need to set the Combined Mesh Prefab field. Create a prefab asset, drag an empty game object into it, and drag it to the 'Combined Mesh Prefab' field.");
            return(false);
        }
        if (mom.meshCombiner.resultSceneObject != null &&
            (MBVersionEditor.GetPrefabType(mom.meshCombiner.resultSceneObject) == MB_PrefabType.modelPrefab ||
             MBVersionEditor.GetPrefabType(mom.meshCombiner.resultSceneObject) == MB_PrefabType.prefab))
        {
            Debug.LogWarning("Result Game Object was a project asset not a scene object instance. Clearing this field.");
            mom.meshCombiner.resultSceneObject = null;
        }

        mom.ClearMesh();
        if (mom.AddDeleteGameObjects(mom.GetObjectsToCombine().ToArray(), null, false))
        {
            mom.Apply(UnwrapUV2);
            if (createdDummyTextureBakeResults)
            {
                Debug.Log(String.Format("Successfully baked {0} meshes each material is mapped to its own submesh.", mom.GetObjectsToCombine().Count));
            }
            else
            {
                Debug.Log(String.Format("Successfully baked {0} meshes", mom.GetObjectsToCombine().Count));
            }


            if (prefabOrSceneObject == MB2_OutputOptions.bakeIntoSceneObject)
            {
                MB_PrefabType pt = MBVersionEditor.GetPrefabType(mom.meshCombiner.resultSceneObject);
                if (pt == MB_PrefabType.prefab || pt == MB_PrefabType.modelPrefab)
                {
                    Debug.LogError("Combined Mesh Object is a prefab asset. If output option bakeIntoSceneObject then this must be an instance in the scene.");
                    return(false);
                }
            }
            else if (prefabOrSceneObject == MB2_OutputOptions.bakeIntoPrefab)
            {
                string prefabPth = AssetDatabase.GetAssetPath(mom.resultPrefab);
                if (prefabPth == null || prefabPth.Length == 0)
                {
                    Debug.LogError("Could not save result to prefab. Result Prefab value is not an Asset.");
                    return(false);
                }
                string baseName    = Path.GetFileNameWithoutExtension(prefabPth);
                string folderPath  = prefabPth.Substring(0, prefabPth.Length - baseName.Length - 7);
                string newFilename = folderPath + baseName + "-mesh";
                SaveMeshsToAssetDatabase(mom, folderPath, newFilename);


                if (mom.meshCombiner.renderType == MB_RenderType.skinnedMeshRenderer)
                {
                    Debug.LogWarning("Render type is skinned mesh renderer. " +
                                     "Can't create prefab until all bones have been added to the combined mesh object " + mom.resultPrefab +
                                     " Add the bones then drag the combined mesh object to the prefab.");
                }
                RebuildPrefab(mom);

                MB_Utility.Destroy(mom.meshCombiner.resultSceneObject);
            }
            else
            {
                Debug.LogError("Unknown parameter");
                return(false);
            }
        }
        else
        {
            if (mom.clearBuffersAfterBake)
            {
                mom.meshCombiner.ClearBuffers();
            }
            if (createdDummyTextureBakeResults)
            {
                MB_Utility.Destroy(mom.textureBakeResults);
            }
            return(false);
        }
        if (mom.clearBuffersAfterBake)
        {
            mom.meshCombiner.ClearBuffers();
        }
        if (createdDummyTextureBakeResults)
        {
            MB_Utility.Destroy(mom.textureBakeResults);
        }
        return(true);
    }
コード例 #17
0
        public static void ConfigureTextureArraysFromObjsToCombine(MB3_TextureBaker mom, SerializedProperty resultMaterialsTexArrays, SerializedObject textureBaker)
        {
            if (mom.GetObjectsToCombine().Count == 0)
            {
                Debug.LogError("You need to add some objects to combine before building the texture array result materials.");
                return;
            }
            if (resultMaterialsTexArrays.arraySize > 0)
            {
                Debug.LogError("You already have some texture array result materials configured. You must remove these before doing this operation.");
                return;
            }
            if (mom.textureBakeResults == null)
            {
                Debug.LogError("Texture Bake Result asset must be set before using this operation.");
                return;
            }

            //validate that the objects to be combined are valid
            for (int i = 0; i < mom.GetObjectsToCombine().Count; i++)
            {
                GameObject go = mom.GetObjectsToCombine()[i];
                if (go == null)
                {
                    Debug.LogError("Null object in list of objects to combine at position " + i);
                    return;
                }

                if (MB_Utility.GetMesh(go) == null)
                {
                    Debug.LogError("Could not get mesh for object in list of objects to combine at position " + i);
                    return;
                }

                Renderer r = go.GetComponent <Renderer>();
                if (r == null || (!(r is MeshRenderer) && !(r is SkinnedMeshRenderer)))
                {
                    Debug.LogError("GameObject at position " + i + " in list of objects to combine did not have a renderer");
                    return;
                }
                if (r.sharedMaterial == null)
                {
                    Debug.LogError("GameObject at position " + i + " in list of objects to combine has a null material");
                    return;
                }
            }

            //Will sort into "result material"
            //  slices
            Dictionary <MB3_TextureBakerEditorInternal.MultiMatSubmeshInfo, List <Slice> > shader2ResultMat_map = new Dictionary <MB3_TextureBakerEditorInternal.MultiMatSubmeshInfo, List <Slice> >();

            // first pass split by shader and analyse meshes.
            List <GameObject> objsToCombine = mom.GetObjectsToCombine();

            for (int meshIdx = 0; meshIdx < objsToCombine.Count; meshIdx++)
            {
                GameObject srcGo = objsToCombine[meshIdx];
                Mesh       mesh  = MB_Utility.GetMesh(srcGo);
                Renderer   r     = MB_Utility.GetRenderer(srcGo);

                if (mom.LOG_LEVEL >= MB2_LogLevel.trace)
                {
                    Debug.Log("1st Pass 'Split By Shader' Processing Mesh: " + mesh + " Num submeshes: " + r.sharedMaterials.Length);
                }
                for (int submeshIdx = 0; submeshIdx < r.sharedMaterials.Length; submeshIdx++)
                {
                    if (r.sharedMaterials[submeshIdx] == null)
                    {
                        continue;
                    }

                    MB3_TextureBakerEditorInternal.MultiMatSubmeshInfo newKey = new MB3_TextureBakerEditorInternal.MultiMatSubmeshInfo(r.sharedMaterials[submeshIdx].shader, r.sharedMaterials[submeshIdx]);
                    // Initially we fill the list of srcMaterials with garbage MB_MaterialAndUVRects. Will get proper ones when we atlas pack.
                    MB_MaterialAndUVRect submeshMaterial = new MB_MaterialAndUVRect(
                        r.sharedMaterials[submeshIdx],
                        new Rect(0, 0, 0, 0),              // garbage value
                        false,                             //garbage value
                        new Rect(0, 0, 0, 0),              // garbage value
                        new Rect(0, 0, 0, 0),              // garbage value
                        new Rect(0, 0, 1, 1),              // garbage value
                        MB_TextureTilingTreatment.unknown, // garbage value
                        r.name);
                    submeshMaterial.objectsThatUse = new List <GameObject>();
                    submeshMaterial.objectsThatUse.Add(r.gameObject);
                    if (!shader2ResultMat_map.ContainsKey(newKey))
                    {
                        // this is a new shader create a new result material
                        Slice srcMaterials = new Slice
                        {
                            atlasRects    = new List <MB_MaterialAndUVRect>(),
                            numAtlasRects = 1,
                        };
                        srcMaterials.atlasRects.Add(submeshMaterial);
                        List <Slice> binsOfMatsThatUseShader = new List <Slice>();
                        binsOfMatsThatUseShader.Add(srcMaterials);
                        if (mom.LOG_LEVEL >= MB2_LogLevel.trace)
                        {
                            Debug.Log("  Adding Source Material: " + submeshMaterial.material);
                        }
                        shader2ResultMat_map.Add(newKey, binsOfMatsThatUseShader);
                    }
                    else
                    {
                        // there is a result material that uses this shader. Add this source material
                        Slice srcMaterials = shader2ResultMat_map[newKey][0]; // There should only be one list of source materials
                        if (srcMaterials.atlasRects.Find(x => x.material == submeshMaterial.material) == null)
                        {
                            if (mom.LOG_LEVEL >= MB2_LogLevel.trace)
                            {
                                Debug.Log("  Adding Source Material: " + submeshMaterial.material);
                            }
                            srcMaterials.atlasRects.Add(submeshMaterial);
                        }
                    }
                }
            }

            int resMatCount = 0;

            foreach (MB3_TextureBakerEditorInternal.MultiMatSubmeshInfo resultMat in shader2ResultMat_map.Keys)
            {
                // at this point there there should be only one slice with all the source materials
                resMatCount++;

                // For each result material, all source materials are in the first slice.
                // We will now split these using a texture packer. Each "atlas" generated by the packer will be a slice.
                {
                    // All source materials should be in the first slice at this point.
                    List <Slice>      slices                = shader2ResultMat_map[resultMat];
                    List <Slice>      newSlices             = new List <Slice>();
                    Slice             firstSlice            = slices[0];
                    List <Material>   allMatsThatUserShader = new List <Material>();
                    List <GameObject> objsThatUseFirstSlice = new List <GameObject>();
                    for (int i = 0; i < firstSlice.atlasRects.Count; i++)
                    {
                        allMatsThatUserShader.Add(firstSlice.atlasRects[i].material);
                        if (!objsThatUseFirstSlice.Contains(firstSlice.atlasRects[i].objectsThatUse[0]))
                        {
                            objsThatUseFirstSlice.Add(firstSlice.atlasRects[i].objectsThatUse[0]);
                        }
                    }

                    MB3_TextureCombiner combiner = mom.CreateAndConfigureTextureCombiner();
                    combiner.packingAlgorithm    = MB2_PackingAlgorithmEnum.MeshBakerTexturePacker;
                    combiner.saveAtlasesAsAssets = false;
                    combiner.fixOutOfBoundsUVs   = true;
                    combiner.doMergeDistinctMaterialTexturesThatWouldExceedAtlasSize = true;
                    List <AtlasPackingResult> packingResults = new List <AtlasPackingResult>();
                    Material tempMat = new Material(resultMat.shader);

                    if (mom.LOG_LEVEL >= MB2_LogLevel.debug)
                    {
                        Debug.Log("======== 2nd pass. Use atlas packer to split the first slice into multiple if it exceeds atlas size. ");
                    }
                    combiner.CombineTexturesIntoAtlases(null, null, tempMat, mom.GetObjectsToCombine(), allMatsThatUserShader, null, packingResults,
                                                        onlyPackRects: true, splitAtlasWhenPackingIfTooBig: true);
                    if (mom.LOG_LEVEL >= MB2_LogLevel.debug)
                    {
                        Debug.Log("======== Completed packing with texture packer. numPackingResults: " + packingResults.Count);
                    }
                    newSlices.Clear();

                    // The texture packing just split the atlas into multiple atlases. Each atlas will become a "slice".
                    for (int newSliceIdx = 0; newSliceIdx < packingResults.Count; newSliceIdx++)
                    {
                        List <MB_MaterialAndUVRect> sourceMats     = new List <MB_MaterialAndUVRect>();
                        List <MB_MaterialAndUVRect> packedMatRects = (List <MB_MaterialAndUVRect>)packingResults[newSliceIdx].data;
                        HashSet <Rect> distinctAtlasRects          = new HashSet <Rect>();
                        for (int packedMatRectIdx = 0; packedMatRectIdx < packedMatRects.Count; packedMatRectIdx++)
                        {
                            MB_MaterialAndUVRect muvr = packedMatRects[packedMatRectIdx];
                            distinctAtlasRects.Add(muvr.atlasRect);
                            {
                                Rect    encapsulatingRect = muvr.GetEncapsulatingRect();
                                Vector2 sizeInAtlas_px    = new Vector2(
                                    packingResults[newSliceIdx].atlasX * encapsulatingRect.width,
                                    packingResults[newSliceIdx].atlasY * encapsulatingRect.height);
                            }
                            sourceMats.Add(muvr);
                        }

                        Slice slice = new Slice()
                        {
                            atlasRects    = sourceMats,
                            packingResult = packingResults[newSliceIdx],
                            numAtlasRects = distinctAtlasRects.Count,
                        };

                        newSlices.Add(slice);
                    }

                    // Replace first slice with split version.
                    if (mom.LOG_LEVEL >= MB2_LogLevel.debug)
                    {
                        Debug.Log("First slice exceeded atlas size splitting it into " + newSlices.Count + " slices");
                    }
                    slices.RemoveAt(0);
                    for (int i = 0; i < newSlices.Count; i++)
                    {
                        slices.Insert(i, newSlices[i]);
                    }
                }
            }

            // build the texture array result materials
            if (shader2ResultMat_map.Count == 0)
            {
                Debug.LogError("Found no materials in list of objects to combine");
            }
            mom.resultMaterialsTexArray = new MB_MultiMaterialTexArray[shader2ResultMat_map.Count];
            int k = 0;

            foreach (MB3_TextureBakerEditorInternal.MultiMatSubmeshInfo resMatKey in shader2ResultMat_map.Keys)
            {
                List <Slice>             srcSlices = shader2ResultMat_map[resMatKey];
                MB_MultiMaterialTexArray mm        = mom.resultMaterialsTexArray[k] = new MB_MultiMaterialTexArray();
                for (int sliceIdx = 0; sliceIdx < srcSlices.Count; sliceIdx++)
                {
                    Slice            slice    = srcSlices[sliceIdx];
                    MB_TexArraySlice resSlice = new MB_TexArraySlice();
                    List <Material>  usedMats = new List <Material>();

                    for (int srcMatIdx = 0; srcMatIdx < slice.atlasRects.Count; srcMatIdx++)
                    {
                        MB_MaterialAndUVRect matAndUVRect = slice.atlasRects[srcMatIdx];
                        List <GameObject>    objsThatUse  = matAndUVRect.objectsThatUse;
                        for (int objsThatUseIdx = 0; objsThatUseIdx < objsThatUse.Count; objsThatUseIdx++)
                        {
                            GameObject obj = objsThatUse[objsThatUseIdx];
                            if (!resSlice.ContainsMaterialAndMesh(slice.atlasRects[srcMatIdx].material, MB_Utility.GetMesh(obj)))
                            {
                                resSlice.sourceMaterials.Add(
                                    new MB_TexArraySliceRendererMatPair()
                                {
                                    renderer       = obj,
                                    sourceMaterial = slice.atlasRects[srcMatIdx].material
                                }
                                    );
                            }
                        }
                    }

                    {
                        // Should we use considerUVs
                        bool doConsiderUVs = false;
                        //     If there is more than one atlas rectangle in a slice then use considerUVs
                        if (slice.numAtlasRects > 1)
                        {
                            doConsiderUVs = true;
                        }
                        else
                        {
                            //     There is only one source material, could be:
                            //          - lots of tiling (don't want consider UVs)
                            //          - We are extracting a small part of a large atlas (want considerUVs)
                            if (slice.packingResult.atlasX >= mom.maxAtlasSize ||
                                slice.packingResult.atlasY >= mom.maxAtlasSize)
                            {
                                doConsiderUVs = false; // lots of tiling
                            }
                            else
                            {
                                doConsiderUVs = true; // extracting a small part of an atlas
                            }
                        }

                        resSlice.considerMeshUVs = doConsiderUVs;
                    }

                    mm.slices.Add(resSlice);
                }

                // Enforce integrity. If a material appears in more than one slice then all those slices must be considerUVs=true
                {
                    // collect all distinct materials
                    HashSet <Material>         distinctMats   = new HashSet <Material>();
                    Dictionary <Material, int> mat2sliceCount = new Dictionary <Material, int>();
                    for (int sliceIdx = 0; sliceIdx < mm.slices.Count; sliceIdx++)
                    {
                        for (int sliceMatIdx = 0; sliceMatIdx < mm.slices[sliceIdx].sourceMaterials.Count; sliceMatIdx++)
                        {
                            Material mat = mm.slices[sliceIdx].sourceMaterials[sliceMatIdx].sourceMaterial;
                            distinctMats.Add(mat);
                            mat2sliceCount[mat] = 0;
                        }
                    }

                    // Count the number of slices that use each material.
                    foreach (Material mat in distinctMats)
                    {
                        for (int sliceIdx = 0; sliceIdx < mm.slices.Count; sliceIdx++)
                        {
                            if (mm.slices[sliceIdx].ContainsMaterial(mat))
                            {
                                mat2sliceCount[mat] = mat2sliceCount[mat] + 1;
                            }
                        }
                    }

                    // Check that considerUVs is true for any materials that appear more than once
                    foreach (Material mat in distinctMats)
                    {
                        if (mat2sliceCount[mat] > 1)
                        {
                            for (int sliceIdx = 0; sliceIdx < mm.slices.Count; sliceIdx++)
                            {
                                if (mm.slices[sliceIdx].ContainsMaterial(mat))
                                {
                                    if (mom.LOG_LEVEL >= MB2_LogLevel.debug &&
                                        mm.slices[sliceIdx].considerMeshUVs)
                                    {
                                        Debug.Log("There was a material " + mat + " that was used by more than one slice and considerUVs was false. sliceIdx:" + sliceIdx);
                                    }
                                    mm.slices[sliceIdx].considerMeshUVs = true;
                                }
                            }
                        }
                    }
                }

                // Cleanup. remove "Renderer"s from source materials that do not use considerUVs and delete extra
                {
                    // put any slices with consider UVs first
                    List <MB_TexArraySlice> newSlices = new List <MB_TexArraySlice>();
                    for (int sliceIdx = 0; sliceIdx < mm.slices.Count; sliceIdx++)
                    {
                        if (mm.slices[sliceIdx].considerMeshUVs == true)
                        {
                            newSlices.Add(mm.slices[sliceIdx]);
                        }
                    }

                    // for any slices without considerUVs, remove "renderer" and truncate
                    for (int sliceIdx = 0; sliceIdx < mm.slices.Count; sliceIdx++)
                    {
                        MB_TexArraySlice slice = mm.slices[sliceIdx];
                        if (slice.considerMeshUVs == false)
                        {
                            newSlices.Add(slice);
                            HashSet <Material> distinctMats = slice.GetDistinctMaterials();
                            slice.sourceMaterials.Clear();
                            foreach (Material mat in distinctMats)
                            {
                                slice.sourceMaterials.Add(new MB_TexArraySliceRendererMatPair()
                                {
                                    sourceMaterial = mat
                                });
                            }
                        }
                    }

                    mm.slices = newSlices;
                }

                string   pth           = AssetDatabase.GetAssetPath(mom.textureBakeResults);
                string   baseName      = Path.GetFileNameWithoutExtension(pth);
                string   folderPath    = pth.Substring(0, pth.Length - baseName.Length - 6);
                string   matName       = folderPath + baseName + "-mat" + k + ".mat";
                Material existingAsset = AssetDatabase.LoadAssetAtPath <Material>(matName);
                if (!existingAsset)
                {
                    Material newMat = new Material(Shader.Find("Standard"));
                    // Don't try to configure the material we need the user to pick a shader that has TextureArrays
                    AssetDatabase.CreateAsset(newMat, matName);
                }

                mm.combinedMaterial = (Material)AssetDatabase.LoadAssetAtPath(matName, typeof(Material));
                k++;
            }


            MBVersionEditor.UpdateIfDirtyOrScript(textureBaker);
            textureBaker.Update();
        }
コード例 #18
0
        /* tried to see if the MultiMaterialConfig could be done using the GroupBy filters. Saddly it didn't work */
        public static void ConfigureMutiMaterialsFromObjsToCombine2(MB3_TextureBaker mom, SerializedProperty resultMaterials, SerializedObject textureBaker)
        {
            if (mom.GetObjectsToCombine().Count == 0)
            {
                Debug.LogError("You need to add some objects to combine before building the multi material list.");
                return;
            }
            if (resultMaterials.arraySize > 0)
            {
                Debug.LogError("You already have some source to combined material mappings configured. You must remove these before doing this operation.");
                return;
            }
            if (mom.textureBakeResults == null)
            {
                Debug.LogError("Texture Bake Result asset must be set before using this operation.");
                return;
            }

            //validate that the objects to be combined are valid
            for (int i = 0; i < mom.GetObjectsToCombine().Count; i++)
            {
                GameObject go = mom.GetObjectsToCombine()[i];
                if (go == null)
                {
                    Debug.LogError("Null object in list of objects to combine at position " + i);
                    return;
                }
                Renderer r = go.GetComponent <Renderer>();
                if (r == null || (!(r is MeshRenderer) && !(r is SkinnedMeshRenderer)))
                {
                    Debug.LogError("GameObject at position " + i + " in list of objects to combine did not have a renderer");
                    return;
                }
                if (r.sharedMaterial == null)
                {
                    Debug.LogError("GameObject at position " + i + " in list of objects to combine has a null material");
                    return;
                }
            }

            IGroupByFilter[] filters = new IGroupByFilter[3];
            filters[0] = new GroupByOutOfBoundsUVs();
            filters[1] = new GroupByShader();
            filters[2] = new MB3_GroupByStandardShaderType();

            List <GameObjectFilterInfo> gameObjects = new List <GameObjectFilterInfo>();
            HashSet <GameObject>        objectsAlreadyIncludedInBakers = new HashSet <GameObject>();

            for (int i = 0; i < mom.GetObjectsToCombine().Count; i++)
            {
                GameObjectFilterInfo goaw = new GameObjectFilterInfo(mom.GetObjectsToCombine()[i], objectsAlreadyIncludedInBakers, filters);
                if (goaw.materials.Length > 0) //don't consider renderers with no materials
                {
                    gameObjects.Add(goaw);
                }
            }

            //analyse meshes
            Dictionary <int, MB_Utility.MeshAnalysisResult> meshAnalysisResultCache = new Dictionary <int, MB_Utility.MeshAnalysisResult>();
            int totalVerts = 0;

            for (int i = 0; i < gameObjects.Count; i++)
            {
                //string rpt = String.Format("Processing {0} [{1} of {2}]", gameObjects[i].go.name, i, gameObjects.Count);
                //EditorUtility.DisplayProgressBar("Analysing Scene", rpt + " A", .6f);
                Mesh mm     = MB_Utility.GetMesh(gameObjects[i].go);
                int  nVerts = 0;
                if (mm != null)
                {
                    nVerts += mm.vertexCount;
                    MB_Utility.MeshAnalysisResult mar;
                    if (!meshAnalysisResultCache.TryGetValue(mm.GetInstanceID(), out mar))
                    {
                        //EditorUtility.DisplayProgressBar("Analysing Scene", rpt + " Check Out Of Bounds UVs", .6f);
                        MB_Utility.hasOutOfBoundsUVs(mm, ref mar);
                        //Rect dummy = mar.uvRect;
                        MB_Utility.doSubmeshesShareVertsOrTris(mm, ref mar);
                        meshAnalysisResultCache.Add(mm.GetInstanceID(), mar);
                    }
                    if (mar.hasOutOfBoundsUVs)
                    {
                        int w = (int)mar.uvRect.width;
                        int h = (int)mar.uvRect.height;
                        gameObjects[i].outOfBoundsUVs = true;
                        gameObjects[i].warning       += " [WARNING: has uvs outside the range (0,1) tex is tiled " + w + "x" + h + " times]";
                    }
                    if (mar.hasOverlappingSubmeshVerts)
                    {
                        gameObjects[i].submeshesOverlap = true;
                        gameObjects[i].warning         += " [WARNING: Submeshes share verts or triangles. 'Multiple Combined Materials' feature may not work.]";
                    }
                }
                totalVerts += nVerts;
                //EditorUtility.DisplayProgressBar("Analysing Scene", rpt + " Validate OBuvs Multi Material", .6f);
                Renderer mr = gameObjects[i].go.GetComponent <Renderer>();
                if (!MB_Utility.AreAllSharedMaterialsDistinct(mr.sharedMaterials))
                {
                    gameObjects[i].warning += " [WARNING: Object uses same material on multiple submeshes. This may produce poor results when used with multiple materials or fix out of bounds uvs.]";
                }
            }

            List <GameObjectFilterInfo> objsNotAddedToBaker = new List <GameObjectFilterInfo>();

            Dictionary <GameObjectFilterInfo, List <List <GameObjectFilterInfo> > > gs2bakeGroupMap = MB3_MeshBakerEditorWindow.sortIntoBakeGroups3(gameObjects, objsNotAddedToBaker, filters, false, mom.maxAtlasSize);

            mom.resultMaterials = new MB_MultiMaterial[gs2bakeGroupMap.Keys.Count];
            string pth        = AssetDatabase.GetAssetPath(mom.textureBakeResults);
            string baseName   = Path.GetFileNameWithoutExtension(pth);
            string folderPath = pth.Substring(0, pth.Length - baseName.Length - 6);
            int    k          = 0;

            foreach (GameObjectFilterInfo m in gs2bakeGroupMap.Keys)
            {
                MB_MultiMaterial mm = mom.resultMaterials[k] = new MB_MultiMaterial();
                mm.sourceMaterials = new List <Material>();
                mm.sourceMaterials.Add(m.materials[0]);
                string   matName = folderPath + baseName + "-mat" + k + ".mat";
                Material newMat  = new Material(Shader.Find("Diffuse"));
                MB3_TextureBaker.ConfigureNewMaterialToMatchOld(newMat, m.materials[0]);
                AssetDatabase.CreateAsset(newMat, matName);
                mm.combinedMaterial = (Material)AssetDatabase.LoadAssetAtPath(matName, typeof(Material));
                k++;
            }
            MBVersionEditor.UpdateIfDirtyOrScript(textureBaker);
        }
コード例 #19
0
    /// <summary>
    ///  Bakes a combined mesh.
    /// </summary>
    /// <param name="so">If this is being called from Inspector code then pass in the SerializedObject for the component.
    /// This is necessary for "bake into prefab" which can corrupt the SerializedObject.</param>
    public static bool BakeIntoCombined(MB3_MeshBakerCommon mom, out bool createdDummyTextureBakeResults, ref SerializedObject so)
    {
        MB2_OutputOptions prefabOrSceneObject = mom.meshCombiner.outputOption;

        createdDummyTextureBakeResults = false;

        // Initial Validate
        {
            if (mom.meshCombiner.resultSceneObject != null &&
                (MBVersionEditor.PrefabUtility_GetPrefabType(mom.meshCombiner.resultSceneObject) == MB_PrefabType.modelPrefabAsset ||
                 MBVersionEditor.PrefabUtility_GetPrefabType(mom.meshCombiner.resultSceneObject) == MB_PrefabType.prefabAsset))
            {
                Debug.LogWarning("Result Game Object was a project asset not a scene object instance. Clearing this field.");
                mom.meshCombiner.resultSceneObject = null;
            }

            if (prefabOrSceneObject != MB2_OutputOptions.bakeIntoPrefab && prefabOrSceneObject != MB2_OutputOptions.bakeIntoSceneObject)
            {
                Debug.LogError("Paramater prefabOrSceneObject must be bakeIntoPrefab or bakeIntoSceneObject");
                return(false);
            }

            if (prefabOrSceneObject == MB2_OutputOptions.bakeIntoPrefab)
            {
                if (MB3_MeshCombiner.EVAL_VERSION)
                {
                    Debug.LogError("Cannot BakeIntoPrefab with evaluation version.");
                    return(false);
                }

                if (mom.resultPrefab == null)
                {
                    Debug.LogError("Need to set the Combined Mesh Prefab field. Create a prefab asset, drag an empty game object into it, and drag it to the 'Combined Mesh Prefab' field.");
                    return(false);
                }

                string prefabPth = AssetDatabase.GetAssetPath(mom.resultPrefab);
                if (prefabPth == null || prefabPth.Length == 0)
                {
                    Debug.LogError("Could not save result to prefab. Result Prefab value is not a project asset. Is it an instance in the scene?");
                    return(false);
                }
            }
        }

        {
            // Find or create texture bake results
            MB3_TextureBaker tb = mom.GetComponentInParent <MB3_TextureBaker>();
            if (mom.textureBakeResults == null && tb != null)
            {
                mom.textureBakeResults = tb.textureBakeResults;
            }

            if (mom.textureBakeResults == null)
            {
                if (_OkToCreateDummyTextureBakeResult(mom))
                {
                    createdDummyTextureBakeResults = true;
                    List <GameObject> gos = mom.GetObjectsToCombine();
                    if (mom.GetNumObjectsInCombined() > 0)
                    {
                        if (mom.clearBuffersAfterBake)
                        {
                            mom.ClearMesh();
                        }
                        else
                        {
                            Debug.LogError("'Texture Bake Result' must be set to add more objects to a combined mesh that already contains objects. Try enabling 'clear buffers after bake'");
                            return(false);
                        }
                    }
                    mom.textureBakeResults = MB2_TextureBakeResults.CreateForMaterialsOnRenderer(gos.ToArray(), mom.meshCombiner.GetMaterialsOnTargetRenderer());
                    if (mom.meshCombiner.LOG_LEVEL >= MB2_LogLevel.debug)
                    {
                        Debug.Log("'Texture Bake Result' was not set. Creating a temporary one. Each material will be mapped to a separate submesh.");
                    }
                }
            }
        }

        // Second level of validation now that TextureBakeResults exists.
        MB2_ValidationLevel vl = Application.isPlaying ? MB2_ValidationLevel.quick : MB2_ValidationLevel.robust;

        if (!MB3_MeshBakerRoot.DoCombinedValidate(mom, MB_ObjsToCombineTypes.sceneObjOnly, new MB3_EditorMethods(), vl))
        {
            return(false);
        }

        // Add Delete Game Objects
        bool success;

        if (prefabOrSceneObject == MB2_OutputOptions.bakeIntoSceneObject)
        {
            success = _BakeIntoCombinedSceneObject(mom, createdDummyTextureBakeResults, ref so);
        }
        else if (prefabOrSceneObject == MB2_OutputOptions.bakeIntoPrefab)
        {
            success = _BakeIntoCombinedPrefab(mom, createdDummyTextureBakeResults, ref so);
        }
        else
        {
            Debug.LogError("Should be impossible.");
            success = false;
        }

        if (mom.clearBuffersAfterBake)
        {
            mom.meshCombiner.ClearBuffers();
        }
        if (createdDummyTextureBakeResults)
        {
            MB_Utility.Destroy(mom.textureBakeResults);
        }
        return(success);
    }
コード例 #20
0
    /// <summary>
    /// We will modify the source object so duplicate them
    /// </summary>
    /// <param name="tempGameObjectInstances"></param>
    public static void _DuplicateSrcObjectInstancesAndUnpack(MB_RenderType renderType, GameObject[] objsToCombine, List <Transform> tempGameObjectInstances)
    {
        Debug.Assert(renderType == MB_RenderType.skinnedMeshRenderer, "RenderType must be Skinned Mesh Renderer");
        // first pass, collect the prefab-instance roots for each of the src objects.
        Transform[] sceneInstanceParents = new Transform[objsToCombine.Length];
        for (int i = 0; i < objsToCombine.Length; i++)
        {
            // Get the prefab root
            GameObject pr = null;
            {
                MB_PrefabType pt = MBVersionEditor.PrefabUtility_GetPrefabType(objsToCombine[i]);
                if (pt == MB_PrefabType.scenePefabInstance || pt == MB_PrefabType.isInstanceAndNotAPartOfAnyPrefab)
                {
                    pr = MBVersionEditor.PrefabUtility_GetPrefabInstanceRoot(objsToCombine[i]);
                }

                if (pr == null)
                {
                    pr = _FindCommonAncestorForBonesAnimatorAndSmr(objsToCombine[i]);
                }
            }

            sceneInstanceParents[i] = pr.transform;
        }

        // second pass, some of the parents could be children of other parents. ensure that we are
        // using the uppermost ancestor for all.
        for (int i = 0; i < objsToCombine.Length; i++)
        {
            sceneInstanceParents[i] = _FindUppermostParent(objsToCombine[i], sceneInstanceParents);
        }

        // Now build a map of sceneInstanceParents to the renderers contained beneath.
        Dictionary <Transform, List <Transform> > srcPrefabInstances2Renderers = new Dictionary <Transform, List <Transform> >();

        for (int i = 0; i < objsToCombine.Length; i++)
        {
            List <Transform> renderersUsed;
            if (!srcPrefabInstances2Renderers.TryGetValue(sceneInstanceParents[i], out renderersUsed))
            {
                renderersUsed = new List <Transform>();
                srcPrefabInstances2Renderers.Add(sceneInstanceParents[i], renderersUsed);
            }

            renderersUsed.Add(objsToCombine[i].transform);
        }

        // Duplicate the prefab-instance-root scene objects
        List <Transform> srcRoots  = new List <Transform>(srcPrefabInstances2Renderers.Keys);
        List <Transform> targRoots = new List <Transform>();

        for (int i = 0; i < srcRoots.Count; i++)
        {
            Transform  src = srcRoots[i];
            GameObject n   = GameObject.Instantiate <GameObject>(src.gameObject);
            n.transform.rotation   = src.rotation;
            n.transform.position   = src.position;
            n.transform.localScale = src.localScale;
            targRoots.Add(n.transform);
            tempGameObjectInstances.Add(targRoots[i]);
            _CheckSrcRootScale(renderType, src);
        }

        // Find the correct duplicated objsToCombine in the new instances that maps to objs in "objsToCombine".
        List <GameObject> newObjsToCombine = new List <GameObject>();

        for (int i = 0; i < srcRoots.Count; i++)
        {
            List <Transform> renderers = srcPrefabInstances2Renderers[srcRoots[i]];
            for (int j = 0; j < renderers.Count; j++)
            {
                Transform t = MB_BatchPrefabBakerEditorFunctions.FindCorrespondingTransform(srcRoots[i], renderers[j], targRoots[i]);
                Debug.Assert(!newObjsToCombine.Contains(t.gameObject));
                newObjsToCombine.Add(t.gameObject);
            }
        }
        Debug.Assert(newObjsToCombine.Count == objsToCombine.Length);

        for (int i = 0; i < newObjsToCombine.Count; i++)
        {
            //GameObject go = newObjsToCombine[i];
            //SerializedObject so = null;
            //MB_PrefabType pt = MBVersionEditor.GetPrefabType(go);
            //if (pt == MB_PrefabType.sceneInstance)
            //{
            //    MBVersionEditor.UnpackPrefabInstance(go, ref so);
            //}

            objsToCombine[i] = newObjsToCombine[i];
        }
    }
コード例 #21
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();
        }
コード例 #22
0
    // The serialized object reference is necessary to work around a nasty unity bug.
    public static GameObject RebuildPrefab(MB3_MeshBakerCommon mom, ref SerializedObject so, bool leaveInstanceInSceneAfterBake, List <Transform> tempPrefabInstanceRoots, GameObject[] objsToCombine)
    {
        if (MB3_MeshCombiner.EVAL_VERSION)
        {
            return(null);
        }

        if (mom.meshCombiner.LOG_LEVEL >= MB2_LogLevel.debug)
        {
            Debug.Log("Rebuilding Prefab: " + mom.resultPrefab);
        }
        GameObject prefabRoot     = mom.resultPrefab;
        GameObject instanceRootGO = mom.meshCombiner.resultSceneObject;

        /*
         * GameObject instanceRootGO = (GameObject)PrefabUtility.InstantiatePrefab(prefabRoot);
         * instanceRootGO.transform.position = Vector3.zero;
         * instanceRootGO.transform.rotation = Quaternion.identity;
         * instanceRootGO.transform.localScale = Vector3.one;
         *
         * //remove everything in the prefab.
         *
         * MBVersionEditor.UnpackPrefabInstance(instanceRootGO, ref so);
         * int numChildren = instanceRootGO.transform.childCount;
         * for (int i = numChildren - 1; i >= 0; i--)
         * {
         *  MB_Utility.Destroy(instanceRootGO.transform.GetChild(i).gameObject);
         * }
         *
         * if (mom is MB3_MeshBaker)
         * {
         *  MB3_MeshBaker mb = (MB3_MeshBaker)mom;
         *  MB3_MeshCombinerSingle mbs = (MB3_MeshCombinerSingle)mb.meshCombiner;
         *  MB3_MeshCombinerSingle.BuildPrefabHierarchy(mbs, instanceRootGO, mbs.GetMesh());
         * }
         * else if (mom is MB3_MultiMeshBaker)
         * {
         *  MB3_MultiMeshBaker mmb = (MB3_MultiMeshBaker)mom;
         *  MB3_MultiMeshCombiner mbs = (MB3_MultiMeshCombiner)mmb.meshCombiner;
         *  for (int i = 0; i < mbs.meshCombiners.Count; i++)
         *  {
         *      MB3_MeshCombinerSingle.BuildPrefabHierarchy(mbs.meshCombiners[i].combinedMesh, instanceRootGO, mbs.meshCombiners[i].combinedMesh.GetMesh(), true);
         *  }
         * }
         * else
         * {
         *  Debug.LogError("Argument was not a MB3_MeshBaker or an MB3_MultiMeshBaker.");
         * }
         */

        if (mom.meshCombiner.settings.renderType == MB_RenderType.skinnedMeshRenderer)
        {
            _MoveBonesToCombinedMeshPrefabAndDeleteRenderers(instanceRootGO.transform, tempPrefabInstanceRoots, objsToCombine);
        }

        string prefabPth = AssetDatabase.GetAssetPath(prefabRoot);

        MBVersionEditor.PrefabUtility_ReplacePrefab(instanceRootGO, prefabPth, MB_ReplacePrefabOption.connectToPrefab);
        mom.resultPrefab = AssetDatabase.LoadAssetAtPath <GameObject>(prefabPth);
        if (!leaveInstanceInSceneAfterBake)
        {
            Editor.DestroyImmediate(instanceRootGO);
        }

        return(instanceRootGO);
    }
コード例 #23
0
        public void CopyBoneWeightsFromSeamMeshToOtherMeshes(MB3_BoneWeightCopier bwc)
        {
            if (bwc.seamMesh == null)
            {
                Debug.LogError("The seamMesh cannot be null.");
                return;
            }

            UnityEngine.Object pr        = (UnityEngine.Object)PrefabUtility.GetPrefabObject(bwc.seamMesh.gameObject);
            string             assetPath = null;

            if (pr != null)
            {
                assetPath = AssetDatabase.GetAssetPath(pr);
            }
            if (assetPath != null)
            {
                ModelImporter mi = (ModelImporter)AssetImporter.GetAtPath(assetPath);
                if (mi != null)
                {
                    if (mi.optimizeMesh)
                    {
                        Debug.LogError(string.Format("The seam mesh has 'optimized' checked in the asset importer. This will result in no vertices. Uncheck 'optimized'."));
                        return;
                    }
                }
            }
            //todo check that output game object exists and is a prefab
            if (bwc.outputPrefab == null)
            {
                Debug.LogError(string.Format("The output game object must be assigned and must be a prefab of a game object in the project folder."));
                return;
            }
            if (MBVersionEditor.GetPrefabType(bwc.outputPrefab) != MB_PrefabType.prefab)
            {
                Debug.LogError("The output game object must be a prefab. Create a prefab in the project and drag an empty game object to it.");
                return;
            }

            //duplicate the source prefab and the meshes
            if (copyOfInput != null)
            {
                DestroyImmediate(copyOfInput);
            }
            copyOfInput = (GameObject)GameObject.Instantiate(bwc.inputGameObject);
            SkinnedMeshRenderer[] targSkinnedMeshes = copyOfInput.GetComponentsInChildren <SkinnedMeshRenderer>();
            Mesh[] targs = new Mesh[targSkinnedMeshes.Length];
            for (int i = 0; i < targSkinnedMeshes.Length; i++)
            {
                if (targSkinnedMeshes[i].sharedMesh == null)
                {
                    Debug.LogError(string.Format("Skinned Mesh {0} does not have a mesh", targSkinnedMeshes[i]));
                    return;
                }
                MB_PrefabType pt = MBVersionEditor.GetPrefabType(targSkinnedMeshes[i].gameObject);
                if (pt == MB_PrefabType.modelPrefab)
                {
                    Debug.LogError(string.Format("Target Mesh {0} is an imported model prefab. Can't modify these meshes because changes will be overwritten the next time the model is saved or reimported. Try instantiating the prefab and using skinned meshes from the scene instance.", i));
                    return;
                }
                targs[i] = (Mesh)GameObject.Instantiate(targSkinnedMeshes[i].sharedMesh);
            }
            MB3_CopyBoneWeights.CopyBoneWeightsFromSeamMeshToOtherMeshes(bwc.radius, bwc.seamMesh.sharedMesh, targs);
            SaveMeshesToOutputFolderAndAssignToSMRs(targs, targSkinnedMeshes);

            EditorUtility.SetDirty(copyOfInput);


            // TODO tried using 2018 replace prefab but there were errors.
            //MBVersionEditor.ReplacePrefab(copyOfInput, assetPath, MB_ReplacePrefabOption.connectToPrefab | MB_ReplacePrefabOption.nameBased);
            PrefabUtility.ReplacePrefab(copyOfInput, bwc.outputPrefab, ReplacePrefabOptions.ConnectToPrefab | ReplacePrefabOptions.ReplaceNameBased);

            AssetDatabase.SaveAssets();
            DestroyImmediate(copyOfInput);
        }