源战役客户端
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

337 行
14 KiB

  1. using UnityEngine;
  2. using System;
  3. using System.Text;
  4. using System.Collections;
  5. using System.Collections.Generic;
  6. using DigitalOpus.MB.Core;
  7. using LuaFramework;
  8. /// <summary>
  9. /// Used internally during the material baking process
  10. /// </summary>
  11. [Serializable]
  12. public class MB_AtlasesAndRects{
  13. public Texture2D[] atlases;
  14. [NonSerialized]
  15. public List<MB_MaterialAndUVRect> mat2rect_map;
  16. public string[] texPropertyNames;
  17. }
  18. [System.Serializable]
  19. public class MB_MultiMaterial{
  20. public Material combinedMaterial;
  21. public List<Material> sourceMaterials = new List<Material>();
  22. }
  23. [System.Serializable]
  24. public class MB_MaterialAndUVRect
  25. {
  26. public Material material;
  27. //The UV rect in the source texture that was used when copying from source texture to destinationAtlas.
  28. //If _fixOutOfBoundsUVs it may be smaller than, same size, or larger than 0..1. larger than means that these meshes have out of bounds UVs
  29. //If !_fixOutOfBoundsUVs it will be 0..1
  30. public Rect atlasRect;
  31. public Rect atlasSubrectMaterialOnly; //the subrectangle of atlasRect assuming only material tiling
  32. public MB_MaterialAndUVRect(Material m, Rect destRect, Rect matTilingTransformRect)
  33. {
  34. material = m;
  35. atlasRect = destRect;
  36. atlasSubrectMaterialOnly = matTilingTransformRect;
  37. }
  38. public override int GetHashCode()
  39. {
  40. return material.GetInstanceID() ^ atlasSubrectMaterialOnly.GetHashCode();
  41. }
  42. public override bool Equals(object obj)
  43. {
  44. if (!(obj is MB_MaterialAndUVRect)) return false;
  45. return (material == ((MB_MaterialAndUVRect)obj).material && atlasSubrectMaterialOnly == ((MB_MaterialAndUVRect)obj).atlasSubrectMaterialOnly);
  46. }
  47. }
  48. /// <summary>
  49. /// This class stores the results from an MB2_TextureBaker when materials are combined into atlases. It stores
  50. /// a list of materials and the corresponding UV rectangles in the atlases. It also stores the configuration
  51. /// options that were used to generate the combined material.
  52. ///
  53. /// It can be saved as an asset in the project so that textures can be baked in one scene and used in another.
  54. ///
  55. /// </summary>
  56. public class MB2_TextureBakeResults : ScriptableObject {
  57. public MB_AtlasesAndRects[] combinedMaterialInfo;
  58. //Depricated
  59. public Material[] materials;
  60. public Rect[] prefabUVRects;
  61. public MB_MaterialAndUVRect[] materialsAndUVRects;
  62. public Material resultMaterial;
  63. public MB_MultiMaterial[] resultMaterials;
  64. public bool doMultiMaterial;
  65. public bool fixOutOfBoundsUVs;
  66. /// <summary>
  67. /// Creates for materials on renderer.
  68. /// </summary>
  69. /// <returns>Generates an MB2_TextureBakeResult that can be used if all objects to be combined use the same material.
  70. /// Returns a MB2_TextureBakeResults that will map all materials used by renderer r to
  71. /// the rectangle 0,0..1,1 in the atlas.</returns>
  72. /// <param name="r">The red component.</param>
  73. public static MB2_TextureBakeResults CreateForMaterialsOnRenderer(Renderer r){
  74. MB2_TextureBakeResults tbr = (MB2_TextureBakeResults) ScriptableObject.CreateInstance( typeof(MB2_TextureBakeResults) );
  75. //Material[] ms = r.sharedMaterials;
  76. //MB_MaterialAndUVRect[] mss = new MB_MaterialAndUVRect[r.sharedMaterials.Length];
  77. List<MB_MaterialAndUVRect> mss = new List<MB_MaterialAndUVRect>();
  78. Material[] ms;
  79. for (int i = 0; i < r.sharedMaterials.Length; i++)
  80. {
  81. if (r.sharedMaterials[i] != null)
  82. {
  83. MB_MaterialAndUVRect matAndUVRect = new MB_MaterialAndUVRect(r.sharedMaterials[i], new Rect(0f, 0f, 1f, 1f), new Rect(0f,0f,1f,1f));
  84. if (!mss.Contains(matAndUVRect))
  85. {
  86. mss.Add(matAndUVRect);
  87. }
  88. }
  89. }
  90. if (r.sharedMaterials.Length > 1) {
  91. tbr.prefabUVRects = new Rect[mss.Count];
  92. tbr.materials = ms = new Material[mss.Count];
  93. tbr.resultMaterials = new MB_MultiMaterial[mss.Count];
  94. for (int i = 0; i < mss.Count; i++){
  95. ms[i] = mss[i].material;
  96. tbr.prefabUVRects[i] = new Rect(0f,0f,1f,1f);
  97. tbr.resultMaterials[i] = new MB_MultiMaterial();
  98. List<Material> sourceMats = new List<Material>();
  99. sourceMats.Add (ms[i]);
  100. tbr.resultMaterials[i].sourceMaterials = sourceMats;
  101. tbr.resultMaterials[i].combinedMaterial = ms[i];
  102. }
  103. tbr.doMultiMaterial = true;
  104. } else {
  105. tbr.doMultiMaterial = false;
  106. tbr.prefabUVRects = new Rect[]{new Rect(0f,0f,1f,1f)};
  107. tbr.materials = ms = new Material[] { mss[0].material };
  108. tbr.resultMaterial = mss[0].material;
  109. tbr.resultMaterials = new MB_MultiMaterial[] { new MB_MultiMaterial() };
  110. List<Material> sourceMats = new List<Material>();
  111. sourceMats.Add(ms[0]);
  112. tbr.resultMaterials[0].sourceMaterials = sourceMats;
  113. tbr.resultMaterials[0].combinedMaterial = mss[0].material;
  114. }
  115. tbr.materialsAndUVRects = mss.ToArray();
  116. tbr.fixOutOfBoundsUVs = false;
  117. return tbr;
  118. }
  119. public bool ContainsMaterial(Material m)
  120. {
  121. if (materialsAndUVRects.Length == 0) {
  122. materialsAndUVRects = new MB_MaterialAndUVRect[materials.Length];
  123. for (int i = 0; i < materialsAndUVRects.Length; i++){
  124. materialsAndUVRects[i] = new MB_MaterialAndUVRect(materials[i], prefabUVRects[i],new Rect(0f,0f,1f,1f));
  125. }
  126. }
  127. for (int i = 0; i < materialsAndUVRects.Length; i++)
  128. {
  129. if (materialsAndUVRects[i].material == m){
  130. return true;
  131. }
  132. }
  133. return false;
  134. }
  135. public string GetDescription(){
  136. StringBuilder sb = new StringBuilder();
  137. sb.Append("Shaders:\n");
  138. HashSet<Shader> shaders = new HashSet<Shader>();
  139. if (materialsAndUVRects != null){
  140. for (int i = 0; i < materialsAndUVRects.Length; i++){
  141. shaders.Add(materialsAndUVRects[i].material.shader);
  142. }
  143. }
  144. foreach(Shader m in shaders){
  145. sb.Append(" ").Append(m.name).AppendLine();
  146. }
  147. sb.Append("Materials:\n");
  148. if (materialsAndUVRects != null){
  149. for (int i = 0; i < materialsAndUVRects.Length; i++){
  150. sb.Append(" ").Append(materialsAndUVRects[i].material.name).AppendLine();
  151. }
  152. }
  153. return sb.ToString();
  154. }
  155. public class Material2AtlasRectangleMapper
  156. {
  157. MB2_TextureBakeResults tbr;
  158. //bool allMatsAreUnique;
  159. int[] numTimesMatAppearsInAtlas;
  160. MB_MaterialAndUVRect[] matsAndSrcUVRect;
  161. //Rect[] uvRectInAtlas;
  162. public Material2AtlasRectangleMapper(MB2_TextureBakeResults res)
  163. {
  164. tbr = res;
  165. matsAndSrcUVRect = res.materialsAndUVRects;
  166. //uvRectInAtlas = res.prefabUVRects;
  167. //allMatsAreUnique = true;
  168. //backward compatibility. this may be an old TextureBakeResult which has no materialsAndUVRects if so then build it now
  169. if (matsAndSrcUVRect == null || matsAndSrcUVRect.Length == 0)
  170. {
  171. matsAndSrcUVRect = new MB_MaterialAndUVRect[res.materials.Length];
  172. for (int i = 0; i < res.materials.Length; i++)
  173. {
  174. matsAndSrcUVRect[i] = new MB_MaterialAndUVRect(res.materials[i], res.prefabUVRects[i],new Rect(0f,0f,1f,1f));
  175. }
  176. res.materialsAndUVRects = matsAndSrcUVRect;
  177. }
  178. //count the number of times a material appears in the atlas. used for fast lookup
  179. numTimesMatAppearsInAtlas = new int[matsAndSrcUVRect.Length];
  180. for (int i = 0; i < matsAndSrcUVRect.Length; i++)
  181. {
  182. if (numTimesMatAppearsInAtlas[i] > 1)
  183. {
  184. continue;
  185. }
  186. int count = 1;
  187. for (int j = i + 1; j < matsAndSrcUVRect.Length; j++)
  188. {
  189. if (matsAndSrcUVRect[i].material == matsAndSrcUVRect[j].material)
  190. {
  191. count++;
  192. }
  193. }
  194. numTimesMatAppearsInAtlas[i] = count;
  195. if (count > 1)
  196. {
  197. //allMatsAreUnique = false;
  198. for (int j = i + 1; j < matsAndSrcUVRect.Length; j++)
  199. {
  200. if (matsAndSrcUVRect[i].material == matsAndSrcUVRect[j].material)
  201. {
  202. numTimesMatAppearsInAtlas[j] = count;
  203. }
  204. }
  205. }
  206. }
  207. }
  208. //a material can appear more than once in an atlas if using fixOutOfBoundsUVs.
  209. //in this case need to use the UV rect of the mesh to find the correct rectangle.
  210. public bool TryMapMaterialToUVRect(Material mat, Mesh m, int submeshIdx, MB3_MeshCombinerSingle.MeshChannelsCache meshChannelCache, Dictionary<int, MB_Utility.MeshAnalysisResult[]> meshAnalysisCache,
  211. out Rect rectInAtlas, out Rect subrectInAtlasMatTiling, ref String errorMsg)
  212. {
  213. if (tbr.materialsAndUVRects.Length == 0 && tbr.materials.Length > 0) {
  214. errorMsg = "The 'Material Bake Result' needs to be re-baked to be compatible with this version of Mesh Baker. Please re-bake using the MB3_TextureBaker.";
  215. rectInAtlas = new Rect();
  216. subrectInAtlasMatTiling = new Rect();
  217. return false;
  218. }
  219. if (mat == null)
  220. {
  221. rectInAtlas = new Rect();
  222. subrectInAtlasMatTiling = new Rect();
  223. errorMsg = String.Format("Mesh {0} Had no material on submesh {1} cannot map to a material in the atlas", m.name, submeshIdx);
  224. return false;
  225. }
  226. if (submeshIdx >= m.subMeshCount)
  227. {
  228. errorMsg = "Submesh index is greater than the number of submeshes";
  229. rectInAtlas = new Rect();
  230. subrectInAtlasMatTiling = new Rect();
  231. return false;
  232. }
  233. //find the first index of this material
  234. int idx = -1;
  235. for (int i = 0; i < matsAndSrcUVRect.Length; i++)
  236. {
  237. if (mat == matsAndSrcUVRect[i].material)
  238. {
  239. idx = i;
  240. break;
  241. }
  242. }
  243. // if couldn't find material
  244. if (idx == -1)
  245. {
  246. rectInAtlas = new Rect();
  247. subrectInAtlasMatTiling = new Rect();
  248. errorMsg = String.Format("Material {0} could not be found in the Material Bake Result", mat.name);
  249. return false;
  250. }
  251. if (!tbr.fixOutOfBoundsUVs)
  252. {
  253. if (numTimesMatAppearsInAtlas[idx] != 1)
  254. {
  255. LogManager.LogError("There is a problem with this TextureBakeResults. FixOutOfBoundsUVs is false and a material appears more than once.");
  256. }
  257. rectInAtlas = matsAndSrcUVRect[idx].atlasRect;
  258. subrectInAtlasMatTiling = matsAndSrcUVRect[idx].atlasSubrectMaterialOnly;
  259. return true;
  260. } else {
  261. //todo what if no UVs
  262. //Find UV rect in source mesh
  263. MB_Utility.MeshAnalysisResult[] mar;
  264. if (!meshAnalysisCache.TryGetValue(m.GetInstanceID(), out mar))
  265. {
  266. mar = new MB_Utility.MeshAnalysisResult[m.subMeshCount];
  267. for (int j = 0; j < m.subMeshCount; j++)
  268. {
  269. Vector2[] uvss = meshChannelCache.GetUv0Raw(m);
  270. MB_Utility.hasOutOfBoundsUVs(uvss, m, ref mar[j], j);
  271. }
  272. meshAnalysisCache.Add(m.GetInstanceID(), mar);
  273. }
  274. //this could be a mesh that was not used in the texture baking that has huge UV tiling too big for the rect that was baked
  275. //find a record that has an atlas uvRect capable of containing this
  276. bool found = false;
  277. for (int i = idx; i < matsAndSrcUVRect.Length; i++)
  278. {
  279. if (matsAndSrcUVRect[i].material == mat)
  280. {
  281. //calculate what the UV rect in the atlas would be if we combined the material tiling of this rect with the UV tiling of this submesh
  282. Rect potentialRect = new Rect();
  283. Rect uvR = mar[submeshIdx].uvRect;
  284. Rect matR = matsAndSrcUVRect[i].atlasSubrectMaterialOnly;
  285. potentialRect = MB3_UVTransformUtility.CombineTransforms(ref matR,ref uvR);
  286. //MB3_UVTransformUtility.Canonicalize(ref potentialRect);
  287. // test to see if this would fit in what was baked in the atlas
  288. Rect rr = new Rect(0f, 0f, 1f, 1f);
  289. if (MB3_UVTransformUtility.RectContains(ref rr, ref potentialRect)) {
  290. idx = i;
  291. found = true;
  292. break;
  293. }
  294. }
  295. }
  296. if (found)
  297. {
  298. rectInAtlas = matsAndSrcUVRect[idx].atlasRect;
  299. subrectInAtlasMatTiling = matsAndSrcUVRect[idx].atlasSubrectMaterialOnly;
  300. return true;
  301. } else
  302. {
  303. rectInAtlas = new Rect();
  304. subrectInAtlasMatTiling = new Rect();
  305. errorMsg = String.Format("Could not find a tiled rectangle in the atlas capable of containing the uv and material tiling on mesh {0}", m.name);
  306. return false;
  307. }
  308. }
  309. }
  310. }
  311. }