/**<summary>Combines meshes and generates texture atlases. NOTE running coroutines at runtime does not work in Unity 4</summary>
         *  <param name="progressInfo">A delegate function that will be called to report progress.</param>
         *  <param name="textureEditorMethods">If called from the editor should be an instance of MB2_EditorMethods. If called at runtime should be null.</param>
         *  <remarks>Combines meshes and generates texture atlases</remarks> */
        public bool CombineTexturesIntoAtlases(ProgressUpdateDelegate progressInfo, MB_AtlasesAndRects resultAtlasesAndRects, Material resultMaterial, List <GameObject> objsToMesh, List <Material> allowedMaterialsFilter, MB2_EditorMethodsInterface textureEditorMethods = null, List <AtlasPackingResult> packingResults = null, bool onlyPackRects = false)
        {
            CombineTexturesIntoAtlasesCoroutineResult result = new CombineTexturesIntoAtlasesCoroutineResult();

            RunCorutineWithoutPause(_CombineTexturesIntoAtlases(progressInfo, result, resultAtlasesAndRects, resultMaterial, objsToMesh, allowedMaterialsFilter, textureEditorMethods, packingResults, onlyPackRects), 0);
            return(result.success);
        }
Example #2
0
 void bake(MB2_TextureBaker target)
 {
     MB_AtlasesAndRects[] mAndAs = null;
     try{
         mAndAs = _bakeTexturesOnly(target);
     } catch (Exception e) {
         Debug.LogError(e);
     } finally {
         EditorUtility.ClearProgressBar();
         if (mAndAs != null)
         {
             for (int j = 0; j < mAndAs.Length; j++)
             {
                 MB_AtlasesAndRects mAndA = mAndAs[j];
                 if (mAndA != null && mAndA.atlases != null)
                 {
                     for (int i = 0; i < mAndA.atlases.Length; i++)
                     {
                         if (mAndA.atlases[i] != null)
                         {
                             MB_Utility.Destroy(mAndA.atlases[i]);
                         }
                     }
                 }
             }
         }
     }
 }
Example #3
0
        internal static bool[] DetermineWhichPropertiesHaveTextures(MB_AtlasesAndRects[] resultAtlasesAndRectSlices)
        {
            bool[] hasTexForProperty = new bool[resultAtlasesAndRectSlices[0].texPropertyNames.Length];
            for (int i = 0; i < hasTexForProperty.Length; i++)
            {
                hasTexForProperty[i] = false;
            }

            int numSlices = resultAtlasesAndRectSlices.Length;

            for (int sliceIdx = 0; sliceIdx < numSlices; sliceIdx++)
            {
                MB_AtlasesAndRects slice = resultAtlasesAndRectSlices[sliceIdx];
                Debug.Assert(slice.texPropertyNames.Length == hasTexForProperty.Length);
                for (int propIdx = 0; propIdx < hasTexForProperty.Length; propIdx++)
                {
                    if (slice.atlases[propIdx] != null)
                    {
                        hasTexForProperty[propIdx] = true;
                    }
                }
            }

            return(hasTexForProperty);
        }
    void saveAtlasesToAssetDatabase(MB_AtlasesAndRects newMesh, Material resMat)
    {
        Texture2D[] atlases          = newMesh.atlases;
        string[]    texPropertyNames = newMesh.texPropertyNames;
        string      prefabPth        = AssetDatabase.GetAssetPath(resMat);

        if (prefabPth == null || prefabPth.Length == 0)
        {
            Debug.LogError("Could not save result to prefab. Result Prefab value is not an Asset.");
            return;
        }
        string baseName       = System.IO.Path.GetFileNameWithoutExtension(prefabPth);
        string folderPath     = prefabPth.Substring(0, prefabPth.Length - baseName.Length - 4);
        string fullFolderPath = Application.dataPath + folderPath.Substring("Assets".Length, folderPath.Length - "Assets".Length);

        for (int i = 0; i < atlases.Length; i++)
        {
            string pth = fullFolderPath + baseName + "-" + texPropertyNames[i] + "-atlas" + i + ".png";
            Debug.Log("Created atlas for: " + texPropertyNames[i] + " at " + pth);
            //need to create a copy because sometimes the packed atlases are not in ARGB32 format
            Texture2D newTex = MB_Utility.createTextureCopy(atlases[i]);
            byte[]    bytes  = newTex.EncodeToPNG();
            DestroyImmediate(newTex);
            updateProgressBar("Saving atlas " + pth, .8f);
            File.WriteAllBytes(pth, bytes);
            AssetDatabase.Refresh();

            string relativePath = folderPath + baseName + "-" + texPropertyNames[i] + "-atlas" + i + ".png";

            _setMaterialTextureProperty(resMat, newMesh.texPropertyNames[i], relativePath);
        }
    }
Example #5
0
        /**<summary>Combines meshes and generates texture atlases. NOTE running coroutines at runtime does not work in Unity 4</summary>
         *  <param name="progressInfo">A delegate function that will be called to report progress.</param>
         *  <param name="textureEditorMethods">If called from the editor should be an instance of MB2_EditorMethods. If called at runtime should be null.</param>
         *  <remarks>Combines meshes and generates texture atlases</remarks> */
        public bool CombineTexturesIntoAtlases(ProgressUpdateDelegate progressInfo, MB_AtlasesAndRects resultAtlasesAndRects, Material resultMaterial, List <GameObject> objsToMesh, List <Material> allowedMaterialsFilter, MB2_EditorMethodsInterface textureEditorMethods = null, List <AtlasPackingResult> packingResults = null, bool onlyPackRects = false, bool splitAtlasWhenPackingIfTooBig = false)
        {
            CombineTexturesIntoAtlasesCoroutineResult result = new CombineTexturesIntoAtlasesCoroutineResult();

            RunCorutineWithoutPause(_CombineTexturesIntoAtlases(progressInfo, result, resultAtlasesAndRects, resultMaterial, objsToMesh, allowedMaterialsFilter, textureEditorMethods, packingResults, onlyPackRects, splitAtlasWhenPackingIfTooBig), 0);
            if (result.success == false)
            {
                Debug.LogError("Failed to generate atlases.");
            }
            return(result.success);
        }
