예제 #1
0
        public static bool ValidateFolderIsInProject(string fieldName, string folder)
        {
            if (folder == null)
            {
                Debug.LogError(fieldName + " must be set");
                return(false);
            }

            if (folder.StartsWith("Assets"))
            {
                folder = MB_BatchPrefabBakerEditorFunctions.ConvertProjectRelativePathToFullPath(folder);
            }

            if (folder.StartsWith(Application.dataPath))
            {
                string relativePath = "Assets" + folder.Substring(Application.dataPath.Length);
                string gid          = AssetDatabase.AssetPathToGUID(relativePath);
                if (gid == null || gid.Length == 0)
                {
                    Debug.LogError(fieldName + " must be an existing folder in the Unity project Assets folder");
                    return(false);
                }
            }
            else
            {
                Debug.LogError(fieldName + " must be an existing folder in the Unity project Assets folder");
                return(false);
            }

            return(true);
        }
        public override void OnInspectorGUI()
        {
            serializedObject.Update();
            MB3_BoneWeightCopier bwc = (MB3_BoneWeightCopier)target;


            EditorGUILayout.HelpBox("== BETA (please report problems) ==\n\n" +
                                    "This tool helps create skinned mesh parts that can be mix and matched to customize characters. " +
                                    "It adjusts the boneWeights, positions, normals and tangents at the joins to have the same values so there are no tears." +
                                    "\n\n" +
                                    "1) Model the skinned meshes and attach them all to the same rig. The rig may have multiple arms, hands, hair etc...\n" +
                                    "2) At every seam (eg. between an arm mesh and hand mesh) there must be a set of vertices duplicated in both meshes.\n" +
                                    "3) Create one additional mesh that contains another copy of all the geometry. This will be called the Seam Mesh\n" +
                                    "4) Attach it to the rig and adjust the bone weights. This will be the master set of bone weights that will be copied to all the other skinned meshes.\n" +
                                    "5) Mark the seam vertices using the UV channel.\n" +
                                    "    verts with UV > (.5,.5) are seam verts\n" +
                                    "    verts with UV < (.5,.5) are ignored\n" +
                                    "6) Import the model into Unity and create an instance of it in the scene\n" +
                                    "7) Assign the Seam Mesh to the Seam Mesh field\n" +
                                    "8) Assign the parent game object of all the skinned meshes to the Input Game Object field\n" +
                                    "9) Adjust the radius\n" +
                                    "10) Choose an output folder and save the meshes\n" +
                                    "11) Click 'Copy Bone Weights From Seam Mesh'\n", MessageType.Info);

            EditorGUILayout.PropertyField(radiusProp, gc_radius);
            EditorGUILayout.PropertyField(seamMeshProp, gc_seamMesh);
            EditorGUILayout.PropertyField(inputGameObjectProp, gc_inputGameObject);
            EditorGUILayout.PropertyField(outputPrefabProp, gc_outputPrefab);
            //if (GUILayout.Button("Get Skinned Meshes From Input Game Object")) {
            //	GetSkinnedMeshesFromGameObject(bwc);
            //}
            //EditorGUILayout.PropertyField(targetMeshesProp,true);

            if (GUILayout.Button("Copy Bone Weights From Seam Mesh"))
            {
                CopyBoneWeightsFromSeamMeshToOtherMeshes(bwc);
            }
            EditorGUILayout.Separator();
            EditorGUILayout.Separator();
            EditorGUILayout.LabelField("Save Meshes To Project Folder", EditorStyles.boldLabel);
            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.PropertyField(outputFolderProp, gc_outputFolder);
            if (GUILayout.Button("Browse"))
            {
                string path = EditorUtility.OpenFolderPanel("Browse For Output Folder", "", "");
                path = MB_BatchPrefabBakerEditorFunctions.ConvertFullPathToProjectRelativePath(path);
                outputFolderProp.stringValue = path;
            }
            EditorGUILayout.EndHorizontal();
            if (GUILayout.Button("Set Output Folder To Output Prefab Folder"))
            {
                string path = AssetDatabase.GetAssetPath(bwc.outputPrefab);
                path = new System.IO.FileInfo(path).Directory.FullName.Replace('\\', '/');
                path = MB_BatchPrefabBakerEditorFunctions.ConvertFullPathToProjectRelativePath(path);
                outputFolderProp.stringValue = path;
            }
            serializedObject.ApplyModifiedProperties();
        }
