Assignment for RMIT Mixed Reality in 2020
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.

566 lines
14 KiB

  1. /************************************************************************************
  2. Filename : ONSPPropagationMaterialEditor.cs
  3. Content : Propagation material editor class
  4. Attach to geometry to define material properties
  5. Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
  6. Licensed under the Oculus SDK Version 3.5 (the "License");
  7. you may not use the Oculus SDK except in compliance with the License,
  8. which is provided at the time of installation or download, or which
  9. otherwise accompanies this software in either electronic or hard copy form.
  10. You may obtain a copy of the License at
  11. https://developer.oculus.com/licenses/sdk-3.5/
  12. Unless required by applicable law or agreed to in writing, the Oculus SDK
  13. distributed under the License is distributed on an "AS IS" BASIS,
  14. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15. See the License for the specific language governing permissions and
  16. limitations under the License.
  17. ************************************************************************************/
  18. using UnityEditor;
  19. using UnityEngine;
  20. using Spectrum = ONSPPropagationMaterial.Spectrum;
  21. using Point = ONSPPropagationMaterial.Point;
  22. [CustomEditor(typeof(ONSPPropagationMaterial))]
  23. internal sealed class ONSPPropagationMaterialEditor : Editor{
  24. private enum AxisScale{ Lin, Log, Sqr }
  25. private sealed class SpectrumDrawer{
  26. private const float cutoff = 20000f;
  27. private static readonly Texture2D texture = EditorGUIUtility.whiteTexture;
  28. private static readonly GUIStyle textStyle = new GUIStyle{
  29. alignment = TextAnchor.MiddleLeft,
  30. clipping = TextClipping.Overflow,
  31. fontSize = 8,
  32. fontStyle = FontStyle.Bold,
  33. wordWrap = false,
  34. normal = new GUIStyleState{ textColor = Color.grey },
  35. focused = new GUIStyleState{ textColor = Color.grey }
  36. };
  37. private static int focus;
  38. private readonly string label;
  39. private readonly AxisScale scale;
  40. private readonly Spectrum spectrum;
  41. private bool dragInitiated;
  42. private bool isDragging;
  43. private bool displaySpectrum;
  44. private bool displayPoints;
  45. internal bool IsFocus{
  46. get{
  47. return focus == spectrum.GetHashCode();
  48. }
  49. }
  50. internal SpectrumDrawer(string label, Spectrum spectrum, AxisScale scale){
  51. this.label = label;
  52. this.spectrum = spectrum;
  53. this.scale = scale;
  54. }
  55. internal void Draw(Event e){
  56. displaySpectrum = EditorGUILayout.Foldout(displaySpectrum, label);
  57. if(displaySpectrum){
  58. EditorGUI.indentLevel++;
  59. DrawSpectrum(e);
  60. displayPoints = EditorGUILayout.Foldout(displayPoints, "Points");
  61. if(displayPoints){
  62. EditorGUI.indentLevel++;
  63. DrawPoints();
  64. EditorGUI.indentLevel--;
  65. }
  66. EditorGUI.indentLevel--;
  67. }
  68. }
  69. internal void LoadFoldoutState(){
  70. displaySpectrum = EditorPrefs.GetBool(label + "Spectrum", true);
  71. displayPoints = EditorPrefs.GetBool(label + "Points", false);
  72. }
  73. internal void SaveFoldoutState(){
  74. EditorPrefs.SetBool(label + "Spectrum", displaySpectrum);
  75. EditorPrefs.SetBool(label + "Points", displayPoints);
  76. }
  77. private void DrawSpectrum(Event e){
  78. float height = 10 * EditorGUIUtility.singleLineHeight;
  79. Rect r = EditorGUILayout.GetControlRect(true, height);
  80. r.width -= rightMargin;
  81. DrawDataTicks(r);
  82. r = AudioCurveRendering.BeginCurveFrame(r);
  83. AudioCurveRendering.DrawFilledCurve(r, EvaluateCurve, AudioCurveRendering.kAudioOrange);
  84. DrawFrequencyTicks(r);
  85. HandleEvent(r, e);
  86. if(IsFocus) DrawSelected(r);
  87. AudioCurveRendering.EndCurveFrame();
  88. }
  89. private void DrawPoints(){
  90. var points = spectrum.points;
  91. int lines = points.Count > 0 ? points.Count + 2 : 1;
  92. float height = EditorGUIUtility.singleLineHeight * lines;
  93. Rect r1 = EditorGUILayout.GetControlRect(true, height);
  94. r1.width -= rightMargin;
  95. r1.height = EditorGUIUtility.singleLineHeight;
  96. {
  97. int oldCount = points.Count;
  98. int newCount = EditorGUI.DelayedIntField(r1, "Size", oldCount);
  99. r1.y += r1.height;
  100. if(newCount < points.Count){
  101. points.RemoveRange(newCount, oldCount - newCount);
  102. Undo.SetCurrentGroupName("Points Removed");
  103. GUI.changed = true;
  104. } else if(newCount > oldCount){
  105. if(newCount > points.Capacity)
  106. points.Capacity = newCount;
  107. for(int i = oldCount; i < newCount; i++)
  108. points.Add(new Point(125 * (1 << i)));
  109. Undo.SetCurrentGroupName("Points Added");
  110. GUI.changed = true;
  111. }
  112. }
  113. if(points.Count > 0){
  114. Rect r2 = new Rect(r1.xMax + 9, r1.y + r1.height * 1.125f, 24, r1.height * .75f);
  115. r1.width /= 2;
  116. EditorGUI.LabelField(r1, "Frequency");
  117. r1.x += r1.width;
  118. EditorGUI.LabelField(r1, "Data");
  119. r1.x -= r1.width;
  120. r1.y += r1.height;
  121. for(int i = 0; i < points.Count; i++){
  122. points[i].frequency = EditorGUI.FloatField(r1, points[i].frequency);
  123. points[i].frequency = Mathf.Clamp(points[i].frequency, 0f, cutoff);
  124. r1.x += r1.width;
  125. points[i].data = EditorGUI.FloatField(r1, points[i].data);
  126. points[i].data = Mathf.Clamp01(points[i].data);
  127. r1.x -= r1.width;
  128. r1.y += r1.height;
  129. if(GUI.Button(r2, "–")){
  130. RemovePointAt(i);
  131. break;
  132. }
  133. r2.y += r1.height;
  134. }
  135. }
  136. }
  137. private void DrawDataTicks(Rect r){
  138. const int ticks = 10;
  139. Rect label = new Rect(r.xMax + 9, r.y - r.height / (2 * ticks), 24, r.height / ticks);
  140. Rect tick = new Rect(r.xMax + 2, r.y - 1, 4.5f, 2);
  141. for(int i = 0; i <= ticks; i++){
  142. float value = MapData(1 - (float)i / ticks, false);
  143. EditorGUI.DrawRect(tick, textStyle.normal.textColor);
  144. GUI.Label(label, value.ToString("0.000"), textStyle);
  145. tick.y += label.height;
  146. label.y += label.height;
  147. }
  148. }
  149. private void DrawFrequencyTicks(Rect r){
  150. Rect tick = new Rect(r.x, r.y, 1, r.height);
  151. Rect label = new Rect(r.x, r.yMax - 1.5f * EditorGUIUtility.singleLineHeight, 32, EditorGUIUtility.singleLineHeight);
  152. for(int i = 1; i < 30; i++){
  153. float frequency;
  154. if(MapFrequencyTick(i, out frequency)){
  155. tick.x = MapFrequency(frequency) * r.width;
  156. tick.height = label.y - r.y;
  157. tick.width = 2;
  158. EditorGUI.DrawRect(tick, textStyle.normal.textColor);
  159. tick.y = label.yMax;
  160. tick.height = r.yMax - label.yMax;
  161. EditorGUI.DrawRect(tick, textStyle.normal.textColor);
  162. label.x = tick.x - 2;
  163. GUI.Label(label, FrequencyToString(frequency), textStyle);
  164. tick.y = r.y;
  165. tick.height = r.height;
  166. tick.width = 1;
  167. } else{
  168. tick.x = MapFrequency(frequency) * r.width;
  169. EditorGUI.DrawRect(tick, textStyle.normal.textColor);
  170. }
  171. }
  172. }
  173. private void DrawSelected(Rect r){
  174. if(spectrum.points.Count > spectrum.selection){
  175. const float radius = 12;
  176. Vector2 position = MapPointPosition(r, spectrum.points[spectrum.selection]);
  177. Vector2 size = new Vector2(radius, radius);
  178. r = new Rect(position - size / 2, size);
  179. #if UNITY_5
  180. GUI.DrawTexture(r, texture, ScaleMode.StretchToFill, false, 0);
  181. GUI.DrawTexture(r, texture, ScaleMode.StretchToFill, false, 0);
  182. #else
  183. GUI.DrawTexture(r, texture, ScaleMode.StretchToFill, false, 0, Color.white, 0, radius);
  184. GUI.DrawTexture(r, texture, ScaleMode.StretchToFill, false, 0, Color.black, 2, radius);
  185. #endif
  186. }
  187. }
  188. private void HandleEvent(Rect r, Event e){
  189. Vector2 position = e.mousePosition;
  190. switch(e.type){
  191. case EventType.MouseDown:
  192. if(r.Contains(position)){
  193. if(e.clickCount == 2){
  194. spectrum.selection = spectrum.points.Count;
  195. spectrum.points.Add(MapMouseEvent(r, position));
  196. Undo.SetCurrentGroupName("Point Added");
  197. GUI.changed = true;
  198. } else{
  199. int selection = spectrum.selection;
  200. float minDistance = float.MaxValue;
  201. for(int i = 0; i < spectrum.points.Count; i++){
  202. float distance = Vector2.Distance(MapPointPosition(r, spectrum.points[i]), position);
  203. if(distance < minDistance){
  204. selection = i;
  205. minDistance = distance;
  206. }
  207. }
  208. if(selection != spectrum.selection){
  209. spectrum.selection = selection;
  210. Undo.SetCurrentGroupName("Point Selected");
  211. GUI.changed = true;
  212. }
  213. }
  214. focus = spectrum.GetHashCode();
  215. dragInitiated = true;
  216. } else{
  217. isDragging = false;
  218. focus = 0;
  219. }
  220. e.Use();
  221. break;
  222. case EventType.MouseDrag:
  223. if(dragInitiated){
  224. dragInitiated = false;
  225. isDragging = true;
  226. }
  227. if(isDragging && spectrum.selection < spectrum.points.Count){
  228. spectrum.points[spectrum.selection] = MapMouseEvent(r, position);
  229. e.Use();
  230. }
  231. break;
  232. case EventType.Ignore:
  233. case EventType.MouseUp:
  234. dragInitiated = false;
  235. if(isDragging){
  236. isDragging = false;
  237. Undo.SetCurrentGroupName("Point Moved");
  238. GUI.changed = true;
  239. e.Use();
  240. }
  241. break;
  242. case EventType.KeyDown:
  243. switch(e.keyCode){
  244. case KeyCode.Delete:
  245. case KeyCode.Backspace:
  246. if(spectrum.selection < spectrum.points.Count){
  247. RemovePointAt(spectrum.selection);
  248. e.Use();
  249. }
  250. break;
  251. }
  252. break;
  253. }
  254. }
  255. private void RemovePointAt(int index){
  256. spectrum.points.RemoveAt(index);
  257. if(spectrum.selection == index)
  258. spectrum.selection = spectrum.points.Count;
  259. Undo.SetCurrentGroupName("Point Removed");
  260. GUI.changed = true;
  261. }
  262. private float EvaluateCurve(float f){
  263. return 2 * MapData(spectrum[MapFrequency(f, false)]) - 1;
  264. }
  265. private Vector2 MapPointPosition(Rect r, Point point){
  266. return new Vector2{
  267. x = r.x + r.width * MapFrequency(point.frequency),
  268. y = r.y + r.height * (1 - MapData(point.data))
  269. };
  270. }
  271. private Point MapMouseEvent(Rect r, Vector2 v){
  272. return new Point{
  273. frequency = v.x < r.xMin ? 0 : v.x > r.xMax ? cutoff : MapFrequency((v.x - r.x) / r.width, false),
  274. data = v.y < r.yMin ? 1 : v.y > r.yMax ? 0 : MapData(1 - (v.y - r.y) / r.height, false)
  275. };
  276. }
  277. private float MapData(float f, bool forward = true){
  278. switch(scale){
  279. case AxisScale.Log:
  280. return forward ? f < 1e-3f ? 0 : 1 + Mathf.Log10(f) / 3 : Mathf.Pow(10, -3 * (1 - f));
  281. case AxisScale.Sqr:
  282. return forward ? Mathf.Sqrt(f) : f * f;
  283. default:
  284. case AxisScale.Lin:
  285. return f;
  286. }
  287. }
  288. public static bool MapFrequencyTick(int i, out float frequency){
  289. int power = i / 9 + 1;
  290. int multiplier = i % 9 + 1;
  291. frequency = multiplier * Mathf.Pow(10, power);
  292. return multiplier == 1;
  293. }
  294. public static float MapFrequency(float f, bool forward = true){
  295. return forward ? f < 10 ? 0 : Mathf.Log(f / 10, cutoff / 10) : 10 * Mathf.Pow(cutoff / 10, f);
  296. }
  297. private static string FrequencyToString(float frequency){
  298. if(frequency < 1000)
  299. return string.Format("{0:F0} Hz", frequency);
  300. else
  301. return string.Format("{0:F0} kHz", frequency * .001f);
  302. }
  303. }
  304. private const float rightMargin = 36;
  305. private SpectrumDrawer absorption, scattering, transmission;
  306. private void OnEnable(){
  307. GetSpectra(out absorption, out scattering, out transmission);
  308. absorption.LoadFoldoutState();
  309. scattering.LoadFoldoutState();
  310. transmission.LoadFoldoutState();
  311. }
  312. private void OnDisable(){
  313. absorption.SaveFoldoutState();
  314. scattering.SaveFoldoutState();
  315. transmission.SaveFoldoutState();
  316. }
  317. public override void OnInspectorGUI(){
  318. ONSPPropagationMaterial material = target as ONSPPropagationMaterial;
  319. EditorGUI.BeginChangeCheck();
  320. Rect r = EditorGUILayout.GetControlRect();
  321. r.width -= rightMargin;
  322. ONSPPropagationMaterial.Preset newPreset =
  323. (ONSPPropagationMaterial.Preset)EditorGUI.EnumPopup(r, "Preset", material.preset);
  324. Event e = Event.current;
  325. EventType type = e.type;
  326. absorption.Draw(e);
  327. scattering.Draw(e);
  328. transmission.Draw(e);
  329. if(EditorGUI.EndChangeCheck()){
  330. string groupName = Undo.GetCurrentGroupName();
  331. Undo.RegisterCompleteObjectUndo(material, groupName);
  332. if(groupName == "Point Added")
  333. Undo.CollapseUndoOperations(Undo.GetCurrentGroup() - 1);
  334. if(material.preset != newPreset)
  335. material.preset = newPreset;
  336. else
  337. material.preset = ONSPPropagationMaterial.Preset.Custom;
  338. if(Application.isPlaying)
  339. material.UploadMaterial();
  340. }
  341. }
  342. private void GetSpectra(out SpectrumDrawer absorption,
  343. out SpectrumDrawer scattering,
  344. out SpectrumDrawer transmission){
  345. ONSPPropagationMaterial material = target as ONSPPropagationMaterial;
  346. absorption = new SpectrumDrawer("Absorption", material.absorption, AxisScale.Sqr);
  347. scattering = new SpectrumDrawer("Scattering", material.scattering, AxisScale.Lin);
  348. transmission = new SpectrumDrawer("Transmission", material.transmission, AxisScale.Sqr);
  349. }
  350. }