Ejemplo n.º 1
0
		public static Mesh BakeMeshesInPlace(MB3_MeshCombinerSingle mom, List<GameObject> objsToMesh, string saveFolder, ProgressUpdateDelegate updateProgressBar){
			if (MB3_MeshCombiner.EVAL_VERSION) return null; 
	
			if (!Directory.Exists(Application.dataPath + saveFolder.Substring(6))){
				Debug.Log((Application.dataPath + saveFolder.Substring(6)));
				Debug.Log(Path.GetFullPath(Application.dataPath + saveFolder.Substring(6)));
				Debug.LogError("The selected Folder For Meshes does not exist or is not inside the projects Assets folder. Please 'Choose Folder For Bake In Place Meshes' that is inside the project's assets folder.");	
				return null;
			}

			MB3_EditorMethods editorMethods = new MB3_EditorMethods();
			mom.DestroyMeshEditor(editorMethods);
			
			MB_RenderType originalRenderType = mom.renderType;
			Mesh outMesh = null;
			for (int i = 0; i < objsToMesh.Count; i++){
				if (objsToMesh[i] == null){
					Debug.LogError("The " + i + "th object on the list of objects to combine is 'None'. Use Command-Delete on Mac OS X; Delete or Shift-Delete on Windows to remove this one element.");
					return null;					
				}
				string[] objNames = GenerateNames(objsToMesh);
				outMesh = BakeOneMesh(mom, saveFolder + "/" + objNames[i], objsToMesh[i]);
				if (updateProgressBar != null) updateProgressBar("Created mesh saving mesh on " + objsToMesh[i].name + " to asset " + objNames[i],.6f);				
			}
			mom.renderType = originalRenderType;
			return outMesh;
		}
	/// <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;
	}
		public void SetReadFlags(ProgressUpdateDelegate progressInfo){
			for (int i = 0; i < _texturesWithReadWriteFlagSet.Count; i++){
				if (progressInfo != null) progressInfo("Restoring read flag for " + _texturesWithReadWriteFlagSet[i],.9f);
				SetReadWriteFlag(_texturesWithReadWriteFlagSet[i], false,false);
			}
			_texturesWithReadWriteFlagSet.Clear();		
			foreach (Texture2D tex in _textureFormatMap.Keys){
				if (progressInfo != null) progressInfo("Restoring format for " + tex,.9f);
				SetTextureFormat(tex, _textureFormatMap[tex],false,_textureFormatMap[tex].isNormalMap);
			}
			_textureFormatMap.Clear();		
		}
		public static Mesh BakeMeshesInPlace(MB2_MeshCombiner mom, List<GameObject> objsToMesh, string saveFolder, ProgressUpdateDelegate updateProgressBar){
			if (MB2_MeshCombiner.EVAL_VERSION) return null;
				
			Mesh mesh;
	
			if (!Directory.Exists(Application.dataPath + saveFolder.Substring(6,saveFolder.Length-6))){
				Debug.Log((Application.dataPath + saveFolder));
				Debug.Log(Path.GetFullPath(Application.dataPath + saveFolder));
				Debug.LogError("The selected Folder For Meshes does not exist or is not inside the projects Assets folder. Please 'Choose Folder For Bake In Place Meshes' that is inside the project's assets folder.");	
				return null;
			}

			MB2_EditorMethods editorMethods = new MB2_EditorMethods();
			mom.DestroyMeshEditor(editorMethods);
			
			GameObject[] objs = new GameObject[1];
			MB_RenderType originalRenderType = mom.renderType;
			Mesh outMesh = null;
			for (int i = 0; i < objsToMesh.Count; i++){
				if (objsToMesh[i] == null){
					Debug.LogError("The " + i + "th object on the list of objects to combine is 'None'. Use Command-Delete on Mac OS X; Delete or Shift-Delete on Windows to remove this one element.");
					return null;					
				}
				string[] objNames = GenerateNames(objsToMesh);
				objs[0] = objsToMesh[i];
				Renderer r = MB_Utility.GetRenderer(objsToMesh[i]);
				if (r is SkinnedMeshRenderer){
					mom.renderType = MB_RenderType.skinnedMeshRenderer;	
				} else {
					mom.renderType = MB_RenderType.meshRenderer;
				}
				mesh = mom.AddDeleteGameObjects(objs,null,false);
				if (mesh != null){
					mom.Apply();
					Mesh mf = MB_Utility.GetMesh(objs[0]);
					if (mf != null){
						string newFilename = saveFolder + "/" + objNames[i];
						if (updateProgressBar != null) updateProgressBar("Created mesh saving mesh on " + objs[0].name + " to asset " + newFilename,.6f);
						if (newFilename != null && newFilename.Length != 0){
							Debug.Log("Creating mesh for " + objs[0].name + " with adjusted UVs at: " + newFilename);
							AssetDatabase.CreateAsset(mesh,  newFilename);
							outMesh = (Mesh) AssetDatabase.LoadAssetAtPath(newFilename, typeof(Mesh));
						} else {
							Debug.LogWarning("Could not save mesh for " + objs[0].name);	
						}
					}
				}
				mom.DestroyMeshEditor(editorMethods);
			}
			mom.renderType = originalRenderType;
			return outMesh;
		}
Ejemplo n.º 5
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();
        }
    }
Ejemplo n.º 6
0
 public abstract IEnumerator CreateAtlases(ProgressUpdateDelegate progressInfo,
                                           TexturePipelineData data,
                                           TextureCombineHandler combiner,
                                           AtlasPackingResult packedAtlasRects,
                                           Texture2D[] atlases,
                                           EditorMethodsInterface textureEditorMethods);
