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._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; }
internal static void BuildAtlas( AtlasPackingResult packedAtlasRects, List <MB_TexSet> distinctMaterialTextures, int propIdx, int atlasSizeX, int atlasSizeY, Mesh m, List <Material> generatedMats, ShaderTextureProperty property, MB3_TextureCombinerPipeline.TexturePipelineData data, MB3_TextureCombiner combiner, MB2_EditorMethodsInterface textureEditorMethods, MB2_LogLevel LOG_LEVEL) { // Collect vertices and quads for mesh that we will use for the atlas. Debug.Assert(generatedMats.Count == 0, "Previous mats should have been destroyed"); generatedMats.Clear(); List <Vector3> vs = new List <Vector3>(); List <Vector2> uvs = new List <Vector2>(); // One submesh and material per texture that we are packing List <int>[] ts = new List <int> [distinctMaterialTextures.Count]; for (int i = 0; i < ts.Length; i++) { ts[i] = new List <int>(); } MeshBakerMaterialTexture.readyToBuildAtlases = true; GC.Collect(); MB3_TextureCombinerPackerRoot.CreateTemporaryTexturesForAtlas(data.distinctMaterialTextures, combiner, propIdx, data); Rect[] uvRects = packedAtlasRects.rects; for (int texSetIdx = 0; texSetIdx < distinctMaterialTextures.Count; texSetIdx++) { MB_TexSet texSet = distinctMaterialTextures[texSetIdx]; MeshBakerMaterialTexture matTex = texSet.ts[propIdx]; 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 = matTex.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); r = new Rect(x, y, ww, hh); if (ww == 0 || hh == 0) { Debug.LogError("Image in atlas has no height or width " + r); } 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())); AtlasPadding padding = packedAtlasRects.padding[texSetIdx]; AddNineSlicedRect(r, padding.leftRight, padding.topBottom, samplingRect.GetRect(), vs, uvs, ts[texSetIdx], t.width, t.height, t.name); Material mt = new Material(Shader.Find("MeshBaker/Unlit/UnlitWithAlpha")); bool isSavingAsANormalMapAssetThatWillBeImported = property.isNormalMap && data._saveAtlasesAsAssets; MBVersion.PipelineType pipelineType = MBVersion.DetectPipeline(); if (pipelineType == MBVersion.PipelineType.URP) { ConfigureMaterial_DefaultPipeline(mt, t, isSavingAsANormalMapAssetThatWillBeImported, LOG_LEVEL); //ConfigureMaterial_URP(mt, t, isSavingAsANormalMapAssetThatWillBeImported, LOG_LEVEL); } else if (pipelineType == MBVersion.PipelineType.HDRP) { ConfigureMaterial_DefaultPipeline(mt, t, isSavingAsANormalMapAssetThatWillBeImported, LOG_LEVEL); } else { ConfigureMaterial_DefaultPipeline(mt, t, isSavingAsANormalMapAssetThatWillBeImported, LOG_LEVEL); } generatedMats.Add(mt); } // Apply to the mesh m.Clear(); m.vertices = vs.ToArray(); m.uv = uvs.ToArray(); m.subMeshCount = ts.Length; for (int i = 0; i < m.subMeshCount; i++) { m.SetIndices(ts[i].ToArray(), MeshTopology.Triangles, i); } MeshBakerMaterialTexture.readyToBuildAtlases = false; }