You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

672 lines
28 KiB

  1. using UnityEngine;
  2. using UnityEngine.PostProcessing;
  3. using System;
  4. using System.Collections.Generic;
  5. using System.Linq.Expressions;
  6. namespace UnityEditor.PostProcessing
  7. {
  8. using Settings = ColorGradingModel.Settings;
  9. using Tonemapper = ColorGradingModel.Tonemapper;
  10. using ColorWheelMode = ColorGradingModel.ColorWheelMode;
  11. [PostProcessingModelEditor(typeof(ColorGradingModel))]
  12. public class ColorGradingModelEditor : PostProcessingModelEditor
  13. {
  14. static GUIContent[] s_Tonemappers =
  15. {
  16. new GUIContent("None"),
  17. new GUIContent("Filmic (ACES)"),
  18. new GUIContent("Neutral")
  19. };
  20. struct TonemappingSettings
  21. {
  22. public SerializedProperty tonemapper;
  23. public SerializedProperty neutralBlackIn;
  24. public SerializedProperty neutralWhiteIn;
  25. public SerializedProperty neutralBlackOut;
  26. public SerializedProperty neutralWhiteOut;
  27. public SerializedProperty neutralWhiteLevel;
  28. public SerializedProperty neutralWhiteClip;
  29. }
  30. struct BasicSettings
  31. {
  32. public SerializedProperty exposure;
  33. public SerializedProperty temperature;
  34. public SerializedProperty tint;
  35. public SerializedProperty hueShift;
  36. public SerializedProperty saturation;
  37. public SerializedProperty contrast;
  38. }
  39. struct ChannelMixerSettings
  40. {
  41. public SerializedProperty[] channels;
  42. public SerializedProperty currentEditingChannel;
  43. }
  44. struct ColorWheelsSettings
  45. {
  46. public SerializedProperty mode;
  47. public SerializedProperty log;
  48. public SerializedProperty linear;
  49. }
  50. static GUIContent[] s_Curves =
  51. {
  52. new GUIContent("YRGB"),
  53. new GUIContent("Hue VS Hue"),
  54. new GUIContent("Hue VS Sat"),
  55. new GUIContent("Sat VS Sat"),
  56. new GUIContent("Lum VS Sat")
  57. };
  58. struct CurvesSettings
  59. {
  60. public SerializedProperty master;
  61. public SerializedProperty red;
  62. public SerializedProperty green;
  63. public SerializedProperty blue;
  64. public SerializedProperty hueVShue;
  65. public SerializedProperty hueVSsat;
  66. public SerializedProperty satVSsat;
  67. public SerializedProperty lumVSsat;
  68. public SerializedProperty currentEditingCurve;
  69. public SerializedProperty curveY;
  70. public SerializedProperty curveR;
  71. public SerializedProperty curveG;
  72. public SerializedProperty curveB;
  73. }
  74. TonemappingSettings m_Tonemapping;
  75. BasicSettings m_Basic;
  76. ChannelMixerSettings m_ChannelMixer;
  77. ColorWheelsSettings m_ColorWheels;
  78. CurvesSettings m_Curves;
  79. CurveEditor m_CurveEditor;
  80. Dictionary<SerializedProperty, Color> m_CurveDict;
  81. // Neutral tonemapping curve helper
  82. const int k_CurveResolution = 24;
  83. const float k_NeutralRangeX = 2f;
  84. const float k_NeutralRangeY = 1f;
  85. Vector3[] m_RectVertices = new Vector3[4];
  86. Vector3[] m_LineVertices = new Vector3[2];
  87. Vector3[] m_CurveVertices = new Vector3[k_CurveResolution];
  88. Rect m_NeutralCurveRect;
  89. public override void OnEnable()
  90. {
  91. // Tonemapping settings
  92. m_Tonemapping = new TonemappingSettings
  93. {
  94. tonemapper = FindSetting((Settings x) => x.tonemapping.tonemapper),
  95. neutralBlackIn = FindSetting((Settings x) => x.tonemapping.neutralBlackIn),
  96. neutralWhiteIn = FindSetting((Settings x) => x.tonemapping.neutralWhiteIn),
  97. neutralBlackOut = FindSetting((Settings x) => x.tonemapping.neutralBlackOut),
  98. neutralWhiteOut = FindSetting((Settings x) => x.tonemapping.neutralWhiteOut),
  99. neutralWhiteLevel = FindSetting((Settings x) => x.tonemapping.neutralWhiteLevel),
  100. neutralWhiteClip = FindSetting((Settings x) => x.tonemapping.neutralWhiteClip)
  101. };
  102. // Basic settings
  103. m_Basic = new BasicSettings
  104. {
  105. exposure = FindSetting((Settings x) => x.basic.postExposure),
  106. temperature = FindSetting((Settings x) => x.basic.temperature),
  107. tint = FindSetting((Settings x) => x.basic.tint),
  108. hueShift = FindSetting((Settings x) => x.basic.hueShift),
  109. saturation = FindSetting((Settings x) => x.basic.saturation),
  110. contrast = FindSetting((Settings x) => x.basic.contrast)
  111. };
  112. // Channel mixer
  113. m_ChannelMixer = new ChannelMixerSettings
  114. {
  115. channels = new[]
  116. {
  117. FindSetting((Settings x) => x.channelMixer.red),
  118. FindSetting((Settings x) => x.channelMixer.green),
  119. FindSetting((Settings x) => x.channelMixer.blue)
  120. },
  121. currentEditingChannel = FindSetting((Settings x) => x.channelMixer.currentEditingChannel)
  122. };
  123. // Color wheels
  124. m_ColorWheels = new ColorWheelsSettings
  125. {
  126. mode = FindSetting((Settings x) => x.colorWheels.mode),
  127. log = FindSetting((Settings x) => x.colorWheels.log),
  128. linear = FindSetting((Settings x) => x.colorWheels.linear)
  129. };
  130. // Curves
  131. m_Curves = new CurvesSettings
  132. {
  133. master = FindSetting((Settings x) => x.curves.master.curve),
  134. red = FindSetting((Settings x) => x.curves.red.curve),
  135. green = FindSetting((Settings x) => x.curves.green.curve),
  136. blue = FindSetting((Settings x) => x.curves.blue.curve),
  137. hueVShue = FindSetting((Settings x) => x.curves.hueVShue.curve),
  138. hueVSsat = FindSetting((Settings x) => x.curves.hueVSsat.curve),
  139. satVSsat = FindSetting((Settings x) => x.curves.satVSsat.curve),
  140. lumVSsat = FindSetting((Settings x) => x.curves.lumVSsat.curve),
  141. currentEditingCurve = FindSetting((Settings x) => x.curves.e_CurrentEditingCurve),
  142. curveY = FindSetting((Settings x) => x.curves.e_CurveY),
  143. curveR = FindSetting((Settings x) => x.curves.e_CurveR),
  144. curveG = FindSetting((Settings x) => x.curves.e_CurveG),
  145. curveB = FindSetting((Settings x) => x.curves.e_CurveB)
  146. };
  147. // Prepare the curve editor and extract curve display settings
  148. m_CurveDict = new Dictionary<SerializedProperty, Color>();
  149. var settings = CurveEditor.Settings.defaultSettings;
  150. m_CurveEditor = new CurveEditor(settings);
  151. AddCurve(m_Curves.master, new Color(1f, 1f, 1f), 2, false);
  152. AddCurve(m_Curves.red, new Color(1f, 0f, 0f), 2, false);
  153. AddCurve(m_Curves.green, new Color(0f, 1f, 0f), 2, false);
  154. AddCurve(m_Curves.blue, new Color(0f, 0.5f, 1f), 2, false);
  155. AddCurve(m_Curves.hueVShue, new Color(1f, 1f, 1f), 0, true);
  156. AddCurve(m_Curves.hueVSsat, new Color(1f, 1f, 1f), 0, true);
  157. AddCurve(m_Curves.satVSsat, new Color(1f, 1f, 1f), 0, false);
  158. AddCurve(m_Curves.lumVSsat, new Color(1f, 1f, 1f), 0, false);
  159. }
  160. void AddCurve(SerializedProperty prop, Color color, uint minPointCount, bool loop)
  161. {
  162. var state = CurveEditor.CurveState.defaultState;
  163. state.color = color;
  164. state.visible = false;
  165. state.minPointCount = minPointCount;
  166. state.onlyShowHandlesOnSelection = true;
  167. state.zeroKeyConstantValue = 0.5f;
  168. state.loopInBounds = loop;
  169. m_CurveEditor.Add(prop, state);
  170. m_CurveDict.Add(prop, color);
  171. }
  172. public override void OnDisable()
  173. {
  174. m_CurveEditor.RemoveAll();
  175. }
  176. public override void OnInspectorGUI()
  177. {
  178. DoGUIFor("Tonemapping", DoTonemappingGUI);
  179. EditorGUILayout.Space();
  180. DoGUIFor("Basic", DoBasicGUI);
  181. EditorGUILayout.Space();
  182. DoGUIFor("Channel Mixer", DoChannelMixerGUI);
  183. EditorGUILayout.Space();
  184. DoGUIFor("Trackballs", DoColorWheelsGUI);
  185. EditorGUILayout.Space();
  186. DoGUIFor("Grading Curves", DoCurvesGUI);
  187. }
  188. void DoGUIFor(string title, Action func)
  189. {
  190. EditorGUILayout.LabelField(title, EditorStyles.boldLabel);
  191. EditorGUI.indentLevel++;
  192. func();
  193. EditorGUI.indentLevel--;
  194. }
  195. void DoTonemappingGUI()
  196. {
  197. int tid = EditorGUILayout.Popup(EditorGUIHelper.GetContent("Tonemapper"), m_Tonemapping.tonemapper.intValue, s_Tonemappers);
  198. if (tid == (int)Tonemapper.Neutral)
  199. {
  200. DrawNeutralTonemappingCurve();
  201. EditorGUILayout.PropertyField(m_Tonemapping.neutralBlackIn, EditorGUIHelper.GetContent("Black In"));
  202. EditorGUILayout.PropertyField(m_Tonemapping.neutralWhiteIn, EditorGUIHelper.GetContent("White In"));
  203. EditorGUILayout.PropertyField(m_Tonemapping.neutralBlackOut, EditorGUIHelper.GetContent("Black Out"));
  204. EditorGUILayout.PropertyField(m_Tonemapping.neutralWhiteOut, EditorGUIHelper.GetContent("White Out"));
  205. EditorGUILayout.PropertyField(m_Tonemapping.neutralWhiteLevel, EditorGUIHelper.GetContent("White Level"));
  206. EditorGUILayout.PropertyField(m_Tonemapping.neutralWhiteClip, EditorGUIHelper.GetContent("White Clip"));
  207. }
  208. m_Tonemapping.tonemapper.intValue = tid;
  209. }
  210. void DrawNeutralTonemappingCurve()
  211. {
  212. using (new GUILayout.HorizontalScope())
  213. {
  214. GUILayout.Space(EditorGUI.indentLevel * 15f);
  215. m_NeutralCurveRect = GUILayoutUtility.GetRect(128, 80);
  216. }
  217. // Background
  218. m_RectVertices[0] = PointInRect( 0f, 0f);
  219. m_RectVertices[1] = PointInRect(k_NeutralRangeX, 0f);
  220. m_RectVertices[2] = PointInRect(k_NeutralRangeX, k_NeutralRangeY);
  221. m_RectVertices[3] = PointInRect( 0f, k_NeutralRangeY);
  222. Handles.DrawSolidRectangleWithOutline(
  223. m_RectVertices,
  224. Color.white * 0.1f,
  225. Color.white * 0.4f
  226. );
  227. // Horizontal lines
  228. for (var i = 1; i < k_NeutralRangeY; i++)
  229. DrawLine(0, i, k_NeutralRangeX, i, 0.4f);
  230. // Vertical lines
  231. for (var i = 1; i < k_NeutralRangeX; i++)
  232. DrawLine(i, 0, i, k_NeutralRangeY, 0.4f);
  233. // Label
  234. Handles.Label(
  235. PointInRect(0, k_NeutralRangeY) + Vector3.right,
  236. "Neutral Tonemapper", EditorStyles.miniLabel
  237. );
  238. // Precompute some values
  239. var tonemap = ((ColorGradingModel)target).settings.tonemapping;
  240. const float scaleFactor = 20f;
  241. const float scaleFactorHalf = scaleFactor * 0.5f;
  242. float inBlack = tonemap.neutralBlackIn * scaleFactor + 1f;
  243. float outBlack = tonemap.neutralBlackOut * scaleFactorHalf + 1f;
  244. float inWhite = tonemap.neutralWhiteIn / scaleFactor;
  245. float outWhite = 1f - tonemap.neutralWhiteOut / scaleFactor;
  246. float blackRatio = inBlack / outBlack;
  247. float whiteRatio = inWhite / outWhite;
  248. const float a = 0.2f;
  249. float b = Mathf.Max(0f, Mathf.LerpUnclamped(0.57f, 0.37f, blackRatio));
  250. float c = Mathf.LerpUnclamped(0.01f, 0.24f, whiteRatio);
  251. float d = Mathf.Max(0f, Mathf.LerpUnclamped(0.02f, 0.20f, blackRatio));
  252. const float e = 0.02f;
  253. const float f = 0.30f;
  254. float whiteLevel = tonemap.neutralWhiteLevel;
  255. float whiteClip = tonemap.neutralWhiteClip / scaleFactorHalf;
  256. // Tonemapping curve
  257. var vcount = 0;
  258. while (vcount < k_CurveResolution)
  259. {
  260. float x = k_NeutralRangeX * vcount / (k_CurveResolution - 1);
  261. float y = NeutralTonemap(x, a, b, c, d, e, f, whiteLevel, whiteClip);
  262. if (y < k_NeutralRangeY)
  263. {
  264. m_CurveVertices[vcount++] = PointInRect(x, y);
  265. }
  266. else
  267. {
  268. if (vcount > 1)
  269. {
  270. // Extend the last segment to the top edge of the rect.
  271. var v1 = m_CurveVertices[vcount - 2];
  272. var v2 = m_CurveVertices[vcount - 1];
  273. var clip = (m_NeutralCurveRect.y - v1.y) / (v2.y - v1.y);
  274. m_CurveVertices[vcount - 1] = v1 + (v2 - v1) * clip;
  275. }
  276. break;
  277. }
  278. }
  279. if (vcount > 1)
  280. {
  281. Handles.color = Color.white * 0.9f;
  282. Handles.DrawAAPolyLine(2.0f, vcount, m_CurveVertices);
  283. }
  284. }
  285. void DrawLine(float x1, float y1, float x2, float y2, float grayscale)
  286. {
  287. m_LineVertices[0] = PointInRect(x1, y1);
  288. m_LineVertices[1] = PointInRect(x2, y2);
  289. Handles.color = Color.white * grayscale;
  290. Handles.DrawAAPolyLine(2f, m_LineVertices);
  291. }
  292. Vector3 PointInRect(float x, float y)
  293. {
  294. x = Mathf.Lerp(m_NeutralCurveRect.x, m_NeutralCurveRect.xMax, x / k_NeutralRangeX);
  295. y = Mathf.Lerp(m_NeutralCurveRect.yMax, m_NeutralCurveRect.y, y / k_NeutralRangeY);
  296. return new Vector3(x, y, 0);
  297. }
  298. float NeutralCurve(float x, float a, float b, float c, float d, float e, float f)
  299. {
  300. return ((x * (a * x + c * b) + d * e) / (x * (a * x + b) + d * f)) - e / f;
  301. }
  302. float NeutralTonemap(float x, float a, float b, float c, float d, float e, float f, float whiteLevel, float whiteClip)
  303. {
  304. x = Mathf.Max(0f, x);
  305. // Tonemap
  306. float whiteScale = 1f / NeutralCurve(whiteLevel, a, b, c, d, e, f);
  307. x = NeutralCurve(x * whiteScale, a, b, c, d, e, f);
  308. x *= whiteScale;
  309. // Post-curve white point adjustment
  310. x /= whiteClip;
  311. return x;
  312. }
  313. void DoBasicGUI()
  314. {
  315. EditorGUILayout.PropertyField(m_Basic.exposure, EditorGUIHelper.GetContent("Post Exposure (EV)"));
  316. EditorGUILayout.PropertyField(m_Basic.temperature);
  317. EditorGUILayout.PropertyField(m_Basic.tint);
  318. EditorGUILayout.PropertyField(m_Basic.hueShift);
  319. EditorGUILayout.PropertyField(m_Basic.saturation);
  320. EditorGUILayout.PropertyField(m_Basic.contrast);
  321. }
  322. void DoChannelMixerGUI()
  323. {
  324. int currentChannel = m_ChannelMixer.currentEditingChannel.intValue;
  325. EditorGUI.BeginChangeCheck();
  326. {
  327. using (new EditorGUILayout.HorizontalScope())
  328. {
  329. EditorGUILayout.PrefixLabel("Channel");
  330. if (GUILayout.Toggle(currentChannel == 0, EditorGUIHelper.GetContent("Red|Red output channel."), EditorStyles.miniButtonLeft)) currentChannel = 0;
  331. if (GUILayout.Toggle(currentChannel == 1, EditorGUIHelper.GetContent("Green|Green output channel."), EditorStyles.miniButtonMid)) currentChannel = 1;
  332. if (GUILayout.Toggle(currentChannel == 2, EditorGUIHelper.GetContent("Blue|Blue output channel."), EditorStyles.miniButtonRight)) currentChannel = 2;
  333. }
  334. }
  335. if (EditorGUI.EndChangeCheck())
  336. {
  337. GUI.FocusControl(null);
  338. }
  339. var serializedChannel = m_ChannelMixer.channels[currentChannel];
  340. m_ChannelMixer.currentEditingChannel.intValue = currentChannel;
  341. var v = serializedChannel.vector3Value;
  342. v.x = EditorGUILayout.Slider(EditorGUIHelper.GetContent("Red|Modify influence of the red channel within the overall mix."), v.x, -2f, 2f);
  343. v.y = EditorGUILayout.Slider(EditorGUIHelper.GetContent("Green|Modify influence of the green channel within the overall mix."), v.y, -2f, 2f);
  344. v.z = EditorGUILayout.Slider(EditorGUIHelper.GetContent("Blue|Modify influence of the blue channel within the overall mix."), v.z, -2f, 2f);
  345. serializedChannel.vector3Value = v;
  346. }
  347. void DoColorWheelsGUI()
  348. {
  349. int wheelMode = m_ColorWheels.mode.intValue;
  350. using (new EditorGUILayout.HorizontalScope())
  351. {
  352. GUILayout.Space(15);
  353. if (GUILayout.Toggle(wheelMode == (int)ColorWheelMode.Linear, "Linear", EditorStyles.miniButtonLeft)) wheelMode = (int)ColorWheelMode.Linear;
  354. if (GUILayout.Toggle(wheelMode == (int)ColorWheelMode.Log, "Log", EditorStyles.miniButtonRight)) wheelMode = (int)ColorWheelMode.Log;
  355. }
  356. m_ColorWheels.mode.intValue = wheelMode;
  357. EditorGUILayout.Space();
  358. if (wheelMode == (int)ColorWheelMode.Linear)
  359. {
  360. EditorGUILayout.PropertyField(m_ColorWheels.linear);
  361. WheelSetTitle(GUILayoutUtility.GetLastRect(), "Linear Controls");
  362. }
  363. else if (wheelMode == (int)ColorWheelMode.Log)
  364. {
  365. EditorGUILayout.PropertyField(m_ColorWheels.log);
  366. WheelSetTitle(GUILayoutUtility.GetLastRect(), "Log Controls");
  367. }
  368. }
  369. static void WheelSetTitle(Rect position, string label)
  370. {
  371. var matrix = GUI.matrix;
  372. var rect = new Rect(position.x - 10f, position.y, TrackballGroupDrawer.m_Size, TrackballGroupDrawer.m_Size);
  373. GUIUtility.RotateAroundPivot(-90f, rect.center);
  374. GUI.Label(rect, label, FxStyles.centeredMiniLabel);
  375. GUI.matrix = matrix;
  376. }
  377. void ResetVisibleCurves()
  378. {
  379. foreach (var curve in m_CurveDict)
  380. {
  381. var state = m_CurveEditor.GetCurveState(curve.Key);
  382. state.visible = false;
  383. m_CurveEditor.SetCurveState(curve.Key, state);
  384. }
  385. }
  386. void SetCurveVisible(SerializedProperty prop)
  387. {
  388. var state = m_CurveEditor.GetCurveState(prop);
  389. state.visible = true;
  390. m_CurveEditor.SetCurveState(prop, state);
  391. }
  392. bool SpecialToggle(bool value, string name, out bool rightClicked)
  393. {
  394. var rect = GUILayoutUtility.GetRect(EditorGUIHelper.GetContent(name), EditorStyles.toolbarButton);
  395. var e = Event.current;
  396. rightClicked = (e.type == EventType.MouseUp && rect.Contains(e.mousePosition) && e.button == 1);
  397. return GUI.Toggle(rect, value, name, EditorStyles.toolbarButton);
  398. }
  399. static Material s_MaterialSpline;
  400. void DoCurvesGUI()
  401. {
  402. EditorGUILayout.Space();
  403. EditorGUI.indentLevel -= 2;
  404. ResetVisibleCurves();
  405. using (new EditorGUI.DisabledGroupScope(serializedProperty.serializedObject.isEditingMultipleObjects))
  406. {
  407. int curveEditingId = 0;
  408. // Top toolbar
  409. using (new GUILayout.HorizontalScope(EditorStyles.toolbar))
  410. {
  411. curveEditingId = EditorGUILayout.Popup(m_Curves.currentEditingCurve.intValue, s_Curves, EditorStyles.toolbarPopup, GUILayout.MaxWidth(150f));
  412. bool y = false, r = false, g = false, b = false;
  413. if (curveEditingId == 0)
  414. {
  415. EditorGUILayout.Space();
  416. bool rightClickedY, rightClickedR, rightClickedG, rightClickedB;
  417. y = SpecialToggle(m_Curves.curveY.boolValue, "Y", out rightClickedY);
  418. r = SpecialToggle(m_Curves.curveR.boolValue, "R", out rightClickedR);
  419. g = SpecialToggle(m_Curves.curveG.boolValue, "G", out rightClickedG);
  420. b = SpecialToggle(m_Curves.curveB.boolValue, "B", out rightClickedB);
  421. if (!y && !r && !g && !b)
  422. {
  423. r = g = b = false;
  424. y = true;
  425. }
  426. if (rightClickedY || rightClickedR || rightClickedG || rightClickedB)
  427. {
  428. y = rightClickedY;
  429. r = rightClickedR;
  430. g = rightClickedG;
  431. b = rightClickedB;
  432. }
  433. if (y) SetCurveVisible(m_Curves.master);
  434. if (r) SetCurveVisible(m_Curves.red);
  435. if (g) SetCurveVisible(m_Curves.green);
  436. if (b) SetCurveVisible(m_Curves.blue);
  437. m_Curves.curveY.boolValue = y;
  438. m_Curves.curveR.boolValue = r;
  439. m_Curves.curveG.boolValue = g;
  440. m_Curves.curveB.boolValue = b;
  441. }
  442. else
  443. {
  444. switch (curveEditingId)
  445. {
  446. case 1: SetCurveVisible(m_Curves.hueVShue);
  447. break;
  448. case 2: SetCurveVisible(m_Curves.hueVSsat);
  449. break;
  450. case 3: SetCurveVisible(m_Curves.satVSsat);
  451. break;
  452. case 4: SetCurveVisible(m_Curves.lumVSsat);
  453. break;
  454. }
  455. }
  456. GUILayout.FlexibleSpace();
  457. if (GUILayout.Button("Reset", EditorStyles.toolbarButton))
  458. {
  459. switch (curveEditingId)
  460. {
  461. case 0:
  462. if (y) m_Curves.master.animationCurveValue = AnimationCurve.Linear(0f, 0f, 1f, 1f);
  463. if (r) m_Curves.red.animationCurveValue = AnimationCurve.Linear(0f, 0f, 1f, 1f);
  464. if (g) m_Curves.green.animationCurveValue = AnimationCurve.Linear(0f, 0f, 1f, 1f);
  465. if (b) m_Curves.blue.animationCurveValue = AnimationCurve.Linear(0f, 0f, 1f, 1f);
  466. break;
  467. case 1: m_Curves.hueVShue.animationCurveValue = new AnimationCurve();
  468. break;
  469. case 2: m_Curves.hueVSsat.animationCurveValue = new AnimationCurve();
  470. break;
  471. case 3: m_Curves.satVSsat.animationCurveValue = new AnimationCurve();
  472. break;
  473. case 4: m_Curves.lumVSsat.animationCurveValue = new AnimationCurve();
  474. break;
  475. }
  476. }
  477. m_Curves.currentEditingCurve.intValue = curveEditingId;
  478. }
  479. // Curve area
  480. var settings = m_CurveEditor.settings;
  481. var rect = GUILayoutUtility.GetAspectRect(2f);
  482. var innerRect = settings.padding.Remove(rect);
  483. if (Event.current.type == EventType.Repaint)
  484. {
  485. // Background
  486. EditorGUI.DrawRect(rect, new Color(0.15f, 0.15f, 0.15f, 1f));
  487. if (s_MaterialSpline == null)
  488. s_MaterialSpline = new Material(Shader.Find("Hidden/Post FX/UI/Curve Background")) { hideFlags = HideFlags.HideAndDontSave };
  489. if (curveEditingId == 1 || curveEditingId == 2)
  490. DrawBackgroundTexture(innerRect, 0);
  491. else if (curveEditingId == 3 || curveEditingId == 4)
  492. DrawBackgroundTexture(innerRect, 1);
  493. // Bounds
  494. Handles.color = Color.white;
  495. Handles.DrawSolidRectangleWithOutline(innerRect, Color.clear, new Color(0.8f, 0.8f, 0.8f, 0.5f));
  496. // Grid setup
  497. Handles.color = new Color(1f, 1f, 1f, 0.05f);
  498. int hLines = (int)Mathf.Sqrt(innerRect.width);
  499. int vLines = (int)(hLines / (innerRect.width / innerRect.height));
  500. // Vertical grid
  501. int gridOffset = Mathf.FloorToInt(innerRect.width / hLines);
  502. int gridPadding = ((int)(innerRect.width) % hLines) / 2;
  503. for (int i = 1; i < hLines; i++)
  504. {
  505. var offset = i * Vector2.right * gridOffset;
  506. offset.x += gridPadding;
  507. Handles.DrawLine(innerRect.position + offset, new Vector2(innerRect.x, innerRect.yMax - 1) + offset);
  508. }
  509. // Horizontal grid
  510. gridOffset = Mathf.FloorToInt(innerRect.height / vLines);
  511. gridPadding = ((int)(innerRect.height) % vLines) / 2;
  512. for (int i = 1; i < vLines; i++)
  513. {
  514. var offset = i * Vector2.up * gridOffset;
  515. offset.y += gridPadding;
  516. Handles.DrawLine(innerRect.position + offset, new Vector2(innerRect.xMax - 1, innerRect.y) + offset);
  517. }
  518. }
  519. // Curve editor
  520. if (m_CurveEditor.OnGUI(rect))
  521. {
  522. Repaint();
  523. GUI.changed = true;
  524. }
  525. if (Event.current.type == EventType.Repaint)
  526. {
  527. // Borders
  528. Handles.color = Color.black;
  529. Handles.DrawLine(new Vector2(rect.x, rect.y - 18f), new Vector2(rect.xMax, rect.y - 18f));
  530. Handles.DrawLine(new Vector2(rect.x, rect.y - 19f), new Vector2(rect.x, rect.yMax));
  531. Handles.DrawLine(new Vector2(rect.x, rect.yMax), new Vector2(rect.xMax, rect.yMax));
  532. Handles.DrawLine(new Vector2(rect.xMax, rect.yMax), new Vector2(rect.xMax, rect.y - 18f));
  533. // Selection info
  534. var selection = m_CurveEditor.GetSelection();
  535. if (selection.curve != null && selection.keyframeIndex > -1)
  536. {
  537. var key = selection.keyframe.Value;
  538. var infoRect = innerRect;
  539. infoRect.x += 5f;
  540. infoRect.width = 100f;
  541. infoRect.height = 30f;
  542. GUI.Label(infoRect, string.Format("{0}\n{1}", key.time.ToString("F3"), key.value.ToString("F3")), FxStyles.preLabel);
  543. }
  544. }
  545. }
  546. /*
  547. EditorGUILayout.HelpBox(
  548. @"Curve editor cheat sheet:
  549. - [Del] or [Backspace] to remove a key
  550. - [Ctrl] to break a tangent handle
  551. - [Shift] to align tangent handles
  552. - [Double click] to create a key on the curve(s) at mouse position
  553. - [Alt] + [Double click] to create a key on the curve(s) at a given time",
  554. MessageType.Info);
  555. */
  556. EditorGUILayout.Space();
  557. EditorGUI.indentLevel += 2;
  558. }
  559. void DrawBackgroundTexture(Rect rect, int pass)
  560. {
  561. float scale = EditorGUIUtility.pixelsPerPoint;
  562. var oldRt = RenderTexture.active;
  563. var rt = RenderTexture.GetTemporary(Mathf.CeilToInt(rect.width * scale), Mathf.CeilToInt(rect.height * scale), 0, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Linear);
  564. s_MaterialSpline.SetFloat("_DisabledState", GUI.enabled ? 1f : 0.5f);
  565. s_MaterialSpline.SetFloat("_PixelScaling", EditorGUIUtility.pixelsPerPoint);
  566. Graphics.Blit(null, rt, s_MaterialSpline, pass);
  567. RenderTexture.active = oldRt;
  568. GUI.DrawTexture(rect, rt);
  569. RenderTexture.ReleaseTemporary(rt);
  570. }
  571. }
  572. }