Ejemplo n.º 7
0
    public MB_AtlasesAndRects[] CreateAtlases(ProgressUpdateDelegate progressInfo)
    {
        if (doMultiMaterial)
        {
            for (int i = 0; i < resultMaterials.Length; i++)
            {
                MB_MultiMaterial mm         = resultMaterials[i];
                Shader           targShader = mm.combinedMaterial.shader;
                for (int j = 0; j < mm.sourceMaterials.Count; j++)
                {
                    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
        {
            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[]      resMatsToPass = new Material[1];
        List <Material> sourceMats    = null;

        for (int i = 0; i < results.Length; i++)
        {
            if (doMultiMaterial)
            {
                sourceMats       = resultMaterials[i].sourceMaterials;
                resMatsToPass[0] = resultMaterials[i].combinedMaterial;
            }
            else
            {
                resMatsToPass[0] = resultMaterial;
            }
            Debug.Log("Creating atlases for result material " + resMatsToPass[0]);
            if (!tc.combineTexturesIntoAtlases(progressInfo, results[i], resMatsToPass, objsToMesh, sourceMats, atlasPadding, customShaderPropNames, resizePowerOfTwoTextures, fixOutOfBoundsUVs, 1024))
            {
                return(null);
            }
        }
        updateMaterialToRectMapping(results);
        return(results);
    }
        public IEnumerator CreateAtlases(ProgressUpdateDelegate progressInfo,
                                         MB3_TextureCombinerPipeline.TexturePipelineData data, MB3_TextureCombiner combiner,
                                         AtlasPackingResult packedAtlasRects,
                                         Texture2D[] atlases, MB2_EditorMethodsInterface textureEditorMethods,
                                         MB2_LogLevel LOG_LEVEL)
        {
            Debug.Assert(!data.OnlyOneTextureInAtlasReuseTextures());
            Rect[] uvRects = packedAtlasRects.rects;

            int atlasSizeX = packedAtlasRects.atlasX;
            int atlasSizeY = packedAtlasRects.atlasY;

            if (LOG_LEVEL >= MB2_LogLevel.debug)
            {
                Debug.Log("Generated atlas will be " + atlasSizeX + "x" + atlasSizeY);
            }

            //create a game object
            GameObject renderAtlasesGO = null;

            try
            {
                renderAtlasesGO = new GameObject("MBrenderAtlasesGO");
                MB3_AtlasPackerRenderTexture atlasRenderTexture = renderAtlasesGO.AddComponent <MB3_AtlasPackerRenderTexture>();
                renderAtlasesGO.AddComponent <Camera>();
                if (data._considerNonTextureProperties && LOG_LEVEL >= MB2_LogLevel.warn)
                {
                    Debug.LogError("Blend Non-Texture Properties has limited functionality when used with Mesh Baker Texture Packer Fast. If no texture is pesent, then a small texture matching the non-texture property will be created and used in the atlas. But non-texture properties will not be blended into texture.");
                }

                for (int propIdx = 0; propIdx < data.numAtlases; propIdx++)
                {
                    Texture2D atlas = null;
                    if (!MB3_TextureCombinerPipeline._ShouldWeCreateAtlasForThisProperty(propIdx, data._considerNonTextureProperties, data.allTexturesAreNullAndSameColor))
                    {
                        atlas = null;
                        if (LOG_LEVEL >= MB2_LogLevel.debug)
                        {
                            Debug.Log("Not creating atlas for " + data.texPropertyNames[propIdx].name + " because textures are null and default value parameters are the same.");
                        }
                    }
                    else
                    {
                        GC.Collect();

                        MB3_TextureCombinerPackerRoot.CreateTemporaryTexturesForAtlas(data.distinctMaterialTextures, combiner, propIdx, data);

                        if (progressInfo != null)
                        {
                            progressInfo("Creating Atlas '" + data.texPropertyNames[propIdx].name + "'", .01f);
                        }
                        // ===========
                        // configure it
                        if (LOG_LEVEL >= MB2_LogLevel.debug)
                        {
                            Debug.Log("About to render " + data.texPropertyNames[propIdx].name + " isNormal=" + data.texPropertyNames[propIdx].isNormalMap);
                        }
                        atlasRenderTexture.LOG_LEVEL                    = LOG_LEVEL;
                        atlasRenderTexture.width                        = atlasSizeX;
                        atlasRenderTexture.height                       = atlasSizeY;
                        atlasRenderTexture.padding                      = data._atlasPadding;
                        atlasRenderTexture.rects                        = uvRects;
                        atlasRenderTexture.textureSets                  = data.distinctMaterialTextures;
                        atlasRenderTexture.indexOfTexSetToRender        = propIdx;
                        atlasRenderTexture.texPropertyName              = data.texPropertyNames[propIdx];
                        atlasRenderTexture.isNormalMap                  = data.texPropertyNames[propIdx].isNormalMap;
                        atlasRenderTexture.fixOutOfBoundsUVs            = data._fixOutOfBoundsUVs;
                        atlasRenderTexture.considerNonTextureProperties = data._considerNonTextureProperties;
                        atlasRenderTexture.resultMaterialTextureBlender = data.nonTexturePropertyBlender;
                        // call render on it
                        atlas = atlasRenderTexture.OnRenderAtlas(combiner);

                        // destroy it
                        // =============
                        if (LOG_LEVEL >= MB2_LogLevel.debug)
                        {
                            Debug.Log("Saving atlas " + data.texPropertyNames[propIdx].name + " w=" + atlas.width + " h=" + atlas.height + " id=" + atlas.GetInstanceID());
                        }
                    }
                    atlases[propIdx] = atlas;
                    if (progressInfo != null)
                    {
                        progressInfo("Saving atlas: '" + data.texPropertyNames[propIdx].name + "'", .04f);
                    }
                    if (data.resultType == MB2_TextureBakeResults.ResultType.atlas)
                    {
                        MB3_TextureCombinerPackerRoot.SaveAtlasAndConfigureResultMaterial(data, textureEditorMethods, atlases[propIdx], data.texPropertyNames[propIdx], propIdx);
                    }

                    combiner._destroyTemporaryTextures(data.texPropertyNames[propIdx].name); // need to save atlases before doing this
                }
            }
            catch (Exception ex)
            {
                //Debug.LogError(ex);
                Debug.LogError(ex.Message + "\n" + ex.StackTrace.ToString());
            }
            finally
            {
                if (renderAtlasesGO != null)
                {
                    MB_Utility.Destroy(renderAtlasesGO);
                }
            }
            yield break;
        }
		public void CopyScaledAndTiledToAtlas(MeshBakerMaterialTexture source, int targX, int targY, int targW, int targH, bool fixOutOfBoundsUVs, int maxSize, Color[] atlasPixels, int atlasWidth, ProgressUpdateDelegate progressInfo=null){			
			if (LOG_LEVEL >= MB2_LogLevel.debug) Debug.Log("CopyScaledAndTiledToAtlas: " + source.t + " inAtlasX=" + targX + " inAtlasY=" + targY + " inAtlasW=" + targW + " inAtlasH=" + targH);
			float newWidth = targW;
			float newHeight = targH;
			float scx = source.scale.x;
			float scy = source.scale.y;
			float ox = source.offset.x;
			float oy = source.offset.y;
			if (fixOutOfBoundsUVs){
				scx *= source.obUVscale.x;
				scy *= source.obUVscale.y;
				ox += source.obUVoffset.x;
				oy += source.obUVoffset.y;
			}
			int w = (int) newWidth;
			int h = (int) newHeight;
			Texture2D t = source.t;
			if (t == null){
				t = _createTemporaryTexture(2,2,TextureFormat.ARGB32, true);
				MB_Utility.setSolidColor(t,Color.clear);
			}
			t = _addWatermark(t);
			for (int i = 0;i < w; i++){
				if (progressInfo != null && w > 0) progressInfo("CopyScaledAndTiledToAtlas " + (((float)i/(float)w)*100f).ToString("F0"),.2f);
				for (int j = 0;j < h; j++){
					float u = i/newWidth*scx + ox;
					float v = j/newHeight*scy + oy;
					atlasPixels[(targY + j) * atlasWidth + targX + i] = t.GetPixelBilinear(u,v);
				}			
			}
		}		
Ejemplo n.º 10
0
		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"));
		}
	public void CreateAndSaveAtlases(ProgressUpdateDelegate progressInfo, MB2_EditorMethodsInterface textureFormatTracker){
		CreateAtlases(progressInfo,true,textureFormatTracker);
	}	
		//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;
		}
        internal static IEnumerator CopyScaledAndTiledToAtlas(MeshBakerMaterialTexture source, MB_TexSet sourceMaterial,
                                                              ShaderTextureProperty shaderPropertyName, DRect srcSamplingRect, int targX, int targY, int targW, int targH,
                                                              AtlasPadding padding,
                                                              Color[][] atlasPixels, bool isNormalMap,
                                                              MB3_TextureCombinerPipeline.TexturePipelineData data,
                                                              MB3_TextureCombiner combiner,
                                                              ProgressUpdateDelegate progressInfo = null,
                                                              MB2_LogLevel LOG_LEVEL = MB2_LogLevel.info)
        {
            //HasFinished = false;
            Texture2D t = source.GetTexture2D();

            if (LOG_LEVEL >= MB2_LogLevel.debug)
            {
                Debug.Log(String.Format("CopyScaledAndTiledToAtlas: {0} inAtlasX={1} inAtlasY={2} inAtlasW={3} inAtlasH={4} paddX={5} paddY={6} srcSamplingRect={7}",
                                        t, targX, targY, targW, targH, padding.leftRight, padding.topBottom, srcSamplingRect));
            }
            float newWidth  = targW;
            float newHeight = targH;
            float scx       = (float)srcSamplingRect.width;
            float scy       = (float)srcSamplingRect.height;
            float ox        = (float)srcSamplingRect.x;
            float oy        = (float)srcSamplingRect.y;
            int   w         = (int)newWidth;
            int   h         = (int)newHeight;

            if (data._considerNonTextureProperties)
            {
                t = combiner._createTextureCopy(shaderPropertyName.name, t);
                t = data.nonTexturePropertyBlender.TintTextureWithTextureCombiner(t, sourceMaterial, shaderPropertyName);
            }
            for (int i = 0; i < w; i++)
            {
                if (progressInfo != null && w > 0)
                {
                    progressInfo("CopyScaledAndTiledToAtlas " + (((float)i / (float)w) * 100f).ToString("F0"), .2f);
                }
                for (int j = 0; j < h; j++)
                {
                    float u = i / newWidth * scx + ox;
                    float v = j / newHeight * scy + oy;
                    atlasPixels[targY + j][targX + i] = t.GetPixelBilinear(u, v);
                }
            }

            //bleed the border colors into the padding
            for (int i = 0; i < w; i++)
            {
                for (int j = 1; j <= padding.topBottom; j++)
                {
                    //top margin
                    atlasPixels[(targY - j)][targX + i] = atlasPixels[(targY)][targX + i];
                    //bottom margin
                    atlasPixels[(targY + h - 1 + j)][targX + i] = atlasPixels[(targY + h - 1)][targX + i];
                }
            }
            for (int j = 0; j < h; j++)
            {
                for (int i = 1; i <= padding.leftRight; i++)
                {
                    //left margin
                    atlasPixels[(targY + j)][targX - i] = atlasPixels[(targY + j)][targX];
                    //right margin
                    atlasPixels[(targY + j)][targX + w + i - 1] = atlasPixels[(targY + j)][targX + w - 1];
                }
            }
            //corners
            for (int i = 1; i <= padding.leftRight; i++)
            {
                for (int j = 1; j <= padding.topBottom; j++)
                {
                    atlasPixels[(targY - j)][targX - i]                 = atlasPixels[targY][targX];
                    atlasPixels[(targY + h - 1 + j)][targX - i]         = atlasPixels[(targY + h - 1)][targX];
                    atlasPixels[(targY + h - 1 + j)][targX + w + i - 1] = atlasPixels[(targY + h - 1)][targX + w - 1];
                    atlasPixels[(targY - j)][targX + w + i - 1]         = atlasPixels[targY][targX + w - 1];
                    yield return(null);
                }
                yield return(null);
            }
            //			Debug.Log("copyandscaledatlas finished too!");
            //HasFinished = true;
            yield break;
        }
        public override IEnumerator CreateAtlases(ProgressUpdateDelegate progressInfo,
                                                  MB3_TextureCombinerPipeline.TexturePipelineData data, MB3_TextureCombiner combiner,
                                                  AtlasPackingResult packedAtlasRects,
                                                  Texture2D[] atlases, MB2_EditorMethodsInterface textureEditorMethods,
                                                  MB2_LogLevel LOG_LEVEL)
        {
            Rect[] uvRects = packedAtlasRects.rects;

            int atlasSizeX = packedAtlasRects.atlasX;
            int atlasSizeY = packedAtlasRects.atlasY;

            if (LOG_LEVEL >= MB2_LogLevel.debug)
            {
                Debug.Log("Generated atlas will be " + atlasSizeX + "x" + atlasSizeY);
            }

            for (int propIdx = 0; propIdx < data.numAtlases; propIdx++)
            {
                Texture2D             atlas    = null;
                ShaderTextureProperty property = data.texPropertyNames[propIdx];
                if (!MB3_TextureCombinerPipeline._ShouldWeCreateAtlasForThisProperty(propIdx, data._considerNonTextureProperties, data.allTexturesAreNullAndSameColor))
                {
                    atlas = null;
                    if (LOG_LEVEL >= MB2_LogLevel.debug)
                    {
                        Debug.Log("=== Not creating atlas for " + property.name + " because textures are null and default value parameters are the same.");
                    }
                }
                else
                {
                    if (LOG_LEVEL >= MB2_LogLevel.debug)
                    {
                        Debug.Log("=== Creating atlas for " + property.name);
                    }

                    GC.Collect();

                    CreateTemporaryTexturesForAtlas(data.distinctMaterialTextures, combiner, propIdx, data);

                    //use a jagged array because it is much more efficient in memory
                    Color[][] atlasPixels = new Color[atlasSizeY][];
                    for (int j = 0; j < atlasPixels.Length; j++)
                    {
                        atlasPixels[j] = new Color[atlasSizeX];
                    }

                    bool isNormalMap = false;
                    if (property.isNormalMap)
                    {
                        isNormalMap = true;
                    }

                    for (int texSetIdx = 0; texSetIdx < data.distinctMaterialTextures.Count; texSetIdx++)
                    {
                        MB_TexSet texSet = data.distinctMaterialTextures[texSetIdx];
                        MeshBakerMaterialTexture matTex = texSet.ts[propIdx];
                        string s = "Creating Atlas '" + property.name + "' texture " + matTex.GetTexName();
                        if (progressInfo != null)
                        {
                            progressInfo(s, .01f);
                        }
                        if (LOG_LEVEL >= MB2_LogLevel.trace)
                        {
                            Debug.Log(string.Format("Adding texture {0} to atlas {1} for texSet {2} srcMat {3}", matTex.GetTexName(), property.name, texSetIdx, texSet.matsAndGOs.mats[0].GetMaterialName()));
                        }
                        Rect      r  = uvRects[texSetIdx];
                        Texture2D t  = texSet.ts[propIdx].GetTexture2D();
                        int       x  = Mathf.RoundToInt(r.x * atlasSizeX);
                        int       y  = Mathf.RoundToInt(r.y * atlasSizeY);
                        int       ww = Mathf.RoundToInt(r.width * atlasSizeX);
                        int       hh = Mathf.RoundToInt(r.height * atlasSizeY);
                        if (ww == 0 || hh == 0)
                        {
                            Debug.LogError("Image in atlas has no height or width " + r);
                        }
                        if (progressInfo != null)
                        {
                            progressInfo(s + " set ReadWrite flag", .01f);
                        }
                        if (textureEditorMethods != null)
                        {
                            textureEditorMethods.SetReadWriteFlag(t, true, true);
                        }
                        if (progressInfo != null)
                        {
                            progressInfo(s + "Copying to atlas: '" + matTex.GetTexName() + "'", .02f);
                        }
                        DRect samplingRect = texSet.ts[propIdx].GetEncapsulatingSamplingRect();
                        Debug.Assert(!texSet.ts[propIdx].isNull, string.Format("Adding texture {0} to atlas {1} for texSet {2} srcMat {3}", matTex.GetTexName(), property.name, texSetIdx, texSet.matsAndGOs.mats[0].GetMaterialName()));
                        yield return(CopyScaledAndTiledToAtlas(texSet.ts[propIdx], texSet, property, samplingRect, x, y, ww, hh, packedAtlasRects.padding[texSetIdx], atlasPixels, isNormalMap, data, combiner, progressInfo, LOG_LEVEL));
                    }

                    yield return(data.numAtlases);

                    if (progressInfo != null)
                    {
                        progressInfo("Applying changes to atlas: '" + property.name + "'", .03f);
                    }
                    atlas = new Texture2D(atlasSizeX, atlasSizeY, TextureFormat.ARGB32, true);
                    for (int j = 0; j < atlasPixels.Length; j++)
                    {
                        atlas.SetPixels(0, j, atlasSizeX, 1, atlasPixels[j]);
                    }

                    atlas.Apply();
                    if (LOG_LEVEL >= MB2_LogLevel.debug)
                    {
                        Debug.Log("Saving atlas " + property.name + " w=" + atlas.width + " h=" + atlas.height);
                    }
                }

                atlases[propIdx] = atlas;
                if (progressInfo != null)
                {
                    progressInfo("Saving atlas: '" + property.name + "'", .04f);
                }
                System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
                sw.Start();
                if (data.resultType == MB2_TextureBakeResults.ResultType.atlas)
                {
                    if (data._saveAtlasesAsAssets && textureEditorMethods != null)
                    {
                        textureEditorMethods.SaveAtlasToAssetDatabase(atlases[propIdx], data.texPropertyNames[propIdx], propIdx, data.resultMaterial);
                    }
                    else
                    {
                        data.resultMaterial.SetTexture(data.texPropertyNames[propIdx].name, atlases[propIdx]);
                    }

                    data.resultMaterial.SetTextureOffset(data.texPropertyNames[propIdx].name, Vector2.zero);
                    data.resultMaterial.SetTextureScale(data.texPropertyNames[propIdx].name, Vector2.one);
                }


                combiner._destroyTemporaryTextures(data.texPropertyNames[propIdx].name);
            }

            yield break;
        }
Ejemplo n.º 15
0
        public static Mesh BakeMeshesInPlace(MB3_MeshCombinerSingle mom, List <GameObject> objsToMesh, string saveFolder, ProgressUpdateDelegate updateProgressBar)
        {
            if (MB3_MeshCombiner.EVAL_VERSION)
            {
                return(null);
            }
            if (saveFolder.Length < 6)
            {
                Debug.LogError("Please select a folder for meshes.");
                return(null);
            }
            if (!Directory.Exists(Application.dataPath + saveFolder.Substring(6)))
            {
                Debug.Log((Application.dataPath + saveFolder.Substring(6)));
                Debug.Log(Path.GetFullPath(Application.dataPath + saveFolder.Substring(6)));
                Debug.LogError("The selected Folder For Meshes does not exist or is not inside the projects Assets folder. Please 'Choose Folder For Bake In Place Meshes' that is inside the project's assets folder.");
                return(null);
            }

            MB3_EditorMethods editorMethods = new MB3_EditorMethods();

            mom.DestroyMeshEditor(editorMethods);

            MB_RenderType originalRenderType = mom.renderType;
            Mesh          outMesh            = null;

            for (int i = 0; i < objsToMesh.Count; i++)
            {
                if (objsToMesh[i] == null)
                {
                    Debug.LogError("The " + i + "th object on the list of objects to combine is 'None'. Use Command-Delete on Mac OS X; Delete or Shift-Delete on Windows to remove this one element.");
                    return(null);
                }
                string[] objNames = GenerateNames(objsToMesh);
                outMesh = BakeOneMesh(mom, saveFolder + "/" + objNames[i], objsToMesh[i]);
                if (updateProgressBar != null)
                {
                    updateProgressBar("Created mesh saving mesh on " + objsToMesh[i].name + " to asset " + objNames[i], .6f);
                }
            }
            mom.renderType = originalRenderType;
            return(outMesh);
        }
Ejemplo n.º 16
0
 public void Setup(DatabaseInfo databaseInfo, ProgressUpdateDelegate progressUpdate)
 {
     DatabaseInfo   = databaseInfo ?? throw new ArgumentNullException(nameof(databaseInfo));
     ProgressUpdate = progressUpdate ?? throw new ArgumentNullException(nameof(progressUpdate));
 }
    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.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();
        }
    }
        public IEnumerator CreateAtlases(ProgressUpdateDelegate progressInfo,
                                         TexturePipelineData data,
                                         TextureCombineHandler combiner,
                                         AtlasPackingResult packedAtlasRects,
                                         Texture2D[] atlases,
                                         EditorMethodsInterface textureEditorMethods)
        {
            Debug.Assert(!data.IsOnlyOneTextureInAtlasReuseTextures());
            Rect[] uvRects = packedAtlasRects.rects;

            int atlasSizeX = packedAtlasRects.atlasX;
            int atlasSizeY = packedAtlasRects.atlasY;

            Debug.Log("Generated atlas will be " + atlasSizeX + "x" + atlasSizeY);

            //create a game object
            GameObject renderAtlasesGO = null;

            try
            {
                renderAtlasesGO = new GameObject("MBrenderAtlasesGO");
                AtlasPackerRenderTexture atlasRenderTexture = renderAtlasesGO.AddComponent <AtlasPackerRenderTexture>();
                renderAtlasesGO.AddComponent <Camera>();
                if (data._considerNonTextureProperties)
                {
                    Debug.LogWarning("Blend Non-Texture Properties has limited functionality when used with Mesh Baker Texture Packer Fast.");
                }

                for (int propIdx = 0; propIdx < data.numAtlases; propIdx++)
                {
                    Texture2D atlas = null;
                    if (!TextureCombinerPipeline._ShouldWeCreateAtlasForThisProperty(propIdx, data._considerNonTextureProperties, data.allTexturesAreNullAndSameColor))
                    {
                        atlas = null;
                        Debug.Log("Not creating atlas for " + data.texPropertyNames[propIdx].name + " because textures are null and default value parameters are the same.");
                    }
                    else
                    {
                        GC.Collect();

                        TextureCombinerPackerBase.CreateTemporaryTexturesForAtlas(data.distinctMaterialTextures, combiner, propIdx, data);

                        if (progressInfo != null)
                        {
                            progressInfo("Creating Atlas '" + data.texPropertyNames[propIdx].name + "'", .01f);
                        }
                        // ===========
                        // configure it
                        Debug.Log("About to render " + data.texPropertyNames[propIdx].name + " isNormal=" + data.texPropertyNames[propIdx].isNormalMap);
                        atlasRenderTexture.width                        = atlasSizeX;
                        atlasRenderTexture.height                       = atlasSizeY;
                        atlasRenderTexture.padding                      = data._atlasPadding;
                        atlasRenderTexture.rects                        = uvRects;
                        atlasRenderTexture.textureSets                  = data.distinctMaterialTextures;
                        atlasRenderTexture.indexOfTexSetToRender        = propIdx;
                        atlasRenderTexture.texPropertyName              = data.texPropertyNames[propIdx];
                        atlasRenderTexture.isNormalMap                  = data.texPropertyNames[propIdx].isNormalMap;
                        atlasRenderTexture.fixOutOfBoundsUVs            = data._fixOutOfBoundsUVs;
                        atlasRenderTexture.considerNonTextureProperties = data._considerNonTextureProperties;
                        atlasRenderTexture.resultMaterialTextureBlender = data.nonTexturePropertyBlender;
                        // call render on it
                        atlas = atlasRenderTexture.OnRenderAtlas(combiner);

                        // destroy it
                        // =============
                        Debug.Log("Saving atlas " + data.texPropertyNames[propIdx].name + " w=" + atlas.width + " h=" + atlas.height + " id=" + atlas.GetInstanceID());
                    }
                    atlases[propIdx] = atlas;
                    if (progressInfo != null)
                    {
                        progressInfo("Saving atlas: '" + data.texPropertyNames[propIdx].name + "'", .04f);
                    }
                    if (data._saveAtlasesAsAssets && textureEditorMethods != null)
                    {
                        textureEditorMethods.SaveAtlasToAssetDatabase(atlases[propIdx], data.texPropertyNames[propIdx], propIdx, data.resultMaterial);
                    }
                    else
                    {
                        data.resultMaterial.SetTexture(data.texPropertyNames[propIdx].name, atlases[propIdx]);
                    }
                    data.resultMaterial.SetTextureOffset(data.texPropertyNames[propIdx].name, Vector2.zero);
                    data.resultMaterial.SetTextureScale(data.texPropertyNames[propIdx].name, Vector2.one);
                    combiner._destroyTemporaryTextures(data.texPropertyNames[propIdx].name); // need to save atlases before doing this
                }
            }
            catch (Exception ex)
            {
                //Debug.LogError(ex);
                Debug.LogException(ex);
            }
            finally
            {
                if (renderAtlasesGO != null)
                {
                    MeshBakerUtility.Destroy(renderAtlasesGO);
                }
            }
            yield break;
        }
        //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);
            }

            /*
             *          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
            data.allTexturesAreNullAndSameColor = new MB3_TextureCombinerPipeline.CreateAtlasForProperty[data.texPropertyNames.Count];
            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._packingAlgorithm);
            MB3_ITextureCombinerCalculateAtlasRects atlasRectCalculator = new MB3_TextureCombinerCalculateAtlasRectsStandard();
            AtlasPackingResult uvRects = atlasRectCalculator.CalculateAtlasRectangles(data, LOG_LEVEL);

            yield return(MB3_TextureCombinerPipeline.__Step3_BuildAndSaveAtlasesAndStoreResults(result, progressInfo, data, this, texturePaker, uvRects, textureEditorMethods, resultAtlasesAndRects, report, LOG_LEVEL));
        }
        Rect[] __CreateAtlasesMBTexturePackerFast(ProgressUpdateDelegate progressInfo, int numAtlases, List<MB_TexSet> distinctMaterialTextures, List<ShaderTextureProperty> texPropertyNames, bool[] allTexturesAreNullAndSameColor, Material resultMaterial, Texture2D[] atlases, MB2_EditorMethodsInterface textureEditorMethods, int _padding)
        {
            Rect[] uvRects;
            if (distinctMaterialTextures.Count == 1){
                if (LOG_LEVEL >= MB2_LogLevel.debug) Debug.Log("Only one image per atlas. Will re-use original texture");
                uvRects = new Rect[1];
                uvRects[0] = new Rect(0f,0f,1f,1f);
                for (int i = 0; i < numAtlases; i++){
                    MeshBakerMaterialTexture dmt = distinctMaterialTextures[0].ts[i];
                    atlases[i] = dmt.t;
                    resultMaterial.SetTexture(texPropertyNames[i].name,atlases[i]);
                    resultMaterial.SetTextureScale(texPropertyNames[i].name,dmt.scale);
                    resultMaterial.SetTextureOffset(texPropertyNames[i].name,dmt.offset);
                }
            } else {
                List<Vector2> imageSizes = new List<Vector2>();
                for (int i = 0; i < distinctMaterialTextures.Count; i++){
                    imageSizes.Add(new Vector2(distinctMaterialTextures[i].idealWidth, distinctMaterialTextures[i].idealHeight));
                }
                MB2_TexturePacker tp = new MB2_TexturePacker();
                tp.doPowerOfTwoTextures = _meshBakerTexturePackerForcePowerOfTwo;
                int atlasSizeX = 1;
                int atlasSizeY = 1;

                //todo add sanity warnings for huge atlasesr
                int atlasMaxDimension = _maxAtlasSize;

                //if (textureEditorMethods != null) atlasMaxDimension = textureEditorMethods.GetMaximumAtlasDimension();

                uvRects = tp.GetRects(imageSizes,atlasMaxDimension,_padding,out atlasSizeX, out atlasSizeY);
                if (LOG_LEVEL >= MB2_LogLevel.debug) Debug.Log("Generated atlas will be " + atlasSizeX + "x" + atlasSizeY + " (Max atlas size for platform: " + atlasMaxDimension + ")");

                //create a game object
                GameObject renderAtlasesGO = new GameObject("MBrenderAtlasesGO");
                MB3_AtlasPackerRenderTexture atlasRenderTexture = renderAtlasesGO.AddComponent<MB3_AtlasPackerRenderTexture>();
                for (int i = 0; i < numAtlases; i++){
                    Texture2D atlas = null;
                    if (allTexturesAreNullAndSameColor[i]){
                        atlas = null;
                        if (LOG_LEVEL >= MB2_LogLevel.debug) Debug.Log("Not creating atlas for " + texPropertyNames[i].name + " because textures are null and default value parameters are the same.");
                    } else {
                        GC.Collect();
                        if (progressInfo != null) progressInfo("Creating Atlas '" + texPropertyNames[i].name + "'", .01f);
                        // ===========
                        // configure it
                        atlasRenderTexture.width = atlasSizeX;
                        atlasRenderTexture.height = atlasSizeY;
                        atlasRenderTexture.padding = _padding;
                        atlasRenderTexture.rects = uvRects;
                        atlasRenderTexture.textureSets = distinctMaterialTextures;
                        atlasRenderTexture.indexOfTexSetToRender = 0;
                        // call render on it
                        atlas = atlasRenderTexture.OnRenderAtlas();
                        // destroy it
                        // =============
                        if (LOG_LEVEL >= MB2_LogLevel.debug) Debug.Log("Saving atlas " + texPropertyNames[i].name + " w=" + atlas.width + " h=" + atlas.height);
                    }
                    atlases[i] = atlas;
                    if (progressInfo != null) progressInfo("Saving atlas: '" + texPropertyNames[i].name + "'", .04f);
                    if (_saveAtlasesAsAssets && textureEditorMethods != null){
                        textureEditorMethods.SaveAtlasToAssetDatabase(atlases[i], texPropertyNames[i], i, resultMaterial);
                    } else {
                        resultMaterial.SetTexture(texPropertyNames[i].name, atlases[i]);
                    }
                    resultMaterial.SetTextureOffset(texPropertyNames[i].name, Vector2.zero);
                    resultMaterial.SetTextureScale(texPropertyNames[i].name,Vector2.one);
                    _destroyTemporaryTextures(); // need to save atlases before doing this
                }
            }
            return uvRects;
        }
	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;
	}		
		Rect[] __CreateAtlasesMBTexturePacker(ProgressUpdateDelegate progressInfo, int numAtlases, List<MB_TexSet> distinctMaterialTextures, List<string> texPropertyNames, Material resultMaterial, Texture2D[] atlases, MB2_EditorMethodsInterface textureEditorMethods, int _padding){
			Rect[] uvRects;
			if (distinctMaterialTextures.Count == 1){
				if (LOG_LEVEL >= MB2_LogLevel.debug) Debug.Log("Only one image per atlas. Will re-use original texture");
				uvRects = new Rect[1];
				uvRects[0] = new Rect(0f,0f,1f,1f);
				for (int i = 0; i < numAtlases; i++){
					MeshBakerMaterialTexture dmt = distinctMaterialTextures[0].ts[i];
					atlases[i] = dmt.t;
					resultMaterial.SetTexture(texPropertyNames[i],atlases[i]);
					resultMaterial.SetTextureScale(texPropertyNames[i],dmt.scale);
					resultMaterial.SetTextureOffset(texPropertyNames[i],dmt.offset);
				}
			} else {
				List<Vector2> imageSizes = new List<Vector2>();
				for (int i = 0; i < distinctMaterialTextures.Count; i++){
					imageSizes.Add(new Vector2(distinctMaterialTextures[i].idealWidth, distinctMaterialTextures[i].idealHeight));	
				}
				MB2_TexturePacker tp = new MB2_TexturePacker();
				int atlasSizeX = 1;
				int atlasSizeY = 1;
				
				//todo add sanity warnings for huge atlasesr
				int atlasMaxDimension = 4096;
				
				if (textureEditorMethods != null) atlasMaxDimension = textureEditorMethods.GetMaximumAtlasDimension();
				
				uvRects = tp.GetRects(imageSizes,atlasMaxDimension,_padding,out atlasSizeX, out atlasSizeY);
				if (LOG_LEVEL >= MB2_LogLevel.info) Debug.Log("Generated atlas will be " + atlasSizeX + "x" + atlasSizeY + " (Max atlas size for platform: " + atlasMaxDimension + ")");
				for (int i = 0; i < numAtlases; i++){
					GC.Collect();
					if (progressInfo != null) progressInfo("Creating Atlas '" + texPropertyNames[i] + "'", .01f);
					Color[] atlasPixels = new Color[atlasSizeX * atlasSizeY];//atlas.GetPixels();
					for (int j = 0; j < atlasPixels.Length; j++) atlasPixels[j] = Color.clear;
					for (int j = 0; j < distinctMaterialTextures.Count; j++){
						if (LOG_LEVEL >= MB2_LogLevel.trace) MB2_Log.Trace("Adding texture {0} to atlas {1}", distinctMaterialTextures[j].ts[i].t == null ? "null" : distinctMaterialTextures[j].ts[i].t.ToString(),texPropertyNames[i]);
						Rect r = uvRects[j];
						Texture2D t = distinctMaterialTextures[j].ts[i].t;
						int x = Mathf.RoundToInt(r.x * atlasSizeX);
						int y = Mathf.RoundToInt(r.y * atlasSizeY);
						int ww = Mathf.RoundToInt(r.width * atlasSizeX);
						int hh = Mathf.RoundToInt(r.height * atlasSizeY);
						if (ww == 0 || hh == 0) Debug.LogError("Image in atlas has no height or width");
						if (textureEditorMethods != null) textureEditorMethods.SetReadWriteFlag(t, true, true);
						if (progressInfo != null) progressInfo("Copying to atlas: '" + distinctMaterialTextures[j].ts[i].t + "'", .02f);
						CopyScaledAndTiledToAtlas(distinctMaterialTextures[j].ts[i],x,y,ww,hh,fixOutOfBoundsUVs,maxTilingBakeSize,atlasPixels,atlasSizeX,progressInfo);
					}
					if (progressInfo != null) progressInfo("Applying changes to atlas: '" + texPropertyNames[i] + "'", .03f);
					Texture2D atlas = new Texture2D(atlasSizeX, atlasSizeY,TextureFormat.ARGB32, true);
					atlas.SetPixels(atlasPixels);
					atlas.Apply();
					if (LOG_LEVEL >= MB2_LogLevel.debug) Debug.Log("Saving atlas " + texPropertyNames[i] + " w=" + atlas.width + " h=" + atlas.height);
					atlases[i] = atlas;
					if (progressInfo != null) progressInfo("Saving atlas: '" + texPropertyNames[i] + "'", .04f);
					if (saveAtlasesAsAssets && textureEditorMethods != null){
						textureEditorMethods.SaveAtlasToAssetDatabase(atlases[i], texPropertyNames[i], i, resultMaterial);
					} else {
						resultMaterial.SetTexture(texPropertyNames[i], atlases[i]);
					}
					resultMaterial.SetTextureOffset(texPropertyNames[i], Vector2.zero);
					resultMaterial.SetTextureScale(texPropertyNames[i],Vector2.one);
					_destroyTemporaryTextures(); // need to save atlases before doing this				
				}
			}
			return uvRects;
		}
Ejemplo n.º 23
0
        private static IEnumerator _CreateAtlasesCoroutineSingleResultMaterial(int resMatIdx, MB_TextureArrayResultMaterial bakedMatsAndSlicesResMat, MB_MultiMaterialTexArray resMatConfig, MB3_TextureBaker tb, MB3_TextureCombiner combiner, ProgressUpdateDelegate progressInfo, MB3_TextureBaker.CreateAtlasesCoroutineResult coroutineResult, bool saveAtlasesAsAssets = false, MB2_EditorMethodsInterface editorMethods = null, float maxTimePerFrame = .01f)
        {
            MB2_LogLevel LOG_LEVEL = tb.LOG_LEVEL;

            MB_TextureArrayFormatSet[]   textureArrayOutputFormats = tb.textureArrayOutputFormats;
            MB_MultiMaterialTexArray[]   resultMaterialsTexArray   = tb.resultMaterialsTexArray;
            List <ShaderTextureProperty> customShaderProperties    = tb.customShaderProperties;


            if (LOG_LEVEL >= MB2_LogLevel.debug)
            {
                Debug.Log("Baking atlases for result material " + resMatIdx + " num slices:" + resMatConfig.slices.Count);
            }
            // Each result material can be one set of slices per textureProperty. Each slice can be an atlas.
            // Create atlases for each slice.
            List <MB3_TextureCombiner.TemporaryTexture> generatedTemporaryAtlases = new List <MB3_TextureCombiner.TemporaryTexture>();

            {
                combiner.saveAtlasesAsAssets = false; // Don't want generated atlas slices to be assets
                List <MB_TexArraySlice> slicesConfig = resMatConfig.slices;
                for (int sliceIdx = 0; sliceIdx < slicesConfig.Count; sliceIdx++)
                {
                    Material resMatToPass = null;
                    List <MB_TexArraySliceRendererMatPair> srcMatAndObjPairs = slicesConfig[sliceIdx].sourceMaterials;

                    if (LOG_LEVEL >= MB2_LogLevel.trace)
                    {
                        Debug.Log(" Baking atlases for result material:" + resMatIdx + " slice:" + sliceIdx);
                    }
                    resMatToPass = resMatConfig.combinedMaterial;
                    combiner.fixOutOfBoundsUVs = slicesConfig[sliceIdx].considerMeshUVs;
                    MB3_TextureCombiner.CombineTexturesIntoAtlasesCoroutineResult coroutineResult2 = new MB3_TextureCombiner.CombineTexturesIntoAtlasesCoroutineResult();
                    MB_AtlasesAndRects sliceAtlasesAndRectOutput = bakedMatsAndSlicesResMat.slices[sliceIdx];
                    List <Material>    usedMats = new List <Material>();
                    slicesConfig[sliceIdx].GetAllUsedMaterials(usedMats);

                    yield return(combiner.CombineTexturesIntoAtlasesCoroutine(progressInfo, sliceAtlasesAndRectOutput, resMatToPass, slicesConfig[sliceIdx].GetAllUsedRenderers(tb.objsToMesh), usedMats, editorMethods, coroutineResult2, maxTimePerFrame,
                                                                              onlyPackRects: false, splitAtlasWhenPackingIfTooBig: false));

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

                    // Track which slices are new generated texture instances. Atlases could be original texture assets (one tex per atlas) or temporary texture instances in memory that will need to be destroyed.
                    {
                        for (int texPropIdx = 0; texPropIdx < sliceAtlasesAndRectOutput.atlases.Length; texPropIdx++)
                        {
                            Texture2D atlas = sliceAtlasesAndRectOutput.atlases[texPropIdx];
                            if (atlas != null)
                            {
                                bool atlasWasASourceTexture = false;
                                for (int srcMatIdx = 0; srcMatIdx < srcMatAndObjPairs.Count; srcMatIdx++)
                                {
                                    Material srcMat = srcMatAndObjPairs[srcMatIdx].sourceMaterial;
                                    if (srcMat.HasProperty(sliceAtlasesAndRectOutput.texPropertyNames[texPropIdx]) &&
                                        srcMat.GetTexture(sliceAtlasesAndRectOutput.texPropertyNames[texPropIdx]) == atlas)
                                    {
                                        atlasWasASourceTexture = true;
                                        break;
                                    }
                                }

                                if (!atlasWasASourceTexture)
                                {
                                    generatedTemporaryAtlases.Add(new MB3_TextureCombiner.TemporaryTexture(sliceAtlasesAndRectOutput.texPropertyNames[texPropIdx], atlas));
                                }
                            }
                        }
                    } // end visit slices

                    Debug.Assert(combiner._getNumTemporaryTextures() == 0, "Combiner should have no temporary textures.");
                }

                combiner.saveAtlasesAsAssets = saveAtlasesAsAssets; // Restore original setting.
            }

            // Generated atlas textures are temporary for texture arrays. They exist only in memory. Need to be cleaned up after we create slices.
            for (int i = 0; i < generatedTemporaryAtlases.Count; i++)
            {
                combiner.AddTemporaryTexture(generatedTemporaryAtlases[i]);
            }

            List <ShaderTextureProperty> texPropertyNames = new List <ShaderTextureProperty>();

            MB3_TextureCombinerPipeline._CollectPropertyNames(texPropertyNames, customShaderProperties, resMatConfig.combinedMaterial, LOG_LEVEL);

            // The slices are built from different source-material-lists. Each slice can have different sets of texture properties missing (nulls).
            // Build a master list of texture properties.
            bool[] hasTexForProperty = MB_TextureArrays.DetermineWhichPropertiesHaveTextures(bakedMatsAndSlicesResMat.slices);

            List <Texture2D> temporaryTextureAssets = new List <Texture2D>();

            try
            {
                MB_MultiMaterialTexArray resMaterial = resMatConfig;
                Dictionary <string, MB_TexArrayForProperty> resTexArraysByProperty = new Dictionary <string, MB_TexArrayForProperty>();
                {
                    // Initialize so I don't need to check if properties exist later.
                    for (int propIdx = 0; propIdx < texPropertyNames.Count; propIdx++)
                    {
                        if (hasTexForProperty[propIdx])
                        {
                            resTexArraysByProperty[texPropertyNames[propIdx].name] =
                                new MB_TexArrayForProperty(texPropertyNames[propIdx].name, new MB_TextureArrayReference[textureArrayOutputFormats.Length]);
                        }
                    }
                }


                MB3_TextureCombinerNonTextureProperties textureBlender = null;
                textureBlender = new MB3_TextureCombinerNonTextureProperties(LOG_LEVEL, tb.considerNonTextureProperties);
                textureBlender.LoadTextureBlendersIfNeeded(resMatConfig.combinedMaterial);
                textureBlender.AdjustNonTextureProperties(resMatConfig.combinedMaterial, texPropertyNames, editorMethods);

                // Vist each TextureFormatSet
                for (int texFormatSetIdx = 0; texFormatSetIdx < textureArrayOutputFormats.Length; texFormatSetIdx++)
                {
                    MB_TextureArrayFormatSet textureArrayFormatSet = textureArrayOutputFormats[texFormatSetIdx];
                    editorMethods.Clear();

                    MB_TextureArrays.TexturePropertyData texPropertyData = new MB_TextureArrays.TexturePropertyData();
                    MB_TextureArrays.FindBestSizeAndMipCountAndFormatForTextureArrays(texPropertyNames, tb.maxAtlasSize, textureArrayFormatSet, bakedMatsAndSlicesResMat.slices, texPropertyData);

                    // Create textures we might need if they don't exist.
                    {
                        for (int propIdx = 0; propIdx < hasTexForProperty.Length; propIdx++)
                        {
                            if (hasTexForProperty[propIdx])
                            {
                                TextureFormat format       = texPropertyData.formats[propIdx];
                                int           numSlices    = bakedMatsAndSlicesResMat.slices.Length;
                                int           targetWidth  = (int)texPropertyData.sizes[propIdx].x;
                                int           targetHeight = (int)texPropertyData.sizes[propIdx].y;
                                for (int sliceIdx = 0; sliceIdx < numSlices; sliceIdx++)
                                {
                                    if (bakedMatsAndSlicesResMat.slices[sliceIdx].atlases[propIdx] == null)
                                    {
                                        Texture2D sliceTex = new Texture2D(targetWidth, targetHeight, format, texPropertyData.doMips[propIdx]);
                                        Color     col      = textureBlender.GetColorForTemporaryTexture(resMatConfig.slices[sliceIdx].sourceMaterials[0].sourceMaterial, texPropertyNames[propIdx]);
                                        MB_Utility.setSolidColor(sliceTex, col);
                                        bakedMatsAndSlicesResMat.slices[sliceIdx].atlases[propIdx] = editorMethods.CreateTemporaryAssetCopy(sliceTex, targetWidth, targetHeight, format, LOG_LEVEL);
                                        temporaryTextureAssets.Add(bakedMatsAndSlicesResMat.slices[sliceIdx].atlases[propIdx]);
                                        MB_Utility.Destroy(sliceTex);
                                    }
                                }
                            }
                        }
                    }


                    if (LOG_LEVEL >= MB2_LogLevel.debug)
                    {
                        Debug.Log("Converting source textures to readable formats.");
                    }
                    if (MB_TextureArrays.ConvertTexturesToReadableFormat(texPropertyData, bakedMatsAndSlicesResMat.slices, hasTexForProperty, texPropertyNames, combiner, LOG_LEVEL, temporaryTextureAssets, editorMethods))
                    {
                        // We now have a set of slices (one per textureProperty). Build these into Texture2DArray's.
                        if (LOG_LEVEL >= MB2_LogLevel.debug)
                        {
                            Debug.Log("Creating texture arrays");
                        }
                        if (LOG_LEVEL >= MB2_LogLevel.info)
                        {
                            Debug.Log("THERE MAY BE ERRORS IN THE CONSOLE ABOUT 'Rebuilding mipmaps ... not supported'. THESE ARE PROBABLY FALSE POSITIVES AND CAN BE IGNORED.");
                        }
                        Texture2DArray[] textureArrays = MB_TextureArrays.CreateTextureArraysForResultMaterial(texPropertyData, bakedMatsAndSlicesResMat.slices, hasTexForProperty, combiner, LOG_LEVEL);


                        // Now have texture arrays for a result material, for all props. Save it.
                        for (int propIdx = 0; propIdx < textureArrays.Length; propIdx++)
                        {
                            if (hasTexForProperty[propIdx])
                            {
                                MB_TextureArrayReference texRef = new MB_TextureArrayReference(textureArrayFormatSet.name, textureArrays[propIdx]);
                                resTexArraysByProperty[texPropertyNames[propIdx].name].formats[texFormatSetIdx] = texRef;
                                if (saveAtlasesAsAssets)
                                {
                                    editorMethods.SaveTextureArrayToAssetDatabase(textureArrays[propIdx],
                                                                                  textureArrayFormatSet.GetFormatForProperty(texPropertyNames[propIdx].name),
                                                                                  bakedMatsAndSlicesResMat.slices[0].texPropertyNames[propIdx],
                                                                                  propIdx, resMaterial.combinedMaterial);
                                }
                            }
                        }
                    }
                } // end vist format set

                resMaterial.textureProperties = new List <MB_TexArrayForProperty>();
                foreach (MB_TexArrayForProperty val in resTexArraysByProperty.Values)
                {
                    resMaterial.textureProperties.Add(val);
                }
            }
            catch (Exception e)
            {
                Debug.LogError(e.Message + "\n" + e.StackTrace.ToString());
                coroutineResult.isFinished = true;
                coroutineResult.success    = false;
            }
            finally
            {
                editorMethods.RestoreReadFlagsAndFormats(progressInfo);
                combiner._destroyAllTemporaryTextures();
                for (int i = 0; i < temporaryTextureAssets.Count; i++)
                {
                    editorMethods.DestroyAsset(temporaryTextureAssets[i]);
                }
                temporaryTextureAssets.Clear();
            }
        }
        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)
        {
            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'");
                    }
                }
                if (_considerNonTextureProperties)
                {
                    data.nonTexturePropertyBlender = new MB3_TextureCombinerNonTextureProperties(LOG_LEVEL, _considerNonTextureProperties);
                    data.nonTexturePropertyBlender.LoadTextureBlenders();
                    data.nonTexturePropertyBlender.FindBestTextureBlender(resultMaterial);
                }

                if (onlyPackRects)
                {
                    yield return(__RunTexturePacker(result, data, textureEditorMethods, atlasPackingResult));
                }
                else
                {
                    yield return(__CombineTexturesIntoAtlases(progressInfo, result, resultAtlasesAndRects, data, 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();
                _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;
        }
Ejemplo n.º 25
0
    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);
        //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");
        }
    }
Ejemplo n.º 26
0
    SAAtlasesAndRects[] _CreateAtlases(ProgressUpdateDelegate progressInfo, bool saveAtlasesAsAssets = false, SA2EditorMethodsInterface 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);
        }
        if (!DoCombinedValidate(this, SAObjsToCombineTypes.dontCare, editorMethods))
        {
            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 = SAUtility.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);
                    }
                    else 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 = SAUtility.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;
        //        }
        //    }
        //}

        SA3TextureCombiner combiner = new SA3TextureCombiner();

        combiner.LOG_LEVEL             = LOG_LEVEL;
        combiner.atlasPadding          = _atlasPadding;
        combiner.customShaderPropNames = _customShaderPropNames;
        combiner.fixOutOfBoundsUVs     = _fixOutOfBoundsUVs;
        combiner.maxTilingBakeSize     = _maxTilingBakeSize;
        combiner.packingAlgorithm      = _packingAlgorithm;
        combiner.combineTexturePackerForcePowerOfTwo = _combineTexturePackerForcePowerOfTwo;
        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;
        }
        SAAtlasesAndRects[] resultAtlasesAndRects = new SAAtlasesAndRects[numResults];
        for (int i = 0; i < resultAtlasesAndRects.Length; i++)
        {
            resultAtlasesAndRects[i] = new SAAtlasesAndRects();
        }

        //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
        SA3MeshCombineCommon[] mb = GetComponentsInChildren <SA3MeshCombineCommon>();
        for (int i = 0; i < mb.Length; i++)
        {
            mb[i].textureBakeResults = textureBakeResults;
        }

        if (LOG_LEVEL >= SA2LogLevel.info)
        {
            Debug.Log("Created Atlases");
        }
        return(resultAtlasesAndRects);
    }
Ejemplo n.º 27
0
    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.
                    }
                }
            }
        }

        for (int resMatIdx = 0; resMatIdx < resultMaterialsTexArray.Length; resMatIdx++)
        {
            MB_MultiMaterialTexArray textureArraySliceConfig = resultMaterialsTexArray[resMatIdx];
        }

        // 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);
            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");
            }
        }
    }
 public abstract IEnumerator CreateAtlases(ProgressUpdateDelegate progressInfo,
                                           MB3_TextureCombinerPipeline.TexturePipelineData data, MB3_TextureCombiner combiner,
                                           AtlasPackingResult packedAtlasRects,
                                           Texture2D[] atlases, MB2_EditorMethodsInterface textureEditorMethods,
                                           MB2_LogLevel LOG_LEVEL);
Ejemplo n.º 29
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;
	}		
Ejemplo n.º 30
0
    private MB_AtlasesAndRects[] _CreateAtlases(ProgressUpdateDelegate progressInfo, bool saveAtlasesAsAssets = false, MB2_EditorMethodsInterface editorMethods = null)
    {
        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 validationLevel = (!Application.isPlaying) ? MB2_ValidationLevel.robust : MB2_ValidationLevel.quick;

        if (!MB3_MeshBakerRoot.DoCombinedValidate(this, MB_ObjsToCombineTypes.dontCare, editorMethods, validationLevel))
        {
            return(null);
        }
        if (this._doMultiMaterial && !this._ValidateResultMaterials())
        {
            return(null);
        }
        if (!this._doMultiMaterial)
        {
            if (this._resultMaterial == null)
            {
                Debug.LogError("Combined Material is null please create and assign a result material.");
                return(null);
            }
            Shader shader = this._resultMaterial.shader;
            for (int i = 0; i < this.objsToMesh.Count; i++)
            {
                foreach (Material material in MB_Utility.GetGOMaterials(this.objsToMesh[i]))
                {
                    if (material != null && material.shader != shader)
                    {
                        Debug.LogWarning(string.Concat(new object[]
                        {
                            "Game object ",
                            this.objsToMesh[i],
                            " does not use shader ",
                            shader,
                            " it may not have the required textures. If not 2x2 clear textures will be generated."
                        }));
                    }
                }
            }
        }
        for (int k = 0; k < this.objsToMesh.Count; k++)
        {
            foreach (Material x in MB_Utility.GetGOMaterials(this.objsToMesh[k]))
            {
                if (x == null)
                {
                    Debug.LogError("Game object " + this.objsToMesh[k] + " has a null material. Can't build atlases");
                    return(null);
                }
            }
        }
        MB3_TextureCombiner mb3_TextureCombiner = new MB3_TextureCombiner();

        mb3_TextureCombiner.LOG_LEVEL             = this.LOG_LEVEL;
        mb3_TextureCombiner.atlasPadding          = this._atlasPadding;
        mb3_TextureCombiner.maxAtlasSize          = this._maxAtlasSize;
        mb3_TextureCombiner.customShaderPropNames = this._customShaderProperties;
        mb3_TextureCombiner.fixOutOfBoundsUVs     = this._fixOutOfBoundsUVs;
        mb3_TextureCombiner.maxTilingBakeSize     = this._maxTilingBakeSize;
        mb3_TextureCombiner.packingAlgorithm      = this._packingAlgorithm;
        mb3_TextureCombiner.meshBakerTexturePackerForcePowerOfTwo = this._meshBakerTexturePackerForcePowerOfTwo;
        mb3_TextureCombiner.resizePowerOfTwoTextures = this._resizePowerOfTwoTextures;
        mb3_TextureCombiner.saveAtlasesAsAssets      = saveAtlasesAsAssets;
        if (!Application.isPlaying)
        {
            Material[] array;
            if (this._doMultiMaterial)
            {
                array = new Material[this.resultMaterials.Length];
                for (int m = 0; m < array.Length; m++)
                {
                    array[m] = this.resultMaterials[m].combinedMaterial;
                }
            }
            else
            {
                array = new Material[]
                {
                    this._resultMaterial
                };
            }
            mb3_TextureCombiner.SuggestTreatment(this.objsToMesh, array, mb3_TextureCombiner.customShaderPropNames);
        }
        int num = 1;

        if (this._doMultiMaterial)
        {
            num = this.resultMaterials.Length;
        }
        MB_AtlasesAndRects[] array2 = new MB_AtlasesAndRects[num];
        for (int n = 0; n < array2.Length; n++)
        {
            array2[n] = new MB_AtlasesAndRects();
        }
        for (int num2 = 0; num2 < array2.Length; num2++)
        {
            List <Material> allowedMaterialsFilter = null;
            Material        material2;
            if (this._doMultiMaterial)
            {
                allowedMaterialsFilter = this.resultMaterials[num2].sourceMaterials;
                material2 = this.resultMaterials[num2].combinedMaterial;
            }
            else
            {
                material2 = this._resultMaterial;
            }
            Debug.Log("Creating atlases for result material " + material2);
            if (!mb3_TextureCombiner.CombineTexturesIntoAtlases(progressInfo, array2[num2], material2, this.objsToMesh, allowedMaterialsFilter, editorMethods))
            {
                return(null);
            }
        }
        this.textureBakeResults.combinedMaterialInfo = array2;
        this.textureBakeResults.doMultiMaterial      = this._doMultiMaterial;
        this.textureBakeResults.resultMaterial       = this._resultMaterial;
        this.textureBakeResults.resultMaterials      = this.resultMaterials;
        this.textureBakeResults.fixOutOfBoundsUVs    = mb3_TextureCombiner.fixOutOfBoundsUVs;
        this.unpackMat2RectMap(this.textureBakeResults);
        MB3_MeshBakerCommon[] componentsInChildren = base.GetComponentsInChildren <MB3_MeshBakerCommon>();
        for (int num3 = 0; num3 < componentsInChildren.Length; num3++)
        {
            componentsInChildren[num3].textureBakeResults = this.textureBakeResults;
        }
        if (this.LOG_LEVEL >= MB2_LogLevel.info)
        {
            Debug.Log("Created Atlases");
        }
        return(array2);
    }
 /**<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);
 }
Ejemplo n.º 32
0
        public static bool BakeMeshesInPlace(MB3_MeshCombinerSingle mom, List <GameObject> objsToMesh, string saveFolder, bool clearBuffersAfterBake, ProgressUpdateDelegate updateProgressBar)
        {
            if (MB3_MeshCombiner.EVAL_VERSION)
            {
                return(false);
            }
            if (saveFolder.Length < 6)
            {
                Debug.LogError("Please select a folder for meshes.");
                return(false);
            }
            if (!Directory.Exists(Application.dataPath + saveFolder.Substring(6)))
            {
                Debug.Log((Application.dataPath + saveFolder.Substring(6)));
                Debug.Log(Path.GetFullPath(Application.dataPath + saveFolder.Substring(6)));
                Debug.LogError("The selected Folder For Meshes does not exist or is not inside the projects Assets folder. Please 'Choose Folder For Bake In Place Meshes' that is inside the project's assets folder.");
                return(false);
            }

            MB3_EditorMethods editorMethods = new MB3_EditorMethods();

            mom.DestroyMeshEditor(editorMethods);

            MB_RenderType originalRenderType = mom.renderType;
            bool          success            = false;

            string[] objNames = GenerateNames(objsToMesh);
            for (int i = 0; i < objsToMesh.Count; i++)
            {
                if (objsToMesh[i] == null)
                {
                    Debug.LogError("The " + i + "th object on the list of objects to combine is 'None'. Use Command-Delete on Mac OS X; Delete or Shift-Delete on Windows to remove this one element.");
                    return(false);
                }

                Mesh m = new Mesh();
                success = BakeOneMesh(mom, m, objsToMesh[i]);
                if (success)
                {
                    string newMeshFilePath = saveFolder + "/" + objNames[i];
                    Debug.Log("Creating mesh asset at " + newMeshFilePath + " for mesh " + m + " numVerts " + m.vertexCount);
                    AssetDatabase.CreateAsset(mom.GetMesh(), newMeshFilePath);
                }
                if (updateProgressBar != null)
                {
                    updateProgressBar("Created mesh saving mesh on " + objsToMesh[i].name + " to asset " + objNames[i], .6f);
                }
            }
            mom.renderType = originalRenderType;
            MB_Utility.Destroy(mom.resultSceneObject);
            if (clearBuffersAfterBake)
            {
                mom.ClearBuffers();
            }
            return(success);
        }
        //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;
        }
Ejemplo n.º 34
0
    private IEnumerator _CreateAtlasesCoroutine(ProgressUpdateDelegate progressInfo, MB3_TextureCombiner.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 (resultType == MB2_TextureBakeResults.ResultType.textureArray)
        {
            //TODO validate texture arrays.
        }
        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;

        OnCombinedTexturesCoroutineAtlasesAndRects = null;
        if (resultType == MB2_TextureBakeResults.ResultType.textureArray)
        {
            yield return(_CreateAtlasesCoroutineTextureArray(combiner, progressInfo, coroutineResult, saveAtlasesAsAssets, editorMethods, maxTimePerFrame));

            if (!coroutineResult.success)
            {
                yield break;
            }
        }
        else
        {
            yield return(_CreateAtlasesCoroutineAtlases(combiner, progressInfo, coroutineResult, saveAtlasesAsAssets, editorMethods, maxTimePerFrame));

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

        //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;
        }

        coroutineResult.isFinished = true;
    }
Ejemplo n.º 35
0
 public void Execute(ProgressUpdateDelegate updateFunction)
 {
 }
Ejemplo n.º 36
0
        //public IEnumerator agglomerate()
        public void agglomerate(ProgressUpdateDelegate progFunc)
        {
            if (items.Count <= 1)
            {
                clusters = new ClusterNode[0];
                return;
                //yield break;
            }
            clusters = new ClusterNode[items.Count * 2 - 1];
            for (int i = 0; i < items.Count; i++)
            {
                clusters[i] = new ClusterNode(items[i], i);
            }

            float[][] distances = new float[items.Count * 2 - 1][];
            for (int i = 0; i < distances.Length; i++)
            {
                distances[i] = new float[items.Count * 2 - 1];
            }

            int numClussters = items.Count;
            List <ClusterNode> unclustered = new List <ClusterNode>();

            for (int i = 0; i < numClussters; i++)
            {
                unclustered.Add(clusters[i]);
                for (int j = 0; j < numClussters; j++)
                {
                    distances[i][j] = euclidean_distance(clusters[i].centroid, clusters[j].centroid);
                }
            }

            int height = 0;

            System.Diagnostics.Stopwatch timer = new System.Diagnostics.Stopwatch();
            timer.Start();
            while (unclustered.Count > 1)
            {
                height++;
                //find closest pair
                float min = 10e15f;
                int   a, b;
                a = b = -1;
                for (int i = 0; i < unclustered.Count; i++)
                {
                    for (int j = i + 1; j < unclustered.Count; j++)
                    {
                        int   idxa    = unclustered[i].idx;
                        int   idxb    = unclustered[j].idx;
                        float newDist = distances[idxa][idxb];
                        if (newDist < min)
                        {
                            min = newDist;
                            a   = idxa;
                            b   = idxb;
                        }
                    }
                }
                //make a new cluster with pair as children set merge height
                numClussters++;
                ClusterNode cn = new ClusterNode(clusters[a], clusters[b], numClussters - 1, height, min, clusters);
                //remove children from unclustered
                unclustered.Remove(clusters[a]);
                unclustered.Remove(clusters[b]);
                //add new cluster to unclustered
                clusters[numClussters - 1] = cn;
                unclustered.Add(cn);
                //update new clusteres distance
                for (int i = 0; i < numClussters - 1; i++)
                {
                    distances[numClussters - 1][i] = euclidean_distance(clusters[numClussters - 1].centroid, clusters[i].centroid);
                    distances[i][numClussters - 1] = euclidean_distance(clusters[i].centroid, clusters[numClussters - 1].centroid);
                }
                //if (timer.Interval > .2f)
                //{
                //    yield return null;
                //    timer.Start();
                //}
                if (progFunc != null)
                {
                    progFunc("Creating clusters:" + ((float)(items.Count - unclustered.Count) * 100) / items.Count, ((float)(items.Count - unclustered.Count)) / items.Count);
                }
            }
            Debug.Log("Time " + timer.Elapsed);
        }
Ejemplo n.º 37
0
        /// <summary>
        /// 创建贴图 Atlas 协程
        /// </summary>
        /// <returns></returns>
        public IEnumerator CreateAtlasesCoroutine(ProgressUpdateDelegate progressInfo,
                                                  CreateAtlasesCoroutineResult coroutineResult,
                                                  bool saveAtlasesAsAssets             = false,
                                                  EditorMethodsInterface editorMethods = null,
                                                  float maxTimePerFrame = .01f)
        {
            OnCombinedTexturesCoroutineAtlasesAndRects = null;

            //--- 1、合并前检测
            if (maxTimePerFrame <= 0f)
            {
                Debug.LogError("maxTimePerFrame must be a value greater than zero");
                coroutineResult.isFinished = true;
                yield break;
            }

            //验证等级
            ValidationLevel vl = Application.isPlaying ? ValidationLevel.quick : ValidationLevel.robust;

            //验证
            if (!DoCombinedValidate(this, 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 = MeshBakerUtility.GetGOMaterials(objsToMesh[i]);
                    for (int j = 0; j < ms.Length; j++)
                    {
                        Material m = ms[j];
                        if (m != null && m.shader != targShader)
                        {
                            Debug.LogWarning("游戏物体" + objsToMesh[i] + " 没有使用 shader " + targShader +
                                             " it may not have the required textures. " +
                                             "If not small solid color textures will be generated.");
                        }
                    }
                }
            }

            TextureCombineHandler combiner = CreateAndConfigureTextureCombiner();

            combiner.saveAtlasesAsAssets = saveAtlasesAsAssets;

            ////--- 2、初始化存储合并结果的数据结构
            int numResults = 1;

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

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

            //--- 3、开始合并材质(单个,多个)
            for (int i = 0; i < OnCombinedTexturesCoroutineAtlasesAndRects.Length; i++)
            {
                Material        resMatToPass;
                List <Material> sourceMats;
                if (_doMultiMaterial)
                {
                    sourceMats   = resultMaterials[i].sourceMaterials;
                    resMatToPass = resultMaterials[i].combinedMaterial;
                    combiner.fixOutOfBoundsUVs = resultMaterials[i].considerMeshUVs;
                }
                else
                {
                    resMatToPass = _resultMaterial;
                    sourceMats   = null;
                }

                //TextureHandler 材质合并协程结果
                CombineTexturesIntoAtlasesCoroutineResult coroutineResult2 = new 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;
                }
            }

            //--- 4、TextureBakeResults 保存合并结果
            unpackMat2RectMap(textureBakeResults);
            textureBakeResults.doMultiMaterial = _doMultiMaterial;
            if (_doMultiMaterial)
            {
                textureBakeResults.resultMaterials = resultMaterials;
            }
            else
            {
                MultiMaterial[] resMats = new MultiMaterial[1];
                resMats[0] = new 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;
            }

            //--- 5、传递合并结果到 MeshCombiner
            MeshBakerCommon[] mb = GetComponentsInChildren <MeshBakerCommon>();
            for (int i = 0; i < mb.Length; i++)
            {
                mb[i].textureBakeResults = textureBakeResults;
            }
            coroutineResult.isFinished = true;

            //--- 6、合并材质结束回调
            if (coroutineResult.success && onBuiltAtlasesSuccess != null)
            {
                onBuiltAtlasesSuccess();
            }
            if (!coroutineResult.success && onBuiltAtlasesFail != null)
            {
                onBuiltAtlasesFail();
            }
        }
 public void CopyScaledAndTiledToAtlas(MeshBakerMaterialTexture source, int targX, int targY, int targW, int targH, bool _fixOutOfBoundsUVs, int maxSize, Color[][] atlasPixels, int atlasWidth, bool isNormalMap, ProgressUpdateDelegate progressInfo=null)
 {
     if (LOG_LEVEL >= MB2_LogLevel.debug) Debug.Log("CopyScaledAndTiledToAtlas: " + source.t + " inAtlasX=" + targX + " inAtlasY=" + targY + " inAtlasW=" + targW + " inAtlasH=" + targH);
     float newWidth = targW;
     float newHeight = targH;
     float scx = source.scale.x;
     float scy = source.scale.y;
     float ox = source.offset.x;
     float oy = source.offset.y;
     if (_fixOutOfBoundsUVs){
         scx *= source.obUVscale.x;
         scy *= source.obUVscale.y;
         ox += source.obUVoffset.x;
         oy += source.obUVoffset.y;
     }
     int w = (int) newWidth;
     int h = (int) newHeight;
     Texture2D t = source.t;
     if (t == null){
         t = _createTemporaryTexture(16,16,TextureFormat.ARGB32, true);
         MB_Utility.setSolidColor(t,source.colorIfNoTexture);
     //				if (isNormalMap){
     //					MB_Utility.setSolidColor(t,new Color(.5f,.5f,1f));
     //				} else {
     //					MB_Utility.setSolidColor(t,Color.clear);
     //				}
     }
     t = _addWatermark(t);
     //int atlasWidth_plus_targX = atlasWidth + targX;
     for (int i = 0;i < w; i++){
         if (progressInfo != null && w > 0) progressInfo("CopyScaledAndTiledToAtlas " + (((float)i/(float)w)*100f).ToString("F0"),.2f);
         for (int j = 0;j < h; j++){
             float u = i/newWidth*scx + ox;
             float v = j/newHeight*scy + oy;
             atlasPixels[targY + j][ targX + i] = t.GetPixelBilinear(u,v);
         }
     }
     //bleed the border colors into the padding
     for (int i = 0; i < w; i++) {
         for (int j = 1; j <= atlasPadding; j++){
             //top margin
             atlasPixels[(targY - j)][targX + i] = atlasPixels[(targY)][targX + i];
             //bottom margin
             atlasPixels[(targY + h - 1 + j)][targX + i] = atlasPixels[(targY + h - 1)][targX + i];
         }
     }
     for (int j = 0; j < h; j++) {
         for (int i = 1; i <= _atlasPadding; i++){
             //left margin
             atlasPixels[(targY + j)][targX - i] = atlasPixels[(targY + j)][targX];
             //right margin
             atlasPixels[(targY + j)][targX + w + i - 1] = atlasPixels[(targY + j)][targX + w - 1];
         }
     }
     //corners
     for (int i = 1; i <= _atlasPadding; i++) {
         for (int j = 1; j <= _atlasPadding; j++) {
             atlasPixels[(targY-j) ][ targX - i] =           atlasPixels[ targY ][ targX];
             atlasPixels[(targY+h-1+j) ][ targX - i] =       atlasPixels[(targY+h-1) ][ targX];
             atlasPixels[(targY+h-1+j) ][ targX + w + i-1] = atlasPixels[(targY+h-1) ][ targX+w-1];
             atlasPixels[(targY-j) ][ targX + w + i-1] =     atlasPixels[ targY ][ targX+w-1];
         }
     }
 }
Ejemplo n.º 39
0
        public override IEnumerator CreateAtlases(ProgressUpdateDelegate progressInfo,
                                                  MB3_TextureCombinerPipeline.TexturePipelineData data, MB3_TextureCombiner combiner,
                                                  AtlasPackingResult packedAtlasRects,
                                                  Texture2D[] atlases, MB2_EditorMethodsInterface textureEditorMethods,
                                                  MB2_LogLevel LOG_LEVEL)
        {
            Debug.Assert(!data.OnlyOneTextureInAtlasReuseTextures());
            long estArea    = 0;
            int  atlasSizeX = 1;
            int  atlasSizeY = 1;

            Rect[] uvRects = null;
            for (int propIdx = 0; propIdx < data.numAtlases; propIdx++)
            {
                //-----------------------
                ShaderTextureProperty prop  = data.texPropertyNames[propIdx];
                Texture2D             atlas = null;
                if (!MB3_TextureCombinerPipeline._ShouldWeCreateAtlasForThisProperty(propIdx, data._considerNonTextureProperties, data.allTexturesAreNullAndSameColor))
                {
                    atlas = null;
                }
                else
                {
                    if (LOG_LEVEL >= MB2_LogLevel.debug)
                    {
                        Debug.LogWarning("Beginning loop " + propIdx + " num temporary textures " + combiner._getNumTemporaryTextures());
                    }
                    MB3_TextureCombinerPackerRoot.CreateTemporaryTexturesForAtlas(data.distinctMaterialTextures, combiner, propIdx, data);
                    Texture2D[] texToPack = new Texture2D[data.distinctMaterialTextures.Count];
                    for (int texSetIdx = 0; texSetIdx < data.distinctMaterialTextures.Count; texSetIdx++)
                    {
                        MB_TexSet txs     = data.distinctMaterialTextures[texSetIdx];
                        int       tWidth  = txs.idealWidth;
                        int       tHeight = txs.idealHeight;
                        Texture2D tx      = txs.ts[propIdx].GetTexture2D();
                        if (progressInfo != null)
                        {
                            progressInfo("Adjusting for scale and offset " + tx, .01f);
                        }

                        if (textureEditorMethods != null)
                        {
                            textureEditorMethods.SetReadWriteFlag(tx, true, true);
                        }

                        tx = GetAdjustedForScaleAndOffset2(prop.name, txs.ts[propIdx], txs.obUVoffset, txs.obUVscale, data, combiner, LOG_LEVEL);
                        //create a resized copy if necessary
                        if (tx.width != tWidth || tx.height != tHeight)
                        {
                            if (progressInfo != null)
                            {
                                progressInfo("Resizing texture '" + tx + "'", .01f);
                            }
                            if (LOG_LEVEL >= MB2_LogLevel.debug)
                            {
                                Debug.LogWarning("Copying and resizing texture " + prop.name + " from " + tx.width + "x" + tx.height + " to " + tWidth + "x" + tHeight);
                            }
                            tx = combiner._resizeTexture(prop.name, (Texture2D)tx, tWidth, tHeight);
                        }

                        estArea += tx.width * tx.height;
                        if (data._considerNonTextureProperties)
                        {
                            //combine the tintColor with the texture
                            tx = combiner._createTextureCopy(prop.name, tx);
                            data.nonTexturePropertyBlender.TintTextureWithTextureCombiner(tx, data.distinctMaterialTextures[texSetIdx], prop);
                        }

                        texToPack[texSetIdx] = tx;
                    }

                    if (textureEditorMethods != null)
                    {
                        textureEditorMethods.CheckBuildSettings(estArea);
                    }

                    if (Math.Sqrt(estArea) > 3500f)
                    {
                        if (LOG_LEVEL >= MB2_LogLevel.warn)
                        {
                            Debug.LogWarning("The maximum possible atlas size is 4096. Textures may be shrunk");
                        }
                    }

                    atlas = new Texture2D(1, 1, TextureFormat.ARGB32, true);
                    if (progressInfo != null)
                    {
                        progressInfo("Packing texture atlas " + prop.name, .25f);
                    }
                    if (propIdx == 0)
                    {
                        if (progressInfo != null)
                        {
                            progressInfo("Estimated min size of atlases: " + Math.Sqrt(estArea).ToString("F0"), .1f);
                        }
                        if (LOG_LEVEL >= MB2_LogLevel.info)
                        {
                            Debug.Log("Estimated atlas minimum size:" + Math.Sqrt(estArea).ToString("F0"));
                        }
                        int maxAtlasSize = 4096;
                        uvRects = atlas.PackTextures(texToPack, data._atlasPadding, maxAtlasSize, false);
                        if (LOG_LEVEL >= MB2_LogLevel.info)
                        {
                            Debug.Log("After pack textures atlas numTextures " + texToPack.Length + " size " + atlas.width + " " + atlas.height);
                        }
                        atlasSizeX = atlas.width;
                        atlasSizeY = atlas.height;
                        atlas.Apply();
                    }
                    else
                    {
                        if (progressInfo != null)
                        {
                            progressInfo("Copying Textures Into: " + prop.name, .1f);
                        }
                        atlas = _copyTexturesIntoAtlas(texToPack, data._atlasPadding, uvRects, atlasSizeX, atlasSizeY, combiner);
                    }
                }

                atlases[propIdx] = atlas;
                //----------------------

                if (data._saveAtlasesAsAssets && textureEditorMethods != null)
                {
                    textureEditorMethods.SaveAtlasToAssetDatabase(atlases[propIdx], prop, propIdx, data.resultMaterial);
                }
                data.resultMaterial.SetTextureOffset(prop.name, Vector2.zero);
                data.resultMaterial.SetTextureScale(prop.name, Vector2.one);
                combiner._destroyTemporaryTextures(prop.name);
                GC.Collect();
            }
            packedAtlasRects.rects = uvRects;
            yield break;
        }
        Rect[] __CreateAtlasesMBTexturePacker(ProgressUpdateDelegate progressInfo, int numAtlases, List<MB_TexSet> distinctMaterialTextures, List<ShaderTextureProperty> texPropertyNames, bool[] allTexturesAreNullAndSameColor, Material resultMaterial, Texture2D[] atlases, MB2_EditorMethodsInterface textureEditorMethods, int _padding)
        {
            Rect[] uvRects;
            if (distinctMaterialTextures.Count == 1){
                if (LOG_LEVEL >= MB2_LogLevel.debug) Debug.Log("Only one image per atlas. Will re-use original texture");
                uvRects = new Rect[1];
                uvRects[0] = new Rect(0f,0f,1f,1f);
                for (int i = 0; i < numAtlases; i++){
                    MeshBakerMaterialTexture dmt = distinctMaterialTextures[0].ts[i];
                    atlases[i] = dmt.t;
                    resultMaterial.SetTexture(texPropertyNames[i].name,atlases[i]);
                    resultMaterial.SetTextureScale(texPropertyNames[i].name,dmt.scale);
                    resultMaterial.SetTextureOffset(texPropertyNames[i].name,dmt.offset);
                }
            } else {
                List<Vector2> imageSizes = new List<Vector2>();
                for (int i = 0; i < distinctMaterialTextures.Count; i++){
                    imageSizes.Add(new Vector2(distinctMaterialTextures[i].idealWidth, distinctMaterialTextures[i].idealHeight));
                }
                MB2_TexturePacker tp = new MB2_TexturePacker();
                tp.doPowerOfTwoTextures = _meshBakerTexturePackerForcePowerOfTwo;
                int atlasSizeX = 1;
                int atlasSizeY = 1;

                //todo add sanity warnings for huge atlasesr
                int atlasMaxDimension = _maxAtlasSize;

                //if (textureEditorMethods != null) atlasMaxDimension = textureEditorMethods.GetMaximumAtlasDimension();

                uvRects = tp.GetRects(imageSizes,atlasMaxDimension,_padding,out atlasSizeX, out atlasSizeY);
                if (LOG_LEVEL >= MB2_LogLevel.debug) Debug.Log("Generated atlas will be " + atlasSizeX + "x" + atlasSizeY + " (Max atlas size for platform: " + atlasMaxDimension + ")");
                for (int i = 0; i < numAtlases; i++){
                    Texture2D atlas = null;
                    if (allTexturesAreNullAndSameColor[i]){
                        atlas = null;
                        if (LOG_LEVEL >= MB2_LogLevel.debug) Debug.Log("Not creating atlas for " + texPropertyNames[i].name + " because textures are null and default value parameters are the same.");
                    } else {
                        GC.Collect();
                        if (progressInfo != null) progressInfo("Creating Atlas '" + texPropertyNames[i].name + "'", .01f);
                        //use a jagged array because it is much more efficient in memory
                        Color[][] atlasPixels = new Color[atlasSizeY][];
                        for (int j = 0; j < atlasPixels.Length; j++){
                            atlasPixels[j] = new Color[atlasSizeX];
                        }
                        bool isNormalMap = false;
                        if (texPropertyNames[i].isNormalMap) isNormalMap = true;
            //						for (int j = 0; j < atlasPixels.Length; j++) {
            //							for (int k = 0; k < atlasSizeX; k++){
            //								atlasPixels[j][k] = GetColorIfNoTexture(
            //								if (isNormalMap){
            //									atlasPixels[j][k] = new Color(.5f,.5f,1f); //neutral bluish for normal maps
            //								} else {
            //									atlasPixels[j][k] = Color.clear;
            //								}
            //							}
            //						}
                        for (int j = 0; j < distinctMaterialTextures.Count; j++){
                            if (LOG_LEVEL >= MB2_LogLevel.trace) MB2_Log.Trace("Adding texture {0} to atlas {1}", distinctMaterialTextures[j].ts[i].t == null ? "null" : distinctMaterialTextures[j].ts[i].t.ToString(),texPropertyNames[i]);
                            Rect r = uvRects[j];
                            Texture2D t = distinctMaterialTextures[j].ts[i].t;
                            int x = Mathf.RoundToInt(r.x * atlasSizeX);
                            int y = Mathf.RoundToInt(r.y * atlasSizeY);
                            int ww = Mathf.RoundToInt(r.width * atlasSizeX);
                            int hh = Mathf.RoundToInt(r.height * atlasSizeY);
                            if (ww == 0 || hh == 0) Debug.LogError("Image in atlas has no height or width");
                            if (textureEditorMethods != null) textureEditorMethods.SetReadWriteFlag(t, true, true);
                            if (progressInfo != null) progressInfo("Copying to atlas: '" + distinctMaterialTextures[j].ts[i].t + "'", .02f);
                            CopyScaledAndTiledToAtlas(distinctMaterialTextures[j].ts[i],x,y,ww,hh,_fixOutOfBoundsUVs,_maxTilingBakeSize,atlasPixels,atlasSizeX,isNormalMap,progressInfo);
                        }
                        if (progressInfo != null) progressInfo("Applying changes to atlas: '" + texPropertyNames[i].name + "'", .03f);
                        atlas = new Texture2D(atlasSizeX, atlasSizeY,TextureFormat.ARGB32, true);
                        for (int j = 0; j < atlasPixels.Length; j++){
                            atlas.SetPixels(0,j,atlasSizeX,1,atlasPixels[j]);
                        }
                        atlas.Apply();
                        if (LOG_LEVEL >= MB2_LogLevel.debug) Debug.Log("Saving atlas " + texPropertyNames[i].name + " w=" + atlas.width + " h=" + atlas.height);
                    }
                    atlases[i] = atlas;
                    if (progressInfo != null) progressInfo("Saving atlas: '" + texPropertyNames[i].name + "'", .04f);
                    if (_saveAtlasesAsAssets && textureEditorMethods != null){
                        textureEditorMethods.SaveAtlasToAssetDatabase(atlases[i], texPropertyNames[i], i, resultMaterial);
                    } else {
                        resultMaterial.SetTexture(texPropertyNames[i].name, atlases[i]);
                    }
                    resultMaterial.SetTextureOffset(texPropertyNames[i].name, Vector2.zero);
                    resultMaterial.SetTextureScale(texPropertyNames[i].name,Vector2.one);
                    _destroyTemporaryTextures(); // need to save atlases before doing this
                }
            }
            return uvRects;
        }
Ejemplo n.º 41
0
        public IEnumerator CreateAtlases(ProgressUpdateDelegate progressInfo,
                                         MB3_TextureCombinerPipeline.TexturePipelineData data, MB3_TextureCombiner combiner,
                                         AtlasPackingResult packedAtlasRects,
                                         Texture2D[] atlases, MB2_EditorMethodsInterface textureEditorMethods,
                                         MB2_LogLevel LOG_LEVEL)
        {
            Debug.Assert(!data.OnlyOneTextureInAtlasReuseTextures());
            Rect[] uvRects = packedAtlasRects.rects;

            int atlasSizeX = packedAtlasRects.atlasX;
            int atlasSizeY = packedAtlasRects.atlasY;

            if (LOG_LEVEL >= MB2_LogLevel.debug)
            {
                Debug.Log("Generated atlas will be " + atlasSizeX + "x" + atlasSizeY);
            }

            int layer = data._layerTexturePackerFastV2;

            Debug.Assert(layer >= 0 && layer <= 32);

            //create a game object
            mesh             = new Mesh();
            renderAtlasesGO  = null;
            cameraGameObject = null;
            try
            {
                System.Diagnostics.Stopwatch db_time_MB3_TextureCombinerPackerMeshBakerFastV2_CreateAtlases = new System.Diagnostics.Stopwatch();
                db_time_MB3_TextureCombinerPackerMeshBakerFastV2_CreateAtlases.Start();
                renderAtlasesGO  = new GameObject("MBrenderAtlasesGO");
                cameraGameObject = new GameObject("MBCameraGameObject");
                MB3_AtlasPackerRenderTextureUsingMesh atlasRenderer = new MB3_AtlasPackerRenderTextureUsingMesh();
                OneTimeSetup(atlasRenderer, renderAtlasesGO, cameraGameObject, atlasSizeX, atlasSizeY, data._atlasPadding, layer, LOG_LEVEL);

                if (data._considerNonTextureProperties && LOG_LEVEL >= MB2_LogLevel.warn)
                {
                    Debug.LogWarning("Blend Non-Texture Properties has limited functionality when used with Mesh Baker Texture Packer Fast.");
                }

                List <Material> mats = new List <Material>();
                for (int propIdx = 0; propIdx < data.numAtlases; propIdx++)
                {
                    Texture2D atlas = null;
                    if (!MB3_TextureCombinerPipeline._ShouldWeCreateAtlasForThisProperty(propIdx, data._considerNonTextureProperties, data.allTexturesAreNullAndSameColor))
                    {
                        atlas = null;
                        if (LOG_LEVEL >= MB2_LogLevel.debug)
                        {
                            Debug.Log("Not creating atlas for " + data.texPropertyNames[propIdx].name + " because textures are null and default value parameters are the same.");
                        }
                    }
                    else
                    {
                        if (progressInfo != null)
                        {
                            progressInfo("Creating Atlas '" + data.texPropertyNames[propIdx].name + "'", .01f);
                        }

                        // configure it
                        if (LOG_LEVEL >= MB2_LogLevel.debug)
                        {
                            Debug.Log("About to render " + data.texPropertyNames[propIdx].name + " isNormal=" + data.texPropertyNames[propIdx].isNormalMap);
                        }

                        // Create the mesh
                        mats.Clear();

                        MB3_AtlasPackerRenderTextureUsingMesh.MeshAtlas.BuildAtlas(packedAtlasRects, data.distinctMaterialTextures, propIdx, packedAtlasRects.atlasX, packedAtlasRects.atlasY, mesh, mats, data.texPropertyNames[propIdx], data, combiner, textureEditorMethods, LOG_LEVEL);
                        {
                            MeshFilter mf = renderAtlasesGO.GetComponent <MeshFilter>();
                            mf.sharedMesh = mesh;
                            MeshRenderer mrr = renderAtlasesGO.GetComponent <MeshRenderer>();
                            Material[]   mrs = mats.ToArray();
                            mrr.sharedMaterials = mrs;
                        }

                        // Render
                        atlas = atlasRenderer.DoRenderAtlas(cameraGameObject, packedAtlasRects.atlasX, packedAtlasRects.atlasY, data.texPropertyNames[propIdx].isNormalMap, data.texPropertyNames[propIdx]);

                        {
                            for (int i = 0; i < mats.Count; i++)
                            {
                                MB_Utility.Destroy(mats[i]);
                            }
                            mats.Clear();
                        }

                        if (LOG_LEVEL >= MB2_LogLevel.debug)
                        {
                            Debug.Log("Saving atlas " + data.texPropertyNames[propIdx].name + " w=" + atlas.width + " h=" + atlas.height + " id=" + atlas.GetInstanceID());
                        }
                    }
                    atlases[propIdx] = atlas;
                    if (progressInfo != null)
                    {
                        progressInfo("Saving atlas: '" + data.texPropertyNames[propIdx].name + "'", .04f);
                    }
                    if (data.resultType == MB2_TextureBakeResults.ResultType.atlas)
                    {
                        MB3_TextureCombinerPackerRoot.SaveAtlasAndConfigureResultMaterial(data, textureEditorMethods, atlases[propIdx], data.texPropertyNames[propIdx], propIdx);
                    }

                    combiner._destroyTemporaryTextures(data.texPropertyNames[propIdx].name); // need to save atlases before doing this
                }

                if (LOG_LEVEL >= MB2_LogLevel.debug)
                {
                    Debug.LogFormat("Timing MB3_TextureCombinerPackerMeshBakerFastV2.CreateAtlases={0}",
                                    db_time_MB3_TextureCombinerPackerMeshBakerFastV2_CreateAtlases.ElapsedMilliseconds * .001f);
                }
            }
            catch (Exception ex)
            {
                Debug.LogError(ex.Message + "\n" + ex.StackTrace.ToString());
            }
            finally
            {
                if (renderAtlasesGO != null)
                {
                    MB_Utility.Destroy(renderAtlasesGO);
                }
                if (cameraGameObject != null)
                {
                    MB_Utility.Destroy(cameraGameObject);
                }
                if (mesh != null)
                {
                    MB_Utility.Destroy(mesh);
                }
            }
            yield break;
        }
		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;
		}
        /// <summary>
        /// 第一步:
        ///     写入 TexturePipelineData 的 MaterialPropTexturesSet 列表,和 usedObjsToMesh 列表
        /// 每个TexSet在 Atlas 中都是一个矩形。
        /// 如果 allowedMaterialsFilter (过滤器)为空,那么将收集 allObjsToMesh 上的所有材质,usedObjsToMesh 将与allObjsToMesh相同
        /// 否则,将仅包括allowedMaterialsFilter中的材料,而usedObjsToMesh将是使用这些材料的objs。
        /// </summary>
        internal static IEnumerator __Step1_CollectDistinctMatTexturesAndUsedObjects(ProgressUpdateDelegate progressInfo,
                                                                                     CombineTexturesIntoAtlasesCoroutineResult result,
                                                                                     TexturePipelineData data,
                                                                                     EditorMethodsInterface textureEditorMethods,
                                                                                     List <GameObject> usedObjsToMesh)
        {
            // Collect distinct list of textures to combine from the materials on objsToCombine
            // 收集UsedObjects上不同的材质纹理
            bool outOfBoundsUVs = false;
            Dictionary <int, MeshAnalysisResult[]> meshAnalysisResultsCache = new Dictionary <int, MeshAnalysisResult[]>(); //cache results

            for (int i = 0; i < data.allObjsToMesh.Count; i++)
            {
                GameObject obj = data.allObjsToMesh[i];
                //报道进度
                if (progressInfo != null)
                {
                    progressInfo("Collecting textures for " + obj, ((float)i) / data.allObjsToMesh.Count / 2f);
                }

                if (obj == null)
                {
                    Debug.LogError("合并游戏物体列表中包含空物体");
                    result.success = false;
                    yield break;
                }

                Mesh sharedMesh = MeshBakerUtility.GetMesh(obj);
                if (sharedMesh == null)
                {
                    Debug.LogError("游戏物体 " + obj.name + " 网格为空");
                    result.success = false;
                    yield break;
                }

                Material[] sharedMaterials = MeshBakerUtility.GetGOMaterials(obj);
                if (sharedMaterials.Length == 0)
                {
                    Debug.LogError("游戏物体 " + obj.name + " 材质为空.");
                    result.success = false;
                    yield break;
                }

                //analyze mesh or grab cached result of previous analysis, stores one result for each submesh
                //处理网格数据
                MeshAnalysisResult[] meshAnalysisResults;//每个游戏物体的主网格子网格数据数组
                if (!meshAnalysisResultsCache.TryGetValue(sharedMesh.GetInstanceID(), out meshAnalysisResults))
                {
                    meshAnalysisResults = new MeshAnalysisResult[sharedMesh.subMeshCount];
                    for (int j = 0; j < sharedMesh.subMeshCount; j++)
                    {
                        MeshBakerUtility.hasOutOfBoundsUVs(sharedMesh, ref meshAnalysisResults[j], j);
                        if (data._normalizeTexelDensity)
                        {
                            meshAnalysisResults[j].submeshArea = GetSubmeshArea(sharedMesh, j);
                        }

                        if (data._fixOutOfBoundsUVs && !meshAnalysisResults[j].hasUVs)
                        {
                            meshAnalysisResults[j].uvRect = new Rect(0, 0, 1, 1);
                            Debug.LogWarning("Mesh for object " + obj + " has no UV channel but 'consider UVs' is enabled." +
                                             " Assuming UVs will be generated filling 0,0,1,1 rectangle.");
                        }
                    }
                    meshAnalysisResultsCache.Add(sharedMesh.GetInstanceID(), meshAnalysisResults);
                }

                if (data._fixOutOfBoundsUVs)
                {
                    Debug.Log("Mesh Analysis for object " + obj +
                              " numSubmesh=" + meshAnalysisResults.Length +
                              " HasOBUV=" + meshAnalysisResults[0].hasOutOfBoundsUVs +
                              " UVrectSubmesh0=" + meshAnalysisResults[0].uvRect);
                }


                //处理材质数据
                for (int matIdx = 0; matIdx < sharedMaterials.Length; matIdx++)
                {
                    ////for each submesh
                    //if (progressInfo != null)
                    //{
                    //    progressInfo(string.Format("Collecting textures for {0} submesh {1}", obj, matIdx),
                    //        ((float)i) / data.allObjsToMesh.Count / 2f);
                    //}
                    Material mat = sharedMaterials[matIdx];

                    // 材质过滤器
                    if (data.allowedMaterialsFilter != null && !data.allowedMaterialsFilter.Contains(mat))
                    {
                        continue;
                    }

                    outOfBoundsUVs = outOfBoundsUVs || meshAnalysisResults[matIdx].hasOutOfBoundsUVs;

                    if (mat.name.Contains("(Instance)"))
                    {
                        Debug.LogError("The sharedMaterial on object " + obj.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.");
                        result.success = false;
                        yield break;
                    }

                    if (data._fixOutOfBoundsUVs)
                    {
                        if (!MeshBakerUtility.AreAllSharedMaterialsDistinct(sharedMaterials))
                        {
                            Debug.LogWarning("游戏物体 " + obj.name + " 使用相同的材质在多个子网格. " +
                                             "可能生成奇怪的 resultAtlasesAndRects,尤其是与 _fixOutOfBoundsUVs 为 true 时");
                        }
                    }

                    //材质属性所用到的 Texutre
                    MaterialPropTexture[] mts = new MaterialPropTexture[data.texPropertyNames.Count];
                    for (int propIdx = 0; propIdx < data.texPropertyNames.Count; propIdx++)
                    {
                        Texture tx           = null;
                        Vector2 scale        = Vector2.one;
                        Vector2 offset       = Vector2.zero;
                        float   texelDensity = 0f;
                        if (mat.HasProperty(data.texPropertyNames[propIdx].name))
                        {
                            Texture txx = GetTextureConsideringStandardShaderKeywords(data.resultMaterial.shader.name, mat, data.texPropertyNames[propIdx].name);
                            if (txx != null)
                            {
                                if (txx is Texture2D)
                                {
                                    //TextureFormat 验证
                                    tx = txx;
                                    TextureFormat f           = ((Texture2D)tx).format;
                                    bool          isNormalMap = false;
                                    if (!Application.isPlaying && textureEditorMethods != null)
                                    {
                                        isNormalMap = textureEditorMethods.IsNormalMap((Texture2D)tx);
                                    }
                                    if ((f == TextureFormat.ARGB32 ||
                                         f == TextureFormat.RGBA32 ||
                                         f == TextureFormat.BGRA32 ||
                                         f == TextureFormat.RGB24 ||
                                         f == TextureFormat.Alpha8) && !isNormalMap) //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 skewe
                                        //尝试使用tex2.SetPixels(tex1.GetPixels())复制纹理,但是3.5中的bug意味着DTX1和5压缩纹理出现扭曲
                                        if (Application.isPlaying && data._packingAlgorithm != PackingAlgorithmEnum.MeshBakerTexturePacker_Fast)
                                        {
                                            Debug.LogWarning("合并列表中,游戏物体 " + obj.name + " 所使用的 Texture " +
                                                             tx.name + " 使用的格式 " + f +
                                                             "不是: ARGB32, RGBA32, BGRA32, RGB24, Alpha8 或 DXT. " +
                                                             "无法在运行时重新设置尺寸" +
                                                             "If format says 'compressed' try changing it to 'truecolor'");
                                            result.success = false;
                                            yield break;
                                        }
                                        else
                                        {
                                            tx = (Texture2D)mat.GetTexture(data.texPropertyNames[propIdx].name);
                                        }
                                    }
                                }
                                else
                                {
                                    Debug.LogError("合并列表中,游戏物体 " + obj.name + " 渲染网格使用的 Texture 不是 Texture2D. ");
                                    result.success = false;
                                    yield break;
                                }
                            }
                            //像素密度
                            if (tx != null && data._normalizeTexelDensity)
                            {
                                //不考虑平铺和UV采样超出范围
                                if (meshAnalysisResults[propIdx].submeshArea == 0)
                                {
                                    texelDensity = 0f;
                                }
                                else
                                {
                                    texelDensity = (tx.width * tx.height) / (meshAnalysisResults[propIdx].submeshArea);
                                }
                            }
                            //规格,偏移
                            GetMaterialScaleAndOffset(mat, data.texPropertyNames[propIdx].name, out offset, out scale);
                        }

                        mts[propIdx] = new MaterialPropTexture(tx, offset, scale, texelDensity);
                    }

                    // 收集材质参数值的平均值
                    data.nonTexturePropertyBlender.CollectAverageValuesOfNonTextureProperties(data.resultMaterial, mat);

                    Vector2 obUVscale  = new Vector2(meshAnalysisResults[matIdx].uvRect.width, meshAnalysisResults[matIdx].uvRect.height);
                    Vector2 obUVoffset = new Vector2(meshAnalysisResults[matIdx].uvRect.x, meshAnalysisResults[matIdx].uvRect.y);

                    //Add to distinct set of textures if not already there
                    TextureTilingTreatment tilingTreatment = TextureTilingTreatment.none;
                    if (data._fixOutOfBoundsUVs)
                    {
                        tilingTreatment = TextureTilingTreatment.considerUVs;
                    }

                    //合并信息 distinctMaterialTextures 数据设置

                    //材质各参数 Texture,及 UV 偏移数据映射
                    MaterialPropTexturesSet setOfTexs = new MaterialPropTexturesSet(mts, obUVoffset, obUVscale, tilingTreatment);  //one of these per submesh
                    //材质及各变化参数Rect 数据
                    MatAndTransformToMerged matt = new MatAndTransformToMerged(new DRect(obUVoffset, obUVscale), data._fixOutOfBoundsUVs, mat);

                    setOfTexs.matsAndGOs.mats.Add(matt);

                    MaterialPropTexturesSet setOfTexs2 = data.distinctMaterialTextures.Find(x => x.IsEqual(setOfTexs, data._fixOutOfBoundsUVs, data.nonTexturePropertyBlender));
                    if (setOfTexs2 != null)
                    {
                        setOfTexs = setOfTexs2;
                    }
                    else
                    {
                        data.distinctMaterialTextures.Add(setOfTexs);
                    }

                    if (!setOfTexs.matsAndGOs.mats.Contains(matt))
                    {
                        setOfTexs.matsAndGOs.mats.Add(matt);
                    }

                    if (!setOfTexs.matsAndGOs.gos.Contains(obj))
                    {
                        setOfTexs.matsAndGOs.gos.Add(obj);
                        //已使用 游戏物体
                        if (!usedObjsToMesh.Contains(obj))
                        {
                            usedObjsToMesh.Add(obj);
                        }
                    }
                }
            }

            Debug.Log(string.Format("第一阶段完成;" +
                                    "参与合并的游戏物体的不同材质,各自包含与shader属性对应的不同的纹理,收集到 {0} 组 textures,即 {0} 个不同的材质," +
                                    "fixOutOfBoundsUV:{1} " +
                                    "considerNonTextureProperties:{2}",
                                    data.distinctMaterialTextures.Count, data._fixOutOfBoundsUVs, data._considerNonTextureProperties));

            if (data.distinctMaterialTextures.Count == 0)
            {
                Debug.LogError("None of the source object materials matched any of the allowed materials for submesh with result material: " + data.resultMaterial);
                result.success = false;
                yield break;
            }

            TextureCombinerMerging merger = new TextureCombinerMerging(data._considerNonTextureProperties,
                                                                       data.nonTexturePropertyBlender, data._fixOutOfBoundsUVs);

            merger.MergeOverlappingDistinctMaterialTexturesAndCalcMaterialSubrects(data.distinctMaterialTextures);

            yield break;
        }
		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());		
		}
        //第二步:计算每个材质的属性对应的 Textures 统一尺寸
        //每种材质(_mainTex,凹凸,Spec ect ...)中的纹理必须大小相同
        //计算要使用的最佳尺寸。 考虑平铺
        //如果图集中只有一种纹理会使用原始大小
        internal static IEnumerator _Step2_CalculateIdealSizesForTexturesInAtlasAndPadding(ProgressUpdateDelegate progressInfo,
                                                                                           CombineTexturesIntoAtlasesCoroutineResult result,
                                                                                           TexturePipelineData data,
                                                                                           EditorMethodsInterface textureEditorMethods)
        {
            MaterialPropTexture.readyToBuildAtlases = true;
            data.allTexturesAreNullAndSameColor     = CalculateAllTexturesAreNullAndSameColor(data);

            //calculate size of rectangles in atlas
            //计算 atlas 矩形尺寸
            int _padding = data._atlasPadding;

            if (data.distinctMaterialTextures.Count == 1 && data._fixOutOfBoundsUVs == false && data._considerNonTextureProperties == false)
            {
                Debug.Log("所有游戏物体使用相同的材质.将使用 Original textures .");
                _padding = 0;
                data.distinctMaterialTextures[0].SetThisIsOnlyTexSetInAtlasTrue();
                data.distinctMaterialTextures[0].SetTilingTreatmentAndAdjustEncapsulatingSamplingRect(TextureTilingTreatment.edgeToEdgeXY);
            }

            Debug.Assert(data.allTexturesAreNullAndSameColor.Length == data.texPropertyNames.Count,
                         "allTexturesAreNullAndSameColor array must be the same length of texPropertyNames.");

            for (int i = 0; i < data.distinctMaterialTextures.Count; i++)
            {
                Debug.Log("为 TexSet " + i + " of " + data.distinctMaterialTextures.Count + "计算合适的尺寸");
                MaterialPropTexturesSet txs = data.distinctMaterialTextures[i];
                txs.idealWidth  = 1;
                txs.idealHeight = 1;
                int tWidth  = 1;
                int tHeight = 1;
                Debug.Assert(txs.ts.Length == data.texPropertyNames.Count,
                             "length of arrays in each element of distinctMaterialTextures must be texPropertyNames.Count");

                //在 MaterialPropTexturesSet 中所有 MaterialPropTextures 应为相同尺寸
                for (int propIdx = 0; propIdx < data.texPropertyNames.Count; propIdx++)
                {
                    if (_ShouldWeCreateAtlasForThisProperty(propIdx, data._considerNonTextureProperties, data.allTexturesAreNullAndSameColor))
                    {
                        MaterialPropTexture matTex = txs.ts[propIdx];
                        Debug.Log(string.Format("为 texSet {0} ,property {1} 计算合适尺寸", i, data.texPropertyNames[propIdx].name));
                        if (!matTex.matTilingRect.size.Equals(Vector2.one) && data.distinctMaterialTextures.Count > 1)
                        {
                            Debug.LogWarning("Texture " + matTex.GetTexName() + "is tiled by " +
                                             matTex.matTilingRect.size + " tiling will be baked into a texture with maxSize:" +
                                             data._maxTilingBakeSize);
                        }

                        if (!txs.obUVscale.Equals(Vector2.one) && data.distinctMaterialTextures.Count > 1 && data._fixOutOfBoundsUVs)
                        {
                            Debug.LogWarning("Texture " + matTex.GetTexName() +
                                             " has out of bounds UVs that effectively tile by " + txs.obUVscale +
                                             " tiling will be baked into a texture with maxSize:" + data._maxTilingBakeSize);
                        }

                        if (matTex.isNull)
                        {
                            txs.SetEncapsulatingRect(propIdx, data._fixOutOfBoundsUVs);
                            Debug.Log(string.Format("No source texture creating a 16x16 texture for {0} texSet {1} srcMat {2}",
                                                    data.texPropertyNames[propIdx].name, i, txs.matsAndGOs.mats[0].GetMaterialName()));
                        }

                        if (!matTex.isNull)
                        {
                            Vector2 dim = GetAdjustedForScaleAndOffset2Dimensions(matTex, txs.obUVoffset, txs.obUVscale, data);
                            if ((int)(dim.x * dim.y) > tWidth * tHeight)
                            {
                                Debug.Log(" 材质texture " + matTex.GetTexName() + " " + dim + " 需要比" + tWidth + " " + tHeight + "更大的尺寸");
                                tWidth  = (int)dim.x;
                                tHeight = (int)dim.y;
                            }
                        }
                    }
                }

                if (data._resizePowerOfTwoTextures)
                {
                    if (tWidth <= _padding * 5)
                    {
                        Debug.LogWarning(String.Format("Some of the textures have widths close to the size of the padding. " +
                                                       "It is not recommended to use _resizePowerOfTwoTextures with widths this small.", txs.ToString()));
                    }
                    if (tHeight <= _padding * 5)
                    {
                        Debug.LogWarning(String.Format("Some of the textures have heights close to the size of the padding. " +
                                                       "It is not recommended to use _resizePowerOfTwoTextures with heights this small.", txs.ToString()));
                    }
                    if (IsPowerOfTwo(tWidth))
                    {
                        tWidth -= _padding * 2;
                    }
                    if (IsPowerOfTwo(tHeight))
                    {
                        tHeight -= _padding * 2;
                    }
                    if (tWidth < 1)
                    {
                        tWidth = 1;
                    }
                    if (tHeight < 1)
                    {
                        tHeight = 1;
                    }
                }
                Debug.Log("Ideal size is " + tWidth + " " + tHeight);
                txs.idealWidth  = tWidth;
                txs.idealHeight = tHeight;
            }
            data._atlasPadding = _padding;
            yield break;
        }
		Rect[] __CreateAtlasesUnityTexturePacker(ProgressUpdateDelegate progressInfo, int numAtlases, List<MB_TexSet> distinctMaterialTextures, List<string> texPropertyNames, Material resultMaterial, Texture2D[] atlases, MB2_EditorMethodsInterface textureEditorMethods, int _padding){
			Rect[] uvRects;
			if (distinctMaterialTextures.Count == 1){
				if (LOG_LEVEL >= MB2_LogLevel.debug) Debug.Log("Only one image per atlas. Will re-use original texture");
				uvRects = new Rect[1];
				uvRects[0] = new Rect(0f,0f,1f,1f);
				for (int i = 0; i < numAtlases; i++){
					MeshBakerMaterialTexture dmt = distinctMaterialTextures[0].ts[i];
					atlases[i] = dmt.t;
					resultMaterial.SetTexture(texPropertyNames[i],atlases[i]);
					resultMaterial.SetTextureScale(texPropertyNames[i],dmt.scale);
					resultMaterial.SetTextureOffset(texPropertyNames[i],dmt.offset);
				}
			} else {
				long estArea = 0;
				int atlasSizeX = 1;
				int atlasSizeY = 1;
				uvRects = null;
				for (int i = 0; i < numAtlases; i++){ //i is an atlas "MainTex", "BumpMap" etc...
					if (LOG_LEVEL >= MB2_LogLevel.debug) Debug.LogWarning("Beginning loop " + i + " num temporary textures " + _temporaryTextures.Count);
					for(int j = 0; j < distinctMaterialTextures.Count; j++){ //j is a distinct set of textures one for each of "MainTex", "BumpMap" etc...
						MB_TexSet txs = distinctMaterialTextures[j];
						
						int tWidth = txs.idealWidth;
						int tHeight = txs.idealHeight;
		
						Texture2D tx = txs.ts[i].t;
						if (tx == null) tx = txs.ts[i].t = _createTemporaryTexture(tWidth,tHeight,TextureFormat.ARGB32, true);
		
						if (progressInfo != null)
							progressInfo("Adjusting for scale and offset " + tx, .01f);	
						if (textureEditorMethods != null) textureEditorMethods.SetReadWriteFlag(tx, true, true); 
						tx = getAdjustedForScaleAndOffset2(txs.ts[i]);				
						
						//create a resized copy if necessary
						if (tx.width != tWidth || tx.height != tHeight) {
							if (progressInfo != null) progressInfo("Resizing texture '" + tx + "'", .01f);
							if (LOG_LEVEL >= MB2_LogLevel.debug) Debug.LogWarning("Copying and resizing texture " + texPropertyNames[i] + " from " + tx.width + "x" + tx.height + " to " + tWidth + "x" + tHeight);
							if (textureEditorMethods != null) textureEditorMethods.SetReadWriteFlag((Texture2D) tx, true, true);
							tx = _resizeTexture((Texture2D) tx,tWidth,tHeight);
						}
						txs.ts[i].t = tx;
					}
		
					Texture2D[] texToPack = new Texture2D[distinctMaterialTextures.Count];
					for (int j = 0; j < distinctMaterialTextures.Count;j++){
						Texture2D tx = distinctMaterialTextures[j].ts[i].t;
						estArea += tx.width * tx.height;
						texToPack[j] = tx;
					}
					
					if (textureEditorMethods != null) textureEditorMethods.CheckBuildSettings(estArea);
			
					if (Math.Sqrt(estArea) > 3500f){
						if (LOG_LEVEL >= MB2_LogLevel.warn) 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).ToString("F0"), .1f);			
						if (LOG_LEVEL >= MB2_LogLevel.info) Debug.Log("Estimated atlas minimum size:" + Math.Sqrt(estArea).ToString("F0"));
						
						_addWatermark(texToPack);			
						
						if (distinctMaterialTextures.Count == 1){ //don't want to force power of 2 so tiling will still work
							uvRects = new Rect[1] {new Rect(0f,0f,1f,1f)};
							atlases[i] = _copyTexturesIntoAtlas(texToPack,_padding,uvRects,texToPack[0].width,texToPack[0].height);
						} else {
							int maxAtlasSize = 4096;
							uvRects = atlases[i].PackTextures(texToPack,_padding,maxAtlasSize,false);
						}
						
						if (LOG_LEVEL >= MB2_LogLevel.info) Debug.Log("After pack textures atlas size " + atlases[i].width + " " + atlases[i].height);
						atlasSizeX = atlases[i].width;
						atlasSizeY = atlases[i].height;	
						atlases[i].Apply();
					} else {
						if (progressInfo != null)
							progressInfo("Copying Textures Into: " + texPropertyNames[i], .1f);					
						atlases[i] = _copyTexturesIntoAtlas(texToPack,_padding,uvRects, atlasSizeX, atlasSizeY);
					}
					
					if (saveAtlasesAsAssets && textureEditorMethods != null){
						textureEditorMethods.SaveAtlasToAssetDatabase(atlases[i], texPropertyNames[i], i, resultMaterial);
					} else {
						resultMaterial.SetTexture(texPropertyNames[i], atlases[i]);
					}
					resultMaterial.SetTextureOffset(texPropertyNames[i], Vector2.zero);
					resultMaterial.SetTextureScale(texPropertyNames[i],Vector2.one);
					
					_destroyTemporaryTextures(); // need to save atlases before doing this
					GC.Collect();
				}
			}
			return uvRects;
		}	
        /// <summary>
        ///  Texture 合并管线第 3 步,创建 Atlas 并保存资源
        /// </summary>
        /// <returns></returns>
        internal static IEnumerator __Step3_BuildAndSaveAtlasesAndStoreResults(ProgressUpdateDelegate progressInfo,
                                                                               CombineTexturesIntoAtlasesCoroutineResult result,
                                                                               TexturePipelineData data,
                                                                               TextureCombineHandler combiner,
                                                                               ITextureCombinerPacker packer,
                                                                               AtlasPackingResult atlasPackingResult,
                                                                               EditorMethodsInterface textureEditorMethods,
                                                                               AtlasesAndRects resultAtlasesAndRects)
        {
            //run the garbage collector to free up as much memory as possible before bake to reduce MissingReferenceException problems
            GC.Collect();
            Texture2D[] atlases = new Texture2D[data.numAtlases];
            //StringBuilder report = GenerateReport(data);

            //创建图集
            yield return(packer.CreateAtlases(progressInfo, data, combiner, atlasPackingResult, atlases, textureEditorMethods));

            data.nonTexturePropertyBlender.AdjustNonTextureProperties(data.resultMaterial, data.texPropertyNames, data.distinctMaterialTextures, textureEditorMethods);

            if (data.distinctMaterialTextures.Count > 0)
            {
                data.distinctMaterialTextures[0].AdjustResultMaterialNonTextureProperties(data.resultMaterial, data.texPropertyNames);
            }

            //结果报告
            //if (progressInfo != null)
            //    progressInfo("Building Report", .7f);
            ////report on atlases created
            //StringBuilder atlasMessage = new StringBuilder();
            //atlasMessage.AppendLine("---- Atlases ------");
            //for (int i = 0; i < data.numAtlases; i++)
            //{
            //    if (atlases[i] != null)
            //    {
            //        atlasMessage.AppendLine("Created Atlas For: " + data.texPropertyNames[i].name + " h=" + atlases[i].height + " w=" + atlases[i].width);
            //    }
            //    else if (!_ShouldWeCreateAtlasForThisProperty(i, data._considerNonTextureProperties, data.allTexturesAreNullAndSameColor))
            //    {
            //        atlasMessage.AppendLine("Did not create atlas for " + data.texPropertyNames[i].name + " because all source textures were null.");
            //    }
            //}
            //report.Append(atlasMessage.ToString());

            List <MaterialAndUVRect> mat2rect_map = new List <MaterialAndUVRect>();

            for (int i = 0; i < data.distinctMaterialTextures.Count; i++)
            {
                MaterialPropTexturesSet        texSet = data.distinctMaterialTextures[i];
                List <MatAndTransformToMerged> mats   = texSet.matsAndGOs.mats;
                Rect allPropsUseSameTiling_encapsulatingSamplingRect;
                Rect propsUseDifferntTiling_obUVRect;
                texSet.GetRectsForTextureBakeResults(out allPropsUseSameTiling_encapsulatingSamplingRect, out propsUseDifferntTiling_obUVRect);
                for (int j = 0; j < mats.Count; j++)
                {
                    Rect allPropsUseSameTiling_sourceMaterialTiling = texSet.GetMaterialTilingRectForTextureBakerResults(j);
                    MaterialAndUVRect key = new MaterialAndUVRect(
                        mats[j].mat,
                        atlasPackingResult.rects[i],
                        texSet.allTexturesUseSameMatTiling,
                        allPropsUseSameTiling_sourceMaterialTiling,
                        allPropsUseSameTiling_encapsulatingSamplingRect,
                        propsUseDifferntTiling_obUVRect,
                        texSet.tilingTreatment,
                        mats[j].objName);
                    if (!mat2rect_map.Contains(key))
                    {
                        mat2rect_map.Add(key);
                    }
                }
            }

            resultAtlasesAndRects.atlases             = atlases;                                               // one per texture on result shader
            resultAtlasesAndRects.texPropertyNames    = ShaderTextureProperty.GetNames(data.texPropertyNames); // one per texture on source shader
            resultAtlasesAndRects.originMatToRect_map = mat2rect_map;

            if (progressInfo != null)
            {
                progressInfo("Restoring Texture Formats & Read Flags", .8f);
            }
            combiner._destroyAllTemporaryTextures();
            if (textureEditorMethods != null)
            {
                textureEditorMethods.RestoreReadFlagsAndFormats(progressInfo);
            }

            //if (report != null)
            //    Debug.Log(report.ToString());

            yield break;
        }
		/**<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);
		}		
Ejemplo n.º 49
0
    public MB_AtlasesAndRects[] CreateAtlases(ProgressUpdateDelegate progressInfo)
    {
        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);
                }
                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);
            }
            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[]      resMatsToPass = new Material[1];
        List <Material> sourceMats    = null;

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

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

            if (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]);
                            //todo set normal map might be a problem
                            //				_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]);
                        //todo set normal map might be a problem
                        //				_setMaterialTextureProperty(resMat, newMesh.texPropertyNames[i], relativePath);
                    }
                }
            }
        }

        if (VERBOSE)
        {
            Debug.Log("Created Atlases");
        }
        return(results);
    }