SnapManager.cs 61 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300
  1. /*
  2. Copyright (c) 2021 Omar Duarte
  3. Unauthorized copying of this file, via any medium is strictly prohibited.
  4. Writen by Omar Duarte, 2021.
  5. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  6. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  7. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  8. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  9. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  10. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  11. THE SOFTWARE.
  12. */
  13. using UnityEngine;
  14. using System.Linq;
  15. namespace PluginMaster
  16. {
  17. #region DATA & SETTINGS
  18. [System.Serializable]
  19. public struct GridOrigin
  20. {
  21. [SerializeField] private string _name;
  22. [SerializeField] private Pose _pose;
  23. public GridOrigin(string name, Pose point)
  24. {
  25. _name = name;
  26. _pose = point;
  27. }
  28. public string name { get => _name; set => _name = value; }
  29. public Vector3 position { get => _pose.position; set => _pose.position = value; }
  30. public Quaternion rotation { get => _pose.rotation; set => _pose.rotation = value; }
  31. public Pose pose { get => _pose; set => _pose = value; }
  32. }
  33. [System.Serializable]
  34. public class SnapSettings : ISerializationCallbackReceiver
  35. {
  36. [System.Serializable]
  37. private struct Bool3
  38. {
  39. public bool x, y, z;
  40. public Bool3(bool x = true, bool y = false, bool z = true) => (this.x, this.y, this.z) = (x, y, z);
  41. }
  42. [SerializeField] private bool _snappingEnabled = false;
  43. [SerializeField] private Bool3 _snappingOn = new Bool3();
  44. [SerializeField] private bool _visibleGrid = false;
  45. [SerializeField] private Bool3 _gridOn = new Bool3(false, true, false);
  46. [SerializeField] private bool _lockedGrid = false;
  47. [SerializeField] private Vector3 _step = Vector3.one;
  48. [SerializeField] private Vector3 _origin = Vector3.zero;
  49. [SerializeField] private Quaternion _rotation = Quaternion.identity;
  50. [SerializeField] private bool _showPositionHandle = true;
  51. [SerializeField] private bool _showRotationHandle = false;
  52. [SerializeField] private bool _showScaleHandle = false;
  53. [SerializeField] private bool _radialGridEnabled = false;
  54. [SerializeField] private float _radialStep = 1f;
  55. [SerializeField] private int _radialSectors = 8;
  56. [SerializeField] private bool _snapToRadius = true;
  57. [SerializeField] private bool _snapToCircunference = true;
  58. [SerializeField] private Vector3Int _majorLinesGap = Vector3Int.one * 10;
  59. [SerializeField] private bool _midpointSnapping = false;
  60. [SerializeField] private GridOrigin[] _origins = null;
  61. private const string DEFAULT_ORIGIN_NAME = "Default";
  62. [SerializeField] private string _selectedOrigin = DEFAULT_ORIGIN_NAME;
  63. private System.Collections.Generic.Dictionary<string, Pose> _originsDictionary
  64. = new System.Collections.Generic.Dictionary<string, Pose>() { { DEFAULT_ORIGIN_NAME, Pose.identity } };
  65. public System.Action OnGridOriginChange;
  66. public System.Action OnDataChanged;
  67. public void DataChanged(bool repaint = true)
  68. {
  69. if (!repaint)
  70. {
  71. PWBCore.staticData.SetSavePending();
  72. return;
  73. }
  74. PWBCore.SetSavePending();
  75. if (OnDataChanged != null) OnDataChanged();
  76. UnityEditor.SceneView.RepaintAll();
  77. }
  78. public Vector3 step
  79. {
  80. get => _step;
  81. set
  82. {
  83. value = Vector3.Max(value, Vector3.one * 0.1f);
  84. if (_step == value) return;
  85. _step = value;
  86. DataChanged(false);
  87. }
  88. }
  89. public bool snappingEnabled
  90. {
  91. get => _snappingEnabled;
  92. set
  93. {
  94. if (_snappingEnabled == value) return;
  95. _snappingEnabled = value;
  96. if (_snappingEnabled) visibleGrid = true;
  97. DataChanged();
  98. }
  99. }
  100. public bool snappingOnX
  101. {
  102. get => _snappingOn.x;
  103. set
  104. {
  105. if (_snappingOn.x == value) return;
  106. _snappingOn.x = value;
  107. DataChanged();
  108. }
  109. }
  110. public bool snappingOnY
  111. {
  112. get => _snappingOn.y;
  113. set
  114. {
  115. if (_snappingOn.y == value) return;
  116. _snappingOn.y = value;
  117. DataChanged();
  118. }
  119. }
  120. public bool snappingOnZ
  121. {
  122. get => _snappingOn.z;
  123. set
  124. {
  125. if (_snappingOn.z == value) return;
  126. _snappingOn.z = value;
  127. DataChanged();
  128. }
  129. }
  130. public Vector3 origin
  131. {
  132. get => _origin;
  133. set
  134. {
  135. if (_origin == value) return;
  136. _origin = value;
  137. DataChanged(false);
  138. if (OnGridOriginChange != null) OnGridOriginChange();
  139. }
  140. }
  141. public bool lockedGrid
  142. {
  143. get => _lockedGrid;
  144. set
  145. {
  146. if (_lockedGrid == value) return;
  147. _lockedGrid = value;
  148. DataChanged();
  149. }
  150. }
  151. public bool visibleGrid
  152. {
  153. get => _visibleGrid;
  154. set
  155. {
  156. if (_visibleGrid == value) return;
  157. _visibleGrid = value;
  158. DataChanged();
  159. }
  160. }
  161. public bool gridOnX
  162. {
  163. get => _gridOn.x;
  164. set
  165. {
  166. if (_gridOn.x == value) return;
  167. _gridOn.x = value;
  168. if (value)
  169. {
  170. _gridOn.y = _gridOn.z = false;
  171. _snappingOn.x = false;
  172. _snappingOn.y = _snappingOn.z = true;
  173. }
  174. DataChanged();
  175. }
  176. }
  177. public bool gridOnY
  178. {
  179. get => _gridOn.y;
  180. set
  181. {
  182. if (_gridOn.y == value) return;
  183. _gridOn.y = value;
  184. if (value)
  185. {
  186. _gridOn.x = _gridOn.z = false;
  187. _snappingOn.y = false;
  188. _snappingOn.x = _snappingOn.z = true;
  189. }
  190. DataChanged();
  191. }
  192. }
  193. public bool gridOnZ
  194. {
  195. get => _gridOn.z;
  196. set
  197. {
  198. if (_gridOn.z == value) return;
  199. _gridOn.z = value;
  200. if (value)
  201. {
  202. _gridOn.x = _gridOn.y = false;
  203. _snappingOn.z = false;
  204. _snappingOn.y = _snappingOn.x = true;
  205. }
  206. DataChanged();
  207. }
  208. }
  209. public AxesUtils.Axis gridAxis => gridOnX ? AxesUtils.Axis.X : (gridOnY ? AxesUtils.Axis.Y : AxesUtils.Axis.Z);
  210. public Quaternion rotation
  211. {
  212. get => _rotation;
  213. set
  214. {
  215. if (_rotation == value) return;
  216. _rotation = value;
  217. DataChanged(false);
  218. if (OnGridOriginChange != null) OnGridOriginChange();
  219. }
  220. }
  221. public bool showPositionHandle
  222. {
  223. get => _showPositionHandle;
  224. set
  225. {
  226. if (_showPositionHandle == value) return;
  227. _showPositionHandle = value;
  228. if (_showPositionHandle)
  229. {
  230. _showRotationHandle = false;
  231. _showScaleHandle = false;
  232. }
  233. SnapManager.FrameGridOrigin();
  234. DataChanged();
  235. }
  236. }
  237. public bool showRotationHandle
  238. {
  239. get => _showRotationHandle;
  240. set
  241. {
  242. if (_showRotationHandle == value) return;
  243. _showRotationHandle = value;
  244. if (_showRotationHandle)
  245. {
  246. _showPositionHandle = false;
  247. _showScaleHandle = false;
  248. SnapManager.FrameGridOrigin();
  249. }
  250. DataChanged();
  251. }
  252. }
  253. public bool showScaleHandle
  254. {
  255. get => _showScaleHandle;
  256. set
  257. {
  258. if (_showScaleHandle == value) return;
  259. _showScaleHandle = value;
  260. if (_showScaleHandle)
  261. {
  262. _showPositionHandle = false;
  263. _showRotationHandle = false;
  264. SnapManager.FrameGridOrigin();
  265. }
  266. DataChanged();
  267. }
  268. }
  269. public bool radialGridEnabled
  270. {
  271. get => _radialGridEnabled;
  272. set
  273. {
  274. if (_radialGridEnabled == value) return;
  275. _radialGridEnabled = value;
  276. DataChanged();
  277. }
  278. }
  279. public float radialStep
  280. {
  281. get => _radialStep;
  282. set
  283. {
  284. value = Mathf.Max(value, 0.1f);
  285. if (_radialStep == value) return;
  286. _radialStep = value;
  287. DataChanged();
  288. }
  289. }
  290. public int radialSectors
  291. {
  292. get => _radialSectors;
  293. set
  294. {
  295. value = Mathf.Max(value, 3);
  296. if (_radialSectors == value) return;
  297. _radialSectors = value;
  298. DataChanged();
  299. }
  300. }
  301. public bool snapToRadius
  302. {
  303. get => _snapToRadius;
  304. set
  305. {
  306. if (_snapToRadius == value) return;
  307. _snapToRadius = value;
  308. DataChanged();
  309. }
  310. }
  311. public bool snapToCircunference
  312. {
  313. get => _snapToCircunference;
  314. set
  315. {
  316. if (_snapToCircunference == value) return;
  317. _snapToCircunference = value;
  318. }
  319. }
  320. public Vector3Int majorLinesGap
  321. {
  322. get => _majorLinesGap;
  323. set
  324. {
  325. value = Vector3Int.Max(value, Vector3Int.one);
  326. if (_majorLinesGap == value) return;
  327. _majorLinesGap = value;
  328. DataChanged();
  329. }
  330. }
  331. public bool midpointSnapping
  332. {
  333. get => _midpointSnapping;
  334. set
  335. {
  336. if (_midpointSnapping == value) return;
  337. _midpointSnapping = value;
  338. DataChanged();
  339. }
  340. }
  341. #region ORIGINS
  342. public string selectedOrigin
  343. {
  344. get => _selectedOrigin;
  345. set
  346. {
  347. if (_selectedOrigin == value) return;
  348. _selectedOrigin = value;
  349. _origin = _originsDictionary[_selectedOrigin].position;
  350. _rotation = _originsDictionary[_selectedOrigin].rotation;
  351. DataChanged();
  352. if (OnGridOriginChange != null) OnGridOriginChange();
  353. }
  354. }
  355. public void SaveGridOrigin(string name)
  356. {
  357. if (_originsDictionary.ContainsKey(name)) _originsDictionary[name] = new Pose(origin, rotation);
  358. else _originsDictionary.Add(name, new Pose(origin, rotation));
  359. _selectedOrigin = name;
  360. DataChanged();
  361. }
  362. public bool OriginsDictionaryContains(string name) => _originsDictionary.ContainsKey(name);
  363. public Pose GetOrigin(string name) => _originsDictionary[name];
  364. public string[] GetOriginNames() => _originsDictionary.Keys.ToArray();
  365. public void DeleteSelectedOrigin()
  366. {
  367. _originsDictionary.Remove(_selectedOrigin);
  368. selectedOrigin = DEFAULT_ORIGIN_NAME;
  369. }
  370. public int GetIndexOfOrigin(string name) => _originsDictionary.Keys.Select((key, index) => new { key, index })
  371. .FirstOrDefault(pair => pair.key == name)?.index ?? -1;
  372. public int GetIndexOfSelectedOrigin() => GetIndexOfOrigin(selectedOrigin);
  373. public string GetOriginAt(int index) => _originsDictionary.Keys.ElementAt(index);
  374. public void SelectOrigin(int index) => selectedOrigin = GetOriginAt(index);
  375. public void SetNextOrigin()
  376. {
  377. var selectedOriginIdx = GetIndexOfSelectedOrigin();
  378. if (selectedOriginIdx < _originsDictionary.Count - 1) ++selectedOriginIdx;
  379. else selectedOriginIdx = 0;
  380. SelectOrigin(selectedOriginIdx);
  381. }
  382. public void ResetOrigin()
  383. {
  384. _origin = _originsDictionary[_selectedOrigin].position;
  385. _rotation = _originsDictionary[_selectedOrigin].rotation;
  386. DataChanged();
  387. if (OnGridOriginChange != null) OnGridOriginChange();
  388. }
  389. #endregion
  390. public void SetOriginHeight(Vector3 point, AxesUtils.Axis axis)
  391. {
  392. var originPos = origin;
  393. AxesUtils.SetAxisValue(ref originPos, axis, AxesUtils.GetAxisValue(point, axis));
  394. origin = originPos;
  395. }
  396. public bool IsSnappingEnabledInThisDirection(Vector3 direction)
  397. {
  398. bool isParallel(Vector3 other)
  399. => Vector3.Cross(direction, other).magnitude < 0.0000001;
  400. if (isParallel(_rotation * Vector3.up) && _snappingOn.y) return true;
  401. if (isParallel(_rotation * Vector3.right) && _snappingOn.x) return true;
  402. if (isParallel(_rotation * Vector3.forward) && _snappingOn.z) return true;
  403. return false;
  404. }
  405. public Vector3 TransformToGridDirection(Vector3 direction)
  406. {
  407. if (direction == Vector3.zero) return _rotation * Vector3.up;
  408. var xProjection = Vector3.Project(direction, _rotation * Vector3.right);
  409. var yProjection = Vector3.Project(direction, _rotation * Vector3.up);
  410. var zProjection = Vector3.Project(direction, _rotation * Vector3.forward);
  411. var xProjectionMagnitude = xProjection.magnitude;
  412. var yProjectionMagnitude = yProjection.magnitude;
  413. var zProjectionMagnitude = zProjection.magnitude;
  414. var max = Mathf.Max(xProjectionMagnitude, yProjectionMagnitude, zProjectionMagnitude);
  415. if (xProjectionMagnitude == max) return xProjection.normalized;
  416. if (yProjectionMagnitude == max) return yProjection.normalized;
  417. return zProjection.normalized;
  418. }
  419. public void OnBeforeSerialize()
  420. {
  421. _origins = _originsDictionary.Select(pair => new GridOrigin(pair.Key, pair.Value)).ToArray();
  422. }
  423. public void OnAfterDeserialize()
  424. {
  425. if (_origins == null || _origins.Length == 0) return;
  426. _originsDictionary = _origins.ToDictionary(origin => origin.name, origin => origin.pose);
  427. }
  428. }
  429. [System.Serializable]
  430. public class SnapManager
  431. {
  432. private static SnapSettings _staticSettings = new SnapSettings();
  433. [SerializeField] SnapSettings _settings = _staticSettings;
  434. public static SnapSettings settings => _staticSettings;
  435. public static void FrameGridOrigin()
  436. {
  437. var sceneView = (UnityEditor.SceneView)(UnityEditor.SceneView.sceneViews[0]);
  438. if (sceneView == null) return;
  439. var viewportPoint = sceneView.camera.WorldToViewportPoint(settings.origin);
  440. bool originOnScreen = viewportPoint.x > 0 && viewportPoint.y > 0
  441. && viewportPoint.x < 1 && viewportPoint.y < 1;
  442. if (originOnScreen) return;
  443. var activeGO = UnityEditor.Selection.activeGameObject;
  444. var tempGO = new GameObject();
  445. tempGO.transform.position = settings.origin;
  446. UnityEditor.Selection.activeObject = tempGO;
  447. UnityEditor.SceneView.FrameLastActiveSceneView();
  448. UnityEditor.Selection.activeGameObject = activeGO;
  449. GameObject.DestroyImmediate(tempGO);
  450. }
  451. public static void ToggleGridPositionHandle()
  452. {
  453. if (!settings.lockedGrid) settings.lockedGrid = true;
  454. settings.showPositionHandle = !settings.showPositionHandle;
  455. SnapSettingsWindow.RepaintWindow();
  456. }
  457. public static void ToggleGridRotationHandle()
  458. {
  459. if (!settings.lockedGrid) settings.lockedGrid = true;
  460. settings.showRotationHandle = !settings.showRotationHandle;
  461. SnapSettingsWindow.RepaintWindow();
  462. }
  463. public static void ToggleGridScaleHandle()
  464. {
  465. if (!settings.lockedGrid) settings.lockedGrid = true;
  466. settings.showScaleHandle = !settings.showScaleHandle;
  467. SnapSettingsWindow.RepaintWindow();
  468. }
  469. }
  470. #endregion
  471. #region PWBIO
  472. public static partial class PWBIO
  473. {
  474. private static bool _snappedToVertex = false;
  475. private static Vector3 SnapPosition(Vector3 position, bool onGrid, bool applySettings,
  476. float snapStepFactor = 1f, bool ignoreMidpoints = false)
  477. {
  478. var result = position;
  479. if (SnapManager.settings.radialGridEnabled)
  480. {
  481. var rotation = SnapManager.settings.rotation;
  482. if (SnapManager.settings.gridOnX) rotation *= Quaternion.AngleAxis(-90, Vector3.forward);
  483. else if (SnapManager.settings.gridOnZ) rotation *= Quaternion.AngleAxis(-90, Vector3.right);
  484. var localPosition = Quaternion.Inverse(rotation) * (position - SnapManager.settings.origin);
  485. var snappedDirOnPlane = new Vector3(localPosition.x, 0, localPosition.z).normalized;
  486. if (SnapManager.settings.snapToRadius)
  487. {
  488. var sectorAngleRad = TAU / SnapManager.settings.radialSectors;
  489. var angleRad = Mathf.Atan2(localPosition.z, localPosition.x);
  490. var snappedAngleRad = Mathf.Round(angleRad / sectorAngleRad) * sectorAngleRad;
  491. snappedDirOnPlane = new Vector3(Mathf.Cos(snappedAngleRad), 0, Mathf.Sin(snappedAngleRad));
  492. var sizeOnplane = Mathf.Sqrt(localPosition.x * localPosition.x
  493. + localPosition.z * localPosition.z);
  494. var snappedOnPlane = snappedDirOnPlane * sizeOnplane;
  495. var localSnapedPosition = new Vector3(snappedOnPlane.x, localPosition.y, snappedOnPlane.z);
  496. result = rotation * localSnapedPosition + SnapManager.settings.origin;
  497. }
  498. if (SnapManager.settings.snapToCircunference)
  499. {
  500. var sizeOnplane = Mathf.Sqrt(localPosition.x * localPosition.x
  501. + localPosition.z * localPosition.z);
  502. var sizeOnPlaneSnapped = Mathf.Round(sizeOnplane / SnapManager.settings.radialStep)
  503. * SnapManager.settings.radialStep;
  504. var localSnapedPosition = snappedDirOnPlane * sizeOnPlaneSnapped
  505. + new Vector3(0, localPosition.y, 0);
  506. result = rotation * localSnapedPosition + SnapManager.settings.origin;
  507. }
  508. }
  509. else
  510. {
  511. var localPosition = Quaternion.Inverse(SnapManager.settings.rotation)
  512. * (position - SnapManager.settings.origin);
  513. float Snap(float step, float value)
  514. {
  515. if (!ignoreMidpoints && SnapManager.settings.midpointSnapping) step *= 0.5f;
  516. return Mathf.Round(value / step) * step;
  517. }
  518. var localSnappedPosition = new Vector3(
  519. Snap(SnapManager.settings.step.x * snapStepFactor, localPosition.x),
  520. Snap(SnapManager.settings.step.y * snapStepFactor, localPosition.y),
  521. Snap(SnapManager.settings.step.z * snapStepFactor, localPosition.z));
  522. result = SnapManager.settings.rotation * (applySettings ? new Vector3(
  523. SnapManager.settings.snappingOnX ? localSnappedPosition.x : onGrid ? 0 : localPosition.x,
  524. SnapManager.settings.snappingOnY ? localSnappedPosition.y : onGrid ? 0 : localPosition.y,
  525. SnapManager.settings.snappingOnZ ? localSnappedPosition.z : onGrid ? 0 : localPosition.z)
  526. : localSnappedPosition) + SnapManager.settings.origin;
  527. }
  528. return result;
  529. }
  530. private static Vector3 SnapAndUpdateGridOrigin(Vector3 point, bool snapToGrid,
  531. bool paintOnPalettePrefabs, bool paintOnMeshesWithoutCollider, bool paintOnTheGrid,
  532. Vector3 projectionDirection)
  533. {
  534. if (snapToGrid)
  535. {
  536. point = SnapPosition(point, paintOnTheGrid, true);
  537. var direction = SnapManager.settings.TransformToGridDirection(SnapManager.settings.rotation
  538. * projectionDirection);
  539. if (!paintOnTheGrid && !SnapManager.settings.IsSnappingEnabledInThisDirection(direction))
  540. {
  541. var ray = new Ray(point - direction, direction);
  542. if (MouseRaycast(ray, out RaycastHit hit, out GameObject collider, float.MaxValue, -1,
  543. paintOnPalettePrefabs, paintOnMeshesWithoutCollider)) point = hit.point;
  544. }
  545. }
  546. UpdateGridOrigin(point);
  547. return point;
  548. }
  549. private static Vector3 SnapFloorTilePosition(Vector3 position, out Vector3 localPosition)
  550. {
  551. var origin = SnapManager.settings.origin + SnapManager.settings.rotation
  552. * (SnapManager.settings.step * 0.5f - Vector3.up * SnapManager.settings.step.y);
  553. var localPos = Quaternion.Inverse(SnapManager.settings.rotation) * (position - origin);
  554. float Snap(float step, float value) => Mathf.Round(value / step) * step;
  555. var localSnappedPos = new Vector3(Snap(SnapManager.settings.step.x, localPos.x), 0f,
  556. Snap(SnapManager.settings.step.z, localPos.z));
  557. localPosition = localSnappedPos;
  558. var result = SnapManager.settings.rotation * localSnappedPos + origin;
  559. return result;
  560. }
  561. private static Vector3 SnapWallPosition(Vector3 position, out AxesUtils.Axis axis,
  562. out bool rotateHalfTurn, out Vector3 localPosition)
  563. {
  564. var toolSettings = WallManager.settings;
  565. var origin = SnapManager.settings.origin
  566. + SnapManager.settings.rotation * (Vector3.forward * (SnapManager.settings.step.z / 2)
  567. + Vector3.right * (SnapManager.settings.step.x / 2));
  568. var localPos = Quaternion.Inverse(SnapManager.settings.rotation) * (position - origin);
  569. float Snap(float step, float value) => Mathf.Round(value / step) * step;
  570. var xSnappedToCenter = Snap(SnapManager.settings.step.x, localPos.x);
  571. var zSnappedTocenter = Snap(SnapManager.settings.step.z, localPos.z);
  572. var cellCenter = new Vector3(xSnappedToCenter, 0f, zSnappedTocenter);
  573. var centerToPosition = localPos - cellCenter;
  574. var xDistance = Mathf.Abs(centerToPosition.x);
  575. var zDistance = Mathf.Abs(centerToPosition.z);
  576. var xSnappedToBorder = xSnappedToCenter;
  577. var zSnappedToBorder = zSnappedTocenter;
  578. rotateHalfTurn = false;
  579. if (xDistance > zDistance)
  580. {
  581. if (centerToPosition.x < 0)
  582. {
  583. xSnappedToBorder -= (SnapManager.settings.step.x - WallManager.wallThickness) / 2;
  584. rotateHalfTurn = true;
  585. }
  586. else xSnappedToBorder += (SnapManager.settings.step.x - WallManager.wallThickness) / 2;
  587. axis = AxesUtils.Axis.Z;
  588. }
  589. else
  590. {
  591. if (centerToPosition.z < 0)
  592. {
  593. zSnappedToBorder -= (SnapManager.settings.step.z - WallManager.wallThickness) / 2;
  594. rotateHalfTurn = true;
  595. }
  596. else zSnappedToBorder += (SnapManager.settings.step.z - WallManager.wallThickness) / 2;
  597. axis = AxesUtils.Axis.X;
  598. }
  599. var yOffset = toolSettings.moduleSize.y / 2;
  600. var localSnappedPos = new Vector3(xSnappedToBorder, yOffset, zSnappedToBorder);
  601. localPosition = localSnappedPos;
  602. var result = SnapManager.settings.rotation * localSnappedPos + origin;
  603. return result;
  604. }
  605. private static Vector3 SnapWallPosition(Vector3 startPoint, Vector3 endPoint,
  606. out AxesUtils.Axis axis, out int cellsCount, out bool rotateHalfTurn, out Vector3 localPosition)
  607. {
  608. var segment = endPoint - startPoint;
  609. var localSegment = Quaternion.Inverse(SnapManager.settings.rotation) * segment;
  610. var magnitudeX = Mathf.Abs(localSegment.x);
  611. var magnitudeZ = Mathf.Abs(localSegment.z);
  612. axis = magnitudeX > magnitudeZ ? AxesUtils.Axis.X : AxesUtils.Axis.Z;
  613. float Snap(float step, float value) => Mathf.Round(value / step) * step;
  614. var origin = SnapManager.settings.origin
  615. + SnapManager.settings.rotation * (Vector3.forward * (SnapManager.settings.step.z / 2)
  616. + Vector3.right * (SnapManager.settings.step.x / 2));
  617. var localStartPoint = Quaternion.Inverse(SnapManager.settings.rotation) * (startPoint - origin);
  618. var localStartXSnappedToCenter = Snap(SnapManager.settings.step.x, localStartPoint.x);
  619. var localStartZSnappedTocenter = Snap(SnapManager.settings.step.z, localStartPoint.z);
  620. var localStartCellCenter = new Vector3(localStartXSnappedToCenter, 0f, localStartZSnappedTocenter);
  621. var localEndPoint = Quaternion.Inverse(SnapManager.settings.rotation) * (endPoint - origin);
  622. var localEndXSnappedToCenter = Snap(SnapManager.settings.step.x, localEndPoint.x);
  623. var localEndZSnappedTocenter = Snap(SnapManager.settings.step.z, localEndPoint.z);
  624. var localEndCellCenter = new Vector3(localEndXSnappedToCenter, 0f, localEndZSnappedTocenter);
  625. var localSnappedSegment = localEndCellCenter - localStartCellCenter;
  626. var snappedMagnitudeX = Mathf.Abs(localSnappedSegment.x);
  627. var snappedMagnitudeZ = Mathf.Abs(localSnappedSegment.z);
  628. var localXSnappedToBorder = localEndXSnappedToCenter;
  629. var localZSnappedToBorder = localEndZSnappedTocenter;
  630. rotateHalfTurn = false;
  631. if (axis == AxesUtils.Axis.X)
  632. {
  633. if (localEndPoint.z > localEndCellCenter.z)
  634. localZSnappedToBorder += (SnapManager.settings.step.z - WallManager.wallThickness) / 2;
  635. else
  636. {
  637. localZSnappedToBorder -= (SnapManager.settings.step.z - WallManager.wallThickness) / 2;
  638. rotateHalfTurn = true;
  639. }
  640. cellsCount = Mathf.RoundToInt(snappedMagnitudeX / SnapManager.settings.step.x) + 1;
  641. }
  642. else
  643. {
  644. if (localEndPoint.x > localEndCellCenter.x)
  645. localXSnappedToBorder += (SnapManager.settings.step.x - WallManager.wallThickness) / 2;
  646. else
  647. {
  648. localXSnappedToBorder -= (SnapManager.settings.step.x - WallManager.wallThickness) / 2;
  649. rotateHalfTurn = true;
  650. }
  651. cellsCount = Mathf.RoundToInt(snappedMagnitudeZ / SnapManager.settings.step.z) + 1;
  652. }
  653. if (cellsCount == 1)
  654. {
  655. localXSnappedToBorder = localEndXSnappedToCenter;
  656. localZSnappedToBorder = localEndZSnappedTocenter;
  657. var centerToPosition = localEndPoint - localEndCellCenter;
  658. var xDistance = Mathf.Abs(centerToPosition.x);
  659. var zDistance = Mathf.Abs(centerToPosition.z);
  660. if (xDistance > zDistance)
  661. {
  662. if (centerToPosition.x < 0)
  663. {
  664. localXSnappedToBorder -= (SnapManager.settings.step.x - WallManager.wallThickness) / 2;
  665. rotateHalfTurn = true;
  666. }
  667. else localXSnappedToBorder += (SnapManager.settings.step.x - WallManager.wallThickness) / 2;
  668. axis = AxesUtils.Axis.Z;
  669. }
  670. else
  671. {
  672. if (centerToPosition.z < 0)
  673. {
  674. localZSnappedToBorder -= (SnapManager.settings.step.z - WallManager.wallThickness) / 2;
  675. rotateHalfTurn = true;
  676. }
  677. else localZSnappedToBorder += (SnapManager.settings.step.z - WallManager.wallThickness) / 2;
  678. axis = AxesUtils.Axis.X;
  679. }
  680. }
  681. var yOffset = WallManager.settings.moduleSize.y / 2;
  682. var localSnappedPos = new Vector3(localXSnappedToBorder, yOffset, localZSnappedToBorder);
  683. localPosition = localSnappedPos;
  684. var result = SnapManager.settings.rotation * localSnappedPos + origin;
  685. return result;
  686. }
  687. private static bool SnapToVertex(Ray ray, out RaycastHit closestVertexInfo,
  688. bool in2DMode, GameObject[] selection = null)
  689. {
  690. Vector2 origin2D = ray.origin;
  691. bool snappedToVertex = false;
  692. float radius = 1f;
  693. RaycastHit[] hitArray = null;
  694. Collider2D[] collider2DArray = null;
  695. do
  696. {
  697. if (selection == null)
  698. {
  699. hitArray = new RaycastHit[0];
  700. if (Physics.SphereCast(ray, radius, out RaycastHit hitInfo))
  701. hitArray = new RaycastHit[] { hitInfo };
  702. }
  703. else
  704. {
  705. hitArray = Physics.SphereCastAll(ray, radius);
  706. if (hitArray.Length > 0)
  707. {
  708. var filtered = new System.Collections.Generic.List<RaycastHit>();
  709. foreach (var hit in hitArray)
  710. {
  711. var colliderObj = hit.collider.gameObject;
  712. var hitID = colliderObj.GetInstanceID();
  713. if (PWBCore.IsTempCollider(hitID))
  714. {
  715. colliderObj = PWBCore.GetGameObjectFromTempColliderId(hitID);
  716. hitID = colliderObj.GetInstanceID();
  717. }
  718. foreach (var filter in selection)
  719. {
  720. if (hitID == filter.GetInstanceID()) filtered.Add(hit);
  721. }
  722. }
  723. hitArray = filtered.ToArray();
  724. }
  725. }
  726. if (hitArray.Length > 0)
  727. {
  728. var filtered = new System.Collections.Generic.List<RaycastHit>();
  729. foreach (var hit in hitArray)
  730. {
  731. var obj = hit.collider.gameObject;
  732. if (PWBCore.IsTempCollider(obj.GetInstanceID()))
  733. obj = PWBCore.GetGameObjectFromTempColliderId(obj.GetInstanceID());
  734. if (IsVisible(ref obj)) filtered.Add(hit);
  735. }
  736. hitArray = filtered.ToArray();
  737. if (hitArray.Length > 0) break;
  738. }
  739. if (in2DMode)
  740. {
  741. collider2DArray = Physics2D.OverlapCircleAll(origin2D, radius);
  742. var filtered = new System.Collections.Generic.List<Collider2D>();
  743. foreach (var collider in collider2DArray)
  744. {
  745. var colliderObj = collider.gameObject;
  746. var hitID = colliderObj.GetInstanceID();
  747. if (PWBCore.IsTempCollider(hitID))
  748. {
  749. colliderObj = PWBCore.GetGameObjectFromTempColliderId(hitID);
  750. hitID = colliderObj.GetInstanceID();
  751. }
  752. foreach (var filter in selection)
  753. {
  754. if (hitID == filter.GetInstanceID()) filtered.Add(collider);
  755. }
  756. }
  757. collider2DArray = filtered.ToArray();
  758. if (collider2DArray.Length > 0) break;
  759. }
  760. radius *= 2;
  761. } while (radius <= 1024f);
  762. if (hitArray.Length > 0)
  763. {
  764. float minDist = float.MaxValue;
  765. GameObject closestObj = null;
  766. var closestHitPoint = Vector3.zero;
  767. foreach (var sphereCastHit in hitArray)
  768. {
  769. if (sphereCastHit.distance < minDist)
  770. {
  771. minDist = sphereCastHit.distance;
  772. closestObj = sphereCastHit.collider.gameObject;
  773. if (PWBCore.IsTempCollider(closestObj.GetInstanceID()))
  774. closestObj = PWBCore.GetGameObjectFromTempColliderId(closestObj.GetInstanceID());
  775. }
  776. }
  777. if (DistanceUtils.FindNearestVertexToMouse(out closestVertexInfo, closestObj.transform)) return true;
  778. }
  779. snappedToVertex = false;
  780. closestVertexInfo = new RaycastHit();
  781. if (in2DMode && collider2DArray.Length > 0)
  782. {
  783. float minSqrDistance = float.MaxValue;
  784. if (snappedToVertex) minSqrDistance = ((Vector2)closestVertexInfo.point - origin2D).sqrMagnitude;
  785. foreach (var collider in collider2DArray)
  786. {
  787. var obj = collider.gameObject;
  788. if (PWBCore.IsTempCollider(obj.GetInstanceID()))
  789. obj = PWBCore.GetGameObjectFromTempColliderId(obj.GetInstanceID());
  790. if (DistanceUtils.FindNearestVertexToMouse(out RaycastHit closestVertexInfo2D, obj.transform))
  791. {
  792. var sqrDistance = ((Vector2)closestVertexInfo2D.point - origin2D).sqrMagnitude;
  793. if (sqrDistance < minSqrDistance)
  794. {
  795. minSqrDistance = sqrDistance;
  796. closestVertexInfo = closestVertexInfo2D;
  797. snappedToVertex = true;
  798. }
  799. }
  800. }
  801. }
  802. #if UNITY_2020_2_OR_NEWER
  803. if (!snappedToVertex) return DistanceUtils.FindNearestVertexToMouse(out closestVertexInfo, null);
  804. #endif
  805. return snappedToVertex;
  806. }
  807. private static void UpdateGridOrigin(Vector3 hitPoint)
  808. {
  809. var snapOrigin = SnapManager.settings.origin;
  810. if (!SnapManager.settings.lockedGrid)
  811. {
  812. if (SnapManager.settings.gridOnX) snapOrigin.x = hitPoint.x;
  813. else if (SnapManager.settings.gridOnY) snapOrigin.y = hitPoint.y;
  814. else if (SnapManager.settings.gridOnZ) snapOrigin.z = hitPoint.z;
  815. }
  816. SnapManager.settings.origin = snapOrigin;
  817. }
  818. private static void GridHandles()
  819. {
  820. if (!SnapManager.settings.lockedGrid) return;
  821. var originOffset = SnapManager.settings.origin;
  822. var rotation = SnapManager.settings.rotation;
  823. var snapSize = SnapManager.settings.step;
  824. UnityEditor.Handles.zTest = UnityEngine.Rendering.CompareFunction.Always;
  825. var handleSize = UnityEditor.HandleUtility.GetHandleSize(originOffset);
  826. void DrawSnapGizmos(AxesUtils.Axis forwardAxis, AxesUtils.Axis upwardAxis)
  827. {
  828. var fw = rotation * AxesUtils.GetVector(1, forwardAxis);
  829. var uw = rotation * AxesUtils.GetVector(1, upwardAxis);
  830. var coneSize = handleSize * 0.15f;
  831. var stepSize = SnapManager.settings.radialGridEnabled ? SnapManager.settings.radialStep
  832. : AxesUtils.GetAxisValue(snapSize, forwardAxis);
  833. var conePosFw = originOffset + fw * (handleSize * 1.6f);
  834. var originScreenPos = _sceneViewCamera.WorldToScreenPoint(SnapManager.settings.origin);
  835. var fwScreenPos = _sceneViewCamera.WorldToScreenPoint(conePosFw);
  836. var alpha = Mathf.Clamp01((fwScreenPos - originScreenPos).magnitude / 90 - 0.5f);
  837. var controlId = GUIUtility.GetControlID(FocusType.Passive);
  838. float distFromMouse = UnityEditor.HandleUtility.DistanceToCircle(conePosFw, coneSize / 2);
  839. UnityEditor.HandleUtility.AddControl(controlId, distFromMouse);
  840. bool mouseOver = UnityEditor.HandleUtility.nearestControl == controlId;
  841. UnityEditor.Handles.color = new Color(1f, 1f, mouseOver ? 1 : 0, alpha);
  842. UnityEditor.Handles.ConeHandleCap(controlId, conePosFw,
  843. Quaternion.LookRotation(fw, uw), coneSize, EventType.Repaint);
  844. if (Event.current.button == 0 && Event.current.type == EventType.MouseDown && mouseOver)
  845. SnapManager.settings.origin += fw * stepSize;
  846. var conePosBw = originOffset + fw * (handleSize * 1.3f);
  847. controlId = GUIUtility.GetControlID(FocusType.Passive);
  848. distFromMouse = UnityEditor.HandleUtility.DistanceToCircle(conePosBw, coneSize / 2);
  849. UnityEditor.HandleUtility.AddControl(controlId, distFromMouse);
  850. mouseOver = UnityEditor.HandleUtility.nearestControl == controlId;
  851. UnityEditor.Handles.color = new Color(1f, 1f, mouseOver ? 1 : 0, alpha);
  852. UnityEditor.Handles.ConeHandleCap(controlId, conePosBw,
  853. Quaternion.LookRotation(-fw, -uw), coneSize, EventType.Repaint);
  854. if (Event.current.button == 0 && Event.current.type == EventType.MouseDown && mouseOver)
  855. SnapManager.settings.origin -= fw * stepSize;
  856. }
  857. if (SnapManager.settings.showPositionHandle)
  858. {
  859. SnapManager.settings.origin = UnityEditor.Handles.PositionHandle(originOffset, rotation);
  860. UnityEditor.Handles.zTest = UnityEngine.Rendering.CompareFunction.LessEqual;
  861. UnityEditor.Handles.color = Color.yellow;
  862. UnityEditor.Handles.SphereHandleCap(0, originOffset, rotation,
  863. UnityEditor.HandleUtility.GetHandleSize(originOffset) * 0.2f, EventType.Repaint);
  864. UnityEditor.Handles.zTest = UnityEngine.Rendering.CompareFunction.Always;
  865. DrawSnapGizmos(AxesUtils.Axis.X, AxesUtils.Axis.Y);
  866. DrawSnapGizmos(AxesUtils.Axis.Y, AxesUtils.Axis.Z);
  867. DrawSnapGizmos(AxesUtils.Axis.Z, AxesUtils.Axis.X);
  868. }
  869. else if (SnapManager.settings.showRotationHandle)
  870. SnapManager.settings.rotation = UnityEditor.Handles.RotationHandle(rotation, originOffset);
  871. else if (SnapManager.settings.showScaleHandle)
  872. {
  873. if (SnapManager.settings.radialGridEnabled)
  874. {
  875. var step0 = Vector3.one * SnapManager.settings.radialStep;
  876. var step = UnityEditor.Handles.ScaleHandle(step0, originOffset,
  877. rotation, handleSize);
  878. if (step0 != step)
  879. {
  880. if (step0.x != step.x) SnapManager.settings.radialStep = step.x;
  881. else if (step0.y != step.y) SnapManager.settings.radialStep = step.y;
  882. else SnapManager.settings.radialStep = step.z;
  883. }
  884. }
  885. else
  886. {
  887. SnapManager.settings.step = UnityEditor.Handles.ScaleHandle(SnapManager.settings.step,
  888. originOffset, rotation, handleSize);
  889. }
  890. }
  891. if (SnapManager.settings.origin != originOffset
  892. || SnapManager.settings.rotation != rotation
  893. || SnapManager.settings.step != snapSize)
  894. SnapSettingsWindow.RepaintWindow();
  895. }
  896. private static void DrawGrid(AxesUtils.Axis axis, Vector3 focusPoint, int maxCells, Vector3 snapSize)
  897. {
  898. var rotation = SnapManager.settings.rotation;
  899. UnityEditor.Handles.zTest = UnityEngine.Rendering.CompareFunction.Always;
  900. var focusOffset = Quaternion.Inverse(SnapManager.settings.rotation) * (focusPoint - SnapManager.settings.origin);
  901. var focusOffsetInt = new Vector3Int(Mathf.RoundToInt(focusOffset.x / snapSize.x),
  902. Mathf.RoundToInt(focusOffset.y / snapSize.y), Mathf.RoundToInt(focusOffset.z / snapSize.z));
  903. float GetAlpha(float cell, int majorLinesGap) => (cell % majorLinesGap == 0) ? 0.5f : 0.2f;
  904. for (int i = 0; i < maxCells; ++i)
  905. {
  906. for (int j = 1; j < maxCells; ++j)
  907. {
  908. var p1 = Vector3.zero;
  909. var p2 = Vector3.zero;
  910. var p3 = Vector3.zero;
  911. var p4 = Vector3.zero;
  912. var alpha1 = (maxCells - Mathf.Max(i, j - 1)) / (float)maxCells;
  913. var alpha2 = alpha1;
  914. var alpha3 = alpha1;
  915. var alpha4 = alpha1;
  916. var alpha1R = alpha1;
  917. var alpha2R = alpha1;
  918. var alpha4R = alpha1;
  919. var alpha3R = alpha1;
  920. var color = new Color(0.5f, 1f, 0.5f, 0f);
  921. switch (axis)
  922. {
  923. case AxesUtils.Axis.X:
  924. color = new Color(1f, 0.5f, 0.5f, 0f);
  925. alpha1 *= GetAlpha(i + focusOffsetInt.y, SnapManager.settings.majorLinesGap.y);
  926. alpha2 *= GetAlpha(i - focusOffsetInt.y, SnapManager.settings.majorLinesGap.y);
  927. alpha3 *= GetAlpha(i + focusOffsetInt.z, SnapManager.settings.majorLinesGap.z);
  928. alpha4 *= GetAlpha(i - focusOffsetInt.z, SnapManager.settings.majorLinesGap.z);
  929. alpha1R = alpha1;
  930. alpha2R = alpha2;
  931. alpha3R = alpha4;
  932. alpha4R = alpha3;
  933. p1 += rotation * Vector3.Scale(new Vector3(0f, i, j - 1), snapSize);
  934. p2 += rotation * Vector3.Scale(new Vector3(0f, i, j), snapSize);
  935. p3 += rotation * Vector3.Scale(new Vector3(0f, j - 1, i), snapSize);
  936. p4 += rotation * Vector3.Scale(new Vector3(0f, j, i), snapSize);
  937. break;
  938. case AxesUtils.Axis.Y:
  939. alpha1 *= GetAlpha(i + focusOffsetInt.x, SnapManager.settings.majorLinesGap.x);
  940. alpha2 *= GetAlpha(i - focusOffsetInt.x, SnapManager.settings.majorLinesGap.x);
  941. alpha3 *= GetAlpha(i + focusOffsetInt.z, SnapManager.settings.majorLinesGap.z);
  942. alpha4 *= GetAlpha(i - focusOffsetInt.z, SnapManager.settings.majorLinesGap.z);
  943. alpha1R = alpha2;
  944. alpha2R = alpha1;
  945. alpha3R = alpha3;
  946. alpha4R = alpha4;
  947. p1 += rotation * Vector3.Scale(new Vector3(i, 0f, j - 1), snapSize);
  948. p2 += rotation * Vector3.Scale(new Vector3(i, 0f, j), snapSize);
  949. p3 += rotation * Vector3.Scale(new Vector3(j - 1, 0f, i), snapSize);
  950. p4 += rotation * Vector3.Scale(new Vector3(j, 0f, i), snapSize);
  951. break;
  952. case AxesUtils.Axis.Z:
  953. color = new Color(0.5f, 0.5f, 1f, 0f);
  954. alpha1 *= GetAlpha(i + focusOffsetInt.x, SnapManager.settings.majorLinesGap.x);
  955. alpha2 *= GetAlpha(i - focusOffsetInt.x, SnapManager.settings.majorLinesGap.x);
  956. alpha3 *= GetAlpha(i + focusOffsetInt.y, SnapManager.settings.majorLinesGap.y);
  957. alpha4 *= GetAlpha(i - focusOffsetInt.y, SnapManager.settings.majorLinesGap.y);
  958. alpha1R = alpha1;
  959. alpha2R = alpha2;
  960. alpha3R = alpha4;
  961. alpha4R = alpha3;
  962. p1 += rotation * Vector3.Scale(new Vector3(i, j - 1, 0f), snapSize);
  963. p2 += rotation * Vector3.Scale(new Vector3(i, j, 0f), snapSize);
  964. p3 += rotation * Vector3.Scale(new Vector3(j - 1, i, 0f), snapSize);
  965. p4 += rotation * Vector3.Scale(new Vector3(j, i, 0f), snapSize);
  966. break;
  967. }
  968. UnityEditor.Handles.color = color + new Color(0f, 0f, 0f, alpha1);
  969. UnityEditor.Handles.DrawLine(focusPoint + p1, focusPoint + p2);
  970. UnityEditor.Handles.color = color + new Color(0f, 0f, 0f, alpha2);
  971. UnityEditor.Handles.DrawLine(focusPoint - p1, focusPoint - p2);
  972. UnityEditor.Handles.color = color + new Color(0f, 0f, 0f, alpha3);
  973. UnityEditor.Handles.DrawLine(focusPoint + p3, focusPoint + p4);
  974. UnityEditor.Handles.color = color + new Color(0f, 0f, 0f, alpha4);
  975. UnityEditor.Handles.DrawLine(focusPoint - p3, focusPoint - p4);
  976. if (i == 0) continue;
  977. var r180 = Quaternion.AngleAxis(180, rotation * (axis == AxesUtils.Axis.X ? Vector3.up :
  978. axis == AxesUtils.Axis.Y ? Vector3.forward : Vector3.right));
  979. UnityEditor.Handles.color = color + new Color(0f, 0f, 0f, alpha1R);
  980. UnityEditor.Handles.DrawLine(focusPoint + r180 * p1, focusPoint + r180 * p2);
  981. UnityEditor.Handles.color = color + new Color(0f, 0f, 0f, alpha2R);
  982. UnityEditor.Handles.DrawLine(focusPoint - r180 * p1, focusPoint - r180 * p2);
  983. UnityEditor.Handles.color = color + new Color(0f, 0f, 0f, alpha3R);
  984. UnityEditor.Handles.DrawLine(focusPoint + r180 * p3, focusPoint + r180 * p4);
  985. UnityEditor.Handles.color = color + new Color(0f, 0f, 0f, alpha4R);
  986. UnityEditor.Handles.DrawLine(focusPoint - r180 * p3, focusPoint - r180 * p4);
  987. }
  988. }
  989. }
  990. private static int GetMaxCells(AxesUtils.Axis axis, Vector3 focusPoint, UnityEditor.SceneView sceneView,
  991. out Vector3 snapSize)
  992. {
  993. snapSize = SnapManager.settings.radialGridEnabled ? Vector3.one * SnapManager.settings.radialStep
  994. : SnapManager.settings.step;
  995. var rotation = SnapManager.settings.rotation;
  996. var guiDistance = (UnityEditor.HandleUtility.WorldToGUIPoint(focusPoint)
  997. - UnityEditor.HandleUtility.WorldToGUIPoint(focusPoint + rotation * snapSize)).magnitude;
  998. const int minGuidistance = 30;
  999. if (guiDistance < minGuidistance) snapSize *= Mathf.Round(minGuidistance / guiDistance);
  1000. int maxCells = 10;
  1001. var halfSize = new Vector3(
  1002. axis == AxesUtils.Axis.X ? 0f : maxCells * snapSize.x,
  1003. axis == AxesUtils.Axis.Y ? 0f : maxCells * snapSize.y,
  1004. axis == AxesUtils.Axis.Z ? 0f : maxCells * snapSize.z);
  1005. var axis1Vector = rotation * (axis == AxesUtils.Axis.X ? Vector3.forward
  1006. : axis == AxesUtils.Axis.Y ? Vector3.right : Vector3.up);
  1007. var axis2Vector = rotation * (axis == AxesUtils.Axis.X ? Vector3.up
  1008. : axis == AxesUtils.Axis.Y ? Vector3.forward : Vector3.right);
  1009. var gridAxes = new Vector2[]
  1010. {
  1011. UnityEditor.HandleUtility.WorldToGUIPoint(focusPoint - Vector3.Scale(halfSize, axis1Vector)),
  1012. UnityEditor.HandleUtility.WorldToGUIPoint(focusPoint + Vector3.Scale(halfSize, axis1Vector)),
  1013. UnityEditor.HandleUtility.WorldToGUIPoint(focusPoint - Vector3.Scale(halfSize, axis2Vector)),
  1014. UnityEditor.HandleUtility.WorldToGUIPoint(focusPoint + Vector3.Scale(halfSize, axis2Vector))
  1015. };
  1016. var gridMax = new Vector2(
  1017. Mathf.Max(gridAxes[0].x, gridAxes[1].x, gridAxes[2].x, gridAxes[3].x),
  1018. Mathf.Max(gridAxes[0].y, gridAxes[1].y, gridAxes[2].y, gridAxes[3].y));
  1019. var gridMin = new Vector2(
  1020. Mathf.Min(gridAxes[0].x, gridAxes[1].x, gridAxes[2].x, gridAxes[3].x),
  1021. Mathf.Min(gridAxes[0].y, gridAxes[1].y, gridAxes[2].y, gridAxes[3].y));
  1022. var gridSizeOnGUI = gridMax - gridMin;
  1023. var diff = sceneView.position.size - gridSizeOnGUI;
  1024. if (diff.x > 0 || diff.y > 0)
  1025. {
  1026. float maxRatio = float.MinValue;
  1027. if (diff.x > 0) maxRatio = sceneView.position.size.x / gridSizeOnGUI.x;
  1028. if (diff.y > 0)
  1029. {
  1030. float ratio = sceneView.position.size.y / gridSizeOnGUI.y;
  1031. if (ratio > maxRatio) maxRatio = ratio;
  1032. }
  1033. maxCells = Mathf.CeilToInt((float)maxCells * maxRatio);
  1034. if (maxCells > 30)
  1035. {
  1036. var maxCellsRatio = Mathf.CeilToInt((float)maxCells / 30f);
  1037. snapSize = snapSize * maxCellsRatio;
  1038. maxCells = 30;
  1039. }
  1040. }
  1041. return maxCells;
  1042. }
  1043. private static void DrawRadialGrid(AxesUtils.Axis axis, UnityEditor.SceneView sceneView, int maxCells, float snapSize)
  1044. {
  1045. var rotation = SnapManager.settings.rotation;
  1046. var otherAxes = AxesUtils.GetOtherAxes(axis);
  1047. var normal = rotation * AxesUtils.GetVector(1, axis);
  1048. var tangent = rotation * AxesUtils.GetVector(1, otherAxes[0]);
  1049. var bitangent = rotation * AxesUtils.GetVector(1, otherAxes[1]);
  1050. float radius = 0f;
  1051. for (int i = 1; i < maxCells; ++i)
  1052. {
  1053. radius += snapSize;
  1054. var alpha = (maxCells - i) * 0.5f / (float)maxCells;
  1055. switch (axis)
  1056. {
  1057. case AxesUtils.Axis.X:
  1058. UnityEditor.Handles.color = new Color(1f, 0.5f, 0.5f, alpha);
  1059. break;
  1060. case AxesUtils.Axis.Y:
  1061. UnityEditor.Handles.color = new Color(0.5f, 1f, 0.5f, alpha);
  1062. break;
  1063. case AxesUtils.Axis.Z:
  1064. UnityEditor.Handles.color = new Color(0.5f, 0.5f, 1f, alpha);
  1065. break;
  1066. }
  1067. DrawGridCricle(SnapManager.settings.origin, normal, tangent, bitangent, radius);
  1068. for (int j = 0; j < SnapManager.settings.radialSectors; ++j)
  1069. {
  1070. var radians = TAU * j / SnapManager.settings.radialSectors;
  1071. var tangentDir = new Vector2(Mathf.Cos(radians), Mathf.Sin(radians));
  1072. var worldDir = TangentSpaceToWorld(tangent, bitangent, tangentDir);
  1073. var points = new Vector3[]
  1074. {
  1075. SnapManager.settings.origin + (worldDir * (radius - snapSize)),
  1076. SnapManager.settings.origin + (worldDir * (radius))
  1077. };
  1078. UnityEditor.Handles.DrawAAPolyLine(1, points);
  1079. }
  1080. }
  1081. }
  1082. private static void DrawGridCricle(Vector3 center, Vector3 normal,
  1083. Vector3 tangent, Vector3 bitangent, float radius)
  1084. {
  1085. UnityEditor.Handles.zTest = UnityEngine.Rendering.CompareFunction.Always;
  1086. const float polygonSideSize = 0.3f;
  1087. const int minPolygonSides = 12;
  1088. const int maxPolygonSides = 60;
  1089. var polygonSides = Mathf.Clamp((int)(TAU * radius / polygonSideSize), minPolygonSides, maxPolygonSides);
  1090. var periPoints = new System.Collections.Generic.List<Vector3>();
  1091. for (int i = 0; i < polygonSides; ++i)
  1092. {
  1093. var radians = TAU * i / (polygonSides - 1f);
  1094. var tangentDir = new Vector2(Mathf.Cos(radians), Mathf.Sin(radians));
  1095. var worldDir = TangentSpaceToWorld(tangent, bitangent, tangentDir);
  1096. var periPoint = center + (worldDir * (radius));
  1097. periPoints.Add(periPoint);
  1098. }
  1099. UnityEditor.Handles.DrawAAPolyLine(4 * UnityEditor.Handles.color.a, periPoints.ToArray());
  1100. }
  1101. private static bool _gridShorcutEnabled = false;
  1102. public static bool gridShorcutEnabled => _gridShorcutEnabled;
  1103. private static void GridDuringSceneGui(UnityEditor.SceneView sceneView)
  1104. {
  1105. if (PWBSettings.shortcuts.gridEnableShortcuts.Check())
  1106. {
  1107. if (!_gridShorcutEnabled)
  1108. {
  1109. _gridShorcutEnabled = true;
  1110. Event.current.Use();
  1111. }
  1112. }
  1113. void MoveGridOrigin(AxesUtils.SignedAxis forwardAxis)
  1114. {
  1115. var fw = SnapManager.settings.rotation * forwardAxis;
  1116. var stepSize = SnapManager.settings.radialGridEnabled ? SnapManager.settings.radialStep
  1117. : AxesUtils.GetAxisValue(SnapManager.settings.step, forwardAxis);
  1118. SnapManager.settings.origin += fw * stepSize;
  1119. _gridShorcutEnabled = false;
  1120. }
  1121. if (PWBSettings.shortcuts.gridToggle.Check())
  1122. {
  1123. SnapManager.settings.visibleGrid = !SnapManager.settings.visibleGrid;
  1124. _gridShorcutEnabled = false;
  1125. }
  1126. else if (PWBSettings.shortcuts.gridToggleSnaping.Check()
  1127. && (!PWBSettings.shortcuts.gridToggleSnaping.firstStepEnabled || _gridShorcutEnabled))
  1128. {
  1129. SnapManager.settings.snappingEnabled = !SnapManager.settings.snappingEnabled;
  1130. _gridShorcutEnabled = false;
  1131. }
  1132. else if (PWBSettings.shortcuts.gridToggleLock.Check()
  1133. && (!PWBSettings.shortcuts.gridToggleLock.firstStepEnabled || _gridShorcutEnabled))
  1134. {
  1135. SnapManager.settings.lockedGrid = !SnapManager.settings.lockedGrid;
  1136. _gridShorcutEnabled = false;
  1137. }
  1138. else if (PWBSettings.shortcuts.gridSetOriginPosition.Check() && UnityEditor.Selection.activeTransform != null
  1139. && (!PWBSettings.shortcuts.gridSetOriginPosition.firstStepEnabled || _gridShorcutEnabled))
  1140. {
  1141. SnapManager.settings.origin = UnityEditor.Selection.activeTransform.position;
  1142. SnapManager.settings.showPositionHandle = true;
  1143. _gridShorcutEnabled = false;
  1144. }
  1145. else if (PWBSettings.shortcuts.gridSetOriginRotation.Check() && UnityEditor.Selection.activeTransform != null
  1146. && (!PWBSettings.shortcuts.gridSetOriginRotation.firstStepEnabled || _gridShorcutEnabled))
  1147. {
  1148. SnapManager.settings.rotation = UnityEditor.Selection.activeTransform.rotation;
  1149. SnapManager.settings.showRotationHandle = true;
  1150. _gridShorcutEnabled = false;
  1151. }
  1152. else if (PWBSettings.shortcuts.gridSetSize.Check() && UnityEditor.Selection.activeTransform != null
  1153. && (!PWBSettings.shortcuts.gridSetSize.firstStepEnabled || _gridShorcutEnabled))
  1154. {
  1155. SnapManager.settings.step = BoundsUtils.GetBounds(UnityEditor.Selection.activeTransform,
  1156. UnityEditor.Selection.activeTransform.rotation).size;
  1157. SnapManager.settings.showScaleHandle = true;
  1158. _gridShorcutEnabled = false;
  1159. }
  1160. else if (PWBSettings.shortcuts.gridFrameOrigin.Check()
  1161. && (!PWBSettings.shortcuts.gridFrameOrigin.firstStepEnabled || _gridShorcutEnabled))
  1162. {
  1163. SnapManager.FrameGridOrigin();
  1164. _gridShorcutEnabled = false;
  1165. }
  1166. else if (PWBSettings.shortcuts.gridTogglePositionHandle.Check()
  1167. && (!PWBSettings.shortcuts.gridTogglePositionHandle.firstStepEnabled || _gridShorcutEnabled))
  1168. {
  1169. SnapManager.ToggleGridPositionHandle();
  1170. _gridShorcutEnabled = false;
  1171. }
  1172. else if (PWBSettings.shortcuts.gridToggleRotationHandle.Check()
  1173. && (!PWBSettings.shortcuts.gridToggleRotationHandle.firstStepEnabled || _gridShorcutEnabled))
  1174. {
  1175. SnapManager.ToggleGridRotationHandle();
  1176. _gridShorcutEnabled = false;
  1177. }
  1178. else if (PWBSettings.shortcuts.gridToggleSpacingHandle.Check()
  1179. && (!PWBSettings.shortcuts.gridToggleSpacingHandle.firstStepEnabled || _gridShorcutEnabled))
  1180. {
  1181. SnapManager.ToggleGridScaleHandle();
  1182. _gridShorcutEnabled = false;
  1183. }
  1184. else if (PWBSettings.shortcuts.gridMoveOriginUp.Check()
  1185. && (!PWBSettings.shortcuts.gridMoveOriginUp.firstStepEnabled || _gridShorcutEnabled))
  1186. {
  1187. MoveGridOrigin(AxesUtils.SignedAxis.UP);
  1188. }
  1189. else if (PWBSettings.shortcuts.gridMoveOriginDown.Check()
  1190. && (!PWBSettings.shortcuts.gridMoveOriginDown.firstStepEnabled || _gridShorcutEnabled))
  1191. {
  1192. MoveGridOrigin(AxesUtils.SignedAxis.DOWN);
  1193. }
  1194. else if (PWBSettings.shortcuts.gridNextOrigin.Check()
  1195. && (!PWBSettings.shortcuts.gridNextOrigin.firstStepEnabled || _gridShorcutEnabled))
  1196. {
  1197. SnapManager.settings.SetNextOrigin();
  1198. SnapSettingsWindow.RepaintWindow();
  1199. }
  1200. if (!SnapManager.settings.visibleGrid) return;
  1201. var originOffset = SnapManager.settings.origin;
  1202. var rotation = SnapManager.settings.rotation;
  1203. var axis = SnapManager.settings.gridOnX ? AxesUtils.Axis.X
  1204. : SnapManager.settings.gridOnY ? AxesUtils.Axis.Y : AxesUtils.Axis.Z;
  1205. var camRay = new Ray(sceneView.camera.transform.position, sceneView.camera.transform.forward);
  1206. var plane = new Plane(rotation * (axis == AxesUtils.Axis.X ? Vector3.right
  1207. : axis == AxesUtils.Axis.Y ? Vector3.up : Vector3.forward), originOffset);
  1208. Vector3 focusPoint;
  1209. if (plane.Raycast(camRay, out float distance)) focusPoint = camRay.GetPoint(distance);
  1210. else return;
  1211. var snapSize = SnapManager.settings.step;
  1212. var maxCells = GetMaxCells(axis, focusPoint, sceneView, out snapSize);
  1213. var snapStepFactor = snapSize.x / SnapManager.settings.step.x;
  1214. focusPoint = SnapPosition(focusPoint, SnapManager.settings.snappingEnabled, false, snapStepFactor, true);
  1215. GridHandles();
  1216. if (SnapManager.settings.radialGridEnabled) DrawRadialGrid(axis, sceneView, maxCells, snapSize.x);
  1217. else DrawGrid(axis, focusPoint, maxCells, snapSize);
  1218. }
  1219. private static bool GridRaycast(Ray ray, out RaycastHit hitInfo)
  1220. {
  1221. hitInfo = new RaycastHit();
  1222. var plane = new Plane(SnapManager.settings.rotation * (SnapManager.settings.gridOnX ? Vector3.right
  1223. : SnapManager.settings.gridOnY ? Vector3.up : Vector3.forward), SnapManager.settings.origin);
  1224. if (Vector3.Cross(ray.direction, plane.normal).magnitude < 0.000001)
  1225. plane = new Plane(ray.direction, SnapManager.settings.origin);
  1226. if (plane.Raycast(ray, out float distance))
  1227. {
  1228. hitInfo.normal = plane.normal;
  1229. hitInfo.point = ray.GetPoint(distance);
  1230. return true;
  1231. }
  1232. return false;
  1233. }
  1234. }
  1235. #endregion
  1236. }