Example #6
0
    /**<summary>Combines meshes and generates texture atlases.</summary>
     *  <param name="createTextureAtlases">Whether or not texture atlases should be created. If not uvs will not be adjusted.</param>
     *  <param name="progressInfo">A delegate function that will be called to report progress.</param>
     *  <remarks>Combines meshes and generates texture atlases</remarks> */
    public bool combineTexturesIntoAtlases(ProgressUpdateDelegate progressInfo, MB_AtlasesAndRects results, Material[] resultMaterials, List <GameObject> objsToMesh, List <Material> sourceMaterials, int atlasPadding, List <string> customShaderPropNames, bool resizePowerOfTwoTextures, bool fixOutOfBoundsUVs, int maxTilingBakeSize)
    {
        bool success = false;

        try{
            success = _combineTexturesIntoAtlases(progressInfo, results, resultMaterials, objsToMesh, sourceMaterials, atlasPadding, customShaderPropNames, resizePowerOfTwoTextures, fixOutOfBoundsUVs, maxTilingBakeSize);
        } catch (Exception ex) {
            Debug.LogError(ex);
        } finally {
            _destroyTemporaryTexturesAndSetReadFlags();
        }
        return(success);
    }
    /// <summary>
    /// Creates the atlases.
    /// </summary>
    /// <returns>
    /// The atlases.
    /// </returns>
    /// <param name='progressInfo'>
    /// Progress info is a delegate function that displays a progress dialog. Can be null
    /// </param>
    /// <param name='saveAtlasesAsAssets'>
    /// if true atlases are saved as assets in the project folder. Othersise they are instances in memory
    /// </param>
    /// <param name='editorMethods'>
    /// Texture format tracker. Contains editor functionality such as save assets. Can be null.
    /// </param>
    public MB_AtlasesAndRects[] CreateAtlases(ProgressUpdateDelegate progressInfo, bool saveAtlasesAsAssets = false, MB2_EditorMethodsInterface editorMethods = null)
    {
        MB_AtlasesAndRects[] mAndAs = null;

        try
        {
            _coroutineResult = new MB3_TextureCombiner.CreateAtlasesCoroutineResult();
            MB3_TextureCombiner.RunCorutineWithoutPause(CreateAtlasesCoroutine(progressInfo, _coroutineResult, saveAtlasesAsAssets, editorMethods, 1000f), 0);
            if (_coroutineResult.success && textureBakeResults != null)
            {
                mAndAs = this.OnCombinedTexturesCoroutineAtlasesAndRects;
            }
        }
        catch (Exception ex)
        {
            Debug.LogError(ex.Message + "\n" + ex.StackTrace.ToString());
        }
        finally
        {
            if (saveAtlasesAsAssets)
            { //Atlases were saved to project so we don't need these ones
                if (mAndAs != null)
                {
                    for (int j = 0; j < mAndAs.Length; j++)
                    {
                        MB_AtlasesAndRects mAndA = mAndAs[j];
                        if (mAndA != null && mAndA.atlases != null)
                        {
                            for (int i = 0; i < mAndA.atlases.Length; i++)
                            {
                                if (mAndA.atlases[i] != null)
                                {
                                    if (editorMethods != null)
                                    {
                                        editorMethods.Destroy(mAndA.atlases[i]);
                                    }
                                    else
                                    {
                                        MB_Utility.Destroy(mAndA.atlases[i]);
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }

        return(mAndAs);
    }
    void bakeTexturesOnly()
    {
        if (!doCombinedValidate(MB_ObjsToCombineTypes.prefabOnly))
        {
            return;
        }

        MB_AtlasesAndRects[] mAndAs = null;
        try{
            MB_MeshBaker mbd = (MB_MeshBaker)target;
            mAndAs = mbd.CreateAtlases(updateProgressBar);
            if (mAndAs != null)
            {
                for (int i = 0; i < mAndAs.Length; i++)
                {
                    MB_AtlasesAndRects mAndA = mAndAs[i];
                    updateProgressBar("Created mesh saving assets", .6f);
                    Material resMat = mbd.resultMaterial;
                    if (mbd.doMultiMaterial)
                    {
                        resMat = mbd.resultMaterials[i].combinedMaterial;
                    }
                    saveAtlasesToAssetDatabase(mAndA, resMat);
                    meshBaker.SetIsDifferentCacheDirty();
                    updateProgressBar("Replacing prefab", .7f);
                }
            }
        } catch (Exception e) {
            Debug.LogError(e);
        } finally {
            EditorUtility.ClearProgressBar();
            if (mAndAs != null)
            {
                for (int j = 0; j < mAndAs.Length; j++)
                {
                    MB_AtlasesAndRects mAndA = mAndAs[j];
                    if (mAndA != null && mAndA.atlases != null)
                    {
                        for (int i = 0; i < mAndA.atlases.Length; i++)
                        {
                            if (mAndA.atlases[i] != null)
                            {
                                MB_Utility.Destroy(mAndA.atlases[i]);
                            }
                        }
                    }
                }
            }
        }
    }
Example #9
0
 /// <summary>
 /// Creates the atlases.
 /// </summary>
 /// <returns>
 /// The atlases.
 /// </returns>
 /// <param name='progressInfo'>
 /// Progress info is a delegate function that displays a progress dialog. Can be null
 /// </param>
 /// <param name='saveAtlasesAsAssets'>
 /// if true atlases are saved as assets in the project folder. Othersise they are instances in memory
 /// </param>
 /// <param name='editorMethods'>
 /// Texture format tracker. Contains editor functionality such as save assets. Can be null.
 /// </param>
 public MB_AtlasesAndRects[] CreateAtlases(ProgressUpdateDelegate progressInfo, bool saveAtlasesAsAssets = false, MB2_EditorMethodsInterface editorMethods = null)
 {
     MB_AtlasesAndRects[] mAndAs = null;
     try
     {
         //mAndAs = _CreateAtlases(progressInfo, saveAtlasesAsAssets, editorMethods);
         CreateAtlasesCoroutineResult result = new CreateAtlasesCoroutineResult();
         MB3_TextureCombiner.RunCorutineWithoutPause(CreateAtlasesCoroutine(progressInfo, result, saveAtlasesAsAssets, editorMethods, 1000f), 0);
         if (result.success)
         {
             mAndAs = textureBakeResults.combinedMaterialInfo;
         }
     }
     catch (Exception e)
     {
         Debug.LogError(e);
     }
     finally
     {
         if (saveAtlasesAsAssets)
         { //Atlases were saved to project so we don't need these ones
             if (mAndAs != null)
             {
                 for (int j = 0; j < mAndAs.Length; j++)
                 {
                     MB_AtlasesAndRects mAndA = mAndAs[j];
                     if (mAndA != null && mAndA.atlases != null)
                     {
                         for (int i = 0; i < mAndA.atlases.Length; i++)
                         {
                             if (mAndA.atlases[i] != null)
                             {
                                 if (editorMethods != null)
                                 {
                                     editorMethods.Destroy(mAndA.atlases[i]);
                                 }
                                 else
                                 {
                                     MB_Utility.Destroy(mAndA.atlases[i]);
                                 }
                             }
                         }
                     }
                 }
             }
         }
     }
     return(mAndAs);
 }
Example #10
0
    private void unpackMat2RectMap(MB2_TextureBakeResults resultAtlasesAndRects)
    {
        List <Material> list  = new List <Material>();
        List <Rect>     list2 = new List <Rect>();

        for (int i = 0; i < resultAtlasesAndRects.combinedMaterialInfo.Length; i++)
        {
            MB_AtlasesAndRects          mb_AtlasesAndRects = resultAtlasesAndRects.combinedMaterialInfo[i];
            Dictionary <Material, Rect> mat2rect_map       = mb_AtlasesAndRects.mat2rect_map;
            foreach (Material material in mat2rect_map.Keys)
            {
                list.Add(material);
                list2.Add(mat2rect_map[material]);
            }
        }
        resultAtlasesAndRects.materials     = list.ToArray();
        resultAtlasesAndRects.prefabUVRects = list2.ToArray();
    }
Example #11
0
    void unpackMat2RectMap(MB2_TextureBakeResults results)
    {
        List <Material> ms = new List <Material>();
        List <Rect>     rs = new List <Rect>();

        for (int i = 0; i < results.combinedMaterialInfo.Length; i++)
        {
            MB_AtlasesAndRects          newMesh = results.combinedMaterialInfo[i];
            Dictionary <Material, Rect> map     = newMesh.mat2rect_map;
            foreach (Material m in map.Keys)
            {
                ms.Add(m);
                rs.Add(map[m]);
            }
        }
        results.materials     = ms.ToArray();
        results.prefabUVRects = rs.ToArray();
    }
Example #12
0
    void updateMaterialToRectMapping(MB_AtlasesAndRects[] newMeshs)
    {
        mat2rect_map.Clear();
        List <Material> ms = new List <Material>();
        List <Rect>     rs = new List <Rect>();

        for (int i = 0; i < newMeshs.Length; i++)
        {
            MB_AtlasesAndRects          newMesh = newMeshs[i];
            Dictionary <Material, Rect> map     = newMesh.mat2rect_map;
            foreach (Material m in map.Keys)
            {
                ms.Add(m);
                rs.Add(map[m]);
                mat2rect_map.Add(m, map[m]);
            }
        }
        materials     = ms.ToArray();
        prefabUVRects = rs.ToArray();
    }
Example #13
0
    /*
     * MB_AtlasesAndRects[] _CreateAtlases(ProgressUpdateDelegate progressInfo, bool saveAtlasesAsAssets = false, MB2_EditorMethodsInterface editorMethods = null)
     * {
     *  //validation
     *  if (saveAtlasesAsAssets && editorMethods == null)
     *  {
     *      Debug.LogError("Error in CreateAtlases If saveAtlasesAsAssets = true then editorMethods cannot be null.");
     *      return null;
     *  }
     *  if (saveAtlasesAsAssets && !Application.isEditor)
     *  {
     *      Debug.LogError("Error in CreateAtlases If saveAtlasesAsAssets = true it must be called from the Unity Editor.");
     *      return null;
     *  }
     *  MB2_ValidationLevel vl = Application.isPlaying ? MB2_ValidationLevel.quick : MB2_ValidationLevel.robust;
     *  if (!DoCombinedValidate(this, MB_ObjsToCombineTypes.dontCare, editorMethods, vl))
     *  {
     *      return null;
     *  }
     *  if (_doMultiMaterial && !_ValidateResultMaterials())
     *  {
     *      return null;
     *  }
     *  else if (!_doMultiMaterial)
     *  {
     *      if (_resultMaterial == null)
     *      {
     *          Debug.LogError("Combined Material is null please create and assign a result material.");
     *          return null;
     *      }
     *      Shader targShader = _resultMaterial.shader;
     *      for (int i = 0; i < objsToMesh.Count; i++)
     *      {
     *          Material[] ms = MB_Utility.GetGOMaterials(objsToMesh[i]);
     *          for (int j = 0; j < ms.Length; j++)
     *          {
     *              Material m = ms[j];
     *              if (m != null && m.shader != targShader)
     *              {
     *                  Debug.LogWarning("Game object " + objsToMesh[i] + " does not use shader " + targShader + " it may not have the required textures. If not small solid color textures will be generated.");
     *              }
     *
     *          }
     *      }
     *  }
     *
     *  for (int i = 0; i < objsToMesh.Count; i++)
     *  {
     *      Material[] ms = MB_Utility.GetGOMaterials(objsToMesh[i]);
     *      for (int j = 0; j < ms.Length; j++)
     *      {
     *          Material m = ms[j];
     *          if (m == null)
     *          {
     *              Debug.LogError("Game object " + objsToMesh[i] + " has a null material. Can't build atlases");
     *              return null;
     *          }
     *
     *      }
     *  }
     *
     *  MB3_TextureCombiner combiner = new MB3_TextureCombiner();
     *  combiner.LOG_LEVEL = LOG_LEVEL;
     *  combiner.atlasPadding = _atlasPadding;
     *  combiner.maxAtlasSize = _maxAtlasSize;
     *  combiner.customShaderPropNames = _customShaderProperties;
     *  combiner.fixOutOfBoundsUVs = _fixOutOfBoundsUVs;
     *  combiner.maxTilingBakeSize = _maxTilingBakeSize;
     *  combiner.packingAlgorithm = _packingAlgorithm;
     *  combiner.meshBakerTexturePackerForcePowerOfTwo = _meshBakerTexturePackerForcePowerOfTwo;
     *  combiner.resizePowerOfTwoTextures = _resizePowerOfTwoTextures;
     *  combiner.saveAtlasesAsAssets = saveAtlasesAsAssets;
     *  combiner.considerNonTextureProperties = _considerNonTextureProperties;
     *
     *  // if editor analyse meshes and suggest treatment
     *  if (!Application.isPlaying && _doSuggestTreatment)
     *  {
     *      Material[] rms;
     *      if (_doMultiMaterial)
     *      {
     *          rms = new Material[resultMaterials.Length];
     *          for (int i = 0; i < rms.Length; i++) rms[i] = resultMaterials[i].combinedMaterial;
     *      }
     *      else
     *      {
     *          rms = new Material[1];
     *          rms[0] = _resultMaterial;
     *      }
     *      combiner.SuggestTreatment(objsToMesh, rms, combiner.customShaderPropNames);
     *  }
     *
     *  //initialize structure to store results
     *  int numResults = 1;
     *  if (_doMultiMaterial) numResults = resultMaterials.Length;
     *  MB_AtlasesAndRects[] resultAtlasesAndRects = new MB_AtlasesAndRects[numResults];
     *  for (int i = 0; i < resultAtlasesAndRects.Length; i++)
     *  {
     *      resultAtlasesAndRects[i] = new MB_AtlasesAndRects();
     *  }
     *
     *  //Do the material combining.
     *  for (int i = 0; i < resultAtlasesAndRects.Length; i++)
     *  {
     *      Material resMatToPass = null;
     *      List<Material> sourceMats = null;
     *      if (_doMultiMaterial)
     *      {
     *          sourceMats = resultMaterials[i].sourceMaterials;
     *          resMatToPass = resultMaterials[i].combinedMaterial;
     *      }
     *      else
     *      {
     *          resMatToPass = _resultMaterial;
     *      }
     *      Debug.Log(string.Format("Creating atlases for result material {0} using shader {1}", resMatToPass, resMatToPass.shader));
     *      if (!combiner.CombineTexturesIntoAtlases(progressInfo, resultAtlasesAndRects[i], resMatToPass, objsToMesh, sourceMats, editorMethods))
     *      {
     *          return null;
     *      }
     *  }
     *
     *  //Save the results
     *  textureBakeResults.combinedMaterialInfo = resultAtlasesAndRects;
     *  textureBakeResults.doMultiMaterial = _doMultiMaterial;
     *  textureBakeResults.resultMaterial = _resultMaterial;
     *  textureBakeResults.resultMaterials = resultMaterials;
     *  textureBakeResults.fixOutOfBoundsUVs = combiner.fixOutOfBoundsUVs;
     *  unpackMat2RectMap(textureBakeResults);
     *
     *  //set the texture bake resultAtlasesAndRects on the Mesh Baker component if it exists
     *  MB3_MeshBakerCommon[] mb = GetComponentsInChildren<MB3_MeshBakerCommon>();
     *  for (int i = 0; i < mb.Length; i++)
     *  {
     *      mb[i].textureBakeResults = textureBakeResults;
     *  }
     *
     *  if (LOG_LEVEL >= MB2_LogLevel.info) Debug.Log("Created Atlases");
     *  return resultAtlasesAndRects;
     * }
     */

    void unpackMat2RectMap(MB2_TextureBakeResults tbr)
    {
        List <Material>             ms  = new List <Material>();
        List <MB_MaterialAndUVRect> mss = new List <MB_MaterialAndUVRect>();
        List <Rect> rs = new List <Rect>();

        for (int i = 0; i < tbr.combinedMaterialInfo.Length; i++)
        {
            MB_AtlasesAndRects          newMesh = tbr.combinedMaterialInfo[i];
            List <MB_MaterialAndUVRect> map     = newMesh.mat2rect_map;
            for (int j = 0; j < map.Count; j++)
            {
                mss.Add(map[j]);
                ms.Add(map[j].material);
                rs.Add(map[j].atlasRect);
            }
        }
        tbr.materialsAndUVRects = mss.ToArray();
        tbr.materials           = ms.ToArray();
        tbr.prefabUVRects       = rs.ToArray();
    }
Example #14
0
 public MB_AtlasesAndRects[] CreateAtlases(ProgressUpdateDelegate progressInfo, bool saveAtlasesAsAssets = false, MB2_EditorMethodsInterface editorMethods = null)
 {
     MB_AtlasesAndRects[] array = null;
     try
     {
         array = this._CreateAtlases(progressInfo, saveAtlasesAsAssets, editorMethods);
     }
     catch (Exception message)
     {
         Debug.LogError(message);
     }
     finally
     {
         if (saveAtlasesAsAssets && array != null)
         {
             for (int i = 0; i < array.Length; i++)
             {
                 MB_AtlasesAndRects mB_AtlasesAndRects = array[i];
                 if (mB_AtlasesAndRects != null && mB_AtlasesAndRects.atlases != null)
                 {
                     for (int j = 0; j < mB_AtlasesAndRects.atlases.Length; j++)
                     {
                         if (mB_AtlasesAndRects.atlases[j] != null)
                         {
                             if (editorMethods != null)
                             {
                                 editorMethods.Destroy(mB_AtlasesAndRects.atlases[j]);
                             }
                             else
                             {
                                 MB_Utility.Destroy(mB_AtlasesAndRects.atlases[j]);
                             }
                         }
                     }
                 }
             }
         }
     }
     return(array);
 }
Example #15
0
 /// <summary>
 /// Creates the atlases.
 /// </summary>
 /// <returns>
 /// The atlases.
 /// </returns>
 /// <param name='progressInfo'>
 /// Progress info is a delegate function that displays a progress dialog. Can be null
 /// </param>
 /// <param name='saveAtlasesAsAssets'>
 /// if true atlases are saved as assets in the project folder. Othersise they are instances in memory
 /// </param>
 /// <param name='textureFormatTracker'>
 /// Texture format tracker. Contains editor functionality such as save assets. Can be null.
 /// </param>
 public MB_AtlasesAndRects[] CreateAtlases(ProgressUpdateDelegate progressInfo, bool saveAtlasesAsAssets = false, MB2_EditorMethodsInterface textureFormatTracker = null)
 {
     MB_AtlasesAndRects[] mAndAs = null;
     try{
         mAndAs = _CreateAtlases(progressInfo, saveAtlasesAsAssets, textureFormatTracker);
     } catch (Exception e) {
         Debug.LogError(e);
     } finally {
         if (saveAtlasesAsAssets)              //Atlases were saved to project so we don't need these ones
         {
             if (mAndAs != null)
             {
                 for (int j = 0; j < mAndAs.Length; j++)
                 {
                     MB_AtlasesAndRects mAndA = mAndAs[j];
                     if (mAndA != null && mAndA.atlases != null)
                     {
                         for (int i = 0; i < mAndA.atlases.Length; i++)
                         {
                             if (mAndA.atlases[i] != null)
                             {
                                 if (textureFormatTracker != null)
                                 {
                                     textureFormatTracker.Destroy(mAndA.atlases[i]);
                                 }
                                 else
                                 {
                                     MB_Utility.Destroy(mAndA.atlases[i]);
                                 }
                             }
                         }
                     }
                 }
             }
         }
     }
     return(mAndAs);
 }
Example #16
0
 /**
  * pass in System.IO.File.WriteAllBytes for parameter fileSaveFunction. This is necessary because on Web Player file saving
  * functions only exist for Editor classes
  */
 public void CreateAndSaveAtlases(ProgressUpdateDelegate progressInfo, MB_TextureCombiner.FileSaveFunction fileSaveFunction)
 {
     MB_AtlasesAndRects[] mAndAs = null;
     try{
         if (doCombinedValidate(this, MB_ObjsToCombineTypes.dontCare))
         {
             mAndAs = CreateAtlases(progressInfo, true, fileSaveFunction);
             if (mAndAs != null)
             {
                 MB2_MeshBakerCommon mb = GetComponent <MB2_MeshBakerCommon>();
                 if (mb != null)
                 {
                     mb.textureBakeResults = textureBakeResults;
                 }
             }
         }
     } catch (Exception e) {
         Debug.LogError(e);
     } finally {
         if (mAndAs != null)
         {
             for (int j = 0; j < mAndAs.Length; j++)
             {
                 MB_AtlasesAndRects mAndA = mAndAs[j];
                 if (mAndA != null && mAndA.atlases != null)
                 {
                     for (int i = 0; i < mAndA.atlases.Length; i++)
                     {
                         if (mAndA.atlases[i] != null)
                         {
                             MB_Utility.Destroy(mAndA.atlases[i]);
                         }
                     }
                 }
             }
         }
     }
 }
Example #17
0
    void _saveBakeTextureAssets(MB2_TextureBaker target, MB_AtlasesAndRects[] mAndAs)
    {
        MB2_TextureBaker mbd = (MB2_TextureBaker)target;

        for (int i = 0; i < mAndAs.Length; i++)
        {
            MB_AtlasesAndRects mAndA  = mAndAs[i];
            Material           resMat = mbd.resultMaterial;
            if (mbd.doMultiMaterial)
            {
                resMat = mbd.resultMaterials[i].combinedMaterial;
            }
            _saveAtlasesToAssetDatabase(mAndA, resMat);
        }

        MB2_MeshBaker mb = mbd.GetComponent <MB2_MeshBaker>();

        if (mb != null)
        {
            mb.textureBakeResults = mbd.textureBakeResults;
        }
        EditorUtility.SetDirty(mbd.textureBakeResults);
    }
Example #18
0
    void unpackMat2RectMap(MB2_TextureBakeResults tbr)
    {
        List <Material>             ms  = new List <Material>();
        List <MB_MaterialAndUVRect> mss = new List <MB_MaterialAndUVRect>();
        List <Rect> rs = new List <Rect>();

        for (int i = 0; i < OnCombinedTexturesCoroutineAtlasesAndRects.Length; i++)
        {
            MB_AtlasesAndRects          newMesh = this.OnCombinedTexturesCoroutineAtlasesAndRects[i];
            List <MB_MaterialAndUVRect> map     = newMesh.mat2rect_map;
            if (map != null)
            {
                for (int j = 0; j < map.Count; j++)
                {
                    mss.Add(map[j]);
                    ms.Add(map[j].material);
                    rs.Add(map[j].atlasRect);
                }
            }
        }
        tbr.version             = MB2_TextureBakeResults.VERSION;
        tbr.materialsAndUVRects = mss.ToArray();
    }
Example #19
0
    bool _combineTexturesIntoAtlases(ProgressUpdateDelegate progressInfo, MB_AtlasesAndRects results, Material[] resultMaterials, List <GameObject> objsToMesh, List <Material> sourceMaterials, int atlasPadding, List <string> customShaderPropNames, bool resizePowerOfTwoTextures, bool fixOutOfBoundsUVs, int maxTilingBakeSize)
    {
        _temporaryTextures.Clear();
        _texturesWithReadWriteFlagSet.Clear();
#if UNITY_EDITOR
        _textureFormatMap.Clear();
#endif
        List <GameObject> mcs = objsToMesh;
        if (mcs == null || mcs.Count == 0)
        {
            Debug.LogError("No meshes to combine. Please assign some meshes to combine.");
            return(false);
        }
        if (atlasPadding < 0)
        {
            Debug.LogError("Atlas padding must be zero or greater.");
            return(false);
        }
        if (maxTilingBakeSize < 2 || maxTilingBakeSize > 4096)
        {
            Debug.LogError("Invalid value for max tiling bake size.");
            return(false);
        }

        if (progressInfo != null)
        {
            progressInfo("Collecting textures for " + mcs.Count + " meshes.", .01f);
        }

        List <string> texPropertyNames = new List <string>();
        if (!_collectPropertyNames(resultMaterials, customShaderPropNames, texPropertyNames))
        {
            return(false);
        }

        return(__combineTexturesIntoAtlases(progressInfo, results, texPropertyNames, objsToMesh, sourceMaterials, atlasPadding, resizePowerOfTwoTextures, fixOutOfBoundsUVs, maxTilingBakeSize));
    }
Example #20
0
    public IEnumerator CreateAtlasesCoroutine(ProgressUpdateDelegate progressInfo, CreateAtlasesCoroutineResult coroutineResult, bool saveAtlasesAsAssets = false, MB2_EditorMethodsInterface editorMethods = null, float maxTimePerFrame = .01f)
    {
        MBVersionConcrete mbv = new MBVersionConcrete();

        if (!MB3_TextureCombiner._RunCorutineWithoutPauseIsRunning && (mbv.GetMajorVersion() < 5 || (mbv.GetMajorVersion() == 5 && mbv.GetMinorVersion() < 3)))
        {
            Debug.LogError("Running the texture combiner as a coroutine only works in Unity 5.3 and higher");
            coroutineResult.success = false;
            yield break;
        }
        this.OnCombinedTexturesCoroutineAtlasesAndRects = null;

        if (maxTimePerFrame <= 0f)
        {
            Debug.LogError("maxTimePerFrame must be a value greater than zero");
            coroutineResult.isFinished = true;
            yield break;
        }
        MB2_ValidationLevel vl = Application.isPlaying ? MB2_ValidationLevel.quick : MB2_ValidationLevel.robust;

        if (!DoCombinedValidate(this, MB_ObjsToCombineTypes.dontCare, null, vl))
        {
            coroutineResult.isFinished = true;
            yield break;
        }
        if (_doMultiMaterial && !_ValidateResultMaterials())
        {
            coroutineResult.isFinished = true;
            yield break;
        }
        else if (!_doMultiMaterial)
        {
            if (_resultMaterial == null)
            {
                Debug.LogError("Combined Material is null please create and assign a result material.");
                coroutineResult.isFinished = true;
                yield break;
            }
            Shader targShader = _resultMaterial.shader;
            for (int i = 0; i < objsToMesh.Count; i++)
            {
                Material[] ms = MB_Utility.GetGOMaterials(objsToMesh[i]);
                for (int j = 0; j < ms.Length; j++)
                {
                    Material m = ms[j];
                    if (m != null && m.shader != targShader)
                    {
                        Debug.LogWarning("Game object " + objsToMesh[i] + " does not use shader " + targShader + " it may not have the required textures. If not small solid color textures will be generated.");
                    }
                }
            }
        }

        MB3_TextureCombiner combiner = CreateAndConfigureTextureCombiner();

        combiner.saveAtlasesAsAssets = saveAtlasesAsAssets;

        //initialize structure to store results
        int numResults = 1;

        if (_doMultiMaterial)
        {
            numResults = resultMaterials.Length;
        }
        OnCombinedTexturesCoroutineAtlasesAndRects = new MB_AtlasesAndRects[numResults];
        for (int i = 0; i < OnCombinedTexturesCoroutineAtlasesAndRects.Length; i++)
        {
            OnCombinedTexturesCoroutineAtlasesAndRects[i] = new MB_AtlasesAndRects();
        }

        //Do the material combining.
        for (int i = 0; i < OnCombinedTexturesCoroutineAtlasesAndRects.Length; i++)
        {
            Material        resMatToPass = null;
            List <Material> sourceMats   = null;
            if (_doMultiMaterial)
            {
                sourceMats   = resultMaterials[i].sourceMaterials;
                resMatToPass = resultMaterials[i].combinedMaterial;
                combiner.fixOutOfBoundsUVs = resultMaterials[i].considerMeshUVs;
            }
            else
            {
                resMatToPass = _resultMaterial;
            }

            MB3_TextureCombiner.CombineTexturesIntoAtlasesCoroutineResult coroutineResult2 = new MB3_TextureCombiner.CombineTexturesIntoAtlasesCoroutineResult();
            yield return(combiner.CombineTexturesIntoAtlasesCoroutine(progressInfo, OnCombinedTexturesCoroutineAtlasesAndRects[i], resMatToPass, objsToMesh, sourceMats, editorMethods, coroutineResult2, maxTimePerFrame));

            coroutineResult.success = coroutineResult2.success;
            if (!coroutineResult.success)
            {
                coroutineResult.isFinished = true;
                yield break;
            }
        }

        unpackMat2RectMap(textureBakeResults);
        //Save the results
        textureBakeResults.doMultiMaterial = _doMultiMaterial;
        //textureBakeResults.resultMaterial = _resultMaterial;
        if (_doMultiMaterial)
        {
            textureBakeResults.resultMaterials = resultMaterials;
        }
        else
        {
            MB_MultiMaterial[] resMats = new MB_MultiMaterial[1];
            resMats[0] = new MB_MultiMaterial();
            resMats[0].combinedMaterial = _resultMaterial;
            resMats[0].considerMeshUVs  = _fixOutOfBoundsUVs;
            resMats[0].sourceMaterials  = new List <Material>();
            for (int i = 0; i < textureBakeResults.materialsAndUVRects.Length; i++)
            {
                resMats[0].sourceMaterials.Add(textureBakeResults.materialsAndUVRects[i].material);
            }
            textureBakeResults.resultMaterials = resMats;
        }
        //textureBakeResults.fixOutOfBoundsUVs = combiner.fixOutOfBoundsUVs;


        //set the texture bake resultAtlasesAndRects on the Mesh Baker component if it exists
        MB3_MeshBakerCommon[] mb = GetComponentsInChildren <MB3_MeshBakerCommon>();
        for (int i = 0; i < mb.Length; i++)
        {
            mb[i].textureBakeResults = textureBakeResults;
        }

        if (LOG_LEVEL >= MB2_LogLevel.info)
        {
            Debug.Log("Created Atlases");
        }

        coroutineResult.isFinished = true;
        if (coroutineResult.success && onBuiltAtlasesSuccess != null)
        {
            onBuiltAtlasesSuccess();
        }
        if (!coroutineResult.success && onBuiltAtlasesFail != null)
        {
            onBuiltAtlasesFail();
        }
    }
        //texPropertyNames is the list of texture properties in the resultMaterial
        //allowedMaterialsFilter is a list of materials. Objects without any of these materials will be ignored.
        //                         this is used by the multiple materials filter
        //textureEditorMethods encapsulates editor only functionality such as saving assets and tracking texture assets whos format was changed. Is null if using at runtime.
        bool __CombineTexturesIntoAtlases(ProgressUpdateDelegate progressInfo, MB_AtlasesAndRects resultAtlasesAndRects, Material resultMaterial, List<ShaderTextureProperty> texPropertyNames, List<GameObject> objsToMesh, List<Material> allowedMaterialsFilter, MB2_EditorMethodsInterface textureEditorMethods)
        {
            if (LOG_LEVEL >= MB2_LogLevel.debug) Debug.Log("__CombineTexturesIntoAtlases atlases:" + texPropertyNames.Count + " objsToMesh:" + objsToMesh.Count + " _fixOutOfBoundsUVs:" + _fixOutOfBoundsUVs);

            if (progressInfo != null) progressInfo("Collecting textures ", .01f);
            /*
            each atlas (maintex, bump, spec etc...) will have distinctMaterialTextures.Count images in it.
            each distinctMaterialTextures record is a set of textures, one for each atlas. And a list of materials
            that use that distinct set of textures.
            */
            List<MB_TexSet> distinctMaterialTextures = new List<MB_TexSet>(); //one per distinct set of textures
            List<GameObject> usedObjsToMesh = new List<GameObject>();
            if (!__Step1_CollectDistinctMatTexturesAndUsedObjects(objsToMesh, allowedMaterialsFilter, texPropertyNames, textureEditorMethods, distinctMaterialTextures, usedObjsToMesh)){
                return false;
            }

            if (MB3_MeshCombiner.EVAL_VERSION){
                bool usesAllowedShaders = true;
                for (int i = 0; i < distinctMaterialTextures.Count; i++){
                    for (int j = 0; j < distinctMaterialTextures[i].mats.Count; j++){
                        if (!distinctMaterialTextures[i].mats[j].shader.name.EndsWith("Diffuse") &&
                            !distinctMaterialTextures[i].mats[j].shader.name.EndsWith("Bumped Diffuse")){
                            Debug.LogError ("The free version of Mesh Baker only works with Diffuse and Bumped Diffuse Shaders. The full version can be used with any shader. Material " + distinctMaterialTextures[i].mats[j].name + " uses shader " + distinctMaterialTextures[i].mats[j].shader.name);
                            usesAllowedShaders = false;
                        }
                    }
                }
                if (!usesAllowedShaders) return false;
            }

            //Textures in each material (_mainTex, Bump, Spec ect...) must be same size
            //Calculate the best sized to use. Takes into account tiling
            //if only one texture in atlas re-uses original sizes
            bool[] allTexturesAreNullAndSameColor = new bool[texPropertyNames.Count];
            int _padding = __Step2_CalculateIdealSizesForTexturesInAtlasAndPadding(distinctMaterialTextures,texPropertyNames,allTexturesAreNullAndSameColor);

            __Step3_BuildAndSaveAtlasesAndStoreResults(progressInfo,distinctMaterialTextures,texPropertyNames,allTexturesAreNullAndSameColor,_padding,textureEditorMethods,resultAtlasesAndRects,resultMaterial);

            return true;
        }
 /**<summary>Combines meshes and generates texture atlases.</summary>
 *  <param name="createTextureAtlases">Whether or not texture atlases should be created. If not uvs will not be adjusted.</param>
 *  <param name="progressInfo">A delegate function that will be called to report progress.</param>
 *  <param name="textureEditorMethods">If called from the editor should be an instance of MB2_EditorMethods. If called at runtime should be null.</param>
 *  <remarks>Combines meshes and generates texture atlases</remarks> */
 public bool CombineTexturesIntoAtlases(ProgressUpdateDelegate progressInfo, MB_AtlasesAndRects resultAtlasesAndRects, Material resultMaterial, List<GameObject> objsToMesh, List<Material> allowedMaterialsFilter, MB2_EditorMethodsInterface textureEditorMethods = null)
 {
     return _CombineTexturesIntoAtlases(progressInfo,resultAtlasesAndRects, resultMaterial, objsToMesh, allowedMaterialsFilter, textureEditorMethods);
 }
	MB_AtlasesAndRects[] _CreateAtlases(ProgressUpdateDelegate progressInfo, bool saveAtlasesAsAssets = false, MB2_EditorMethodsInterface textureFormatTracker=null){
		//validation
		if (saveAtlasesAsAssets && textureFormatTracker == null){
			Debug.LogError("Error in CreateAtlases If saveAtlasesAsAssets = true then textureFormatTracker cannot be null.");
			return null;
		}
		if (saveAtlasesAsAssets && !Application.isEditor){
			Debug.LogError("Error in CreateAtlases If saveAtlasesAsAssets = true it must be called from the Unity Editor.");
			return null;			
		}
		if (!doCombinedValidate(this, MB_ObjsToCombineTypes.dontCare, textureFormatTracker)){
			return null;
		}
		if (doMultiMaterial && !_ValidateResultMaterials()){
			return null;
		} else if (!doMultiMaterial){
			if (resultMaterial == null){
				Debug.LogError("Combined Material is null please create and assign a result material.");
				return null;
			}
			Shader targShader = resultMaterial.shader;
			for (int i = 0; i < objsToMesh.Count; i++){
				Material[] ms = MB_Utility.GetGOMaterials(objsToMesh[i]);
				for (int j = 0; j < ms.Length; j++){
					Material m = ms[j];
					if (m != null && m.shader != targShader){
						Debug.LogWarning("Game object " + objsToMesh[i] + " does not use shader " + targShader + " it may not have the required textures. If not 2x2 clear textures will be generated.");
					}

				}
			}
		}

		for (int i = 0; i < objsToMesh.Count; i++){
			Material[] ms = MB_Utility.GetGOMaterials(objsToMesh[i]);
			for (int j = 0; j < ms.Length; j++){
				Material m = ms[j];
				if (m == null){
					Debug.LogError("Game object " + objsToMesh[i] + " has a null material. Can't build atlases");
					return null;
				}

			}
		}		
		
		MB_TextureCombiner combiner = new MB_TextureCombiner();	
		// if editor analyse meshes and suggest treatment
		if (!Application.isPlaying){
			Material[] rms;
			if (doMultiMaterial){
				rms = new Material[resultMaterials.Length];
				for (int i = 0; i < rms.Length; i++) rms[i] = resultMaterials[i].combinedMaterial;
			} else {
				rms = new Material[1];
				rms[0] = resultMaterial;
			}
			combiner.SuggestTreatment(objsToMesh, rms, customShaderPropNames);
		}		
		
		//initialize structure to store results
		int numResults = 1;
		if (doMultiMaterial) numResults = resultMaterials.Length;
		MB_AtlasesAndRects[] resultAtlasesAndRects = new MB_AtlasesAndRects[numResults];
		for (int i = 0; i < resultAtlasesAndRects.Length; i++){
			resultAtlasesAndRects[i] = new MB_AtlasesAndRects();
		}
		
		//Do the material combining.
		for (int i = 0; i < resultAtlasesAndRects.Length; i++){
			Material resMatToPass = null;
			List<Material> sourceMats = null;			
			if (doMultiMaterial) {
				sourceMats = resultMaterials[i].sourceMaterials;
				resMatToPass = resultMaterials[i].combinedMaterial;
			} else {
				resMatToPass = resultMaterial;	
			}
			Debug.Log("Creating atlases for result material " + resMatToPass);
			if(!combiner.combineTexturesIntoAtlases(progressInfo, resultAtlasesAndRects[i], resMatToPass, objsToMesh, sourceMats, atlasPadding, customShaderPropNames, resizePowerOfTwoTextures, fixOutOfBoundsUVs, maxTilingBakeSize, saveAtlasesAsAssets, texturePackingAlgorithm, textureFormatTracker)){
				return null;
			}
		}
		
		//Save the results
		textureBakeResults.combinedMaterialInfo = resultAtlasesAndRects;
		textureBakeResults.doMultiMaterial = doMultiMaterial;
		textureBakeResults.resultMaterial = resultMaterial;
		textureBakeResults.resultMaterials = resultMaterials;
		textureBakeResults.fixOutOfBoundsUVs = fixOutOfBoundsUVs;
		unpackMat2RectMap(textureBakeResults);
		
		//originally did all the assign of atlases to the result materials here
		//don't touch result material assets until we are sure atlas creation worked.
		//unfortunatly Unity has a bug where it Destroys Texture2Ds without warning when memory gets low and generates MissingReferenceException
		//so if generating assets in editor then save and assign atlases as soon as each atlas is created
//			if (Application.isPlaying){
//				if (doMultiMaterial){
//					for (int j = 0; j < resultMaterials.Length; j++){
//						Material resMat = resultMaterials[j].combinedMaterial; //resultMaterials[j].combinedMaterial;
//						Texture2D[] atlases = resultAtlasesAndRects[j].atlases;
//						for(int i = 0; i < atlases.Length;i++){
//							resMat.SetTexture(resultAtlasesAndRects[j].texPropertyNames[i], atlases[i]);
//						}
//					}					
//				} else {
//					Material resMat = resultMaterial; //resultMaterials[j].combinedMaterial;
//					Texture2D[] atlases = resultAtlasesAndRects[0].atlases;
//					for(int i = 0; i < atlases.Length;i++){
//						resMat.SetTexture(resultAtlasesAndRects[0].texPropertyNames[i], atlases[i]);
//					}
//				}
//			}
		
		//set the texture bake resultAtlasesAndRects on the Mesh Baker component if it exists
		MB2_MeshBakerCommon mb = GetComponent<MB2_MeshBakerCommon>();
		if (mb != null){
			mb.textureBakeResults = textureBakeResults;	
		}			
		
		if (VERBOSE) Debug.Log("Created Atlases");		
		return resultAtlasesAndRects;
	}		
		void __Step3_BuildAndSaveAtlasesAndStoreResults(ProgressUpdateDelegate progressInfo, List<MB_TexSet> distinctMaterialTextures, List<ShaderTextureProperty> texPropertyNames, bool[] allTexturesAreNullAndSameColor, int _padding, MB2_EditorMethodsInterface textureEditorMethods, MB_AtlasesAndRects resultAtlasesAndRects, Material resultMaterial){
			System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
			sw.Start();
			// note that we may not create some of the atlases because all textures are null
			int numAtlases = texPropertyNames.Count;

			//generate report want to do this before
			//todo if atlas is compressed then doesn't report correct compression 
			StringBuilder report = new StringBuilder();
			if (numAtlases > 0){
				report = new StringBuilder();
				report.AppendLine("Report");
				for (int i = 0; i < distinctMaterialTextures.Count; i++){
					MB_TexSet txs = distinctMaterialTextures[i];
					report.AppendLine("----------");
					report.Append("This set of textures will be resized to:" + txs.idealWidth + "x" + txs.idealHeight + "\n");
					for (int j = 0; j < txs.ts.Length; j++){
						if (txs.ts[j].t != null){
							report.Append("   [" + texPropertyNames[j].name + " " + txs.ts[j].t.name + " " + txs.ts[j].t.width + "x" + txs.ts[j].t.height + "]");
							if (txs.ts[j].scale != Vector2.one || txs.ts[j].offset != Vector2.zero) report.AppendFormat(" material scale {0} offset{1} ", txs.ts[j].scale.ToString("G4"), txs.ts[j].offset.ToString("G4"));
							if (txs.ts[j].obUVscale != Vector2.one || txs.ts[j].obUVoffset != Vector2.zero) report.AppendFormat(" obUV scale {0} offset{1} ", txs.ts[j].obUVscale.ToString("G4"), txs.ts[j].obUVoffset.ToString("G4"));
							report.AppendLine("");
						} else { 
							report.Append("   [" + texPropertyNames[j].name + " null ");
							if (allTexturesAreNullAndSameColor[j]){
								report.Append ("no atlas will be created all textures null]\n");
							} else {
								report.AppendFormat("a 16x16 texture will be created with color {0}]\n",txs.ts[j].colorIfNoTexture);
							}
						}
					}
					report.AppendLine("");
					report.Append("Materials using:");
					for (int j = 0; j < txs.mats.Count; j++){
						report.Append(txs.mats[j].name + ", ");
					}
					report.AppendLine("");
				}
			}		
	
			if (progressInfo != null) progressInfo("Creating txture atlases.", .1f);

			//run the garbage collector to free up as much memory as possible before bake to reduce MissingReferenceException problems
			GC.Collect();
			Texture2D[] atlases = new Texture2D[numAtlases];			
			Rect[] uvRects;
			if (LOG_LEVEL >= MB2_LogLevel.debug) Debug.Log ("time Step 3 Create And Save Atlases part 1 " + sw.ElapsedMilliseconds.ToString("f5") );
			if (_packingAlgorithm == MB2_PackingAlgorithmEnum.UnitysPackTextures){
				uvRects = __CreateAtlasesUnityTexturePacker(progressInfo, numAtlases, distinctMaterialTextures, texPropertyNames, allTexturesAreNullAndSameColor, resultMaterial, atlases, textureEditorMethods, _padding);
			} else if (_packingAlgorithm == MB2_PackingAlgorithmEnum.MeshBakerTexturePacker) {
				uvRects = __CreateAtlasesMBTexturePacker(progressInfo, numAtlases, distinctMaterialTextures, texPropertyNames, allTexturesAreNullAndSameColor, resultMaterial, atlases, textureEditorMethods, _padding);
			} else {
				uvRects = __CreateAtlasesMBTexturePackerFast(progressInfo, numAtlases, distinctMaterialTextures, texPropertyNames, allTexturesAreNullAndSameColor, resultMaterial, atlases, textureEditorMethods, _padding);
			}
			float t3 = sw.ElapsedMilliseconds;

			AdjustNonTextureProperties(resultMaterial,texPropertyNames,distinctMaterialTextures,textureEditorMethods);

			if (progressInfo != null) progressInfo("Building Report",.7f);
			
			//report on atlases created
			StringBuilder atlasMessage = new StringBuilder();
			atlasMessage.AppendLine("---- Atlases ------");
			for (int i = 0; i < numAtlases; i++){
				if (atlases[i] != null){
					atlasMessage.AppendLine("Created Atlas For: " + texPropertyNames[i].name + " h=" + atlases[i].height + " w=" + atlases[i].width);
				} else if (allTexturesAreNullAndSameColor[i]){
					atlasMessage.AppendLine("Did not create atlas for " + texPropertyNames[i].name + " because all source textures were null.");
				}	
			}
			report.Append(atlasMessage.ToString());
			
			
			Dictionary<Material,Rect> mat2rect_map = new Dictionary<Material, Rect>();
			for (int i = 0; i < distinctMaterialTextures.Count; i++){
				List<Material> mats = distinctMaterialTextures[i].mats;
				for (int j = 0; j < mats.Count; j++){
					if (!mat2rect_map.ContainsKey(mats[j])){
						mat2rect_map.Add(mats[j],uvRects[i]);
					}
				}
			}
			
			resultAtlasesAndRects.atlases = atlases;                             // one per texture on source shader
			resultAtlasesAndRects.texPropertyNames = ShaderTextureProperty.GetNames(texPropertyNames); // one per texture on source shader
			resultAtlasesAndRects.mat2rect_map = mat2rect_map;
			
			if (progressInfo != null) progressInfo("Restoring Texture Formats & Read Flags",.8f);
			_destroyTemporaryTextures();
			if (textureEditorMethods != null) textureEditorMethods.SetReadFlags(progressInfo);
			if (report != null && LOG_LEVEL >= MB2_LogLevel.info) Debug.Log(report.ToString());	
			if (LOG_LEVEL >= MB2_LogLevel.debug) Debug.Log ("Time Step 3 Create And Save Atlases part 3 " + (sw.ElapsedMilliseconds - t3).ToString("f5"));
			if (LOG_LEVEL >= MB2_LogLevel.debug) Debug.Log ("Total time Step 3 Create And Save Atlases " + sw.ElapsedMilliseconds.ToString("f5"));
		}
		bool _combineTexturesIntoAtlases(ProgressUpdateDelegate progressInfo, MB_AtlasesAndRects resultAtlasesAndRects, Material resultMaterial, List<GameObject> objsToMesh, List<Material> allowedMaterialsFilter, MB2_EditorMethodsInterface textureEditorMethods){
			bool success = false;
			try{
				_temporaryTextures.Clear();
				
				if (textureEditorMethods != null) textureEditorMethods.Clear();

				if (objsToMesh == null || objsToMesh.Count == 0){
					Debug.LogError("No meshes to combine. Please assign some meshes to combine.");
					return false;
				}
				if (atlasPadding < 0){
					Debug.LogError("Atlas padding must be zero or greater.");
					return false;
				}
				if (maxTilingBakeSize < 2 || maxTilingBakeSize > 4096){
					Debug.LogError("Invalid value for max tiling bake size.");
					return false;			
				}
				
				if (progressInfo != null)
					progressInfo("Collecting textures for " + objsToMesh.Count + " meshes.", .01f);
				
				List<string> texPropertyNames = new List<string>();	
				if (!_collectPropertyNames(resultMaterial, texPropertyNames)){
					return false;
				}
				success = __combineTexturesIntoAtlases(progressInfo,resultAtlasesAndRects, resultMaterial, texPropertyNames, objsToMesh,allowedMaterialsFilter, textureEditorMethods);
			} catch (MissingReferenceException mrex){
				Debug.LogError("Creating atlases failed a MissingReferenceException was thrown. This is normally only happens when trying to create very large atlases and Unity is running out of Memory. Try changing the 'Texture Packer' to a different option, it may work with an alternate packer. This error is sometimes intermittant. Try baking again.");
				Debug.LogError(mrex);
			} catch (Exception ex){
				Debug.LogError(ex);
			} finally {
				_destroyTemporaryTextures();
				if (textureEditorMethods != null) textureEditorMethods.SetReadFlags(progressInfo);
			}
			return success;
		}
    private IEnumerator _CreateAtlasesCoroutineAtlases(MB3_TextureCombiner combiner, ProgressUpdateDelegate progressInfo, MB3_TextureCombiner.CreateAtlasesCoroutineResult coroutineResult, bool saveAtlasesAsAssets = false, MB2_EditorMethodsInterface editorMethods = null, float maxTimePerFrame = .01f)
    {
        int numResults = 1;

        if (_doMultiMaterial)
        {
            numResults = resultMaterials.Length;
        }

        OnCombinedTexturesCoroutineAtlasesAndRects = new MB_AtlasesAndRects[numResults];
        for (int i = 0; i < OnCombinedTexturesCoroutineAtlasesAndRects.Length; i++)
        {
            OnCombinedTexturesCoroutineAtlasesAndRects[i] = new MB_AtlasesAndRects();
        }

        //Do the material combining.
        for (int i = 0; i < OnCombinedTexturesCoroutineAtlasesAndRects.Length; i++)
        {
            Material        resMatToPass = null;
            List <Material> sourceMats   = null;
            if (_doMultiMaterial)
            {
                sourceMats   = resultMaterials[i].sourceMaterials;
                resMatToPass = resultMaterials[i].combinedMaterial;
                combiner.fixOutOfBoundsUVs = resultMaterials[i].considerMeshUVs;
            }
            else
            {
                resMatToPass = _resultMaterial;
            }

            MB3_TextureCombiner.CombineTexturesIntoAtlasesCoroutineResult coroutineResult2 = new MB3_TextureCombiner.CombineTexturesIntoAtlasesCoroutineResult();
            yield return(combiner.CombineTexturesIntoAtlasesCoroutine(progressInfo, OnCombinedTexturesCoroutineAtlasesAndRects[i], resMatToPass, objsToMesh, sourceMats, editorMethods, coroutineResult2, maxTimePerFrame,
                                                                      onlyPackRects: false, splitAtlasWhenPackingIfTooBig: false));

            coroutineResult.success = coroutineResult2.success;
            if (!coroutineResult.success)
            {
                coroutineResult.isFinished = true;
                yield break;
            }
        }

        unpackMat2RectMap(OnCombinedTexturesCoroutineAtlasesAndRects);
        if (coroutineResult.success && editorMethods != null)
        {
            editorMethods.GetMaterialPrimaryKeysIfAddressables(textureBakeResults);
        }
        //Save the results
        textureBakeResults.resultType = MB2_TextureBakeResults.ResultType.atlas;
        textureBakeResults.resultMaterialsTexArray = new MB_MultiMaterialTexArray[0];
        textureBakeResults.doMultiMaterial         = _doMultiMaterial;
        if (_doMultiMaterial)
        {
            textureBakeResults.resultMaterials = resultMaterials;
        }
        else
        {
            MB_MultiMaterial[] resMats = new MB_MultiMaterial[1];
            resMats[0] = new MB_MultiMaterial();
            resMats[0].combinedMaterial = _resultMaterial;
            resMats[0].considerMeshUVs  = _fixOutOfBoundsUVs;
            resMats[0].sourceMaterials  = new List <Material>();
            for (int i = 0; i < textureBakeResults.materialsAndUVRects.Length; i++)
            {
                resMats[0].sourceMaterials.Add(textureBakeResults.materialsAndUVRects[i].material);
            }
            textureBakeResults.resultMaterials = resMats;
        }

        if (LOG_LEVEL >= MB2_LogLevel.info)
        {
            Debug.Log("Created Atlases");
        }
    }
Example #27
0
        IEnumerator __RunTexturePackerOnly(CombineTexturesIntoAtlasesCoroutineResult result, MB_AtlasesAndRects resultAtlasesAndRects, MB3_TextureCombinerPipeline.TexturePipelineData data, bool splitAtlasWhenPackingIfTooBig, MB2_EditorMethodsInterface textureEditorMethods, List <AtlasPackingResult> packingResult)
        {
            MB3_TextureCombinerPipeline pipeline = new MB3_TextureCombinerPipeline();

            if (LOG_LEVEL >= MB2_LogLevel.debug)
            {
                Debug.Log("__RunTexturePacker texture properties in shader:" + data.texPropertyNames.Count + " objsToMesh:" + data.allObjsToMesh.Count + " _fixOutOfBoundsUVs:" + data._fixOutOfBoundsUVs);
            }
            List <GameObject> usedObjsToMesh = new List <GameObject>();

            yield return(pipeline.__Step1_CollectDistinctMatTexturesAndUsedObjects(null, result, data, this, textureEditorMethods, usedObjsToMesh, LOG_LEVEL));

            if (!result.success)
            {
                yield break;
            }

            data.allTexturesAreNullAndSameColor = new MB3_TextureCombinerPipeline.CreateAtlasForProperty[data.texPropertyNames.Count];
            yield return(pipeline.CalculateIdealSizesForTexturesInAtlasAndPadding(null, result, data, this, textureEditorMethods, LOG_LEVEL));

            if (!result.success)
            {
                yield break;
            }

            MB_ITextureCombinerPacker texturePaker = pipeline.CreatePacker(data.OnlyOneTextureInAtlasReuseTextures(), data._packingAlgorithm);

            //    run the texture packer only
            AtlasPackingResult[] aprs = pipeline.RunTexturePackerOnly(data, splitAtlasWhenPackingIfTooBig, resultAtlasesAndRects, texturePaker, LOG_LEVEL);
            for (int i = 0; i < aprs.Length; i++)
            {
                packingResult.Add(aprs[i]);
            }
        }
Example #28
0
	MB_AtlasesAndRects[] _CreateAtlases(ProgressUpdateDelegate progressInfo, bool saveAtlasesAsAssets = false, MB2_EditorMethodsInterface editorMethods=null){
		//validation
		if (saveAtlasesAsAssets && editorMethods == null){
			Debug.LogError("Error in CreateAtlases If saveAtlasesAsAssets = true then editorMethods cannot be null.");
			return null;
		}
		if (saveAtlasesAsAssets && !Application.isEditor){
			Debug.LogError("Error in CreateAtlases If saveAtlasesAsAssets = true it must be called from the Unity Editor.");
			return null;			
		}
		MB2_ValidationLevel vl = Application.isPlaying ? MB2_ValidationLevel.quick : MB2_ValidationLevel.robust; 
		if (!DoCombinedValidate(this, MB_ObjsToCombineTypes.dontCare, editorMethods, vl)){
			return null;
		}
		if (_doMultiMaterial && !_ValidateResultMaterials()){
			return null;
		} else if (!_doMultiMaterial){
			if (_resultMaterial == null){
				Debug.LogError("Combined Material is null please create and assign a result material.");
				return null;
			}
			Shader targShader = _resultMaterial.shader;
			for (int i = 0; i < objsToMesh.Count; i++){
				Material[] ms = MB_Utility.GetGOMaterials(objsToMesh[i]);
				for (int j = 0; j < ms.Length; j++){
					Material m = ms[j];
					if (m != null && m.shader != targShader){
						Debug.LogWarning("Game object " + objsToMesh[i] + " does not use shader " + targShader + " it may not have the required textures. If not 2x2 clear textures will be generated.");
					}

				}
			}
		}

		for (int i = 0; i < objsToMesh.Count; i++){
			Material[] ms = MB_Utility.GetGOMaterials(objsToMesh[i]);
			for (int j = 0; j < ms.Length; j++){
				Material m = ms[j];
				if (m == null){
					Debug.LogError("Game object " + objsToMesh[i] + " has a null material. Can't build atlases");
					return null;
				}

			}
		}		
		
		MB3_TextureCombiner combiner = new MB3_TextureCombiner();
		combiner.LOG_LEVEL = LOG_LEVEL;
		combiner.atlasPadding = _atlasPadding;
		combiner.maxAtlasSize = _maxAtlasSize;
		combiner.customShaderPropNames = _customShaderProperties;
		combiner.fixOutOfBoundsUVs = _fixOutOfBoundsUVs;
		combiner.maxTilingBakeSize = _maxTilingBakeSize;
		combiner.packingAlgorithm = _packingAlgorithm;
		combiner.meshBakerTexturePackerForcePowerOfTwo = _meshBakerTexturePackerForcePowerOfTwo;
		combiner.resizePowerOfTwoTextures = _resizePowerOfTwoTextures;
		combiner.saveAtlasesAsAssets = saveAtlasesAsAssets;

		// if editor analyse meshes and suggest treatment
		if (!Application.isPlaying){
			Material[] rms;
			if (_doMultiMaterial){
				rms = new Material[resultMaterials.Length];
				for (int i = 0; i < rms.Length; i++) rms[i] = resultMaterials[i].combinedMaterial;
			} else {
				rms = new Material[1];
				rms[0] = _resultMaterial;
			}
			combiner.SuggestTreatment(objsToMesh, rms, combiner.customShaderPropNames);
		}		
		
		//initialize structure to store results
		int numResults = 1;
		if (_doMultiMaterial) numResults = resultMaterials.Length;
		MB_AtlasesAndRects[] resultAtlasesAndRects = new MB_AtlasesAndRects[numResults];
		for (int i = 0; i < resultAtlasesAndRects.Length; i++){
			resultAtlasesAndRects[i] = new MB_AtlasesAndRects();
		}
		
		//Do the material combining.
		for (int i = 0; i < resultAtlasesAndRects.Length; i++){
			Material resMatToPass = null;
			List<Material> sourceMats = null;			
			if (_doMultiMaterial) {
				sourceMats = resultMaterials[i].sourceMaterials;
				resMatToPass = resultMaterials[i].combinedMaterial;
			} else {
				resMatToPass = _resultMaterial;	
			}
			Debug.Log("Creating atlases for result material " + resMatToPass);
			if(!combiner.CombineTexturesIntoAtlases(progressInfo, resultAtlasesAndRects[i], resMatToPass, objsToMesh, sourceMats, editorMethods)){
				return null;
			}
		}
		
		//Save the results
		textureBakeResults.combinedMaterialInfo = resultAtlasesAndRects;
		textureBakeResults.doMultiMaterial = _doMultiMaterial;
		textureBakeResults.resultMaterial = _resultMaterial;
		textureBakeResults.resultMaterials = resultMaterials;
		textureBakeResults.fixOutOfBoundsUVs = combiner.fixOutOfBoundsUVs;
		unpackMat2RectMap(textureBakeResults);
		
		//set the texture bake resultAtlasesAndRects on the Mesh Baker component if it exists
		MB3_MeshBakerCommon[] mb = GetComponentsInChildren<MB3_MeshBakerCommon>();
		for (int i = 0; i < mb.Length; i++){
			mb[i].textureBakeResults = textureBakeResults;
		}
		
		if (LOG_LEVEL >= MB2_LogLevel.info) Debug.Log("Created Atlases");		
		return resultAtlasesAndRects;
	}		
Example #29
0
    bool __combineTexturesIntoAtlases(ProgressUpdateDelegate progressInfo, MB_AtlasesAndRects results, List <string> texPropertyNames, List <GameObject> objsToMesh, List <Material> sourceMaterials, int atlasPadding, bool resizePowerOfTwoTextures, bool fixOutOfBoundsUVs, int maxTilingBakeSize)
    {
        int numTextures                 = texPropertyNames.Count;
        List <GameObject> mcs           = objsToMesh;
        bool             outOfBoundsUVs = false;
        List <MB_TexSet> texsAndObjs    = new List <MB_TexSet>();    //one per distinct set of textures

        if (VERBOSE)
        {
            Debug.Log("__combineTexturesIntoAtlases atlases:" + texPropertyNames.Count + " objsToMesh:" + objsToMesh.Count + " fixOutOfBoundsUVs:" + fixOutOfBoundsUVs);
        }
        for (int i = 0; i < mcs.Count; i++)
        {
            GameObject mc = mcs[i];
            if (VERBOSE)
            {
                Debug.Log("Collecting textures for object " + mc);
            }

            if (mc == null)
            {
                Debug.LogError("The list of objects to mesh contained nulls.");
                return(false);
            }

            Mesh sharedMesh = MB_Utility.GetMesh(mc);
            if (sharedMesh == null)
            {
                Debug.LogError("Object " + mc.name + " in the list of objects to mesh has no mesh.");
                return(false);
            }

            Material[] sharedMaterials = MB_Utility.GetGOMaterials(mc);
            if (sharedMaterials == null)
            {
                Debug.LogError("Object " + mc.name + " in the list of objects has no materials.");
                return(false);
            }

            for (int matIdx = 0; matIdx < sharedMaterials.Length; matIdx++)
            {
                Material mat = sharedMaterials[matIdx];

                //check if this material is on the list of source materaials
                if (sourceMaterials != null && !sourceMaterials.Contains(mat))
                {
                    continue;
                }

                Rect uvBounds         = new Rect();
                bool mcOutOfBoundsUVs = MB_Utility.hasOutOfBoundsUVs(sharedMesh, ref uvBounds, matIdx);
                outOfBoundsUVs = outOfBoundsUVs || mcOutOfBoundsUVs;

                if (mat.name.Contains("(Instance)"))
                {
                    Debug.LogError("The sharedMaterial on object " + mc.name + " has been 'Instanced'. This was probably caused by a script accessing the meshRender.material property in the editor. " +
                                   " The material to UV Rectangle mapping will be incorrect. To fix this recreate the object from its prefab or re-assign its material from the correct asset.");
                    return(false);
                }

                if (fixOutOfBoundsUVs)
                {
                    if (!MB_Utility.validateOBuvsMultiMaterial(sharedMaterials))
                    {
                        Debug.LogWarning("Object " + mc.name + " uses the same material on multiple submeshes. This may generate strange results especially when used with fix out of bounds uvs. Try duplicating the material.");
                    }
                }

                if (progressInfo != null)
                {
                    progressInfo("Collecting textures for " + mat, .01f);
                }

                //collect textures scale and offset for each texture in objects material
                MeshBakerMaterialTexture[] mts = new MeshBakerMaterialTexture[texPropertyNames.Count];
                for (int j = 0; j < texPropertyNames.Count; j++)
                {
                    Texture2D tx         = null;
                    Vector2   scale      = Vector2.one;
                    Vector2   offset     = Vector2.zero;
                    Vector2   obUVscale  = Vector2.one;
                    Vector2   obUVoffset = Vector2.zero;
                    if (mat.HasProperty(texPropertyNames[j]))
                    {
                        Texture txx = mat.GetTexture(texPropertyNames[j]);
                        if (txx != null)
                        {
                            if (txx is Texture2D)
                            {
                                tx = (Texture2D)txx;
                                TextureFormat f = tx.format;
                                if (f == TextureFormat.ARGB32 ||
                                    f == TextureFormat.RGBA32 ||
                                    f == TextureFormat.BGRA32 ||
                                    f == TextureFormat.RGB24 ||
                                    f == TextureFormat.Alpha8
                                    )                             //DXT5 does not work
                                {
                                }
                                else
                                {
                                    //TRIED to copy texture using tex2.SetPixels(tex1.GetPixels()) but bug in 3.5 means DTX1 and 5 compressed textures come out skewed
                                    //Debug.LogWarning(mc.name + " in the list of objects to mesh uses Texture "+tx.name+" uses format " + f + " that is not in: ARGB32, RGBA32, BGRA32, RGB24, Alpha8 or DXT. These formats cannot be resized. MeshBaker will create duplicates.");
                                    //tx = createTextureCopy(tx);
#if UNITY_EDITOR
                                    Debug.LogWarning("Object " + mc.name + " in the list of objects to mesh uses Texture " + tx.name + " uses format " + f + " that is not in: ARGB32, RGBA32, BGRA32, RGB24, Alpha8 or DXT. These textures cannot be resized. Try changing texture format. If format says 'compressed' try changing it to 'truecolor'");
                                    setTextureFormat(tx, TextureImporterFormat.ARGB32, true);
                                    tx = (Texture2D)mat.GetTexture(texPropertyNames[j]);
#else
                                    Debug.LogError("Object " + mc.name + " in the list of objects to mesh uses Texture " + tx.name + " uses format " + f + " that is not in: ARGB32, RGBA32, BGRA32, RGB24, Alpha8 or DXT. These textures cannot be resized at runtime. Try changing texture format. If format says 'compressed' try changing it to 'truecolor'");
                                    return(false);
#endif
                                }
                            }
                            else
                            {
                                Debug.LogError("Object " + mc.name + " in the list of objects to mesh uses a Texture that is not a Texture2D. Cannot build atlases.");
                                return(false);
                            }
                        }
                        offset = mat.GetTextureOffset(texPropertyNames[j]);
                        scale  = mat.GetTextureScale(texPropertyNames[j]);
                    }
                    if (tx == null)
                    {
                        Debug.LogWarning("No texture selected for " + texPropertyNames[j] + " in object " + mcs[i].name);
                    }
                    if (fixOutOfBoundsUVs && mcOutOfBoundsUVs)
                    {
                        obUVscale  = new Vector2(uvBounds.width, uvBounds.height);
                        obUVoffset = new Vector2(uvBounds.x, uvBounds.y);
                    }
                    mts[j] = new MeshBakerMaterialTexture(tx, offset, scale, obUVoffset, obUVscale);
                }

                //Add to distinct set of textures
                MB_TexSet setOfTexs  = new MB_TexSet(mts);
                MB_TexSet setOfTexs2 = texsAndObjs.Find(x => x.Equals(setOfTexs));
                if (setOfTexs2 != null)
                {
                    setOfTexs = setOfTexs2;
                }
                else
                {
                    texsAndObjs.Add(setOfTexs);
                }
                if (!setOfTexs.mats.Contains(mat))
                {
                    setOfTexs.mats.Add(mat);
                }
            }
        }

//		if (texsAndObjs.Count > 1 && outOfBoundsUVs){
//			Debug.LogWarning("An object in the list of objects to be combined has UVs outside the range (0,1). This object can only be combined with objects like itself that use the exact same set of textures.");
//		}

        int _padding = atlasPadding;
        if (texsAndObjs.Count == 1)
        {
            Debug.Log("All objects use the same textures.");
            _padding = 0;
        }

        for (int i = 0; i < texsAndObjs.Count; i++)
        {
            int       tWidth  = 1;
            int       tHeight = 1;
            MB_TexSet txs     = texsAndObjs[i];
            //get the best size all textures in a TexSet must be the same size.
            for (int j = 0; j < txs.ts.Length; j++)
            {
                MeshBakerMaterialTexture matTex = txs.ts[j];
                if (matTex.t == null)
                {
                    Debug.LogWarning("Creating empty texture for " + texPropertyNames[j]);
                    matTex.t = _createTemporaryTexture(tWidth, tHeight, TextureFormat.ARGB32, true);
                }
                if (!matTex.scale.Equals(Vector2.one))
                {
                    Debug.LogWarning("Texture " + matTex.t + "is tiled by " + matTex.scale + " tiling will be baked into a texture with maxSize:" + maxTilingBakeSize);
                }
                if (!matTex.obUVscale.Equals(Vector2.one))
                {
                    Debug.LogWarning("Texture " + matTex.t + "has out of bounds UVs that effectively tile by " + matTex.obUVscale + " tiling will be baked into a texture with maxSize:" + maxTilingBakeSize);
                }

                if (progressInfo != null)
                {
                    progressInfo("Adjusting for scale and offset " + matTex.t, .01f);
                }
                setReadWriteFlag(matTex.t, true, true);
                matTex.t = getAdjustedForScaleAndOffset2(matTex, fixOutOfBoundsUVs, maxTilingBakeSize);

                if (matTex.t.width * matTex.t.height > tWidth * tHeight)
                {
                    tWidth  = matTex.t.width;
                    tHeight = matTex.t.height;
                }
            }
            if (resizePowerOfTwoTextures)
            {
                if (IsPowerOfTwo(tWidth))
                {
                    tWidth -= _padding * 2;
                }
                if (IsPowerOfTwo(tHeight))
                {
                    tHeight -= _padding * 2;
                }
                if (tWidth < 1)
                {
                    tWidth = 1;
                }
                if (tHeight < 1)
                {
                    tHeight = 1;
                }
            }
            txs.idealWidth  = tWidth;
            txs.idealHeight = tHeight;
        }

        Rect[]      uvRects = null;
        Texture2D[] atlases = new Texture2D[numTextures];
        Rect[]      rs      = null;
        long        estArea = 0;

        StringBuilder report = new StringBuilder();
        if (numTextures > 0)
        {
            report = new StringBuilder();
            report.AppendLine("Report");
            for (int i = 0; i < texsAndObjs.Count; i++)
            {
                MB_TexSet txs = texsAndObjs[i];
                report.AppendLine("----------");
                report.Append("Will be resized to:" + txs.idealWidth + "x" + txs.idealHeight);
                for (int j = 0; j < txs.ts.Length; j++)
                {
                    if (txs.ts[j].t != null)
                    {
                        report.Append(" [" + texPropertyNames[j] + " " + txs.ts[j].t.name + " " + txs.ts[j].t.width + "x" + txs.ts[j].t.height + "]");
                    }
                    else
                    {
                        report.Append(" [" + texPropertyNames[j] + " null]");
                    }
                }
                report.AppendLine("");
                report.Append("Materials using:");
                for (int j = 0; j < txs.mats.Count; j++)
                {
                    report.Append(txs.mats[j].name + ", ");
                }
                report.AppendLine("");
            }
        }

        if (progressInfo != null)
        {
            progressInfo("Creating txture atlases.", .1f);
        }

        //Resize and create null textures
        for (int i = 0; i < numTextures; i++)
        {
            for (int j = 0; j < texsAndObjs.Count; j++)
            {
                MB_TexSet txs = texsAndObjs[j];

                int tWidth  = txs.idealWidth;
                int tHeight = txs.idealHeight;

                Texture2D tx = txs.ts[i].t;
                //create a resized copy if necessary
                if (tx.width != tWidth || tx.height != tHeight)
                {
                    if (progressInfo != null)
                    {
                        progressInfo("Resizing texture '" + tx + "'", .01f);
                    }
                    if (VERBOSE)
                    {
                        Debug.Log("Copying and resizing texture " + texPropertyNames[i] + " from " + tx.width + "x" + tx.height + " to " + tWidth + "x" + tHeight);
                    }
                    setReadWriteFlag((Texture2D)tx, true, true);
                    tx = _resizeTexture((Texture2D)tx, tWidth, tHeight);
                }
                txs.ts[i].t = tx;
            }

            Texture2D[] texToPack = new Texture2D[texsAndObjs.Count];
            for (int j = 0; j < texsAndObjs.Count; j++)
            {
                Texture2D tx = texsAndObjs[j].ts[i].t;
                estArea     += tx.width * tx.height;
                texToPack[j] = tx;
            }
#if UNITY_EDITOR
            if (Math.Sqrt(estArea) > 1000f)
            {
                if (EditorUserBuildSettings.selectedBuildTargetGroup != BuildTargetGroup.Standalone)
                {
                    Debug.LogWarning("If the current selected build target is not standalone then the generated atlases may be capped at size 1024. If build target is Standalone then atlases of 4096 can be built");
                }
            }
#endif
            if (Math.Sqrt(estArea) > 3500f)
            {
                Debug.LogWarning("The maximum possible atlas size is 4096. Textures may be shrunk");
            }
            atlases[i] = new Texture2D(1, 1, TextureFormat.ARGB32, true);
            if (progressInfo != null)
            {
                progressInfo("Packing texture atlas " + texPropertyNames[i], .25f);
            }
            if (i == 0)
            {
                if (progressInfo != null)
                {
                    progressInfo("Estimated min size of atlases: " + Math.Sqrt(estArea), .1f);
                }
                Debug.Log("Estimated texture minimum size:" + Math.Sqrt(estArea));
                uvRects = rs = atlases[i].PackTextures(texToPack, _padding, 4096, false);
                Debug.Log("After pack textures size " + atlases[i].width + " " + atlases[i].height);
                atlases[i].Apply();
            }
            else
            {
                atlases[i] = _copyTexturesIntoAtlas(texToPack, _padding, rs, atlases[0].width, atlases[0].height);
            }
            //_destroyTemporaryTexturesAndSetReadFlags();
        }



        Dictionary <Material, Rect> mat2rect_map = new Dictionary <Material, Rect>();
        for (int i = 0; i < texsAndObjs.Count; i++)
        {
            List <Material> mats = texsAndObjs[i].mats;
            for (int j = 0; j < mats.Count; j++)
            {
                if (!mat2rect_map.ContainsKey(mats[j]))
                {
                    mat2rect_map.Add(mats[j], uvRects[i]);
                }
            }
        }

        results.atlases          = atlases;                            // one per texture on source shader
        results.texPropertyNames = texPropertyNames.ToArray();         // one per texture on source shader
        results.mat2rect_map     = mat2rect_map;
        _destroyTemporaryTexturesAndSetReadFlags();
        if (report != null)
        {
            Debug.Log(report.ToString());
        }
        return(true);
    }
		void __Step3_BuildAndSaveAtlasesAndStoreResults(ProgressUpdateDelegate progressInfo, List<MB_TexSet> distinctMaterialTextures, List<string> texPropertyNames, int _padding, MB2_EditorMethodsInterface textureEditorMethods, MB_AtlasesAndRects resultAtlasesAndRects, Material resultMaterial){
			int numAtlases = texPropertyNames.Count;
			//generate report want to do this before
			//todo if atlas is compressed then doesn't report correct compression 
			StringBuilder report = new StringBuilder();
			if (numAtlases > 0){
				report = new StringBuilder();
				report.AppendLine("Report");
				for (int i = 0; i < distinctMaterialTextures.Count; i++){
					MB_TexSet txs = distinctMaterialTextures[i];
					report.AppendLine("----------");
					report.Append("This set of textures will be resized to:" + txs.idealWidth + "x" + txs.idealHeight + "\n");
					for (int j = 0; j < txs.ts.Length; j++){
						if (txs.ts[j].t != null){
							report.Append("   [" + texPropertyNames[j] + " " + txs.ts[j].t.name + " " + txs.ts[j].t.width + "x" + txs.ts[j].t.height + "]");
							if (txs.ts[j].scale != Vector2.one || txs.ts[j].offset != Vector2.zero) report.AppendFormat(" material scale {0} offset{1} ", txs.ts[j].scale.ToString("G4"), txs.ts[j].offset.ToString("G4"));
							if (txs.ts[j].obUVscale != Vector2.one || txs.ts[j].obUVoffset != Vector2.zero) report.AppendFormat(" obUV scale {0} offset{1} ", txs.ts[j].obUVscale.ToString("G4"), txs.ts[j].obUVoffset.ToString("G4"));
							report.AppendLine("");
						} else { 
							report.Append("   [" + texPropertyNames[j] + " null a blank texture will be created]\n");
						}
					}
					report.AppendLine("");
					report.Append("Materials using:");
					for (int j = 0; j < txs.mats.Count; j++){
						report.Append(txs.mats[j].name + ", ");
					}
					report.AppendLine("");
				}
			}		
	
			if (progressInfo != null) progressInfo("Creating txture atlases.", .1f);

			//run the garbage collector to free up as much memory as possible before bake to reduce MissingReferenceException problems
			GC.Collect();
			Texture2D[] atlases = new Texture2D[numAtlases];			
			Rect[] uvRects;
			if (packingAlgorithm == MB2_PackingAlgorithmEnum.UnitysPackTextures){
				uvRects = __CreateAtlasesUnityTexturePacker(progressInfo, numAtlases, distinctMaterialTextures, texPropertyNames, resultMaterial, atlases, textureEditorMethods, _padding);
			} else {
				uvRects = __CreateAtlasesMBTexturePacker(progressInfo, numAtlases, distinctMaterialTextures, texPropertyNames, resultMaterial, atlases, textureEditorMethods, _padding);
			}
			if (progressInfo != null) progressInfo("Building Report",.7f);
			
			//report on atlases created
			StringBuilder atlasMessage = new StringBuilder();
			atlasMessage.AppendLine("---- Atlases ------");
			for (int i = 0; i < numAtlases; i++){
				if (atlases[i] != null) atlasMessage.AppendLine("Created Atlas For: " + texPropertyNames[i] + " h=" + atlases[i].height + " w=" + atlases[i].width);
			}
			report.Append(atlasMessage.ToString());
			
			
			Dictionary<Material,Rect> mat2rect_map = new Dictionary<Material, Rect>();
			for (int i = 0; i < distinctMaterialTextures.Count; i++){
				List<Material> mats = distinctMaterialTextures[i].mats;
				for (int j = 0; j < mats.Count; j++){
					if (!mat2rect_map.ContainsKey(mats[j])){
						mat2rect_map.Add(mats[j],uvRects[i]);
					}
				}
			}
			
			resultAtlasesAndRects.atlases = atlases;                             // one per texture on source shader
			resultAtlasesAndRects.texPropertyNames = texPropertyNames.ToArray(); // one per texture on source shader
			resultAtlasesAndRects.mat2rect_map = mat2rect_map;
			
			if (progressInfo != null) progressInfo("Restoring Texture Formats & Read Flags",.8f);
			_destroyTemporaryTextures();
			if (textureEditorMethods != null) textureEditorMethods.SetReadFlags(progressInfo);
			if (report != null && LOG_LEVEL >= MB2_LogLevel.info) Debug.Log(report.ToString());		
		}
    internal IEnumerator _CreateAtlasesCoroutineTextureArray(MB3_TextureCombiner combiner, ProgressUpdateDelegate progressInfo, MB3_TextureCombiner.CreateAtlasesCoroutineResult coroutineResult, bool saveAtlasesAsAssets = false, MB2_EditorMethodsInterface editorMethods = null, float maxTimePerFrame = .01f)
    {
        MB_TextureArrayResultMaterial[] bakedMatsAndSlices = null;

        // Validate the formats
        if (textureArrayOutputFormats == null || textureArrayOutputFormats.Length == 0)
        {
            Debug.LogError("No Texture Array Output Formats. There must be at least one entry.");
            coroutineResult.isFinished = true;
            yield break;
        }

        for (int i = 0; i < textureArrayOutputFormats.Length; i++)
        {
            if (!textureArrayOutputFormats[i].ValidateTextureImporterFormatsExistsForTextureFormats(editorMethods, i))
            {
                Debug.LogError("Could not map the selected texture format to a Texture Importer Format. Safest options are ARGB32, or RGB24.");
                coroutineResult.isFinished = true;
                yield break;
            }
        }

        for (int resMatIdx = 0; resMatIdx < resultMaterialsTexArray.Length; resMatIdx++)
        {
            MB_MultiMaterialTexArray textureArraySliceConfig = resultMaterialsTexArray[resMatIdx];
            if (textureArraySliceConfig.combinedMaterial == null)
            {
                Debug.LogError("Material is null for Texture Array Slice Configuration: " + resMatIdx + ".");
                coroutineResult.isFinished = true;
                yield break;
            }


            List <MB_TexArraySlice> slices = textureArraySliceConfig.slices;
            for (int sliceIdx = 0; sliceIdx < slices.Count; sliceIdx++)
            {
                for (int srcMatIdx = 0; srcMatIdx < slices[sliceIdx].sourceMaterials.Count; srcMatIdx++)
                {
                    MB_TexArraySliceRendererMatPair sourceMat = slices[sliceIdx].sourceMaterials[srcMatIdx];
                    if (sourceMat.sourceMaterial == null)
                    {
                        Debug.LogError("Source material is null for Texture Array Slice Configuration: " + resMatIdx + " slice: " + sliceIdx);
                        coroutineResult.isFinished = true;
                        yield break;
                    }

                    if (slices[sliceIdx].considerMeshUVs)
                    {
                        if (sourceMat.renderer == null)
                        {
                            Debug.LogError("Renderer is null for Texture Array Slice Configuration: " + resMatIdx + " slice: " + sliceIdx + ". If considerUVs is enabled then a renderer must be supplied for each source material. The same source material can be used multiple times.");
                            coroutineResult.isFinished = true;
                            yield break;
                        }
                    }
                    else
                    {
                        // TODO check for duplicate source mats.
                    }
                }
            }
        }

        // initialize structure to store results. For texture arrays the structure is two layers deep.
        // First layer is resultMaterial / submesh (each result material can use a different shader)
        // Second layer is a set of TextureArrays for the TextureProperties on that result material.
        int numResultMats = resultMaterialsTexArray.Length;

        bakedMatsAndSlices = new MB_TextureArrayResultMaterial[numResultMats];
        for (int resMatIdx = 0; resMatIdx < bakedMatsAndSlices.Length; resMatIdx++)
        {
            bakedMatsAndSlices[resMatIdx] = new MB_TextureArrayResultMaterial();
            int numSlices = resultMaterialsTexArray[resMatIdx].slices.Count;
            MB_AtlasesAndRects[] slices = bakedMatsAndSlices[resMatIdx].slices = new MB_AtlasesAndRects[numSlices];
            for (int j = 0; j < numSlices; j++)
            {
                slices[j] = new MB_AtlasesAndRects();
            }
        }

        // Some of the slices will be atlases (more than one atlas per slice).
        // Do the material combining for these. First loop over the result materials (1 per submeshes).
        for (int resMatIdx = 0; resMatIdx < bakedMatsAndSlices.Length; resMatIdx++)
        {
            yield return(MB_TextureArrays._CreateAtlasesCoroutineSingleResultMaterial(resMatIdx, bakedMatsAndSlices[resMatIdx], resultMaterialsTexArray[resMatIdx],
                                                                                      objsToMesh,
                                                                                      combiner,
                                                                                      textureArrayOutputFormats,
                                                                                      resultMaterialsTexArray,
                                                                                      customShaderProperties,
                                                                                      progressInfo, coroutineResult, saveAtlasesAsAssets, editorMethods, maxTimePerFrame));

            if (!coroutineResult.success)
            {
                yield break;
            }
        }

        if (coroutineResult.success)
        {
            // Save the results into the TextureBakeResults.
            unpackMat2RectMap(bakedMatsAndSlices);
            if (editorMethods != null)
            {
                editorMethods.GetMaterialPrimaryKeysIfAddressables(textureBakeResults);
            }
            textureBakeResults.resultType              = MB2_TextureBakeResults.ResultType.textureArray;
            textureBakeResults.resultMaterials         = new MB_MultiMaterial[0];
            textureBakeResults.resultMaterialsTexArray = resultMaterialsTexArray;
            if (LOG_LEVEL >= MB2_LogLevel.info)
            {
                Debug.Log("Created Texture2DArrays");
            }
        }
        else
        {
            if (LOG_LEVEL >= MB2_LogLevel.info)
            {
                Debug.Log("Failed to create Texture2DArrays");
            }
        }
    }
Example #32
0
        //float _maxTimePerFrameForCoroutine;
        public IEnumerator CombineTexturesIntoAtlasesCoroutine(ProgressUpdateDelegate progressInfo, MB_AtlasesAndRects resultAtlasesAndRects, Material resultMaterial, List <GameObject> objsToMesh, List <Material> allowedMaterialsFilter, MB2_EditorMethodsInterface textureEditorMethods = null, CombineTexturesIntoAtlasesCoroutineResult coroutineResult = null, float maxTimePerFrame = .01f, List <AtlasPackingResult> packingResults = null, bool onlyPackRects = false, bool splitAtlasWhenPackingIfTooBig = false)
        {
            if (!_RunCorutineWithoutPauseIsRunning && (MBVersion.GetMajorVersion() < 5 || (MBVersion.GetMajorVersion() == 5 && MBVersion.GetMinorVersion() < 3)))
            {
                Debug.LogError("Running the texture combiner as a coroutine only works in Unity 5.3 and higher");
                yield return(null);
            }
            coroutineResult.success    = true;
            coroutineResult.isFinished = false;
            if (maxTimePerFrame <= 0f)
            {
                Debug.LogError("maxTimePerFrame must be a value greater than zero");
                coroutineResult.isFinished = true;
                yield break;
            }
            //_maxTimePerFrameForCoroutine = maxTimePerFrame;
            yield return(_CombineTexturesIntoAtlases(progressInfo, coroutineResult, resultAtlasesAndRects, resultMaterial, objsToMesh, allowedMaterialsFilter, textureEditorMethods, packingResults, onlyPackRects, splitAtlasWhenPackingIfTooBig));

            coroutineResult.isFinished = true;
            yield break;
        }
Example #33
0
        IEnumerator _CombineTexturesIntoAtlases(ProgressUpdateDelegate progressInfo, CombineTexturesIntoAtlasesCoroutineResult result, MB_AtlasesAndRects resultAtlasesAndRects, Material resultMaterial, List <GameObject> objsToMesh, List <Material> allowedMaterialsFilter, MB2_EditorMethodsInterface textureEditorMethods, List <AtlasPackingResult> atlasPackingResult, bool onlyPackRects, bool splitAtlasWhenPackingIfTooBig)
        {
            System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
            sw.Start();
            try
            {
                _temporaryTextures.Clear();
                MeshBakerMaterialTexture.readyToBuildAtlases = false;

                if (textureEditorMethods != null)
                {
                    textureEditorMethods.Clear();
                    textureEditorMethods.OnPreTextureBake();
                }

                if (objsToMesh == null || objsToMesh.Count == 0)
                {
                    Debug.LogError("No meshes to combine. Please assign some meshes to combine.");
                    result.success = false;
                    yield break;
                }

                if (_atlasPadding < 0)
                {
                    Debug.LogError("Atlas padding must be zero or greater.");
                    result.success = false;
                    yield break;
                }

                if (_maxTilingBakeSize < 2 || _maxTilingBakeSize > 4096)
                {
                    Debug.LogError("Invalid value for max tiling bake size.");
                    result.success = false;
                    yield break;
                }

                for (int i = 0; i < objsToMesh.Count; i++)
                {
                    Material[] ms = MB_Utility.GetGOMaterials(objsToMesh[i]);
                    for (int j = 0; j < ms.Length; j++)
                    {
                        Material m = ms[j];
                        if (m == null)
                        {
                            Debug.LogError("Game object " + objsToMesh[i] + " has a null material");
                            result.success = false;
                            yield break;
                        }
                    }
                }

                if (progressInfo != null)
                {
                    progressInfo("Collecting textures for " + objsToMesh.Count + " meshes.", .01f);
                }

                MB3_TextureCombinerPipeline.TexturePipelineData data = LoadPipelineData(resultMaterial, new List <ShaderTextureProperty>(), objsToMesh, allowedMaterialsFilter, new List <MB_TexSet>());
                if (!MB3_TextureCombinerPipeline._CollectPropertyNames(data, LOG_LEVEL))
                {
                    result.success = false;
                    yield break;
                }

                if (_fixOutOfBoundsUVs && (_packingAlgorithm == MB2_PackingAlgorithmEnum.MeshBakerTexturePacker_Horizontal ||
                                           _packingAlgorithm == MB2_PackingAlgorithmEnum.MeshBakerTexturePacker_Vertical))
                {
                    if (LOG_LEVEL >= MB2_LogLevel.info)
                    {
                        Debug.LogWarning("'Consider Mesh UVs' is enabled but packing algorithm is MeshBakerTexturePacker_Horizontal or MeshBakerTexturePacker_Vertical. It is recommended to use these packers without using 'Consider Mesh UVs'");
                    }
                }

                data.nonTexturePropertyBlender.LoadTextureBlendersIfNeeded(data.resultMaterial);

                if (onlyPackRects)
                {
                    yield return(__RunTexturePackerOnly(result, data, splitAtlasWhenPackingIfTooBig, textureEditorMethods, atlasPackingResult));
                }
                else
                {
                    yield return(__CombineTexturesIntoAtlases(progressInfo, result, resultAtlasesAndRects, data, splitAtlasWhenPackingIfTooBig, textureEditorMethods));
                }

                /*
                 *      } catch (MissingReferenceException mrex){
                 *              Debug.LogError("Creating atlases failed a MissingReferenceException was thrown. This is normally only happens when trying to create very large atlases and Unity is running out of Memory. Try changing the 'Texture Packer' to a different option, it may work with an alternate packer. This error is sometimes intermittant. Try baking again.");
                 *              Debug.LogError(mrex);
                 *      } catch (Exception ex){
                 *              Debug.LogError(ex);*/
            }
            finally
            {
                _destroyAllTemporaryTextures();
                _restoreProceduralMaterials();
                if (textureEditorMethods != null)
                {
                    textureEditorMethods.RestoreReadFlagsAndFormats(progressInfo);
                    textureEditorMethods.OnPostTextureBake();
                }
                if (LOG_LEVEL >= MB2_LogLevel.debug)
                {
                    Debug.Log("===== Done creating atlases for " + resultMaterial + " Total time to create atlases " + sw.Elapsed.ToString());
                }
            }
            //result.success = success;
        }
Example #34
0
        //texPropertyNames is the list of texture properties in the resultMaterial
        //allowedMaterialsFilter is a list of materials. Objects without any of these materials will be ignored.
        //						 this is used by the multiple materials filter
        //textureEditorMethods encapsulates editor only functionality such as saving assets and tracking texture assets whos format was changed. Is null if using at runtime.
        IEnumerator __CombineTexturesIntoAtlases(ProgressUpdateDelegate progressInfo, CombineTexturesIntoAtlasesCoroutineResult result, MB_AtlasesAndRects resultAtlasesAndRects, MB3_TextureCombinerPipeline.TexturePipelineData data, bool splitAtlasWhenPackingIfTooBig, MB2_EditorMethodsInterface textureEditorMethods)
        {
            if (LOG_LEVEL >= MB2_LogLevel.debug)
            {
                Debug.Log("__CombineTexturesIntoAtlases texture properties in shader:" + data.texPropertyNames.Count + " objsToMesh:" + data.allObjsToMesh.Count + " _fixOutOfBoundsUVs:" + data._fixOutOfBoundsUVs);
            }

            if (progressInfo != null)
            {
                progressInfo("Collecting textures ", .01f);
            }

            /*
             *          each atlas (maintex, bump, spec etc...) will have distinctMaterialTextures.Count images in it.
             *          each distinctMaterialTextures record is a set of textures, one for each atlas. And a list of materials
             *          that use that distinct set of textures.
             */
            List <GameObject> usedObjsToMesh = new List <GameObject>();

            yield return(MB3_TextureCombinerPipeline.__Step1_CollectDistinctMatTexturesAndUsedObjects(progressInfo, result, data, this, textureEditorMethods, usedObjsToMesh, LOG_LEVEL));

            if (!result.success)
            {
                yield break;
            }

            if (MB3_MeshCombiner.EVAL_VERSION)
            {
                bool usesAllowedShaders = true;
                for (int i = 0; i < data.distinctMaterialTextures.Count; i++)
                {
                    for (int j = 0; j < data.distinctMaterialTextures[i].matsAndGOs.mats.Count; j++)
                    {
                        if (!data.distinctMaterialTextures[i].matsAndGOs.mats[j].mat.shader.name.EndsWith("Diffuse") &&
                            !data.distinctMaterialTextures[i].matsAndGOs.mats[j].mat.shader.name.EndsWith("Bumped Diffuse"))
                        {
                            Debug.LogError("The free version of Mesh Baker only works with Diffuse and Bumped Diffuse Shaders. The full version can be used with any shader. Material " + data.distinctMaterialTextures[i].matsAndGOs.mats[j].mat.name + " uses shader " + data.distinctMaterialTextures[i].matsAndGOs.mats[j].mat.shader.name);
                            usesAllowedShaders = false;
                        }
                    }
                }
                if (!usesAllowedShaders)
                {
                    result.success = false;
                    yield break;
                }
            }

            //Textures in each material (_mainTex, Bump, Spec ect...) must be same size
            //Calculate the best sized to use. Takes into account tiling
            //if only one texture in atlas re-uses original sizes
            yield return(MB3_TextureCombinerPipeline.CalculateIdealSizesForTexturesInAtlasAndPadding(progressInfo, result, data, this, textureEditorMethods, LOG_LEVEL));

            if (!result.success)
            {
                yield break;
            }

            //buildAndSaveAtlases
            StringBuilder             report       = MB3_TextureCombinerPipeline.GenerateReport(data);
            MB_ITextureCombinerPacker texturePaker = MB3_TextureCombinerPipeline.CreatePacker(data.OnlyOneTextureInAtlasReuseTextures(), data._packingAlgorithm);

            yield return(texturePaker.ConvertTexturesToReadableFormats(progressInfo, result, data, this, textureEditorMethods, LOG_LEVEL));

            if (!result.success)
            {
                yield break;
            }

            AtlasPackingResult[] uvRects = texturePaker.CalculateAtlasRectangles(data, splitAtlasWhenPackingIfTooBig, LOG_LEVEL);
            yield return(MB3_TextureCombinerPipeline.__Step3_BuildAndSaveAtlasesAndStoreResults(result, progressInfo, data, this, texturePaker, uvRects[0], textureEditorMethods, resultAtlasesAndRects, report, LOG_LEVEL));
        }
Example #35
0
    public MB_AtlasesAndRects[] CreateAtlases(ProgressUpdateDelegate progressInfo, bool saveAtlasesAsAssets = false, MB_TextureCombiner.FileSaveFunction fileSaveFunction = null)
    {
        if (doMultiMaterial)
        {
            for (int i = 0; i < resultMaterials.Length; i++)
            {
                MB_MultiMaterial mm = resultMaterials[i];
                if (mm.combinedMaterial == null)
                {
                    Debug.LogError("Combined Material is null please create and assign a result material.");
                    return(null);
                }
                UnityEngine.Shader targShader = mm.combinedMaterial.shader;
                for (int j = 0; j < mm.sourceMaterials.Count; j++)
                {
                    if (mm.sourceMaterials[j] == null)
                    {
                        Debug.LogError("There are null entries in the list of Source Materials");
                        return(null);
                    }
                    if (targShader != mm.sourceMaterials[j].shader)
                    {
                        Debug.LogWarning("Source material " + mm.sourceMaterials[j] + " does not use shader " + targShader + " it may not have the required textures. If not empty textures will be generated.");
                    }
                }
            }
        }
        else
        {
            if (resultMaterial == null)
            {
                Debug.LogError("Combined Material is null please create and assign a result material.");
                return(null);
            }
            UnityEngine.Shader targShader = resultMaterial.shader;
            for (int i = 0; i < objsToMesh.Count; i++)
            {
                Material[] ms = MB_Utility.GetGOMaterials(objsToMesh[i]);
                for (int j = 0; j < ms.Length; j++)
                {
                    Material m = ms[j];
                    if (m == null)
                    {
                        Debug.LogError("Game object " + objsToMesh[i] + " has a null material. Can't build atlases");
                        return(null);
                    }
                    if (m.shader != targShader)
                    {
                        Debug.LogWarning("Game object " + objsToMesh[i] + " does not use shader " + targShader + " it may not have the required textures. If not empty textures will be generated.");
                    }
                }
            }
        }

        int numResults = 1;

        if (doMultiMaterial)
        {
            numResults = resultMaterials.Length;
        }
        MB_AtlasesAndRects[] results = new MB_AtlasesAndRects[numResults];
        for (int i = 0; i < results.Length; i++)
        {
            results[i] = new MB_AtlasesAndRects();
        }
        MB_TextureCombiner tc = new MB_TextureCombiner();

        Material        resMatToPass = null;
        List <Material> sourceMats   = null;

        for (int i = 0; i < results.Length; i++)
        {
            if (doMultiMaterial)
            {
                sourceMats   = resultMaterials[i].sourceMaterials;
                resMatToPass = resultMaterials[i].combinedMaterial;
            }
            else
            {
                resMatToPass = resultMaterial;
            }
            Debug.Log("Creating atlases for result material " + resMatToPass);
            if (!tc.combineTexturesIntoAtlases(progressInfo, results[i], resMatToPass, objsToMesh, sourceMats, atlasPadding, customShaderPropNames, resizePowerOfTwoTextures, fixOutOfBoundsUVs, maxTilingBakeSize, saveAtlasesAsAssets, texturePackingAlgorithm, fileSaveFunction))
            {
                return(null);
            }
        }

        if (results != null)
        {
            textureBakeResults.combinedMaterialInfo = results;
            textureBakeResults.doMultiMaterial      = doMultiMaterial;
            textureBakeResults.resultMaterial       = resultMaterial;
            textureBakeResults.resultMaterials      = resultMaterials;
            textureBakeResults.fixOutOfBoundsUVs    = fixOutOfBoundsUVs;
            unpackMat2RectMap(textureBakeResults);

            if (UnityEngine.Application.isPlaying)
            {
                if (doMultiMaterial)
                {
                    for (int j = 0; j < resultMaterials.Length; j++)
                    {
                        Material    resMat  = resultMaterials[j].combinedMaterial;                     //resultMaterials[j].combinedMaterial;
                        Texture2D[] atlases = results[j].atlases;
                        for (int i = 0; i < atlases.Length; i++)
                        {
                            resMat.SetTexture(results[j].texPropertyNames[i], atlases[i]);
                            //				_setMaterialTextureProperty(resMat, newMesh.texPropertyNames[i], relativePath);
                        }
                    }
                }
                else
                {
                    Material    resMat  = resultMaterial;                 //resultMaterials[j].combinedMaterial;
                    Texture2D[] atlases = results[0].atlases;
                    for (int i = 0; i < atlases.Length; i++)
                    {
                        resMat.SetTexture(results[0].texPropertyNames[i], atlases[i]);
                        //				_setMaterialTextureProperty(resMat, newMesh.texPropertyNames[i], relativePath);
                    }
                }
            }
        }

        if (VERBOSE)
        {
            Debug.Log("Created Atlases");
        }
        return(results);
    }
		//texPropertyNames is the list of texture properties in the resultMaterial
		//allowedMaterialsFilter is a list of materials. Objects without any of these materials will be ignored.
		//						 this is used by the multiple materials filter
		//textureEditorMethods encapsulates editor only functionality such as saving assets and tracking texture assets whos format was changed. Is null if using at runtime. 
		bool __combineTexturesIntoAtlases(ProgressUpdateDelegate progressInfo, MB_AtlasesAndRects resultAtlasesAndRects, Material resultMaterial, List<string> texPropertyNames, List<GameObject> objsToMesh, List<Material> allowedMaterialsFilter, MB2_EditorMethodsInterface textureEditorMethods){
			if (LOG_LEVEL >= MB2_LogLevel.debug) Debug.Log("__combineTexturesIntoAtlases atlases:" + texPropertyNames.Count + " objsToMesh:" + objsToMesh.Count + " fixOutOfBoundsUVs:" + fixOutOfBoundsUVs);
			
			if (progressInfo != null) progressInfo("Collecting textures ", .01f);
			/*
			each atlas (maintex, bump, spec etc...) will have distinctMaterialTextures.Count images in it.
			each distinctMaterialTextures record is a set of textures, one for each atlas. And a list of materials
			that use that distinct set of textures. 
			*/
			List<MB_TexSet> distinctMaterialTextures = new List<MB_TexSet>(); //one per distinct set of textures
			List<GameObject> usedObjsToMesh = new List<GameObject>();
			if (!__Step1_CollectDistinctMatTexturesAndUsedObjects(objsToMesh, allowedMaterialsFilter, texPropertyNames, textureEditorMethods, distinctMaterialTextures, usedObjsToMesh)){
				return false;	
			}
	
			//Textures in each material (_mainTex, Bump, Spec ect...) must be same size
			//Calculate the best sized to use. Takes into account tiling
			//if only one texture in atlas re-uses original sizes			
			int _padding = __Step2_CalculateIdealSizesForTexturesInAtlasAndPadding(distinctMaterialTextures);	
						
			__Step3_BuildAndSaveAtlasesAndStoreResults(progressInfo,distinctMaterialTextures,texPropertyNames,_padding,textureEditorMethods,resultAtlasesAndRects,resultMaterial);
			
			return true;
		}
        //texPropertyNames is the list of texture properties in the resultMaterial
        //allowedMaterialsFilter is a list of materials. Objects without any of these materials will be ignored.
        //						 this is used by the multiple materials filter
        //textureEditorMethods encapsulates editor only functionality such as saving assets and tracking texture assets whos format was changed. Is null if using at runtime.
        IEnumerator __CombineTexturesIntoAtlases(ProgressUpdateDelegate progressInfo, CombineTexturesIntoAtlasesCoroutineResult result, MB_AtlasesAndRects resultAtlasesAndRects, MB3_TextureCombinerPipeline.TexturePipelineData data, MB2_EditorMethodsInterface textureEditorMethods)
        {
            if (LOG_LEVEL >= MB2_LogLevel.debug)
            {
                Debug.Log("__CombineTexturesIntoAtlases texture properties in shader:" + data.texPropertyNames.Count + " objsToMesh:" + data.allObjsToMesh.Count + " _fixOutOfBoundsUVs:" + data._fixOutOfBoundsUVs);
            }

            if (progressInfo != null)
            {
                progressInfo("Collecting textures ", .01f);
            }

            MB3_TextureCombinerPipeline pipeline = new MB3_TextureCombinerPipeline();

            /*
             * each atlas (maintex, bump, spec etc...) will have distinctMaterialTextures.Count images in it.
             * each distinctMaterialTextures record is a set of textures, one for each atlas. And a list of materials
             * that use that distinct set of textures.
             */
            List <GameObject> usedObjsToMesh = new List <GameObject>();

            yield return(pipeline.__Step1_CollectDistinctMatTexturesAndUsedObjects(progressInfo, result, data, this, textureEditorMethods, usedObjsToMesh, LOG_LEVEL));

            if (!result.success)
            {
                yield break;
            }

            //Textures in each material (_mainTex, Bump, Spec ect...) must be same size
            //Calculate the best sized to use. Takes into account tiling
            //if only one texture in atlas re-uses original sizes
            yield return(pipeline.CalculateIdealSizesForTexturesInAtlasAndPadding(progressInfo, result, data, this, textureEditorMethods, LOG_LEVEL));

            if (!result.success)
            {
                yield break;
            }

            //buildAndSaveAtlases
            StringBuilder             report       = pipeline.GenerateReport(data);
            MB_ITextureCombinerPacker texturePaker = pipeline.CreatePacker(data.OnlyOneTextureInAtlasReuseTextures(), data._packingAlgorithm);

            if (!texturePaker.Validate(data))
            {
                result.success = false;
                yield break;
            }

            yield return(texturePaker.ConvertTexturesToReadableFormats(progressInfo, result, data, this, textureEditorMethods, LOG_LEVEL));

            if (!result.success)
            {
                yield break;
            }

            AtlasPackingResult[] uvRects = texturePaker.CalculateAtlasRectangles(data, false, LOG_LEVEL);
            Debug.Assert(uvRects.Length == 1, "Error, there should not be more than one packing here.");
            yield return(pipeline.__Step3_BuildAndSaveAtlasesAndStoreResults(result, progressInfo, data, this, texturePaker, uvRects[0], textureEditorMethods, resultAtlasesAndRects, report, LOG_LEVEL));
        }
		/**<summary>Combines meshes and generates texture atlases.</summary>
	    *  <param name="createTextureAtlases">Whether or not texture atlases should be created. If not uvs will not be adjusted.</param>
	    *  <param name="progressInfo">A delegate function that will be called to report progress.</param>
	    *  <param name="textureEditorMethods">If called from the editor should be an instance of MB2_EditorMethods. If called at runtime should be null.</param>
	    *  <remarks>Combines meshes and generates texture atlases</remarks> */		
		public bool combineTexturesIntoAtlases(ProgressUpdateDelegate progressInfo, MB_AtlasesAndRects resultAtlasesAndRects, Material resultMaterial, List<GameObject> objsToMesh, List<Material> allowedMaterialsFilter, int atlasPadding, List<string> customShaderPropNames, bool resizePowerOfTwoTextures, bool fixOutOfBoundsUVs, int maxTilingBakeSize, bool saveAtlasesAsAssets = false, MB2_PackingAlgorithmEnum packingAlgorithm = MB2_PackingAlgorithmEnum.UnitysPackTextures, MB2_EditorMethodsInterface textureEditorMethods = null){
			this.atlasPadding = atlasPadding;
			this.resizePowerOfTwoTextures = resizePowerOfTwoTextures;
			this.fixOutOfBoundsUVs = fixOutOfBoundsUVs;
			this.maxTilingBakeSize = maxTilingBakeSize;
			this.saveAtlasesAsAssets = saveAtlasesAsAssets;
			this.packingAlgorithm = packingAlgorithm;
			this.customShaderPropNames = customShaderPropNames;
			return _combineTexturesIntoAtlases(progressInfo,resultAtlasesAndRects, resultMaterial, objsToMesh, allowedMaterialsFilter, textureEditorMethods);
		}		
Example #39
0
    public IEnumerator CreateAtlasesCoroutine(ProgressUpdateDelegate progressInfo, CreateAtlasesCoroutineResult coroutineResult, bool saveAtlasesAsAssets = false, MB2_EditorMethodsInterface editorMethods = null, float maxTimePerFrame = .01f)
    {
        MBVersionConcrete mbv = new MBVersionConcrete();

        if (!MB3_TextureCombiner._RunCorutineWithoutPauseIsRunning && (mbv.GetMajorVersion() < 5 || (mbv.GetMajorVersion() == 5 && mbv.GetMinorVersion() < 3)))
        {
            Debug.LogError("Running the texture combiner as a coroutine only works in Unity 5.3 and higher");
            yield return(null);
        }
        this.OnCombinedTexturesCoroutineAtlasesAndRects = null;
        //if (!Application.isPlaying)
        //{
        //    Debug.LogError("CombineTexturesIntoAtlasesCoroutine should only be called when the game is running. Use CombineTexturesIntoAtlases in the editor.");
        //    _CreateAtlasesCoroutineIsFinished = true;
        //    yield break;
        //}
        if (maxTimePerFrame <= 0f)
        {
            Debug.LogError("maxTimePerFrame must be a value greater than zero");
            coroutineResult.isFinished = true;
            yield break;
        }
        MB2_ValidationLevel vl = Application.isPlaying ? MB2_ValidationLevel.quick : MB2_ValidationLevel.robust;

        if (!DoCombinedValidate(this, MB_ObjsToCombineTypes.dontCare, null, vl))
        {
            coroutineResult.isFinished = true;
            yield break;
        }
        if (_doMultiMaterial && !_ValidateResultMaterials())
        {
            coroutineResult.isFinished = true;
            yield break;
        }
        else if (!_doMultiMaterial)
        {
            if (_resultMaterial == null)
            {
                Debug.LogError("Combined Material is null please create and assign a result material.");
                coroutineResult.isFinished = true;
                yield break;
            }
            Shader targShader = _resultMaterial.shader;
            for (int i = 0; i < objsToMesh.Count; i++)
            {
                Material[] ms = MB_Utility.GetGOMaterials(objsToMesh[i]);
                for (int j = 0; j < ms.Length; j++)
                {
                    Material m = ms[j];
                    if (m != null && m.shader != targShader)
                    {
                        Debug.LogWarning("Game object " + objsToMesh[i] + " does not use shader " + targShader + " it may not have the required textures. If not small solid color textures will be generated.");
                    }
                }
            }
        }

        for (int i = 0; i < objsToMesh.Count; i++)
        {
            Material[] ms = MB_Utility.GetGOMaterials(objsToMesh[i]);
            for (int j = 0; j < ms.Length; j++)
            {
                Material m = ms[j];
                if (m == null)
                {
                    Debug.LogError("Game object " + objsToMesh[i] + " has a null material. Can't build atlases");
                    coroutineResult.isFinished = true;
                    yield break;
                }
            }
        }

        MB3_TextureCombiner combiner = new MB3_TextureCombiner();

        combiner.LOG_LEVEL             = LOG_LEVEL;
        combiner.atlasPadding          = _atlasPadding;
        combiner.maxAtlasSize          = _maxAtlasSize;
        combiner.customShaderPropNames = _customShaderProperties;
        combiner.fixOutOfBoundsUVs     = _fixOutOfBoundsUVs;
        combiner.maxTilingBakeSize     = _maxTilingBakeSize;
        combiner.packingAlgorithm      = _packingAlgorithm;
        combiner.meshBakerTexturePackerForcePowerOfTwo = _meshBakerTexturePackerForcePowerOfTwo;
        combiner.resizePowerOfTwoTextures     = _resizePowerOfTwoTextures;
        combiner.saveAtlasesAsAssets          = saveAtlasesAsAssets;
        combiner.considerNonTextureProperties = _considerNonTextureProperties;

        //initialize structure to store results
        int numResults = 1;

        if (_doMultiMaterial)
        {
            numResults = resultMaterials.Length;
        }
        OnCombinedTexturesCoroutineAtlasesAndRects = new MB_AtlasesAndRects[numResults];
        for (int i = 0; i < OnCombinedTexturesCoroutineAtlasesAndRects.Length; i++)
        {
            OnCombinedTexturesCoroutineAtlasesAndRects[i] = new MB_AtlasesAndRects();
        }

        //Do the material combining.
        for (int i = 0; i < OnCombinedTexturesCoroutineAtlasesAndRects.Length; i++)
        {
            Material        resMatToPass = null;
            List <Material> sourceMats   = null;
            if (_doMultiMaterial)
            {
                sourceMats   = resultMaterials[i].sourceMaterials;
                resMatToPass = resultMaterials[i].combinedMaterial;
            }
            else
            {
                resMatToPass = _resultMaterial;
            }
            Debug.Log(string.Format("Creating atlases for result material {0} using shader {1}", resMatToPass, resMatToPass.shader));
            MB3_TextureCombiner.CombineTexturesIntoAtlasesCoroutineResult coroutineResult2 = new MB3_TextureCombiner.CombineTexturesIntoAtlasesCoroutineResult();
            yield return(combiner.CombineTexturesIntoAtlasesCoroutine(progressInfo, OnCombinedTexturesCoroutineAtlasesAndRects[i], resMatToPass, objsToMesh, sourceMats, editorMethods, coroutineResult2, maxTimePerFrame));

            coroutineResult.success = coroutineResult2.success;
            if (!coroutineResult.success)
            {
                coroutineResult.isFinished = true;
                yield break;
            }
        }

        //Save the results
        textureBakeResults.combinedMaterialInfo = OnCombinedTexturesCoroutineAtlasesAndRects;
        textureBakeResults.doMultiMaterial      = _doMultiMaterial;
        textureBakeResults.resultMaterial       = _resultMaterial;
        textureBakeResults.resultMaterials      = resultMaterials;
        textureBakeResults.fixOutOfBoundsUVs    = combiner.fixOutOfBoundsUVs;
        unpackMat2RectMap(textureBakeResults);

        //set the texture bake resultAtlasesAndRects on the Mesh Baker component if it exists
        MB3_MeshBakerCommon[] mb = GetComponentsInChildren <MB3_MeshBakerCommon>();
        for (int i = 0; i < mb.Length; i++)
        {
            mb[i].textureBakeResults = textureBakeResults;
        }

        if (LOG_LEVEL >= MB2_LogLevel.info)
        {
            Debug.Log("Created Atlases");
        }

        coroutineResult.isFinished = true;
        if (coroutineResult.success && onBuiltAtlasesSuccess != null)
        {
            onBuiltAtlasesSuccess();
        }
        if (!coroutineResult.success && onBuiltAtlasesFail != null)
        {
            onBuiltAtlasesFail();
        }
    }