SplatPainter.cs 54 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350
  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using MTE.Undo;
  5. using UnityEditor;
  6. using UnityEngine;
  7. namespace MTE
  8. {
  9. /// <summary>
  10. /// Splat texture painter
  11. /// </summary>
  12. /// <remarks>
  13. /// naming convention:
  14. /// control textures, "_Control" and "_ControlExtra"
  15. /// splat textures, "_Splat0/1/2/3/4/5/6/7"
  16. /// Only the last few splat textures can be null.
  17. /// Painting textures will normalize all control textures' color rects.
  18. /// </remarks>
  19. internal class SplatPainter : IEditor
  20. {
  21. private static readonly GUIContent[] EditorFilterModeContents =
  22. {
  23. new GUIContent(StringTable.Get(C.SplatPainter_Mode_Filtered),
  24. StringTable.Get(C.SplatPainter_Mode_FilteredDescription)),
  25. new GUIContent(StringTable.Get(C.SplatPainter_Mode_Selected),
  26. StringTable.Get(C.SplatPainter_Mode_SelectedDescription)),
  27. };
  28. public int Id { get; } = 4;
  29. public bool Enabled { get; set; } = true;
  30. public string Name { get; } = "SplatPainter";
  31. public Texture Icon { get; } =
  32. EditorGUIUtility.IconContent("TerrainInspector.TerrainToolSplat").image;
  33. public bool WantMouseMove { get; } = true;
  34. public bool WillEditMesh { get; } = false;
  35. #region Parameters
  36. #region Constant
  37. // default
  38. const EditorFilterMode DefaultPainterMode
  39. = EditorFilterMode.FilteredGameObjects;
  40. const float DefaultBrushSize = 1;
  41. const float DefaultBrushFlow = 0.5f;
  42. const float DefaultBrushAlpha = 0.5f;
  43. // min/max
  44. const float MinBrushSize = 0.1f;
  45. const float MaxBrushSize = 10f;
  46. const float MinBrushFlow = 0.01f;
  47. const float MaxBrushFlow = 1f;
  48. const float MinBrushAlpha = 0.5f;
  49. const float MaxBrushAlpha = 0.5f;
  50. const int MaxHotkeyNumberForTexture = 8;
  51. #endregion
  52. public int brushIndex;
  53. public float brushSize;
  54. public float brushFlow;
  55. private int selectedTextureIndex;
  56. private EditorFilterMode painterMode;
  57. private EditorFilterMode PainterMode
  58. {
  59. get { return this.painterMode; }
  60. set
  61. {
  62. if (value != this.painterMode)
  63. {
  64. EditorPrefs.SetInt("MTE_SplatPainter.painterMode", (int)value);
  65. this.painterMode = value;
  66. }
  67. }
  68. }
  69. /// <summary>
  70. /// Index of selected texture in the texture list; not the layer index.
  71. /// </summary>
  72. public int SelectedTextureIndex
  73. {
  74. get { return this.selectedTextureIndex; }
  75. set
  76. {
  77. var textureListCount = TextureList.Count;
  78. if (value < textureListCount)
  79. {
  80. this.selectedTextureIndex = value;
  81. }
  82. }
  83. }
  84. /// <summary>
  85. /// Index of selected brush
  86. /// </summary>
  87. public int BrushIndex
  88. {
  89. get { return brushIndex; }
  90. set
  91. {
  92. if (brushIndex != value)
  93. {
  94. preview.SetPreviewMaskTexture(value);
  95. brushIndex = value;
  96. }
  97. }
  98. }
  99. /// <summary>
  100. /// Brush size (unit: 1 BrushUnit)
  101. /// </summary>
  102. public float BrushSize
  103. {
  104. get { return brushSize; }
  105. set
  106. {
  107. value = Mathf.Clamp(value, MinBrushSize, MaxBrushSize);
  108. if (!MathEx.AmostEqual(brushSize, value))
  109. {
  110. brushSize = value;
  111. EditorPrefs.SetFloat("MTE_SplatPainter.brushSize", value);
  112. if (PainterMode == EditorFilterMode.FilteredGameObjects)
  113. {
  114. preview.SetPreviewSize(BrushSizeInU3D/2);
  115. }
  116. else
  117. {
  118. //preview size for SelectedGameObject mode are set in OnSceneGUI
  119. }
  120. }
  121. }
  122. }
  123. //real brush size
  124. private float BrushSizeInU3D { get { return BrushSize * Settings.BrushUnit; } }
  125. /// <summary>
  126. /// Brush flow
  127. /// </summary>
  128. public float BrushFlow
  129. {
  130. get { return brushFlow; }
  131. set
  132. {
  133. value = Mathf.Clamp(value, MinBrushFlow, MaxBrushFlow);
  134. if (Mathf.Abs(brushFlow - value) > 0.0001f)
  135. {
  136. brushFlow = value;
  137. EditorPrefs.SetFloat("MTE_SplatPainter.brushFlow", value);
  138. }
  139. }
  140. }
  141. #endregion
  142. public SplatPainter()
  143. {
  144. MTEContext.EnableEvent += (sender, args) =>
  145. {
  146. if (MTEContext.editor == this)
  147. {
  148. LoadSavedParamter();
  149. LoadTextureList();
  150. if (PainterMode == EditorFilterMode.SelectedGameObject)
  151. {
  152. BuildEditingInfoForLegacyMode(Selection.activeGameObject);
  153. }
  154. if (TextureList.Count != 0)
  155. {
  156. if (SelectedTextureIndex < 0)
  157. {
  158. SelectedTextureIndex = 0;
  159. }
  160. LoadPreview();
  161. }
  162. }
  163. };
  164. MTEContext.EditTypeChangedEvent += (sender, args) =>
  165. {
  166. if (MTEContext.editor == this)
  167. {
  168. LoadSavedParamter();
  169. LoadTextureList();
  170. if (PainterMode == EditorFilterMode.SelectedGameObject)
  171. {
  172. BuildEditingInfoForLegacyMode(Selection.activeGameObject);
  173. }
  174. if (TextureList.Count != 0)
  175. {
  176. if (SelectedTextureIndex < 0 || SelectedTextureIndex > TextureList.Count - 1)
  177. {
  178. SelectedTextureIndex = 0;
  179. }
  180. LoadPreview();
  181. }
  182. }
  183. else
  184. {
  185. if (preview != null)
  186. {
  187. preview.UnLoadPreview();
  188. }
  189. }
  190. };
  191. MTEContext.SelectionChangedEvent += (sender, args) =>
  192. {
  193. if (MTEContext.editor == this)
  194. {
  195. if (args.SelectedGameObject)
  196. {
  197. if (PainterMode == EditorFilterMode.SelectedGameObject)
  198. {
  199. BuildEditingInfoForLegacyMode(args.SelectedGameObject);
  200. }
  201. }
  202. }
  203. };
  204. MTEContext.TextureChangedEvent += (sender, args) =>
  205. {
  206. if (MTEContext.editor == this)
  207. {
  208. LoadTextureList();
  209. if (PainterMode == EditorFilterMode.SelectedGameObject)
  210. {
  211. BuildEditingInfoForLegacyMode(Selection.activeGameObject);
  212. }
  213. }
  214. };
  215. MTEContext.DisableEvent += (sender, args) =>
  216. {
  217. if (preview != null)
  218. {
  219. preview.UnLoadPreview();
  220. }
  221. };
  222. MTEContext.EditTargetsLoadedEvent += (sender, args) =>
  223. {
  224. if (MTEContext.editor == this)
  225. {
  226. LoadTextureList();
  227. }
  228. };
  229. // Load default parameters
  230. painterMode = DefaultPainterMode;
  231. brushSize = DefaultBrushSize;
  232. brushFlow = DefaultBrushFlow;
  233. }
  234. private void LoadPreview()
  235. {
  236. var texture = TextureList[SelectedTextureIndex];
  237. preview.LoadPreview(texture, BrushSizeInU3D, BrushIndex);
  238. }
  239. private void LoadSavedParamter()
  240. {
  241. // Load parameters from the EditorPrefs
  242. painterMode = (EditorFilterMode)EditorPrefs.GetInt(
  243. "MTE_SplatPainter.painterMode", (int)DefaultPainterMode);
  244. brushSize = EditorPrefs.GetFloat("MTE_SplatPainter.brushSize", DefaultBrushSize);
  245. brushFlow = EditorPrefs.GetFloat("MTE_SplatPainter.brushFlow", DefaultBrushFlow);
  246. }
  247. private GameObject targetGameObject { get; set; }
  248. private Mesh targetMesh { get; set; }
  249. private Material targetMaterial { get; set; }
  250. private Texture2D[] controlTextures { get; } = new Texture2D[2] {null, null};
  251. private void BuildEditingInfoForLegacyMode(GameObject gameObject)
  252. {
  253. //reset
  254. this.TextureList.Clear();
  255. this.controlTextures[0] = null;
  256. this.controlTextures[1] = null;
  257. this.targetGameObject = null;
  258. this.targetMaterial = null;
  259. this.targetMesh = null;
  260. //check gameObject
  261. if (!gameObject)
  262. {
  263. return;
  264. }
  265. if (PainterMode != EditorFilterMode.SelectedGameObject)
  266. {
  267. return;
  268. }
  269. var meshFilter = gameObject.GetComponent<MeshFilter>();
  270. if (!meshFilter)
  271. {
  272. return;
  273. }
  274. var meshRenderer = gameObject.GetComponent<MeshRenderer>();
  275. if (!meshRenderer)
  276. {
  277. return;
  278. }
  279. var material = meshRenderer.sharedMaterial;
  280. if (!meshRenderer)
  281. {
  282. return;
  283. }
  284. if (MTEShaders.IsMTETextureArrayShader(material.shader))
  285. {
  286. return;
  287. }
  288. //collect targets info
  289. this.targetGameObject = gameObject;
  290. this.targetMaterial = material;
  291. this.targetMesh = meshFilter.sharedMesh;
  292. // splat textures
  293. LoadTextureList();
  294. LoadControlTextures();
  295. if (controlTextures[0] == null)
  296. {
  297. return;
  298. }
  299. // Preview
  300. if (TextureList.Count != 0)
  301. {
  302. if (SelectedTextureIndex < 0 || SelectedTextureIndex > TextureList.Count - 1)
  303. {
  304. SelectedTextureIndex = 0;
  305. }
  306. LoadPreview();
  307. }
  308. }
  309. public string Header { get { return StringTable.Get(C.SplatPainter_Header); } }
  310. public string Description { get { return StringTable.Get(C.SplatPainter_Description); } }
  311. private static class Styles
  312. {
  313. public static string NoGameObjectSelectedHintText;
  314. private static bool unloaded= true;
  315. public static void Init()
  316. {
  317. if (!unloaded) return;
  318. NoGameObjectSelectedHintText
  319. = StringTable.Get(C.Info_PleaseSelectAGameObjectWithVaildMesh);
  320. unloaded = false;
  321. }
  322. }
  323. public void DoArgsGUI()
  324. {
  325. Styles.Init();
  326. EditorGUI.BeginChangeCheck();
  327. this.PainterMode = (EditorFilterMode)GUILayout.Toolbar(
  328. (int)this.PainterMode, EditorFilterModeContents);
  329. if (EditorGUI.EndChangeCheck()
  330. && PainterMode == EditorFilterMode.SelectedGameObject)
  331. {
  332. BuildEditingInfoForLegacyMode(Selection.activeGameObject);
  333. }
  334. if (PainterMode == EditorFilterMode.SelectedGameObject
  335. && Selection.activeGameObject == null)
  336. {
  337. EditorGUILayout.HelpBox(Styles.NoGameObjectSelectedHintText, MessageType.Warning);
  338. return;
  339. }
  340. BrushIndex = Utility.ShowBrushes(BrushIndex);
  341. // Splat-textures
  342. if (!Settings.CompactGUI)
  343. {
  344. GUILayout.Label(StringTable.Get(C.Textures), MTEStyles.SubHeader);
  345. }
  346. EditorGUILayout.BeginVertical("box");
  347. {
  348. var textureListCount = TextureList.Count;
  349. if (textureListCount == 0)
  350. {
  351. if (PainterMode == EditorFilterMode.FilteredGameObjects)
  352. {
  353. EditorGUILayout.LabelField(
  354. StringTable.Get(C.Info_SplatPainter_NoSplatTextureFound),
  355. GUILayout.Height(64));
  356. }
  357. else
  358. {
  359. EditorGUILayout.LabelField(
  360. StringTable.Get(C.Info_SplatPainter_NoSplatTextureFoundOnSelectedObject),
  361. GUILayout.Height(64));
  362. }
  363. }
  364. else
  365. {
  366. for (int i = 0; i < textureListCount; i += 4)
  367. {
  368. EditorGUILayout.BeginHorizontal();
  369. {
  370. var oldBgColor = GUI.backgroundColor;
  371. for (int j = 0; j < 4; j++)
  372. {
  373. if (i + j >= textureListCount) break;
  374. EditorGUILayout.BeginVertical();
  375. var texture = TextureList[i + j];
  376. bool toggleOn = SelectedTextureIndex == i + j;
  377. if (toggleOn)
  378. {
  379. GUI.backgroundColor = new Color(62 / 255.0f, 125 / 255.0f, 231 / 255.0f);
  380. }
  381. GUIContent toggleContent;
  382. if (i + j + 1 <= MaxHotkeyNumberForTexture)
  383. {
  384. toggleContent = new GUIContent(texture,
  385. StringTable.Get(C.Hotkey) + ':' + StringTable.Get(C.NumPad) + (i + j + 1));
  386. }
  387. else
  388. {
  389. toggleContent = new GUIContent(texture);
  390. }
  391. var new_toggleOn = GUILayout.Toggle(toggleOn,
  392. toggleContent, GUI.skin.button,
  393. GUILayout.Width(64), GUILayout.Height(64));
  394. GUI.backgroundColor = oldBgColor;
  395. if (new_toggleOn && !toggleOn)
  396. {
  397. SelectedTextureIndex = i + j;
  398. // reload the preview
  399. if (PainterMode == EditorFilterMode.SelectedGameObject)
  400. {
  401. preview.LoadPreviewFromObject(texture, BrushSizeInU3D, BrushIndex, targetGameObject);
  402. }
  403. else
  404. {
  405. preview.LoadPreview(texture, BrushSizeInU3D, BrushIndex);
  406. }
  407. }
  408. EditorGUILayout.EndVertical();
  409. }
  410. }
  411. EditorGUILayout.EndHorizontal();
  412. }
  413. }
  414. }
  415. EditorGUILayout.EndVertical();
  416. //Settings
  417. if (!Settings.CompactGUI)
  418. {
  419. EditorGUILayout.Space();
  420. GUILayout.Label(StringTable.Get(C.Settings), MTEStyles.SubHeader);
  421. }
  422. BrushSize = EditorGUILayoutEx.Slider(StringTable.Get(C.Size), "-", "+", BrushSize, MinBrushSize, MaxBrushSize);
  423. BrushFlow = EditorGUILayoutEx.SliderLog10(StringTable.Get(C.Flow), "[", "]", BrushFlow, MinBrushFlow, MaxBrushFlow);
  424. GUILayout.FlexibleSpace();
  425. EditorGUILayout.HelpBox(StringTable.Get(C.Info_WillBeSavedInstantly),
  426. MessageType.Info, true);
  427. }
  428. public HashSet<Hotkey> DefineHotkeys()
  429. {
  430. var hashSet = new HashSet<Hotkey>
  431. {
  432. new Hotkey(this, KeyCode.Minus, () =>
  433. {
  434. BrushFlow -= 0.01f;
  435. MTEEditorWindow.Instance.Repaint();
  436. }),
  437. new Hotkey(this, KeyCode.Equals, () =>
  438. {
  439. BrushFlow += 0.01f;
  440. MTEEditorWindow.Instance.Repaint();
  441. }),
  442. new Hotkey(this, KeyCode.LeftBracket, () =>
  443. {
  444. BrushSize -= 1;
  445. MTEEditorWindow.Instance.Repaint();
  446. }),
  447. new Hotkey(this, KeyCode.RightBracket, () =>
  448. {
  449. BrushSize += 1;
  450. MTEEditorWindow.Instance.Repaint();
  451. }),
  452. };
  453. for (int i = 0; i < MaxHotkeyNumberForTexture; i++)
  454. {
  455. int index = i;
  456. var hotkey = new Hotkey(this, KeyCode.Keypad0+index+1, () =>
  457. {
  458. SelectedTextureIndex = index;
  459. // reload the preview
  460. if (PainterMode == EditorFilterMode.SelectedGameObject)
  461. {
  462. preview.LoadPreviewFromObject(TextureList[SelectedTextureIndex], BrushSizeInU3D,
  463. BrushIndex, targetGameObject);
  464. }
  465. else
  466. {
  467. preview.LoadPreview(TextureList[SelectedTextureIndex], BrushSizeInU3D,
  468. BrushIndex);
  469. }
  470. MTEEditorWindow.Instance.Repaint();
  471. });
  472. hashSet.Add(hotkey);
  473. }
  474. return hashSet;
  475. }
  476. // buffers of editing helpers
  477. private readonly List<TextureModifyGroup> modifyGroups = new List<TextureModifyGroup>(4);
  478. private float[] BrushStrength = new float[1024 * 1024];//buffer for brush blending to forbid re-allocate big array every frame when painting.
  479. private readonly List<Color[]> modifyingSections = new List<Color[]>(2);
  480. private UndoTransaction currentUndoTransaction;
  481. public void OnSceneGUI()
  482. {
  483. var e = Event.current;
  484. if (preview == null || !preview.IsReady || TextureList.Count == 0)
  485. {
  486. return;
  487. }
  488. if (e.commandName == "UndoRedoPerformed")
  489. {
  490. SceneView.RepaintAll();
  491. return;
  492. }
  493. if (!(EditorWindow.mouseOverWindow is SceneView))
  494. {
  495. return;
  496. }
  497. // do nothing when mouse middle/right button, control/alt key is pressed
  498. if (e.button != 0 || e.control || e.alt)
  499. return;
  500. HandleUtility.AddDefaultControl(0);
  501. var ray = HandleUtility.GUIPointToWorldRay(e.mousePosition);
  502. RaycastHit raycastHit;
  503. if (PainterMode == EditorFilterMode.SelectedGameObject)
  504. {
  505. if (!targetGameObject || !targetMaterial || !targetMesh)
  506. {
  507. return;
  508. }
  509. if (!Physics.Raycast(ray, out raycastHit, Mathf.Infinity, ~targetGameObject.layer))
  510. {
  511. return;
  512. }
  513. var currentBrushSize = BrushSizeInU3D/2;
  514. if (Settings.ShowBrushRect)
  515. {
  516. Utility.ShowBrushRect(raycastHit.point, currentBrushSize);
  517. }
  518. var controlIndex = SelectedTextureIndex / 4;
  519. var controlTexture = controlTextures[controlIndex];
  520. var controlWidth = controlTexture.width;
  521. var controlHeight = controlTexture.height;
  522. var meshSize = targetGameObject.GetComponent<MeshRenderer>().bounds.size.x;
  523. var brushSizeInTexel = (int) Mathf.Round(BrushSizeInU3D/meshSize*controlWidth);
  524. preview.SetNormalizedBrushSize(BrushSizeInU3D/meshSize);
  525. preview.SetNormalizedBrushCenter(raycastHit.textureCoord);
  526. preview.SetPreviewSize(BrushSizeInU3D/2);
  527. preview.MoveTo(raycastHit.point);
  528. SceneView.RepaintAll();
  529. if ((e.type == EventType.MouseDrag && e.alt == false && e.shift == false && e.button == 0) ||
  530. (e.type == EventType.MouseDown && e.shift == false && e.alt == false && e.button == 0))
  531. {
  532. // 1. Collect all sections to be modified
  533. var sections = new List<Color[]>();
  534. var texelUV = raycastHit.textureCoord;
  535. var pX = Mathf.FloorToInt(texelUV.x * controlWidth);
  536. var pY = Mathf.FloorToInt(texelUV.y * controlHeight);
  537. var x = Mathf.Clamp(pX - brushSizeInTexel / 2, 0, controlWidth - 1);
  538. var y = Mathf.Clamp(pY - brushSizeInTexel / 2, 0, controlHeight - 1);
  539. var width = Mathf.Clamp((pX + brushSizeInTexel / 2), 0, controlWidth) - x;
  540. var height = Mathf.Clamp((pY + brushSizeInTexel / 2), 0, controlHeight) - y;
  541. for (var i = 0; i < controlTextures.Length; i++)
  542. {
  543. var texture = controlTextures[i];
  544. if (texture == null) continue;
  545. sections.Add(texture.GetPixels(x, y, width, height, 0));
  546. }
  547. // 2. Modify target
  548. var replaced = sections[controlIndex];
  549. var maskTexture = (Texture2D) MTEStyles.brushTextures[BrushIndex];
  550. BrushStrength = new float[brushSizeInTexel * brushSizeInTexel];
  551. for (var i = 0; i < brushSizeInTexel; i++)
  552. {
  553. for (var j = 0; j < brushSizeInTexel; j++)
  554. {
  555. BrushStrength[j * brushSizeInTexel + i] =
  556. maskTexture.GetPixelBilinear(((float) i) / brushSizeInTexel,
  557. ((float) j) / brushSizeInTexel).a;
  558. }
  559. }
  560. var controlColor = new Color();
  561. controlColor[SelectedTextureIndex % 4] = 1.0f;
  562. for (var i = 0; i < height; i++)
  563. {
  564. for (var j = 0; j < width; j++)
  565. {
  566. var index = (i * width) + j;
  567. var Stronger =
  568. BrushStrength[
  569. Mathf.Clamp((y + i) - (pY - brushSizeInTexel / 2), 0,
  570. brushSizeInTexel - 1) *
  571. brushSizeInTexel +
  572. Mathf.Clamp((x + j) - (pX - brushSizeInTexel / 2), 0,
  573. brushSizeInTexel - 1)] *
  574. BrushFlow;
  575. replaced[index] = Color.Lerp(replaced[index], controlColor, Stronger);
  576. }
  577. }
  578. if (e.type == EventType.MouseDown)
  579. {
  580. using (new UndoTransaction())
  581. {
  582. var material = targetMaterial;
  583. if (material.HasProperty("_Control"))
  584. {
  585. Texture2D texture = (Texture2D) material.GetTexture("_Control");
  586. if (texture != null)
  587. {
  588. var originalColors = texture.GetPixels();
  589. UndoRedoManager.Instance().Push(a =>
  590. {
  591. texture.ModifyPixels(a);
  592. texture.Apply();
  593. Save(texture);
  594. }, originalColors, "Paint control texture");
  595. }
  596. }
  597. if (material.HasProperty("_ControlExtra"))
  598. {
  599. Texture2D texture = (Texture2D) material.GetTexture("_ControlExtra");
  600. if (texture != null)
  601. {
  602. var originalColors = texture.GetPixels();
  603. UndoRedoManager.Instance().Push(a =>
  604. {
  605. texture.ModifyPixels(a);
  606. texture.Apply();
  607. Save(texture);
  608. }, originalColors, "Paint control texture");
  609. }
  610. }
  611. }
  612. }
  613. controlTexture.SetPixels(x, y, width, height, replaced);
  614. controlTexture.Apply();
  615. // 3. Normalize other control textures
  616. NormalizeWeightsLegacy(sections);
  617. for (var i = 0; i < controlTextures.Length; i++)
  618. {
  619. var texture = controlTextures[i];
  620. if (texture == null)
  621. {
  622. continue;
  623. }
  624. if (texture == controlTexture)
  625. {
  626. continue;
  627. }
  628. texture.SetPixels(x, y, width, height, sections[i]);
  629. texture.Apply();
  630. }
  631. }
  632. else if (e.type == EventType.MouseUp && e.alt == false && e.button == 0)
  633. {
  634. foreach (var texture in controlTextures)
  635. {
  636. if (texture)
  637. {
  638. Save(texture);
  639. }
  640. }
  641. }
  642. }
  643. else
  644. {
  645. if(Physics.Raycast(ray, out raycastHit,
  646. Mathf.Infinity,
  647. 1 << MTEContext.TargetLayer//only hit target layer
  648. ))
  649. {
  650. //check tag
  651. if (!raycastHit.transform.CompareTag(MTEContext.TargetTag))
  652. {
  653. return;
  654. }
  655. var currentBrushSize = BrushSizeInU3D;
  656. if (Settings.ShowBrushRect)
  657. {
  658. Utility.ShowBrushRect(raycastHit.point, currentBrushSize/2);
  659. }
  660. var hitPoint = raycastHit.point;
  661. preview.MoveTo(hitPoint);
  662. float meshSize = 1.0f;
  663. // collect modify group
  664. modifyGroups.Clear();
  665. foreach (var target in MTEContext.Targets)
  666. {
  667. //MTEDebug.Log("Check if we can paint on target.");
  668. var meshRenderer = target.GetComponent<MeshRenderer>();
  669. if (meshRenderer == null) continue;
  670. var meshFilter = target.GetComponent<MeshFilter>();
  671. if (meshFilter == null) continue;
  672. var mesh = meshFilter.sharedMesh;
  673. if (mesh == null) continue;
  674. Vector2 textureUVMin;//min texture uv that is to be modified
  675. Vector2 textureUVMax;//max texture uv that is to be modified
  676. Vector2 brushUVMin;//min brush mask uv that will be used
  677. Vector2 brushUVMax;//max brush mask uv that will be used
  678. {
  679. //MTEDebug.Log("Start: Check if they intersect with each other.");
  680. // check if the brush rect intersects with the `Mesh.bounds` of this target
  681. var hitPointLocal = target.transform.InverseTransformPoint(hitPoint);//convert hit point from world space to target mesh space
  682. Bounds brushBounds = new Bounds(center: new Vector3(hitPointLocal.x, 0, hitPointLocal.z), size: new Vector3(currentBrushSize, 99999, currentBrushSize));
  683. Bounds meshBounds = mesh.bounds;//TODO rename this
  684. Bounds paintingBounds;
  685. var intersected = meshBounds.Intersect(brushBounds, out paintingBounds);
  686. if(!intersected) continue;
  687. Vector2 paintingBounds2D_min = new Vector2(paintingBounds.min.x, paintingBounds.min.z);
  688. Vector2 paintingBounds2D_max = new Vector2(paintingBounds.max.x, paintingBounds.max.z);
  689. //calculate which part of control texture should be modified
  690. Vector2 meshRendererBounds2D_min = new Vector2(meshBounds.min.x, meshBounds.min.z);
  691. Vector2 meshRendererBounds2D_max = new Vector2(meshBounds.max.x, meshBounds.max.z);
  692. textureUVMin = MathEx.NormalizeTo01(rangeMin: meshRendererBounds2D_min, rangeMax: meshRendererBounds2D_max, value: paintingBounds2D_min);
  693. textureUVMax = MathEx.NormalizeTo01(rangeMin: meshRendererBounds2D_min, rangeMax: meshRendererBounds2D_max, value: paintingBounds2D_max);
  694. if (target.transform == raycastHit.transform)
  695. {
  696. meshSize = meshBounds.size.x;
  697. }
  698. //calculate which part of brush mask texture should be used
  699. Vector2 brushBounds2D_min = new Vector2(brushBounds.min.x, brushBounds.min.z);
  700. Vector2 brushBounds2D_max = new Vector2(brushBounds.max.x, brushBounds.max.z);
  701. brushUVMin = MathEx.NormalizeTo01(rangeMin: brushBounds2D_min, rangeMax: brushBounds2D_max, value: paintingBounds2D_min);
  702. brushUVMax = MathEx.NormalizeTo01(rangeMin: brushBounds2D_min, rangeMax: brushBounds2D_max, value: paintingBounds2D_max);
  703. if (Settings.DebugMode)
  704. {
  705. Handles.color = Color.blue;
  706. HandlesEx.DrawRectangle(paintingBounds2D_min, paintingBounds2D_max);
  707. Handles.color = new Color(255, 128, 166);
  708. HandlesEx.DrawRectangle(meshRendererBounds2D_min, meshRendererBounds2D_max);
  709. Handles.color = Color.green;
  710. HandlesEx.DrawRectangle(brushBounds2D_min, brushBounds2D_max);
  711. }
  712. //MTEDebug.Log("End: Check if they intersect with each other.");
  713. }
  714. if (e.button == 0 && (e.type == EventType.MouseDown || e.type == EventType.MouseDrag))
  715. {
  716. //MTEDebug.Log("Start handling mouse down.");
  717. // find the splat-texture in the material, get the X (splatIndex) from `_SplatX`
  718. var selectedTexture = TextureList[SelectedTextureIndex];
  719. var material = meshRenderer.sharedMaterial;
  720. if (material == null)
  721. {
  722. MTEDebug.LogError("Failed to find material on target GameObject's MeshRenderer. " +
  723. "The first material on the MeshRenderer should be editable by MTE.");
  724. return;
  725. }
  726. //MTEDebug.Log("Finding the selected texture in the material.");
  727. var splatIndex = material.FindSplatTexture(selectedTexture);
  728. if (splatIndex < 0)
  729. {
  730. continue;
  731. }
  732. //MTEDebug.Log("get number of splat-textures in the material.");
  733. int splatTotal = GetSplatTextureCount(material);
  734. //MTEDebug.Log("check control textures.");
  735. // check control textures
  736. var controlTexture0_ = material.GetTexture("_Control");
  737. Texture2D controlTexture0 = null, controlTexture1 = null;
  738. if (controlTexture0_ != null)
  739. {
  740. controlTexture0 = (Texture2D)controlTexture0_;
  741. }
  742. else
  743. {
  744. throw new InvalidOperationException(string.Format("[MTE] \"_Control\" is not assigned or existing in material<{0}>.", material.name));
  745. }
  746. if (material.HasProperty("_ControlExtra"))
  747. {
  748. var controlTexture1_ = material.GetTexture("_ControlExtra");
  749. if (controlTexture1_ == null)
  750. {
  751. throw new InvalidOperationException(string.Format("[MTE] \"_ControlExtra\" is not assigned or existing in material<{0}>.", material.name));
  752. }
  753. controlTexture1 = (Texture2D)controlTexture1_;
  754. }
  755. // check which control texture is to be modified
  756. Texture2D controlTexture = controlTexture0;
  757. if (splatIndex >= 4)
  758. {
  759. controlTexture = controlTexture1;
  760. }
  761. System.Diagnostics.Debug.Assert(controlTexture != null, "controlTexture != null");
  762. //get modifying texel rect of the control texture
  763. int x = (int)Mathf.Clamp(textureUVMin.x * (controlTexture.width - 1), 0, controlTexture.width - 1);
  764. int y = (int)Mathf.Clamp(textureUVMin.y * (controlTexture.height - 1), 0, controlTexture.height - 1);
  765. int width = Mathf.Clamp(Mathf.FloorToInt(textureUVMax.x * controlTexture.width) - x, 0, controlTexture.width - x);
  766. int height = Mathf.Clamp(Mathf.FloorToInt(textureUVMax.y * controlTexture.height) - y, 0, controlTexture.height - y);
  767. var texelRect = new Rect(x, y, width, height);
  768. modifyGroups.Add(new TextureModifyGroup(target, splatIndex, splatTotal, controlTexture0, controlTexture1, texelRect, brushUVMin, brushUVMax));
  769. //MTEDebug.Log("End handling mouse down.");
  770. }
  771. }
  772. preview.SetNormalizedBrushSize(BrushSizeInU3D/meshSize);
  773. preview.SetNormalizedBrushCenter(raycastHit.textureCoord);
  774. //record undo operation for targets that to be modified
  775. if (e.button == 0 && e.type == EventType.MouseDown)
  776. {
  777. currentUndoTransaction = new UndoTransaction("Paint Texture");
  778. }
  779. if (currentUndoTransaction != null &&
  780. e.button == 0 && e.type==EventType.MouseDown)
  781. {
  782. foreach (var modifyGroup in modifyGroups)
  783. {
  784. var gameObject = modifyGroup.gameObject;
  785. var material = gameObject.GetComponent<MeshRenderer>().sharedMaterial;
  786. if (material.HasProperty("_Control"))
  787. {
  788. Texture2D texture = (Texture2D)material.GetTexture("_Control");
  789. if (texture != null)
  790. {
  791. var originalColors = texture.GetPixels();
  792. UndoRedoManager.Instance().Push(a =>
  793. {
  794. texture.ModifyPixels(a);
  795. texture.Apply();
  796. Save(texture);
  797. }, originalColors, "Paint control texture");
  798. }
  799. }
  800. if (material.HasProperty("_ControlExtra"))
  801. {
  802. Texture2D texture = (Texture2D) material.GetTexture("_ControlExtra");
  803. if (texture != null)
  804. {
  805. var originalColors = texture.GetPixels();
  806. UndoRedoManager.Instance().Push(a =>
  807. {
  808. texture.ModifyPixels(a);
  809. texture.Apply();
  810. Save(texture);
  811. }, originalColors, "Paint control texture");
  812. }
  813. }
  814. }
  815. }
  816. if (e.button == 0 && e.type == EventType.MouseUp)
  817. {
  818. Debug.Assert(currentUndoTransaction != null);
  819. currentUndoTransaction.Dispose();
  820. }
  821. // execute the modification
  822. if (modifyGroups.Count != 0)
  823. {
  824. for (int i = 0; i < modifyGroups.Count; i++)
  825. {
  826. var modifyGroup = modifyGroups[i];
  827. var gameObject = modifyGroup.gameObject;
  828. var material = gameObject.GetComponent<MeshRenderer>().sharedMaterial;
  829. Utility.SetTextureReadable(material.GetTexture("_Control"));
  830. if (material.HasProperty("_ControlExtra"))
  831. {
  832. Utility.SetTextureReadable(material.GetTexture("_ControlExtra"));
  833. }
  834. PaintTexture(modifyGroup.controlTexture0, modifyGroup.controlTexture1, modifyGroup.splatIndex, modifyGroup.splatTotal, modifyGroup.texelRect, modifyGroup.minUV, modifyGroup.maxUV);
  835. }
  836. }
  837. // auto save when mouse up
  838. if (e.type == EventType.MouseUp && e.button == 0)
  839. {
  840. foreach (var texture2D in DirtyTextureSet)
  841. {
  842. Save(texture2D);
  843. }
  844. DirtyTextureSet.Clear();
  845. }
  846. }
  847. }
  848. SceneView.RepaintAll();
  849. }
  850. private static int GetSplatTextureCount(Material material)
  851. {
  852. var hasPackedSplat012 = material.HasProperty("_PackedSplat0")
  853. && material.HasProperty("_PackedSplat1")
  854. && material.HasProperty("_PackedSplat2");
  855. var hasPackedSplat345 = material.HasProperty("_PackedSplat3")
  856. && material.HasProperty("_PackedSplat4")
  857. && material.HasProperty("_PackedSplat5");
  858. if(hasPackedSplat012)
  859. {
  860. if (hasPackedSplat345)
  861. {
  862. return 8;
  863. }
  864. return 4;
  865. }
  866. int splatTotal;
  867. if (material.HasProperty("_Splat7"))
  868. {
  869. splatTotal = 8;
  870. }
  871. else if (material.HasProperty("_Splat6"))
  872. {
  873. splatTotal = 7;
  874. }
  875. else if (material.HasProperty("_Splat5"))
  876. {
  877. splatTotal = 6;
  878. }
  879. else if (material.HasProperty("_Splat4"))
  880. {
  881. splatTotal = 5;
  882. }
  883. else if (material.HasProperty("_Splat3"))
  884. {
  885. splatTotal = 4;
  886. }
  887. else if (material.HasProperty("_Splat2"))
  888. {
  889. splatTotal = 3;
  890. }
  891. else if (material.HasProperty("_Splat1"))
  892. {
  893. splatTotal = 2;
  894. }
  895. else
  896. {
  897. throw new InvalidShaderException(
  898. "[MTE] Cannot find property _Splat1/2/3/4/5/6/7 or _PackedSplat0/1/2/3/4/5 in shader.");
  899. }
  900. return splatTotal;
  901. }
  902. private void PaintTexture(Texture2D controlTexture0, Texture2D controlTexture1, int splatIndex, int splatTotal, Rect texelRect, Vector2 minUV, Vector2 maxUV)
  903. {
  904. // check parameters
  905. if (controlTexture0 == null)
  906. {
  907. throw new ArgumentNullException("controlTexture0");
  908. }
  909. if (splatIndex > 3 && controlTexture1 == null)
  910. {
  911. throw new ArgumentException("[MTE] splatIndex is 4/5/6/7 but controlTexture1 is null.", "controlTexture1");
  912. }
  913. if (splatIndex < 0 || splatIndex > 7)
  914. {
  915. throw new ArgumentOutOfRangeException("splatIndex", splatIndex, "splatIndex should be 0/1/2/3/4/5/6/7.");
  916. }
  917. // collect the pixel sections to modify
  918. modifyingSections.Clear();
  919. int x = (int)texelRect.x;
  920. int y = (int)texelRect.y;
  921. int width = (int)texelRect.width;
  922. int height = (int)texelRect.height;
  923. modifyingSections.Add(controlTexture0.GetPixels(x, y, width, height, 0));
  924. if (controlTexture1 != null)
  925. {
  926. modifyingSections.Add(controlTexture1.GetPixels(x, y, width, height, 0));
  927. }
  928. // sample brush strength from the mask texture
  929. var maskTexture = (Texture2D) MTEStyles.brushTextures[BrushIndex];
  930. if (BrushStrength.Length < width*height)//enlarge buffer if it is not big enough
  931. {
  932. BrushStrength = new float[width * height];
  933. }
  934. var unitUV_u = (maxUV.x - minUV.x)/(width-1);
  935. if (width == 1)
  936. {
  937. unitUV_u = maxUV.x - minUV.x;
  938. }
  939. var unitUV_v = (maxUV.y - minUV.y)/(height-1);
  940. if (height == 1)
  941. {
  942. unitUV_v = maxUV.y - minUV.y;
  943. }
  944. for (var i = 0; i < height; i++)
  945. {
  946. float v = minUV.y + i * unitUV_v;
  947. for (var j = 0; j < width; j++)
  948. {
  949. var pixelIndex = i * width + j;
  950. float u = minUV.x + j * unitUV_u;
  951. BrushStrength[pixelIndex] = maskTexture.GetPixelBilinear(u, v).a;
  952. }
  953. }
  954. // blend the pixel section
  955. for (var i = 0; i < height; i++)
  956. {
  957. for (var j = 0; j < width; j++)
  958. {
  959. var pixelIndex = i * width + j;
  960. var factor = BrushStrength[pixelIndex] * BrushFlow;
  961. var oldWeight = GetWeight(modifyingSections, j, i, width, splatIndex);
  962. var newWeight = Mathf.Lerp(oldWeight, 1, factor);
  963. SetWeight(modifyingSections, j, i, width, splatIndex, newWeight);
  964. NormalizeWeights(j, i, width, splatIndex, splatTotal);
  965. }
  966. }
  967. // modify the control texture
  968. if(splatTotal >= 5)
  969. {
  970. controlTexture0.SetPixels(x, y, width, height, modifyingSections[0]);
  971. controlTexture0.Apply();
  972. System.Diagnostics.Debug.Assert(controlTexture1 != null, nameof(controlTexture1) + " != null");
  973. controlTexture1.SetPixels(x, y, width, height, modifyingSections[1]);
  974. controlTexture1.Apply();
  975. DirtyTextureSet.Add(controlTexture0);
  976. DirtyTextureSet.Add(controlTexture1);
  977. }
  978. else
  979. {
  980. controlTexture0.SetPixels(x, y, width, height, modifyingSections[0]);
  981. controlTexture0.Apply();
  982. DirtyTextureSet.Add(controlTexture0);
  983. }
  984. }
  985. private static float GetWeight(List<Color[]> colorData, int x, int y, int width, int splatIndex)
  986. {
  987. var colors = colorData[splatIndex / 4];
  988. var weight = colors[y * width + x][splatIndex % 4];
  989. return weight;
  990. }
  991. private static void SetWeight(List<Color[]> colorData, int x, int y, int width, int splatIndex, float weight)
  992. {
  993. var colors = colorData[splatIndex / 4];
  994. var color = colors[y * width + x];
  995. color[splatIndex % 4] = weight;
  996. colors[y * width + x] = color;
  997. }
  998. private void NormalizeWeights(int x, int y, int width, int splatIndex, int splatTotal)
  999. {
  1000. float newWeight = GetWeight(modifyingSections, x, y, width, splatIndex);
  1001. float otherWeights = 0;
  1002. for (int i = 0; i < splatTotal; i++)
  1003. {
  1004. if (i != splatIndex)
  1005. {
  1006. otherWeights += GetWeight(modifyingSections, x, y, width, i);
  1007. }
  1008. }
  1009. if (otherWeights >= 1/255.0f)
  1010. {
  1011. float k = (1 - newWeight) / otherWeights;
  1012. for (int i = 0; i < splatTotal; i++)
  1013. {
  1014. if (i != splatIndex)
  1015. {
  1016. var weight = k * GetWeight(modifyingSections, x, y, width, i);
  1017. SetWeight(modifyingSections, x, y, width, i, weight);
  1018. }
  1019. }
  1020. }
  1021. else
  1022. {
  1023. for (int i = 0; i < splatTotal; i++)
  1024. {
  1025. var weight = (i == splatIndex) ? 1 : 0;
  1026. SetWeight(modifyingSections, x, y, width, i, weight);
  1027. }
  1028. }
  1029. }
  1030. private void NormalizeWeightsLegacy(List<Color[]> sections)
  1031. {
  1032. var colorCount = sections[0].Length;
  1033. for (var i = 0; i < colorCount; i++)
  1034. {
  1035. var total = 0f;
  1036. for (var j = 0; j < sections.Count; j++)
  1037. {
  1038. var color = sections[j][i];
  1039. total += color[0] + color[1] + color[2] + color[3];
  1040. if(j == SelectedTextureIndex/4)
  1041. {
  1042. total -= color[SelectedTextureIndex%4];
  1043. }
  1044. }
  1045. if(total > 0.01)
  1046. {
  1047. var a = sections[SelectedTextureIndex/4][i][SelectedTextureIndex%4];
  1048. var k = (1 - a)/total;
  1049. for (var j = 0; j < sections.Count; j++)
  1050. {
  1051. for (var l = 0; l < 4; l++)
  1052. {
  1053. if(!(j == SelectedTextureIndex/4 && l == SelectedTextureIndex%4))
  1054. {
  1055. sections[j][i][l] *= k;
  1056. }
  1057. }
  1058. }
  1059. }
  1060. else
  1061. {
  1062. for (var j = 0; j < sections.Count; j++)
  1063. {
  1064. sections[j][i][SelectedTextureIndex%4] = (j != SelectedTextureIndex/4) ? 0 : 1;
  1065. }
  1066. }
  1067. }
  1068. }
  1069. public static readonly HashSet<Texture2D> DirtyTextureSet = new HashSet<Texture2D>();
  1070. private static void Save(Texture2D texture)
  1071. {
  1072. if(texture == null)
  1073. {
  1074. throw new ArgumentNullException("texture");
  1075. }
  1076. var path = AssetDatabase.GetAssetPath(texture);
  1077. var bytes = texture.EncodeToPNG();
  1078. if(bytes == null || bytes.Length == 0)
  1079. {
  1080. throw new Exception("[MTE] Failed to save texture to png file.");
  1081. }
  1082. File.WriteAllBytes(path, bytes);
  1083. MTEDebug.LogFormat("Texture<{0}> saved to <{1}>.", texture.name, path);
  1084. }
  1085. private Preview preview = new Preview(isArray: false);
  1086. //Don't modify this field, it's used by MTE editors internally
  1087. public List<Texture> TextureList = new List<Texture>(16);
  1088. /// <summary>
  1089. /// load all splat textures form targets
  1090. /// </summary>
  1091. public void LoadTextureList()
  1092. {
  1093. TextureList.Clear();
  1094. if (painterMode == EditorFilterMode.SelectedGameObject)
  1095. {
  1096. MTEDebug.Log("Loading layer textures on selected GameObject...");
  1097. LoadTargetTextures(targetGameObject);
  1098. }
  1099. else
  1100. {
  1101. MTEDebug.Log("Loading layer textures on target GameObject(s)...");
  1102. foreach (var target in MTEContext.Targets)
  1103. {
  1104. LoadTargetTextures(target);
  1105. }
  1106. }
  1107. // make collected splat textures readable
  1108. Utility.SetTextureReadable(TextureList, true);
  1109. MTEDebug.LogFormat("{0} layer textures loaded.", TextureList.Count);
  1110. }
  1111. private void LoadTargetTextures(GameObject target)
  1112. {
  1113. if (!target)
  1114. {
  1115. return;
  1116. }
  1117. var meshRenderer = target.GetComponent<MeshRenderer>();
  1118. if (meshRenderer == null)
  1119. {
  1120. return;
  1121. }
  1122. var material = meshRenderer.sharedMaterial;
  1123. if (!material)
  1124. {
  1125. return;
  1126. }
  1127. if (!CheckIfMaterialAssetPathAvailable(material))
  1128. {
  1129. return;
  1130. }
  1131. Shader shader = material.shader;
  1132. if (shader == null)
  1133. {
  1134. MTEDebug.LogWarning(string.Format("The material<{0}> isn't using a valid shader!", material.name));
  1135. return;
  1136. }
  1137. //regular shaders: find textures from shader properties
  1138. var propertyCount = ShaderUtil.GetPropertyCount(shader);
  1139. for (int j = 0; j < propertyCount; j++)
  1140. {
  1141. if (ShaderUtil.GetPropertyType(shader, j) == ShaderUtil.ShaderPropertyType.TexEnv)
  1142. {
  1143. var propertyName = ShaderUtil.GetPropertyName(shader, j); //propertyName should be _Splat0/1/2/3/4
  1144. if (propertyName.StartsWith("_Splat"))
  1145. {
  1146. var texture = material.GetTexture(propertyName);
  1147. if (texture is Texture2DArray)
  1148. {
  1149. continue;
  1150. }
  1151. if (texture != null && !TextureList.Contains(texture))
  1152. {
  1153. TextureList.Add(texture);
  1154. }
  1155. }
  1156. }
  1157. }
  1158. //packed shaders: find textures from related parameter asset
  1159. var parameters = material.LoadPackedShaderGUIParameters();
  1160. if (parameters != null)
  1161. {
  1162. foreach (var texture in parameters.SplatTextures)
  1163. {
  1164. if (texture != null && !TextureList.Contains(texture))
  1165. {
  1166. TextureList.Add(texture);
  1167. }
  1168. }
  1169. }
  1170. }
  1171. private void LoadControlTextures()
  1172. {
  1173. if (!targetMaterial)
  1174. {
  1175. return;
  1176. }
  1177. var material = targetMaterial;
  1178. Texture controlTexture0_ = null;
  1179. if (material.HasProperty("_Control"))
  1180. {
  1181. controlTexture0_ = material.GetTexture("_Control");
  1182. }
  1183. if (controlTexture0_ != null)
  1184. {
  1185. controlTextures[0] = (Texture2D)controlTexture0_;
  1186. }
  1187. else
  1188. {
  1189. MTEDebug.LogWarning(
  1190. $"[MTE] \"_Control\" is not assigned or existing in material<{material.name}>.");
  1191. }
  1192. if (material.HasProperty("_ControlExtra"))
  1193. {
  1194. var controlTexture1_ = material.GetTexture("_ControlExtra");
  1195. if (controlTexture1_ == null)
  1196. {
  1197. MTEDebug.LogWarning(
  1198. $"[MTE] \"_ControlExtra\" is not assigned or existing in material<{material.name}>.");
  1199. }
  1200. else
  1201. {
  1202. controlTextures[1] = (Texture2D)controlTexture1_;
  1203. }
  1204. }
  1205. }
  1206. private static bool CheckIfMaterialAssetPathAvailable(Material material)
  1207. {
  1208. var relativePathOfMaterial = AssetDatabase.GetAssetPath(material);
  1209. if (relativePathOfMaterial.StartsWith("Resources"))
  1210. {//built-in material
  1211. return false;
  1212. }
  1213. return true;
  1214. }
  1215. }
  1216. }