GravityToolManager.cs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  1. /*
  2. Copyright (c) 2020 Omar Duarte
  3. Unauthorized copying of this file, via any medium is strictly prohibited.
  4. Writen by Omar Duarte, 2020.
  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 class GravityToolSettings : BrushToolBase
  20. {
  21. [SerializeField] private SimulateGravityData _simData = new SimulateGravityData();
  22. [SerializeField] private float _height = 10f;
  23. [SerializeField] private bool _createTempColliders = true;
  24. public SimulateGravityData simData => _simData;
  25. public float height
  26. {
  27. get => _height;
  28. set
  29. {
  30. value = Mathf.Max(value, 0f);
  31. if (_height == value) return;
  32. _height = value;
  33. }
  34. }
  35. public bool createTempColliders
  36. {
  37. get
  38. {
  39. if (PWBCore.staticData.tempCollidersAction == PWBData.TempCollidersAction.NEVER_CREATE)
  40. return false;
  41. return _createTempColliders;
  42. }
  43. set
  44. {
  45. if (_createTempColliders == value) return;
  46. _createTempColliders = value;
  47. DataChanged();
  48. }
  49. }
  50. public override void Copy(IToolSettings other)
  51. {
  52. var otherGravityToolSettings = other as GravityToolSettings;
  53. if (otherGravityToolSettings == null) return;
  54. base.Copy(other);
  55. _simData.Copy(otherGravityToolSettings._simData);
  56. _height = otherGravityToolSettings.height;
  57. _createTempColliders = otherGravityToolSettings.createTempColliders;
  58. }
  59. public GravityToolSettings Clone()
  60. {
  61. var clone = new GravityToolSettings();
  62. clone.Copy(this);
  63. return clone;
  64. }
  65. public GravityToolSettings() : base() => _brushShape = BrushShape.POINT;
  66. }
  67. [System.Serializable]
  68. public class GravityToolManager : ToolManagerBase<GravityToolSettings>
  69. {
  70. private static float _surfaceDistanceSensitivityStatic = 1.0f;
  71. [SerializeField] private float _surfaceDistanceSensitivity = _surfaceDistanceSensitivityStatic;
  72. public static float surfaceDistanceSensitivity
  73. {
  74. get => _surfaceDistanceSensitivityStatic;
  75. set
  76. {
  77. value = Mathf.Clamp(value, 0f, 1f);
  78. if (_surfaceDistanceSensitivityStatic == value) return;
  79. _surfaceDistanceSensitivityStatic = value;
  80. PWBCore.staticData.Save();
  81. }
  82. }
  83. public override void OnBeforeSerialize()
  84. {
  85. base.OnBeforeSerialize();
  86. _surfaceDistanceSensitivity = _surfaceDistanceSensitivityStatic;
  87. }
  88. public override void OnAfterDeserialize()
  89. {
  90. base.OnAfterDeserialize();
  91. _surfaceDistanceSensitivityStatic = _surfaceDistanceSensitivity;
  92. }
  93. }
  94. #endregion
  95. #region PWBIO
  96. public static partial class PWBIO
  97. {
  98. private static Mesh _gravityLinesMesh = null;
  99. private static Material _gravityLinesMaterial = null;
  100. private static readonly int OPACITY_PROP_ID = Shader.PropertyToID("_opacity");
  101. public static void InitializeGravityHeight()
  102. {
  103. if (PaletteManager.selectedBrush == null) return;
  104. GravityToolManager.settings.height = PaletteManager.selectedBrush.maxBrushSize.y * 3;
  105. }
  106. private static void GravityToolDuringSceneGUI(UnityEditor.SceneView sceneView)
  107. {
  108. if (GravityToolManager.settings.createTempColliders)
  109. PWBCore.CreateTempCollidersWithinFrustum(sceneView.camera);
  110. BrushstrokeMouseEvents(GravityToolManager.settings);
  111. var mousePos = Event.current.mousePosition;
  112. if (_pinned) mousePos = _pinMouse;
  113. var mouseRay = UnityEditor.HandleUtility.GUIPointToWorldRay(mousePos);
  114. bool snappedToVertex = false;
  115. var closestVertexInfo = new RaycastHit();
  116. if (_snapToVertex)
  117. snappedToVertex = SnapToVertex(mouseRay, out closestVertexInfo, sceneView.in2DMode);
  118. if (snappedToVertex) mouseRay.origin = closestVertexInfo.point - mouseRay.direction;
  119. if (MouseRaycast(mouseRay, out RaycastHit hit, out GameObject c, float.MaxValue, -1, paintOnPalettePrefabs: true, castOnMeshesWithoutCollider: true))
  120. DrawGravityBrush(ref hit, sceneView.camera);
  121. else return;
  122. void AddHeight(float value)
  123. {
  124. GravityToolManager.settings.height += value;
  125. ToolProperties.RepainWindow();
  126. }
  127. if (Event.current.button == 0 && !Event.current.alt
  128. && (Event.current.type == EventType.MouseDown || Event.current.type == EventType.MouseDrag))
  129. {
  130. var paintedObjectsDic = Paint(GravityToolManager.settings, PAINT_CMD, false);
  131. if (!paintedObjectsDic.ContainsKey(string.Empty)) return;
  132. var paintedObjects = paintedObjectsDic[string.Empty].Select(i => i.Item1).ToArray();
  133. var finalPoses = GravityUtils.SimulateGravity(paintedObjects, GravityToolManager.settings.simData, false);
  134. for (int i = 0; i < paintedObjects.Length; ++i)
  135. {
  136. var obj = paintedObjects[i];
  137. var parent = obj.transform.parent;
  138. var position = obj.transform.position;
  139. var rotation = obj.transform.rotation;
  140. var localScale = obj.transform.localScale;
  141. var colliders = obj.GetComponentsInChildren<MeshCollider>();
  142. foreach (var collider in colliders)
  143. {
  144. if (collider == null) continue;
  145. if (UnityEditor.PrefabUtility.IsAddedComponentOverride(collider))
  146. UnityEditor.PrefabUtility.RevertAddedComponent(collider,
  147. UnityEditor.InteractionMode.AutomatedAction);
  148. }
  149. obj.transform.SetParent(parent);
  150. obj.transform.position = position;
  151. obj.transform.rotation = rotation;
  152. obj.transform.localScale = localScale;
  153. PWBCore.AddTempCollider(obj, finalPoses[i]);
  154. }
  155. }
  156. if (PWBSettings.shortcuts.gravitySubtract1UnitFromSurfDist.Check()) AddHeight(-1f);
  157. else if (PWBSettings.shortcuts.gravityAdd1UnitToSurfDist.Check()) AddHeight(1f);
  158. else if (PWBSettings.shortcuts.gravitySubtract01UnitFromSurfDist.Check()) AddHeight(-0.1f);
  159. else if (PWBSettings.shortcuts.gravityAdd01UnitToSurfDist.Check()) AddHeight(0.1f);
  160. else if (PWBSettings.shortcuts.gravitySurfDist.Check())
  161. {
  162. var delta = Mathf.Sign(PWBSettings.shortcuts.gravitySurfDist.combination.delta)
  163. * GravityToolManager.surfaceDistanceSensitivity;
  164. GravityToolManager.settings.height = Mathf.Max((GravityToolManager.settings.height + delta * 0.5f)
  165. * (1f + delta * 0.02f), 0.05f);
  166. ToolProperties.RepainWindow();
  167. }
  168. if (Event.current.button == 1)
  169. {
  170. if (Event.current.type == EventType.MouseDown && Event.current.control)
  171. {
  172. _pinned = true;
  173. _pinMouse = Event.current.mousePosition;
  174. Event.current.Use();
  175. }
  176. }
  177. //GravityInfoText(sceneView, hit.point);
  178. }
  179. private static void GravityInfoText(UnityEditor.SceneView sceneView, Vector3 hitPoint)
  180. {
  181. if (!PWBCore.staticData.showInfoText) return;
  182. if (_paintStroke.Count == 0) return;
  183. var labelTexts = new string[]
  184. { $"{hitPoint.x.ToString("F2")}, {hitPoint.y.ToString("F2")}, {hitPoint.z.ToString("F2")}" };
  185. InfoText.Draw(sceneView, labelTexts);
  186. }
  187. private static void DrawGravityBrush(ref RaycastHit hit, Camera camera)
  188. {
  189. var settings = GravityToolManager.settings;
  190. PWBCore.UpdateTempCollidersIfHierarchyChanged();
  191. hit.point = SnapAndUpdateGridOrigin(hit.point, SnapManager.settings.snappingEnabled,
  192. true, true, false, Vector3.down);
  193. var tangent = GetTangent(Vector3.up);
  194. var bitangent = Vector3.Cross(hit.normal, tangent);
  195. if (settings.brushShape == BrushToolSettings.BrushShape.SQUARE)
  196. {
  197. DrawSquareIndicator(hit.point, hit.normal, settings.radius,
  198. settings.height, tangent, bitangent, Vector3.up, true, true, drawDropArea: true);
  199. }
  200. else
  201. {
  202. DrawCricleIndicator(hit.point, hit.normal,
  203. settings.brushShape == BrushToolBase.BrushShape.POINT ? 0.1f : settings.radius,
  204. settings.height, tangent, bitangent, Vector3.up, true, true, drawDropArea: true);
  205. }
  206. if (_gravityLinesMesh == null)
  207. {
  208. _gravityLinesMesh = new Mesh();
  209. _gravityLinesMesh.SetVertices(new Vector3[] { new Vector3(-1, -1, 0), new Vector3(1, -1, 0),
  210. new Vector3(1, 1, 0), new Vector3(-1, 1, 0) });
  211. _gravityLinesMesh.uv = new Vector2[] { new Vector2(1, 0), new Vector2(0, 0),
  212. new Vector2(0, 1), new Vector2(1, 1) };
  213. _gravityLinesMesh.SetTriangles(new int[] { 0, 1, 2, 0, 2, 3 }, 0);
  214. _gravityLinesMesh.RecalculateNormals();
  215. }
  216. if (_gravityLinesMaterial == null)
  217. _gravityLinesMaterial = new Material(Resources.Load<Material>("Materials/GravityLines"));
  218. var camEulerY = Mathf.Abs(Vector3.SignedAngle(Vector3.up, camera.transform.up, camera.transform.forward));
  219. var gravityLinesOpacity = 1f - Mathf.Min((camEulerY > 90f ? 180f - camEulerY : camEulerY) / 60f, 1f);
  220. _gravityLinesMaterial.SetFloat(OPACITY_PROP_ID, gravityLinesOpacity);
  221. var hitToCamXZ = camera.transform.position - hit.point;
  222. hitToCamXZ.y = 0f;
  223. var gravityLinesRotation = Quaternion.AngleAxis(camera.transform.eulerAngles.y, Vector3.up);
  224. var radius = settings.brushShape == BrushToolBase.BrushShape.POINT
  225. ? 0.5F : settings.radius;
  226. var gravityLinesMatrix = Matrix4x4.TRS(hit.point + new Vector3(0f, 3f * radius, 0f),
  227. gravityLinesRotation, new Vector3(0.5f, 2f, 1f) * radius);
  228. Graphics.DrawMesh(_gravityLinesMesh, gravityLinesMatrix, _gravityLinesMaterial, 0, camera);
  229. Transform surface = null;
  230. if (hit.collider != null) surface = hit.collider.transform;
  231. GravityStrokePreview(hit.point + new Vector3(0f, settings.height, 0f), tangent,
  232. bitangent, camera, surface);
  233. }
  234. private static void GravityStrokePreview(Vector3 center, Vector3 tangent,
  235. Vector3 bitangent, Camera camera, Transform surface)
  236. {
  237. _paintStroke.Clear();
  238. foreach (var strokeItem in BrushstrokeManager.brushstroke)
  239. {
  240. var prefab = strokeItem.settings.prefab;
  241. if (prefab == null) continue;
  242. var h = strokeItem.settings.bottomMagnitude;
  243. BrushSettings brushSettings = strokeItem.settings;
  244. if (GravityToolManager.settings.overwriteBrushProperties)
  245. brushSettings = GravityToolManager.settings.brushSettings;
  246. var strokePosition = TangentSpaceToWorld(tangent, bitangent,
  247. new Vector2(strokeItem.tangentPosition.x, strokeItem.tangentPosition.y));
  248. var itemPosition = strokePosition + center + new Vector3(0f, h * strokeItem.scaleMultiplier.y, 0f);
  249. var itemRotation = Quaternion.AngleAxis(_brushAngle, Vector3.up)
  250. * Quaternion.Euler(strokeItem.additionalAngle);
  251. if (GravityToolManager.settings.orientAlongBrushstroke)
  252. {
  253. itemRotation = Quaternion.LookRotation(_strokeDirection, Vector3.up);
  254. itemPosition = center + itemRotation * strokePosition;
  255. }
  256. itemPosition += itemRotation * brushSettings.localPositionOffset;
  257. var rootToWorld = Matrix4x4.TRS(itemPosition, itemRotation, strokeItem.scaleMultiplier)
  258. * Matrix4x4.Translate(-prefab.transform.position);
  259. var itemScale = Vector3.Scale(prefab.transform.localScale, strokeItem.scaleMultiplier);
  260. var layer = GravityToolManager.settings.overwritePrefabLayer
  261. ? GravityToolManager.settings.layer : prefab.layer;
  262. Transform parentTransform = GetParent(GravityToolManager.settings, prefab.name, false, surface);
  263. _paintStroke.Add(new PaintStrokeItem(prefab, itemPosition,
  264. itemRotation * Quaternion.Euler(prefab.transform.eulerAngles),
  265. itemScale, layer, parentTransform, surface, strokeItem.flipX, strokeItem.flipY));
  266. PreviewBrushItem(prefab, rootToWorld, layer, camera, false, false, strokeItem.flipX, strokeItem.flipY);
  267. }
  268. }
  269. private static Vector3 GetObjectHalfSize(Transform transform)
  270. {
  271. var size = new Vector3(0.1f, 0.1f, 0.1f);
  272. var childrenRenderer = transform.GetComponentsInChildren<Renderer>();
  273. foreach (var child in childrenRenderer) size = Vector3.Max(size, child.bounds.size);
  274. return size / 2f;
  275. }
  276. }
  277. #endregion
  278. }