MaterialInspector.cs 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606
  1. using System.Collections.Generic;
  2. using BansheeEngine;
  3. namespace BansheeEditor
  4. {
  5. /// <summary>
  6. /// Renders an inspector for the <see cref="Material"/> resource.
  7. /// </summary>
  8. [CustomInspector(typeof (Material))]
  9. internal class MaterialInspector : Inspector
  10. {
  11. private MaterialParamGUI[] guiParams;
  12. private GUIResourceField shaderField;
  13. /// <inheritdoc/>
  14. protected internal override void Initialize()
  15. {
  16. Material material = InspectedObject as Material;
  17. if (material == null)
  18. return;
  19. shaderField = new GUIResourceField(typeof(Shader), new LocEdString("Shader"));
  20. shaderField.Value = material.Shader;
  21. shaderField.OnChanged += (x) =>
  22. {
  23. Shader shader = Resources.Load<Shader>(x);
  24. material.Shader = shader;
  25. RebuildParamGUI(material);
  26. };
  27. Layout.AddElement(shaderField);
  28. RebuildParamGUI(material);
  29. }
  30. /// <inheritdoc/>
  31. protected internal override InspectableState Refresh()
  32. {
  33. Material material = InspectedObject as Material;
  34. if (material == null)
  35. return InspectableState.NotModified;
  36. if (material.Shader != shaderField.Value)
  37. {
  38. shaderField.Value = material.Shader;
  39. RebuildParamGUI(material);
  40. }
  41. if (guiParams != null)
  42. {
  43. foreach (var param in guiParams)
  44. param.Refresh(material);
  45. }
  46. return InspectableState.NotModified;
  47. }
  48. /// <summary>
  49. /// Recreates GUI elements for all material parameters.
  50. /// </summary>
  51. /// <param name="material">Material to create parameters for</param>
  52. private void RebuildParamGUI(Material material)
  53. {
  54. if (guiParams != null)
  55. {
  56. foreach (var param in guiParams)
  57. param.Destroy();
  58. guiParams = null;
  59. }
  60. if (material != null && material.Shader != null)
  61. guiParams = CreateMaterialGUI(material, Layout);
  62. }
  63. /// <summary>
  64. /// Creates a set of objects in which each object represents a GUI for a material parameter.
  65. /// </summary>
  66. /// <param name="mat">Material for whose parameters to create GUI for.</param>
  67. /// <param name="layout">Layout to add the parameter GUI elements to.</param>
  68. /// <returns>A material parameter GUI object for each supported material parameter.</returns>
  69. static internal MaterialParamGUI[] CreateMaterialGUI(Material mat, GUILayout layout)
  70. {
  71. Shader shader = mat.Shader;
  72. if (shader == null)
  73. return new MaterialParamGUI[0];
  74. List<MaterialParamGUI> guiParams = new List<MaterialParamGUI>();
  75. ShaderParameter[] shaderParams = shader.Parameters;
  76. foreach (var param in shaderParams)
  77. {
  78. if (param.Internal)
  79. continue;
  80. switch (param.Type)
  81. {
  82. case ShaderParameterType.Float:
  83. layout.AddSpace(5);
  84. guiParams.Add(new MaterialParamFloatGUI(param, mat, layout));
  85. break;
  86. case ShaderParameterType.Vector2:
  87. layout.AddSpace(5);
  88. guiParams.Add(new MaterialParamVec2GUI(param, mat, layout));
  89. break;
  90. case ShaderParameterType.Vector3:
  91. layout.AddSpace(5);
  92. guiParams.Add(new MaterialParamVec3GUI(param, mat, layout));
  93. break;
  94. case ShaderParameterType.Vector4:
  95. layout.AddSpace(5);
  96. guiParams.Add(new MaterialParamVec4GUI(param, mat, layout));
  97. break;
  98. case ShaderParameterType.Matrix3:
  99. layout.AddSpace(5);
  100. guiParams.Add(new MaterialParamMat3GUI(param, mat, layout));
  101. break;
  102. case ShaderParameterType.Matrix4:
  103. layout.AddSpace(5);
  104. guiParams.Add(new MaterialParamMat4GUI(param, mat, layout));
  105. break;
  106. case ShaderParameterType.Color:
  107. layout.AddSpace(5);
  108. guiParams.Add(new MaterialParamColorGUI(param, mat, layout));
  109. break;
  110. case ShaderParameterType.Texture2D:
  111. case ShaderParameterType.Texture3D:
  112. case ShaderParameterType.TextureCube:
  113. layout.AddSpace(5);
  114. guiParams.Add(new MaterialParamTextureGUI(param, mat, layout));
  115. break;
  116. }
  117. }
  118. return guiParams.ToArray();
  119. }
  120. }
  121. /// <summary>
  122. /// Contains GUI element(s) for a single parameter in a <see cref="Material"/>.
  123. /// </summary>
  124. internal abstract class MaterialParamGUI
  125. {
  126. protected ShaderParameter shaderParam;
  127. /// <summary>
  128. /// Creates a new material parameter GUI.
  129. /// </summary>
  130. /// <param name="shaderParam">Shader parameter to create the GUI for.</param>
  131. protected MaterialParamGUI(ShaderParameter shaderParam)
  132. {
  133. this.shaderParam = shaderParam;
  134. }
  135. /// <summary>
  136. /// Checks if the data stored in GUI and in the material matches, and updates the GUI if it doesn't.
  137. /// </summary>
  138. /// <param name="material">Material whose data to check.</param>
  139. internal abstract void Refresh(Material material);
  140. /// <summary>
  141. /// Destroys the internal GUI elements.
  142. /// </summary>
  143. internal abstract void Destroy();
  144. }
  145. /// <summary>
  146. /// Contains GUI element(s) for a single floating point parameter in a <see cref="Material"/>.
  147. /// </summary>
  148. internal class MaterialParamFloatGUI : MaterialParamGUI
  149. {
  150. private GUIFloatField guiElem;
  151. /// <summary>
  152. /// Creates a new material parameter GUI.
  153. /// </summary>
  154. /// <param name="shaderParam">Shader parameter to create the GUI for. Must be of floating point type.</param>
  155. /// <param name="material">Material the parameter is a part of.</param>
  156. /// <param name="layout">Layout to append the GUI elements to.</param>
  157. internal MaterialParamFloatGUI(ShaderParameter shaderParam, Material material, GUILayout layout)
  158. : base(shaderParam)
  159. {
  160. LocString title = new LocEdString(shaderParam.Name);
  161. guiElem = new GUIFloatField(title);
  162. guiElem.OnChanged += (x) =>
  163. {
  164. material.SetFloat(shaderParam.Name, x);
  165. EditorApplication.SetDirty(material);
  166. };
  167. layout.AddElement(guiElem);
  168. }
  169. /// <inheritdoc/>
  170. internal override void Refresh(Material material)
  171. {
  172. guiElem.Value = material.GetFloat(shaderParam.Name);
  173. }
  174. /// <inheritdoc/>
  175. internal override void Destroy()
  176. {
  177. guiElem.Destroy();
  178. }
  179. }
  180. /// <summary>
  181. /// Contains GUI element(s) for a single 2D vector parameter in a <see cref="Material"/>.
  182. /// </summary>
  183. internal class MaterialParamVec2GUI : MaterialParamGUI
  184. {
  185. private GUIVector2Field guiElem;
  186. /// <summary>
  187. /// Creates a new material parameter GUI.
  188. /// </summary>
  189. /// <param name="shaderParam">Shader parameter to create the GUI for. Must be of 2D vector type.</param>
  190. /// <param name="material">Material the parameter is a part of.</param>
  191. /// <param name="layout">Layout to append the GUI elements to.</param>
  192. internal MaterialParamVec2GUI(ShaderParameter shaderParam, Material material, GUILayout layout)
  193. : base(shaderParam)
  194. {
  195. LocString title = new LocEdString(shaderParam.Name);
  196. guiElem = new GUIVector2Field(title);
  197. guiElem.OnChanged += (x) =>
  198. {
  199. material.SetVector2(shaderParam.Name, x);
  200. EditorApplication.SetDirty(material);
  201. };
  202. layout.AddElement(guiElem);
  203. }
  204. /// <inheritdoc/>
  205. internal override void Refresh(Material material)
  206. {
  207. guiElem.Value = material.GetVector2(shaderParam.Name);
  208. }
  209. /// <inheritdoc/>
  210. internal override void Destroy()
  211. {
  212. guiElem.Destroy();
  213. }
  214. }
  215. /// <summary>
  216. /// Contains GUI element(s) for a single 3D vector parameter in a <see cref="Material"/>.
  217. /// </summary>
  218. internal class MaterialParamVec3GUI : MaterialParamGUI
  219. {
  220. private GUIVector3Field guiElem;
  221. /// <summary>
  222. /// Creates a new material parameter GUI.
  223. /// </summary>
  224. /// <param name="shaderParam">Shader parameter to create the GUI for. Must be of 3D vector type.</param>
  225. /// <param name="material">Material the parameter is a part of.</param>
  226. /// <param name="layout">Layout to append the GUI elements to.</param>
  227. internal MaterialParamVec3GUI(ShaderParameter shaderParam, Material material, GUILayout layout)
  228. : base(shaderParam)
  229. {
  230. LocString title = new LocEdString(shaderParam.Name);
  231. guiElem = new GUIVector3Field(title);
  232. guiElem.OnChanged += (x) =>
  233. {
  234. material.SetVector3(shaderParam.Name, x);
  235. EditorApplication.SetDirty(material);
  236. };
  237. layout.AddElement(guiElem);
  238. }
  239. /// <inheritdoc/>
  240. internal override void Refresh(Material material)
  241. {
  242. guiElem.Value = material.GetVector3(shaderParam.Name);
  243. }
  244. /// <inheritdoc/>
  245. internal override void Destroy()
  246. {
  247. guiElem.Destroy();
  248. }
  249. }
  250. /// <summary>
  251. /// Contains GUI element(s) for a single 4D vector parameter in a <see cref="Material"/>.
  252. /// </summary>
  253. internal class MaterialParamVec4GUI : MaterialParamGUI
  254. {
  255. private GUIVector4Field guiElem;
  256. /// <summary>
  257. /// Creates a new material parameter GUI.
  258. /// </summary>
  259. /// <param name="shaderParam">Shader parameter to create the GUI for. Must be of 4D vector type.</param>
  260. /// <param name="material">Material the parameter is a part of.</param>
  261. /// <param name="layout">Layout to append the GUI elements to.</param>
  262. internal MaterialParamVec4GUI(ShaderParameter shaderParam, Material material, GUILayout layout)
  263. : base(shaderParam)
  264. {
  265. LocString title = new LocEdString(shaderParam.Name);
  266. guiElem = new GUIVector4Field(title);
  267. guiElem.OnChanged += (x) =>
  268. {
  269. material.SetVector4(shaderParam.Name, x);
  270. EditorApplication.SetDirty(material);
  271. };
  272. layout.AddElement(guiElem);
  273. }
  274. /// <inheritdoc/>
  275. internal override void Refresh(Material material)
  276. {
  277. guiElem.Value = material.GetVector4(shaderParam.Name);
  278. }
  279. /// <inheritdoc/>
  280. internal override void Destroy()
  281. {
  282. guiElem.Destroy();
  283. }
  284. }
  285. /// <summary>
  286. /// Contains GUI element(s) for a single 3x3 matrix parameter in a <see cref="Material"/>.
  287. /// </summary>
  288. internal class MaterialParamMat3GUI : MaterialParamGUI
  289. {
  290. private const int MAT_SIZE = 3;
  291. private GUILayout mainLayout;
  292. private GUIFloatField[] guiMatFields = new GUIFloatField[MAT_SIZE * MAT_SIZE];
  293. /// <summary>
  294. /// Creates a new material parameter GUI.
  295. /// </summary>
  296. /// <param name="shaderParam">Shader parameter to create the GUI for. Must be of 3x3 matrix type.</param>
  297. /// <param name="material">Material the parameter is a part of.</param>
  298. /// <param name="layout">Layout to append the GUI elements to.</param>
  299. internal MaterialParamMat3GUI(ShaderParameter shaderParam, Material material, GUILayout layout)
  300. : base(shaderParam)
  301. {
  302. LocString title = new LocEdString(shaderParam.Name);
  303. GUILabel guiTitle = new GUILabel(title, GUIOption.FixedWidth(100));
  304. mainLayout = layout.AddLayoutY();
  305. GUILayoutX titleLayout = mainLayout.AddLayoutX();
  306. titleLayout.AddElement(guiTitle);
  307. titleLayout.AddFlexibleSpace();
  308. GUILayoutY contentLayout = mainLayout.AddLayoutY();
  309. GUILayoutX[] rows = new GUILayoutX[MAT_SIZE];
  310. for (int i = 0; i < rows.Length; i++)
  311. rows[i] = contentLayout.AddLayoutX();
  312. for (int row = 0; row < MAT_SIZE; row++)
  313. {
  314. for (int col = 0; col < MAT_SIZE; col++)
  315. {
  316. int index = row * MAT_SIZE + col;
  317. guiMatFields[index] = new GUIFloatField(row + "," + col, 20, "", GUIOption.FixedWidth(80));
  318. GUIFloatField field = guiMatFields[index];
  319. rows[row].AddElement(field);
  320. rows[row].AddSpace(5);
  321. int hoistedRow = row;
  322. int hoistedCol = col;
  323. field.OnChanged += (x) =>
  324. {
  325. Matrix3 value = material.GetMatrix3(shaderParam.Name);
  326. value[hoistedRow, hoistedCol] = x;
  327. material.SetMatrix3(shaderParam.Name, value);
  328. EditorApplication.SetDirty(material);
  329. };
  330. }
  331. }
  332. }
  333. /// <inheritdoc/>
  334. internal override void Refresh(Material material)
  335. {
  336. Matrix3 value = material.GetMatrix3(shaderParam.Name);
  337. for (int row = 0; row < MAT_SIZE; row++)
  338. {
  339. for (int col = 0; col < MAT_SIZE; col++)
  340. {
  341. int index = row * MAT_SIZE + col;
  342. guiMatFields[index].Value = value[row, col];
  343. }
  344. }
  345. }
  346. /// <inheritdoc/>
  347. internal override void Destroy()
  348. {
  349. mainLayout.Destroy();
  350. }
  351. }
  352. /// <summary>
  353. /// Contains GUI element(s) for a single 4x4 matrix parameter in a <see cref="Material"/>.
  354. /// </summary>
  355. internal class MaterialParamMat4GUI : MaterialParamGUI
  356. {
  357. private const int MAT_SIZE = 4;
  358. private GUILayout mainLayout;
  359. private GUIFloatField[] guiMatFields = new GUIFloatField[MAT_SIZE * MAT_SIZE];
  360. /// <summary>
  361. /// Creates a new material parameter GUI.
  362. /// </summary>
  363. /// <param name="shaderParam">Shader parameter to create the GUI for. Must be of 4x4 matrix type.</param>
  364. /// <param name="material">Material the parameter is a part of.</param>
  365. /// <param name="layout">Layout to append the GUI elements to.</param>
  366. internal MaterialParamMat4GUI(ShaderParameter shaderParam, Material material, GUILayout layout)
  367. : base(shaderParam)
  368. {
  369. LocString title = new LocEdString(shaderParam.Name);
  370. GUILabel guiTitle = new GUILabel(title, GUIOption.FixedWidth(100));
  371. mainLayout = layout.AddLayoutY();
  372. GUILayoutX titleLayout = mainLayout.AddLayoutX();
  373. titleLayout.AddElement(guiTitle);
  374. titleLayout.AddFlexibleSpace();
  375. GUILayoutY contentLayout = mainLayout.AddLayoutY();
  376. GUILayoutX[] rows = new GUILayoutX[MAT_SIZE];
  377. for (int i = 0; i < rows.Length; i++)
  378. rows[i] = contentLayout.AddLayoutX();
  379. for (int row = 0; row < MAT_SIZE; row++)
  380. {
  381. for (int col = 0; col < MAT_SIZE; col++)
  382. {
  383. int index = row * MAT_SIZE + col;
  384. guiMatFields[index] = new GUIFloatField(row + "," + col, 20, "", GUIOption.FixedWidth(80));
  385. GUIFloatField field = guiMatFields[index];
  386. rows[row].AddElement(field);
  387. rows[row].AddSpace(5);
  388. int hoistedRow = row;
  389. int hoistedCol = col;
  390. field.OnChanged += (x) =>
  391. {
  392. Matrix4 value = material.GetMatrix4(shaderParam.Name);
  393. value[hoistedRow, hoistedCol] = x;
  394. material.SetMatrix4(shaderParam.Name, value);
  395. EditorApplication.SetDirty(material);
  396. };
  397. }
  398. }
  399. }
  400. /// <inheritdoc/>
  401. internal override void Refresh(Material material)
  402. {
  403. Matrix4 value = material.GetMatrix4(shaderParam.Name);
  404. for (int row = 0; row < MAT_SIZE; row++)
  405. {
  406. for (int col = 0; col < MAT_SIZE; col++)
  407. {
  408. int index = row * MAT_SIZE + col;
  409. guiMatFields[index].Value = value[row, col];
  410. }
  411. }
  412. }
  413. /// <inheritdoc/>
  414. internal override void Destroy()
  415. {
  416. mainLayout.Destroy();
  417. }
  418. }
  419. /// <summary>
  420. /// Contains GUI element(s) for a single color parameter in a <see cref="Material"/>.
  421. /// </summary>
  422. internal class MaterialParamColorGUI : MaterialParamGUI
  423. {
  424. private GUIColorField guiElem;
  425. /// <summary>
  426. /// Creates a new material parameter GUI.
  427. /// </summary>
  428. /// <param name="shaderParam">Shader parameter to create the GUI for. Must be of color type.</param>
  429. /// <param name="material">Material the parameter is a part of.</param>
  430. /// <param name="layout">Layout to append the GUI elements to.</param>
  431. internal MaterialParamColorGUI(ShaderParameter shaderParam, Material material, GUILayout layout)
  432. : base(shaderParam)
  433. {
  434. LocString title = new LocEdString(shaderParam.Name);
  435. guiElem = new GUIColorField(title);
  436. guiElem.OnChanged += (x) =>
  437. {
  438. material.SetColor(shaderParam.Name, x);
  439. EditorApplication.SetDirty(material);
  440. };
  441. layout.AddElement(guiElem);
  442. }
  443. /// <inheritdoc/>
  444. internal override void Refresh(Material material)
  445. {
  446. guiElem.Value = material.GetColor(shaderParam.Name);
  447. }
  448. /// <inheritdoc/>
  449. internal override void Destroy()
  450. {
  451. guiElem.Destroy();
  452. }
  453. }
  454. /// <summary>
  455. /// Contains GUI element(s) for a single texture parameter in a <see cref="Material"/>.
  456. /// </summary>
  457. internal class MaterialParamTextureGUI : MaterialParamGUI
  458. {
  459. private GUITextureField guiElem;
  460. /// <summary>
  461. /// Creates a new material parameter GUI.
  462. /// </summary>
  463. /// <param name="shaderParam">Shader parameter to create the GUI for. Must be of texture type.</param>
  464. /// <param name="material">Material the parameter is a part of.</param>
  465. /// <param name="layout">Layout to append the GUI elements to.</param>
  466. internal MaterialParamTextureGUI(ShaderParameter shaderParam, Material material, GUILayout layout)
  467. : base(shaderParam)
  468. {
  469. LocString title = new LocEdString(shaderParam.Name);
  470. guiElem = new GUITextureField(title);
  471. switch (shaderParam.Type)
  472. {
  473. case ShaderParameterType.Texture2D:
  474. guiElem.OnChanged += (x) =>
  475. {
  476. Texture2D texture = Resources.Load<Texture2D>(x);
  477. material.SetTexture2D(shaderParam.Name, texture);
  478. EditorApplication.SetDirty(material);
  479. };
  480. break;
  481. case ShaderParameterType.Texture3D:
  482. guiElem.OnChanged += (x) =>
  483. {
  484. Texture3D texture = Resources.Load<Texture3D>(x);
  485. material.SetTexture3D(shaderParam.Name, texture);
  486. EditorApplication.SetDirty(material);
  487. };
  488. break;
  489. case ShaderParameterType.TextureCube:
  490. guiElem.OnChanged += (x) =>
  491. {
  492. TextureCube texture = Resources.Load<TextureCube>(x);
  493. material.SetTextureCube(shaderParam.Name, texture);
  494. EditorApplication.SetDirty(material);
  495. };
  496. break;
  497. }
  498. layout.AddElement(guiElem);
  499. }
  500. /// <inheritdoc/>
  501. internal override void Refresh(Material material)
  502. {
  503. Texture value = null;
  504. switch (shaderParam.Type)
  505. {
  506. case ShaderParameterType.Texture2D:
  507. value = material.GetTexture2D(shaderParam.Name);
  508. break;
  509. case ShaderParameterType.Texture3D:
  510. value = material.GetTexture3D(shaderParam.Name);
  511. break;
  512. case ShaderParameterType.TextureCube:
  513. value = material.GetTextureCube(shaderParam.Name);
  514. break;
  515. }
  516. guiElem.Value = value;
  517. }
  518. /// <inheritdoc/>
  519. internal override void Destroy()
  520. {
  521. guiElem.Destroy();
  522. }
  523. }
  524. }