MB3_TextureCombinerPackerUnity.cs 9.9 KB

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