예제 #3
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);
                }
            }
        }
        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();
        }
        private static void _generateMeshBakers(UnityEngine.Object target)
        {
            MB3_MeshBakerGrouper tbg = (MB3_MeshBakerGrouper)target;
            MB3_TextureBaker     tb  = tbg.GetComponent <MB3_TextureBaker>();

            if (tb == null)
            {
                Debug.LogError("There must be an MB3_TextureBaker attached to this game object.");
                return;
            }

            if (tb.GetObjectsToCombine().Count == 0)
            {
                Debug.LogError("The MB3_MeshBakerGrouper creates clusters based on the objects to combine in the MB3_TextureBaker component. There were no objects in this list.");
                return;
            }

            if (tbg.parentSceneObject == null ||
                !MB_Utility.IsSceneInstance(tbg.parentSceneObject.gameObject))
            {
                GameObject g = new GameObject("CombinedMeshes-" + tbg.name);
                tbg.parentSceneObject = g.transform;
            }

            //check if any of the objes that will be added to bakers already exist in child bakers
            List <GameObject> objsWeAreGrouping = tb.GetObjectsToCombine();

            MB3_MeshBakerCommon[] alreadyExistBakers = tbg.GetComponentsInChildren <MB3_MeshBakerCommon>();
            bool foundChildBakersWithObjsToCombine   = false;

            for (int i = 0; i < alreadyExistBakers.Length; i++)
            {
                List <GameObject> childOjs2Combine = alreadyExistBakers[i].GetObjectsToCombine();
                for (int j = 0; j < childOjs2Combine.Count; j++)
                {
                    if (childOjs2Combine[j] != null && objsWeAreGrouping.Contains(childOjs2Combine[j]))
                    {
                        foundChildBakersWithObjsToCombine = true;
                        break;
                    }
                }
            }

            bool proceed = true;

            if (foundChildBakersWithObjsToCombine)
            {
                proceed = EditorUtility.DisplayDialog("Replace Previous Generated Bakers", "Delete child bakers?\n\n" +
                                                      "This grouper has child Mesh Baker objects from a previous clustering. Do you want to delete these and create new ones?", "OK", "Cancel");
            }

            if (tbg.prefabOptions_autoGeneratePrefabs)
            {
                if (!MB_BatchPrefabBakerEditorFunctions.ValidateFolderIsInProject("Output Folder", tbg.prefabOptions_outputFolder))
                {
                    Debug.LogError("If " + gc_prefabOptions_autoGeneratePrefabs.text + " is enabled, you must provide an output folder. Prefabs will be saved in this folder.");
                    proceed = false;
                }
            }

            if (proceed)
            {
                if (foundChildBakersWithObjsToCombine)
                {
                    tbg.DeleteAllChildMeshBakers();
                }
                List <MB3_MeshBakerCommon> newBakers = tbg.grouper.DoClustering(tb, tbg);
                if (newBakers.Count > 0)
                {
                    DoGeneratePrefabsIfNecessary(tbg, newBakers);
                }
            }
        }
        public void DrawGrouperInspector()
        {
            EditorGUILayout.HelpBox("This component helps you group meshes that are close together so they can be combined together." +
                                    " It generates multiple MB3_MeshBaker objects from the List Of Objects to be combined in the MB3_TextureBaker component." +
                                    " Objects that are close together will be grouped together and added to a new child MB3_MeshBaker object.\n\n" +
                                    " TIP: Try the new agglomerative cluster type. It's awsome!", MessageType.Info);
            MB3_MeshBakerGrouper tbg = (MB3_MeshBakerGrouper)target;

            MB3_TextureBaker tb = tbg.GetComponent <MB3_TextureBaker>();

            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.PropertyField(clusterType, gc_ClusterType);
            MB3_MeshBakerGrouper.ClusterType gg = (MB3_MeshBakerGrouper.ClusterType)clusterType.enumValueIndex;
            if ((gg == MB3_MeshBakerGrouper.ClusterType.none && !(tbg.grouper is MB3_MeshBakerGrouperNone)) ||
                (gg == MB3_MeshBakerGrouper.ClusterType.grid && !(tbg.grouper is MB3_MeshBakerGrouperGrid)) ||
                (gg == MB3_MeshBakerGrouper.ClusterType.pie && !(tbg.grouper is MB3_MeshBakerGrouperPie)) ||
                (gg == MB3_MeshBakerGrouper.ClusterType.agglomerative && !(tbg.grouper is MB3_MeshBakerGrouperCluster))
                )
            {
                tbg.CreateGrouper(gg, tbg.data);
                tbg.clusterType = gg;
            }

            if (clusterType.enumValueIndex == (int)MB3_MeshBakerGrouper.ClusterType.grid)
            {
                EditorGUILayout.PropertyField(gridOrigin, gc_GridOrigin);
                EditorGUILayout.PropertyField(cellSize, gc_CellSize);
            }
            else if (clusterType.enumValueIndex == (int)MB3_MeshBakerGrouper.ClusterType.pie)
            {
                EditorGUILayout.PropertyField(gridOrigin, gc_GridOrigin);
                EditorGUILayout.PropertyField(numSegments, gc_NumSegements);
                EditorGUILayout.PropertyField(pieAxis, gc_PieAxis);
                EditorGUILayout.PropertyField(pieRingSpacing, gc_PieRingSpacing);
                EditorGUILayout.PropertyField(pieCombineAllInCenterRing, gc_PieCombineAllInCenterRing);
            }
            else if (clusterType.enumValueIndex == (int)MB3_MeshBakerGrouper.ClusterType.agglomerative)
            {
                float dist    = clusterDistance.floatValue;
                float maxDist = 100f;
                float minDist = .000001f;
                MB3_MeshBakerGrouperCluster cl = null;
                if (tbg.grouper is MB3_MeshBakerGrouperCluster)
                {
                    cl      = (MB3_MeshBakerGrouperCluster)tbg.grouper;
                    maxDist = cl._ObjsExtents;
                    minDist = cl._minDistBetweenClusters;
                    if (dist < minDist)
                    {
                        dist = Mathf.Lerp(minDist, maxDist, .11f);
                    }
                }

                dist = EditorGUILayout.Slider(gc_ClusterDistance, dist, minDist, maxDist);
                clusterDistance.floatValue = dist;

                string btnName = "Refresh Clusters";
                if (cl.cluster == null || cl.cluster.clusters == null || cl.cluster.clusters.Length == 0)
                {
                    btnName = "Click To Build Clusters";
                }
                if (GUILayout.Button(btnName))
                {
                    if (tbg.grouper is MB3_MeshBakerGrouperCluster)
                    {
                        MB3_MeshBakerGrouperCluster cg = (MB3_MeshBakerGrouperCluster)tbg.grouper;
                        if (tb != null)
                        {
                            cg.BuildClusters(tb.GetObjectsToCombine(), updateProgressBar);
                            EditorUtility.ClearProgressBar();
                            Repaint();
                        }
                    }
                }
            }

            EditorGUILayout.PropertyField(clusterOnLMIndex, gc_ClusterOnLMIndex);
            EditorGUILayout.PropertyField(clusterByLODLevel, gc_ClusterByLODLevel);
            EditorGUILayout.PropertyField(includeCellsWithOnlyOneRenderer, gc_IncludeCellsWithOnlyOneRenderer);
            EditorGUILayout.Space();
            EditorGUILayout.LabelField("Prefab Output Settings", EditorStyles.boldLabel);
            EditorGUILayout.PropertyField(prefabOptions_autoGeneratePrefabs, gc_prefabOptions_autoGeneratePrefabs);
            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.PropertyField(prefabOptions_outputFolder, gc_prefabOptions_outputFolder);
            if (GUILayout.Button("Browse"))
            {
                string path = EditorUtility.OpenFolderPanel("Browse For Output Folder", "", "");
                path = MB_BatchPrefabBakerEditorFunctions.ConvertFullPathToProjectRelativePath(path);
                prefabOptions_outputFolder.stringValue = path;
            }
            EditorGUILayout.EndHorizontal();
            EditorGUILayout.Space();
            EditorGUILayout.LabelField("Mesh Baker Settings", EditorStyles.boldLabel);
            EditorGUILayout.HelpBox("These settings will be shared by all created Mesh Bakers.", MessageType.Info);

            UnityEngine.Object oldObjVal = mbSettingsAsset.objectReferenceValue;
            EditorGUILayout.PropertyField(mbSettingsAsset, gc_Settings);

            bool doingTextureArrays = false;

            if (tb != null && tb.textureBakeResults != null)
            {
                doingTextureArrays = tb.textureBakeResults.resultType == MB2_TextureBakeResults.ResultType.textureArray;
            }
            if (mbSettingsAsset.objectReferenceValue == null)
            {
                meshBakerSettingsMe.DrawGUI(tbg.meshBakerSettings, true, doingTextureArrays);
            }
            else
            {
                if (meshBakerSettingsExternal == null || oldObjVal != mbSettingsAsset.objectReferenceValue)
                {
                    UnityEngine.Object targetObj;
                    string             propertyName;
                    ((MB3_MeshCombinerSettings)mbSettingsAsset.objectReferenceValue).GetMeshBakerSettingsAsSerializedProperty(out propertyName, out targetObj);
                    SerializedProperty meshBakerSettings = new SerializedObject(targetObj).FindProperty(propertyName);
                }

                meshBakerSettingsExternal.DrawGUI(((MB3_MeshCombinerSettings)mbSettingsAsset.objectReferenceValue).data, false, doingTextureArrays);
            }
        }
예제 #7
0
        public override void OnInspectorGUI()
        {
            prefabBaker.Update();

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

            EditorGUILayout.PropertyField(prefabRows, true);

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

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

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

            Color oldColor = GUI.backgroundColor;

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

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

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


            prefabBaker.ApplyModifiedProperties();
            prefabBaker.SetIsDifferentCacheDirty();
        }