MB3_TextureCombinerPackerUnity.cs 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. using System;
  5. namespace DigitalOpus.MB.Core
  6. {
  7. internal class MB3_TextureCombinerPackerUnity : MB3_TextureCombinerPackerRoot
  8. {
  9. public override AtlasPackingResult[] CalculateAtlasRectangles(MB3_TextureCombinerPipeline.TexturePipelineData data, bool doMultiAtlas, MB2_LogLevel LOG_LEVEL)
  10. {
  11. Debug.Assert(!data.OnlyOneTextureInAtlasReuseTextures());
  12. //with Unity texture packer we don't find the rectangles, Unity does. When packer is run
  13. return new AtlasPackingResult[] { new AtlasPackingResult(new AtlasPadding[0]) };
  14. }
  15. public override IEnumerator CreateAtlases(ProgressUpdateDelegate progressInfo,
  16. MB3_TextureCombinerPipeline.TexturePipelineData data, MB3_TextureCombiner combiner,
  17. AtlasPackingResult packedAtlasRects,
  18. Texture2D[] atlases, MB2_EditorMethodsInterface textureEditorMethods,
  19. MB2_LogLevel LOG_LEVEL)
  20. {
  21. Debug.Assert(!data.OnlyOneTextureInAtlasReuseTextures());
  22. Rect[] uvRects = packedAtlasRects.rects;
  23. long estArea = 0;
  24. int atlasSizeX = 1;
  25. int atlasSizeY = 1;
  26. uvRects = null;
  27. for (int propIdx = 0; propIdx < data.numAtlases; propIdx++)
  28. {
  29. //-----------------------
  30. ShaderTextureProperty prop = data.texPropertyNames[propIdx];
  31. Texture2D atlas = null;
  32. if (!MB3_TextureCombinerPipeline._ShouldWeCreateAtlasForThisProperty(propIdx, data._considerNonTextureProperties, data.allTexturesAreNullAndSameColor))
  33. {
  34. atlas = null;
  35. }
  36. else
  37. {
  38. if (LOG_LEVEL >= MB2_LogLevel.debug) Debug.LogWarning("Beginning loop " + propIdx + " num temporary textures " + combiner._getNumTemporaryTextures());
  39. MB3_TextureCombinerPackerRoot.CreateTemporaryTexturesForAtlas(data.distinctMaterialTextures, combiner, propIdx, data);
  40. Texture2D[] texToPack = new Texture2D[data.distinctMaterialTextures.Count];
  41. for (int texSetIdx = 0; texSetIdx < data.distinctMaterialTextures.Count; texSetIdx++)
  42. {
  43. MB_TexSet txs = data.distinctMaterialTextures[texSetIdx];
  44. int tWidth = txs.idealWidth;
  45. int tHeight = txs.idealHeight;
  46. Texture2D tx = txs.ts[propIdx].GetTexture2D();
  47. if (progressInfo != null)
  48. {
  49. progressInfo("Adjusting for scale and offset " + tx, .01f);
  50. }
  51. if (textureEditorMethods != null)
  52. {
  53. textureEditorMethods.SetReadWriteFlag(tx, true, true);
  54. }
  55. tx = GetAdjustedForScaleAndOffset2(prop.name, txs.ts[propIdx], txs.obUVoffset, txs.obUVscale, data, combiner, LOG_LEVEL);
  56. //create a resized copy if necessary
  57. if (tx.width != tWidth || tx.height != tHeight)
  58. {
  59. if (progressInfo != null) progressInfo("Resizing texture '" + tx + "'", .01f);
  60. if (LOG_LEVEL >= MB2_LogLevel.debug) Debug.LogWarning("Copying and resizing texture " + prop.name + " from " + tx.width + "x" + tx.height + " to " + tWidth + "x" + tHeight);
  61. tx = combiner._resizeTexture(prop.name, (Texture2D)tx, tWidth, tHeight);
  62. }
  63. estArea += tx.width * tx.height;
  64. if (data._considerNonTextureProperties)
  65. {
  66. //combine the tintColor with the texture
  67. tx = combiner._createTextureCopy(prop.name, tx);
  68. data.nonTexturePropertyBlender.TintTextureWithTextureCombiner(tx, data.distinctMaterialTextures[texSetIdx], prop);
  69. }
  70. texToPack[texSetIdx] = tx;
  71. }
  72. if (textureEditorMethods != null) textureEditorMethods.CheckBuildSettings(estArea);
  73. if (Math.Sqrt(estArea) > 3500f)
  74. {
  75. if (LOG_LEVEL >= MB2_LogLevel.warn) Debug.LogWarning("The maximum possible atlas size is 4096. Textures may be shrunk");
  76. }
  77. atlas = new Texture2D(1, 1, TextureFormat.ARGB32, true);
  78. if (progressInfo != null) progressInfo("Packing texture atlas " + prop.name, .25f);
  79. if (propIdx == 0)
  80. {
  81. if (progressInfo != null) progressInfo("Estimated min size of atlases: " + Math.Sqrt(estArea).ToString("F0"), .1f);
  82. if (LOG_LEVEL >= MB2_LogLevel.info) Debug.Log("Estimated atlas minimum size:" + Math.Sqrt(estArea).ToString("F0"));
  83. int maxAtlasSize = 4096;
  84. uvRects = atlas.PackTextures(texToPack, data._atlasPadding, maxAtlasSize, false);
  85. if (LOG_LEVEL >= MB2_LogLevel.info) Debug.Log("After pack textures atlas size " + atlas.width + " " + atlas.height);
  86. atlasSizeX = atlas.width;
  87. atlasSizeY = atlas.height;
  88. atlas.Apply();
  89. }
  90. else
  91. {
  92. if (progressInfo != null) progressInfo("Copying Textures Into: " + prop.name, .1f);
  93. atlas = _copyTexturesIntoAtlas(texToPack, data._atlasPadding, uvRects, atlasSizeX, atlasSizeY, combiner);
  94. }
  95. }
  96. atlases[propIdx] = atlas;
  97. //----------------------
  98. if (data._saveAtlasesAsAssets && textureEditorMethods != null)
  99. {
  100. textureEditorMethods.SaveAtlasToAssetDatabase(atlases[propIdx], prop, propIdx, data.resultMaterial);
  101. }
  102. data.resultMaterial.SetTextureOffset(prop.name, Vector2.zero);
  103. data.resultMaterial.SetTextureScale(prop.name, Vector2.one);
  104. combiner._destroyTemporaryTextures(prop.name);
  105. GC.Collect();
  106. }
  107. packedAtlasRects.rects = uvRects;
  108. yield break;
  109. }
  110. internal static Texture2D _copyTexturesIntoAtlas(Texture2D[] texToPack, int padding, Rect[] rs, int w, int h, MB3_TextureCombiner combiner)
  111. {
  112. Texture2D ta = new Texture2D(w, h, TextureFormat.ARGB32, true);
  113. MB_Utility.setSolidColor(ta, Color.clear);
  114. for (int i = 0; i < rs.Length; i++)
  115. {
  116. Rect r = rs[i];
  117. Texture2D t = texToPack[i];
  118. Texture2D tmpTex = null;
  119. int x = Mathf.RoundToInt(r.x * w);
  120. int y = Mathf.RoundToInt(r.y * h);
  121. int ww = Mathf.RoundToInt(r.width * w);
  122. int hh = Mathf.RoundToInt(r.height * h);
  123. if (t.width != ww && t.height != hh)
  124. {
  125. tmpTex = t = MB_Utility.resampleTexture(t, ww, hh);
  126. }
  127. ta.SetPixels(x, y, ww, hh, t.GetPixels());
  128. if (tmpTex != null) MB_Utility.Destroy(tmpTex);
  129. }
  130. ta.Apply();
  131. return ta;
  132. }
  133. // used by Unity texture packer to handle tiled textures.
  134. // may create a new texture that has the correct tiling to handle fix out of bounds UVs
  135. internal static Texture2D GetAdjustedForScaleAndOffset2(string propertyName, MeshBakerMaterialTexture source, Vector2 obUVoffset, Vector2 obUVscale, MB3_TextureCombinerPipeline.TexturePipelineData data, MB3_TextureCombiner combiner, MB2_LogLevel LOG_LEVEL)
  136. {
  137. Texture2D sourceTex = source.GetTexture2D();
  138. if (source.matTilingRect.x == 0f && source.matTilingRect.y == 0f && source.matTilingRect.width == 1f && source.matTilingRect.height == 1f)
  139. {
  140. if (data._fixOutOfBoundsUVs)
  141. {
  142. if (obUVoffset.x == 0f && obUVoffset.y == 0f && obUVscale.x == 1f && obUVscale.y == 1f)
  143. {
  144. return sourceTex; //no adjustment necessary
  145. }
  146. }
  147. else
  148. {
  149. return sourceTex; //no adjustment necessary
  150. }
  151. }
  152. Vector2 dim = MB3_TextureCombinerPipeline.GetAdjustedForScaleAndOffset2Dimensions(source, obUVoffset, obUVscale, data, LOG_LEVEL);
  153. if (LOG_LEVEL >= MB2_LogLevel.debug) Debug.LogWarning("GetAdjustedForScaleAndOffset2: " + sourceTex + " " + obUVoffset + " " + obUVscale);
  154. float newWidth = dim.x;
  155. float newHeight = dim.y;
  156. float scx = (float)source.matTilingRect.width;
  157. float scy = (float)source.matTilingRect.height;
  158. float ox = (float)source.matTilingRect.x;
  159. float oy = (float)source.matTilingRect.y;
  160. if (data._fixOutOfBoundsUVs)
  161. {
  162. scx *= obUVscale.x;
  163. scy *= obUVscale.y;
  164. ox = (float)(source.matTilingRect.x * obUVscale.x + obUVoffset.x);
  165. oy = (float)(source.matTilingRect.y * obUVscale.y + obUVoffset.y);
  166. }
  167. Texture2D newTex = combiner._createTemporaryTexture(propertyName, (int)newWidth, (int)newHeight, TextureFormat.ARGB32, true);
  168. for (int i = 0; i < newTex.width; i++)
  169. {
  170. for (int j = 0; j < newTex.height; j++)
  171. {
  172. float u = i / newWidth * scx + ox;
  173. float v = j / newHeight * scy + oy;
  174. newTex.SetPixel(i, j, sourceTex.GetPixelBilinear(u, v));
  175. }
  176. }
  177. newTex.Apply();
  178. return newTex;
  179. }
  180. }
  181. }