源战役客户端
選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

361 行
13 KiB

  1. //----------------------------------------------
  2. // MeshBaker
  3. // Copyright © 2011-2012 Ian Deane
  4. //----------------------------------------------
  5. using UnityEngine;
  6. using System.Collections;
  7. using System.Collections.Specialized;
  8. using System;
  9. using System.Collections.Generic;
  10. using System.Text;
  11. using System.IO;
  12. using DigitalOpus.MB.Core;
  13. using LuaFramework;
  14. /// <summary>
  15. /// Component that handles baking materials into a combined material.
  16. ///
  17. /// The result of the material baking process is a MB2_TextureBakeResults object, which
  18. /// becomes the input for the mesh baking.
  19. ///
  20. /// This class uses the MB_TextureCombiner to do the combining.
  21. ///
  22. /// This class is a Component (MonoBehavior) so it is serialized and found using GetComponent. If
  23. /// you want to access the texture baking functionality without creating a Component then use MB_TextureCombiner
  24. /// directly.
  25. /// </summary>
  26. public class MB3_TextureBaker : MB3_MeshBakerRoot {
  27. public MB2_LogLevel LOG_LEVEL = MB2_LogLevel.info;
  28. [SerializeField] protected MB2_TextureBakeResults _textureBakeResults;
  29. public override MB2_TextureBakeResults textureBakeResults{
  30. get{return _textureBakeResults;}
  31. set{_textureBakeResults = value;}
  32. }
  33. [SerializeField] protected int _atlasPadding = 1;
  34. public virtual int atlasPadding{
  35. get{return _atlasPadding;}
  36. set{_atlasPadding = value;}
  37. }
  38. [SerializeField] protected int _maxAtlasSize = 4096;
  39. public virtual int maxAtlasSize{
  40. get{return _maxAtlasSize;}
  41. set{_maxAtlasSize = value;}
  42. }
  43. [SerializeField] protected bool _resizePowerOfTwoTextures = false;
  44. public virtual bool resizePowerOfTwoTextures{
  45. get{return _resizePowerOfTwoTextures;}
  46. set{_resizePowerOfTwoTextures = value;}
  47. }
  48. [SerializeField] protected bool _fixOutOfBoundsUVs = false;
  49. public virtual bool fixOutOfBoundsUVs{
  50. get{return _fixOutOfBoundsUVs;}
  51. set{_fixOutOfBoundsUVs = value;}
  52. }
  53. [SerializeField] protected int _maxTilingBakeSize = 1024;
  54. public virtual int maxTilingBakeSize{
  55. get{return _maxTilingBakeSize;}
  56. set{_maxTilingBakeSize = value;}
  57. }
  58. [SerializeField] protected MB2_PackingAlgorithmEnum _packingAlgorithm = MB2_PackingAlgorithmEnum.MeshBakerTexturePacker;
  59. public virtual MB2_PackingAlgorithmEnum packingAlgorithm{
  60. get{return _packingAlgorithm;}
  61. set{_packingAlgorithm = value;}
  62. }
  63. [SerializeField] protected bool _meshBakerTexturePackerForcePowerOfTwo = true;
  64. public bool meshBakerTexturePackerForcePowerOfTwo{
  65. get{return _meshBakerTexturePackerForcePowerOfTwo;}
  66. set{_meshBakerTexturePackerForcePowerOfTwo = value;}
  67. }
  68. [SerializeField] protected List<ShaderTextureProperty> _customShaderProperties = new List<ShaderTextureProperty>();
  69. public virtual List<ShaderTextureProperty> customShaderProperties{
  70. get{return _customShaderProperties;}
  71. set{_customShaderProperties = value;}
  72. }
  73. //this is depricated
  74. [SerializeField] protected List<string> _customShaderPropNames_Depricated = new List<string>();
  75. public virtual List<string> customShaderPropNames{
  76. get{return _customShaderPropNames_Depricated;}
  77. set{_customShaderPropNames_Depricated = value;}
  78. }
  79. [SerializeField] protected bool _doMultiMaterial;
  80. public virtual bool doMultiMaterial{
  81. get{return _doMultiMaterial;}
  82. set{_doMultiMaterial = value;}
  83. }
  84. [SerializeField] protected Material _resultMaterial;
  85. public virtual Material resultMaterial{
  86. get{return _resultMaterial;}
  87. set{_resultMaterial = value;}
  88. }
  89. public MB_MultiMaterial[] resultMaterials = new MB_MultiMaterial[0];
  90. public List<GameObject> objsToMesh; //todo make this Renderer
  91. public override List<GameObject> GetObjectsToCombine(){
  92. if (objsToMesh == null) objsToMesh = new List<GameObject>();
  93. return objsToMesh;
  94. }
  95. public MB_AtlasesAndRects[] CreateAtlases(){
  96. return CreateAtlases(null, false, null);
  97. }
  98. /// <summary>
  99. /// Creates the atlases.
  100. /// </summary>
  101. /// <returns>
  102. /// The atlases.
  103. /// </returns>
  104. /// <param name='progressInfo'>
  105. /// Progress info is a delegate function that displays a progress dialog. Can be null
  106. /// </param>
  107. /// <param name='saveAtlasesAsAssets'>
  108. /// if true atlases are saved as assets in the project folder. Othersise they are instances in memory
  109. /// </param>
  110. /// <param name='editorMethods'>
  111. /// Texture format tracker. Contains editor functionality such as save assets. Can be null.
  112. /// </param>
  113. public MB_AtlasesAndRects[] CreateAtlases(ProgressUpdateDelegate progressInfo, bool saveAtlasesAsAssets = false, MB2_EditorMethodsInterface editorMethods=null){
  114. MB_AtlasesAndRects[] mAndAs = null;
  115. try{
  116. mAndAs = _CreateAtlases(progressInfo, saveAtlasesAsAssets, editorMethods);
  117. } catch(Exception e){
  118. Debug.LogError(e);
  119. } finally {
  120. if (saveAtlasesAsAssets){ //Atlases were saved to project so we don't need these ones
  121. if (mAndAs != null){
  122. for(int j = 0; j < mAndAs.Length; j++){
  123. MB_AtlasesAndRects mAndA = mAndAs[j];
  124. if (mAndA != null && mAndA.atlases != null){
  125. for (int i = 0; i < mAndA.atlases.Length; i++){
  126. if (mAndA.atlases[i] != null){
  127. if (editorMethods != null) editorMethods.Destroy(mAndA.atlases[i]);
  128. else MB_Utility.Destroy(mAndA.atlases[i]);
  129. }
  130. }
  131. }
  132. }
  133. }
  134. }
  135. }
  136. return mAndAs;
  137. }
  138. MB_AtlasesAndRects[] _CreateAtlases(ProgressUpdateDelegate progressInfo, bool saveAtlasesAsAssets = false, MB2_EditorMethodsInterface editorMethods=null){
  139. //validation
  140. if (saveAtlasesAsAssets && editorMethods == null){
  141. LogManager.LogError("Error in CreateAtlases If saveAtlasesAsAssets = true then editorMethods cannot be null.");
  142. return null;
  143. }
  144. if (saveAtlasesAsAssets && !Application.isEditor){
  145. LogManager.LogError("Error in CreateAtlases If saveAtlasesAsAssets = true it must be called from the Unity Editor.");
  146. return null;
  147. }
  148. MB2_ValidationLevel vl = Application.isPlaying ? MB2_ValidationLevel.quick : MB2_ValidationLevel.robust;
  149. if (!DoCombinedValidate(this, MB_ObjsToCombineTypes.dontCare, editorMethods, vl)){
  150. return null;
  151. }
  152. if (_doMultiMaterial && !_ValidateResultMaterials()){
  153. return null;
  154. } else if (!_doMultiMaterial){
  155. if (_resultMaterial == null){
  156. LogManager.LogError("Combined Material is null please create and assign a result material.");
  157. return null;
  158. }
  159. Shader targShader = _resultMaterial.shader;
  160. for (int i = 0; i < objsToMesh.Count; i++){
  161. Material[] ms = MB_Utility.GetGOMaterials(objsToMesh[i]);
  162. for (int j = 0; j < ms.Length; j++){
  163. Material m = ms[j];
  164. if (m != null && m.shader != targShader){
  165. LogManager.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.");
  166. }
  167. }
  168. }
  169. }
  170. for (int i = 0; i < objsToMesh.Count; i++){
  171. Material[] ms = MB_Utility.GetGOMaterials(objsToMesh[i]);
  172. for (int j = 0; j < ms.Length; j++){
  173. Material m = ms[j];
  174. if (m == null){
  175. LogManager.LogError("Game object " + objsToMesh[i] + " has a null material. Can't build atlases");
  176. return null;
  177. }
  178. }
  179. }
  180. MB3_TextureCombiner combiner = new MB3_TextureCombiner();
  181. combiner.LOG_LEVEL = LOG_LEVEL;
  182. combiner.atlasPadding = _atlasPadding;
  183. combiner.maxAtlasSize = _maxAtlasSize;
  184. combiner.customShaderPropNames = _customShaderProperties;
  185. combiner.fixOutOfBoundsUVs = _fixOutOfBoundsUVs;
  186. combiner.maxTilingBakeSize = _maxTilingBakeSize;
  187. combiner.packingAlgorithm = _packingAlgorithm;
  188. combiner.meshBakerTexturePackerForcePowerOfTwo = _meshBakerTexturePackerForcePowerOfTwo;
  189. combiner.resizePowerOfTwoTextures = _resizePowerOfTwoTextures;
  190. combiner.saveAtlasesAsAssets = saveAtlasesAsAssets;
  191. // if editor analyse meshes and suggest treatment
  192. if (!Application.isPlaying){
  193. Material[] rms;
  194. if (_doMultiMaterial){
  195. rms = new Material[resultMaterials.Length];
  196. for (int i = 0; i < rms.Length; i++) rms[i] = resultMaterials[i].combinedMaterial;
  197. } else {
  198. rms = new Material[1];
  199. rms[0] = _resultMaterial;
  200. }
  201. combiner.SuggestTreatment(objsToMesh, rms, combiner.customShaderPropNames);
  202. }
  203. //initialize structure to store results
  204. int numResults = 1;
  205. if (_doMultiMaterial) numResults = resultMaterials.Length;
  206. MB_AtlasesAndRects[] resultAtlasesAndRects = new MB_AtlasesAndRects[numResults];
  207. for (int i = 0; i < resultAtlasesAndRects.Length; i++){
  208. resultAtlasesAndRects[i] = new MB_AtlasesAndRects();
  209. }
  210. //Do the material combining.
  211. for (int i = 0; i < resultAtlasesAndRects.Length; i++){
  212. Material resMatToPass = null;
  213. List<Material> sourceMats = null;
  214. if (_doMultiMaterial) {
  215. sourceMats = resultMaterials[i].sourceMaterials;
  216. resMatToPass = resultMaterials[i].combinedMaterial;
  217. } else {
  218. resMatToPass = _resultMaterial;
  219. }
  220. LogManager.Log("Creating atlases for result material " + resMatToPass);
  221. if(!combiner.CombineTexturesIntoAtlases(progressInfo, resultAtlasesAndRects[i], resMatToPass, objsToMesh, sourceMats, editorMethods)){
  222. return null;
  223. }
  224. }
  225. //Save the results
  226. textureBakeResults.combinedMaterialInfo = resultAtlasesAndRects;
  227. textureBakeResults.doMultiMaterial = _doMultiMaterial;
  228. textureBakeResults.resultMaterial = _resultMaterial;
  229. textureBakeResults.resultMaterials = resultMaterials;
  230. textureBakeResults.fixOutOfBoundsUVs = combiner.fixOutOfBoundsUVs;
  231. unpackMat2RectMap(textureBakeResults);
  232. //set the texture bake resultAtlasesAndRects on the Mesh Baker component if it exists
  233. MB3_MeshBakerCommon[] mb = GetComponentsInChildren<MB3_MeshBakerCommon>();
  234. for (int i = 0; i < mb.Length; i++){
  235. mb[i].textureBakeResults = textureBakeResults;
  236. }
  237. if (LOG_LEVEL >= MB2_LogLevel.info) LogManager.Log("Created Atlases");
  238. return resultAtlasesAndRects;
  239. }
  240. void unpackMat2RectMap(MB2_TextureBakeResults tbr){
  241. List<Material> ms = new List<Material>();
  242. List<MB_MaterialAndUVRect> mss = new List<MB_MaterialAndUVRect>();
  243. List<Rect> rs = new List<Rect>();
  244. for (int i = 0; i < tbr.combinedMaterialInfo.Length; i++){
  245. MB_AtlasesAndRects newMesh = tbr.combinedMaterialInfo[i];
  246. List<MB_MaterialAndUVRect> map = newMesh.mat2rect_map;
  247. for(int j = 0; j < map.Count; j++){
  248. mss.Add(map[j]);
  249. ms.Add(map[j].material);
  250. rs.Add(map[j].atlasRect);
  251. }
  252. }
  253. tbr.materialsAndUVRects = mss.ToArray();
  254. tbr.materials = ms.ToArray();
  255. tbr.prefabUVRects = rs.ToArray();
  256. }
  257. public static void ConfigureNewMaterialToMatchOld(Material newMat, Material original){
  258. if (original == null){
  259. LogManager.LogWarning("Original material is null, could not copy properties to " + newMat + ". Setting shader to " + newMat.shader);
  260. return;
  261. }
  262. newMat.shader = original.shader;
  263. newMat.CopyPropertiesFromMaterial(original);
  264. ShaderTextureProperty[] texPropertyNames = MB3_TextureCombiner.shaderTexPropertyNames;
  265. for (int j = 0; j < texPropertyNames.Length; j++){
  266. Vector2 scale = Vector2.one;
  267. Vector2 offset = Vector2.zero;
  268. if (newMat.HasProperty(texPropertyNames[j].name)){
  269. newMat.SetTextureOffset(texPropertyNames[j].name,offset);
  270. newMat.SetTextureScale(texPropertyNames[j].name,scale);
  271. }
  272. }
  273. }
  274. string PrintSet(HashSet<Material> s){
  275. StringBuilder sb = new StringBuilder();
  276. foreach(Material m in s){
  277. sb.Append( m + ",");
  278. }
  279. return sb.ToString();
  280. }
  281. bool _ValidateResultMaterials(){
  282. HashSet<Material> allMatsOnObjs = new HashSet<Material>();
  283. for (int i = 0; i < objsToMesh.Count; i++){
  284. if (objsToMesh[i] != null){
  285. Material[] ms = MB_Utility.GetGOMaterials(objsToMesh[i]);
  286. for (int j = 0; j < ms.Length; j++){
  287. if (ms[j] != null) allMatsOnObjs.Add(ms[j]);
  288. }
  289. }
  290. }
  291. HashSet<Material> allMatsInMapping = new HashSet<Material>();
  292. for (int i = 0; i < resultMaterials.Length; i++){
  293. MB_MultiMaterial mm = resultMaterials[i];
  294. if (mm.combinedMaterial == null){
  295. LogManager.LogError("Combined Material is null please create and assign a result material.");
  296. return false;
  297. }
  298. Shader targShader = mm.combinedMaterial.shader;
  299. for (int j = 0; j < mm.sourceMaterials.Count; j++){
  300. if (mm.sourceMaterials[j] == null){
  301. LogManager.LogError("There are null entries in the list of Source Materials");
  302. return false;
  303. }
  304. if (targShader != mm.sourceMaterials[j].shader){
  305. LogManager.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.");
  306. }
  307. if (allMatsInMapping.Contains(mm.sourceMaterials[j])){
  308. LogManager.LogError("A Material " + mm.sourceMaterials[j] + " appears more than once in the list of source materials in the source material to combined mapping. Each source material must be unique.");
  309. return false;
  310. }
  311. allMatsInMapping.Add(mm.sourceMaterials[j]);
  312. }
  313. }
  314. if (allMatsOnObjs.IsProperSubsetOf(allMatsInMapping)){
  315. allMatsInMapping.ExceptWith(allMatsOnObjs);
  316. LogManager.LogWarning("There are materials in the mapping that are not used on your source objects: " + PrintSet(allMatsInMapping));
  317. }
  318. if (allMatsInMapping.IsProperSubsetOf(allMatsOnObjs)){
  319. allMatsOnObjs.ExceptWith(allMatsInMapping);
  320. LogManager.LogError("There are materials on the objects to combine that are not in the mapping: " + PrintSet(allMatsOnObjs));
  321. return false;
  322. }
  323. return true;
  324. }
  325. }