コード例 #1
0
    public void _bakePrefabs()
    {
        Debug.Log("Batch baking prefabs");
        MB3_BatchPrefabBaker pb = (MB3_BatchPrefabBaker)target;
        MB3_MeshBaker        mb = pb.GetComponent <MB3_MeshBaker>();

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

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

        if (mb.meshCombiner.outputOption != MB2_OutputOptions.bakeMeshAssetsInPlace)
        {
            Debug.LogError("Output option must be bakeMeshAssetsInPlace");
            return;
        }

        MB2_TextureBakeResults tbr = mb.textureBakeResults;

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

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

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

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

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

        sourceMeshes.IntersectWith(allResultMeshes);
        if (sourceMeshes.Count > 0)
        {
            foreach (Mesh m in sourceMeshes)
            {
                Debug.LogError("Mesh " + m + " is used by both the source and result prefabs. The meshes used by the result prefabs must not be the same as the meshes used by the source prefabs. The result meshes can be NULL. The baker will create new mesh assets.");
            }
            return;
        }

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

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

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

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

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

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

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

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

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

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

                //throw new Exception("");
                //bake the mesh
                MB3_MeshCombiner mc = mb.meshCombiner;

                m = MB3_BakeInPlace.BakeOneMesh((MB3_MeshCombinerSingle)mc, meshPath, r.gameObject);

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

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

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

            //replace the result prefab with the source object
            //duplicate the sceneObj so we can replace the clone into the prefab, not the source
            GameObject clone = (GameObject)Instantiate(sceneObj);
            PrefabUtility.ReplacePrefab(clone, pb.prefabRows[i].resultPrefab, ReplacePrefabOptions.ReplaceNameBased);
            DestroyImmediate(clone);
            DestroyImmediate(sceneObj);
            DestroyImmediate(resultPrefab);
        }
        AssetDatabase.Refresh();
        mb.ClearMesh();
    }