123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258 |
- #if UNITY_EDITOR
- using UnityEngine;
- using System.Collections.Generic;
- namespace O3DWB
- {
- public class ObjectGrabSession
- {
- private enum State
- {
- Inactive = 0,
- Moving,
- Rotating,
- Scaling
- }
- private struct ObjectSurfaceInfo
- {
- public Plane SurfacePlane;
- public Vector3 SitPoint;
- }
- private State _state;
- private List<GameObject> _grabbedObjects;
- private Dictionary<GameObject, Vector3> _objectToPivotDir = new Dictionary<GameObject, Vector3>();
- private Dictionary<GameObject, ObjectSurfaceInfo> _objectToSurfaceInfo = new Dictionary<GameObject, ObjectSurfaceInfo>();
- private Dictionary<GameObject, Vector3> _objectToWorldScale = new Dictionary<GameObject, Vector3>();
- private Vector2 _cursorPosAtScaleBegin;
- private ObjectMask _rayHitMask = new ObjectMask();
- private MouseCursorRayHit _currentCursorRayHit;
- private Vector3 _surfaceHitPoint;
- private ObjectGrabSettings _grabSettings;
- public bool IsActive { get { return _state != State.Inactive; } }
- public ObjectGrabSettings Settings { set { if (value != null) _grabSettings = value; } }
- public void Begin(List<GameObject> grabbedObjects)
- {
- if (_grabSettings == null || grabbedObjects == null || grabbedObjects.Count == 0 || IsActive) return;
- _grabbedObjects = Octave3DWorldBuilder.ActiveInstance.GetRoots(grabbedObjects);
- foreach(var grabbedObj in _grabbedObjects) _rayHitMask.ObjectCollectionMask.Mask(grabbedObj.GetAllChildrenIncludingSelf());
- MouseCursorRayHit cursorRayHit = GetCursorRayHit();
- if (!cursorRayHit.WasAnythingHit) return;
- _surfaceHitPoint = cursorRayHit.WasAnObjectHit ? cursorRayHit.ClosestObjectRayHit.HitPoint : cursorRayHit.GridCellRayHit.HitPoint;
- _state = State.Moving;
- foreach(var grabbedObject in _grabbedObjects)
- {
- if(grabbedObject != null)
- {
- _objectToPivotDir.Add(grabbedObject, grabbedObject.transform.position - _surfaceHitPoint);
- }
- }
- }
- public void End()
- {
- _state = State.Inactive;
- if (_grabbedObjects != null) _grabbedObjects.Clear();
- _rayHitMask.ObjectCollectionMask.UnmaskAll();
- _objectToPivotDir.Clear();
- _objectToSurfaceInfo.Clear();
- _objectToWorldScale.Clear();
- }
- public void RenderGizmos()
- {
- if(IsActive && _grabSettings.ShowGrabLines)
- {
- foreach(var grabbedObject in _grabbedObjects)
- {
- GizmosEx.RenderLine(grabbedObject.GetHierarchyWorldOrientedBox().Center, _surfaceHitPoint, _grabSettings.GrabLineColor);
- }
- }
- }
- public void Update()
- {
- if(IsActive)
- {
- if (AllShortcutCombos.Instance.GrabRotateSelection.IsActive()) _state = State.Rotating;
- else if (AllShortcutCombos.Instance.GrabScaleSelection.IsActive())
- {
- if(_state != State.Scaling)
- {
- _objectToWorldScale.Clear();
- foreach (var grabbedObject in _grabbedObjects)
- {
- if (grabbedObject != null)
- {
- _objectToWorldScale.Add(grabbedObject, grabbedObject.transform.lossyScale);
- }
- }
- _cursorPosAtScaleBegin = MouseCursor.Instance.Position;
- _state = State.Scaling;
- }
- }
- else
- {
- // Need to reset the anchor relationships because the cursor was moved without
- // the objects following it.
- if (_state == State.Rotating || _state == State.Scaling)
- {
- _objectToPivotDir.Clear();
- foreach (var grabbedObject in _grabbedObjects)
- {
- if (grabbedObject != null)
- {
- _objectToPivotDir.Add(grabbedObject, grabbedObject.transform.position - _surfaceHitPoint);
- }
- }
- }
- _state = State.Moving;
- }
- _currentCursorRayHit = GetCursorRayHit();
- if (!_currentCursorRayHit.WasAnythingHit) return;
- if(_currentCursorRayHit.WasAnythingHit)
- {
- if (_currentCursorRayHit.WasAnObjectHit) _surfaceHitPoint = _currentCursorRayHit.ClosestObjectRayHit.HitPoint;
- else _surfaceHitPoint = _currentCursorRayHit.GridCellRayHit.HitPoint;
- }
- if (_state == State.Moving || _objectToSurfaceInfo.Count == 0)
- {
- if (_currentCursorRayHit.WasAnObjectHit)
- {
- GameObjectExtensions.RecordObjectTransformsForUndo(_grabbedObjects);
- GameObjectRayHit objectRayHit = _currentCursorRayHit.ClosestObjectRayHit;
- foreach (var grabbedObject in _grabbedObjects)
- {
- if (grabbedObject == null) continue;
- Transform objectTransform = grabbedObject.transform;
- objectTransform.position = objectRayHit.HitPoint + _objectToPivotDir[grabbedObject];
- if (objectRayHit.WasTerrainHit)
- {
- Ray ray = new Ray(grabbedObject.GetHierarchyWorldOrientedBox().Center + Vector3.up, -Vector3.up);
- GameObjectRayHit sitPointHit = null;
- if (objectRayHit.HitObject.RaycastTerrainReverseIfFail(ray, out sitPointHit))
- {
- Plane surfacePlane = new Plane(sitPointHit.HitNormal, sitPointHit.HitPoint);
- if (_grabSettings.AlignAxis) AxisAlignment.AlignObjectAxis(grabbedObject, _grabSettings.AlignmentAxis, sitPointHit.HitNormal);
- grabbedObject.PlaceHierarchyOnPlane(surfacePlane);
- if (!_grabSettings.EmbedInSurfaceWhenNoAlign || _grabSettings.AlignAxis) objectTransform.position += _grabSettings.OffsetFromSurface * sitPointHit.HitNormal;
- if (_grabSettings.EmbedInSurfaceWhenNoAlign && !_grabSettings.AlignAxis) grabbedObject.EmbedInSurfaceByVertex(-Vector3.up, objectRayHit.HitObject);
- ObjectSurfaceInfo surfaceInfo = new ObjectSurfaceInfo();
- surfaceInfo.SurfacePlane = surfacePlane;
- surfaceInfo.SitPoint = sitPointHit.HitPoint;
- SetObjectSurfaceInfo(grabbedObject, surfaceInfo);
- }
- }
- else
- if (objectRayHit.WasMeshHit)
- {
- Ray ray = new Ray(grabbedObject.GetHierarchyWorldOrientedBox().Center + objectRayHit.HitNormal * 2.0f, -objectRayHit.HitNormal);
- GameObjectRayHit sitPointHit = null;
- if (objectRayHit.HitObject.RaycastMeshReverseIfFail(ray, out sitPointHit))
- {
- Plane surfacePlane = new Plane(sitPointHit.HitNormal, sitPointHit.HitPoint);
- if (_grabSettings.AlignAxis) AxisAlignment.AlignObjectAxis(grabbedObject, _grabSettings.AlignmentAxis, sitPointHit.HitNormal);
- grabbedObject.PlaceHierarchyOnPlane(surfacePlane);
- if (!_grabSettings.EmbedInSurfaceWhenNoAlign || _grabSettings.AlignAxis) objectTransform.position += _grabSettings.OffsetFromSurface * sitPointHit.HitNormal;
- if (_grabSettings.EmbedInSurfaceWhenNoAlign && !_grabSettings.AlignAxis) grabbedObject.EmbedInSurfaceByVertex(-sitPointHit.HitNormal, objectRayHit.HitObject);
- ObjectSurfaceInfo surfaceInfo = new ObjectSurfaceInfo();
- surfaceInfo.SurfacePlane = surfacePlane;
- surfaceInfo.SitPoint = sitPointHit.HitPoint;
- SetObjectSurfaceInfo(grabbedObject, surfaceInfo);
- }
- }
- }
- }
- else
- if (_currentCursorRayHit.WasACellHit)
- {
- GameObjectExtensions.RecordObjectTransformsForUndo(_grabbedObjects);
- GridCellRayHit cellRayHit = _currentCursorRayHit.GridCellRayHit;
- foreach (var grabbedObject in _grabbedObjects)
- {
- if (grabbedObject == null) continue;
- Transform objectTransform = grabbedObject.transform;
- objectTransform.position = cellRayHit.HitPoint + _objectToPivotDir[grabbedObject];
- Plane surfacePlane = new Plane(cellRayHit.HitNormal, cellRayHit.HitPoint);
- Vector3 sitPoint = surfacePlane.ProjectPoint(grabbedObject.GetWorldOrientedBox().Center);
- if (_grabSettings.AlignAxis) AxisAlignment.AlignObjectAxis(grabbedObject, _grabSettings.AlignmentAxis, cellRayHit.HitNormal);
- grabbedObject.PlaceHierarchyOnPlane(surfacePlane);
- if (!_grabSettings.EmbedInSurfaceWhenNoAlign || _grabSettings.AlignAxis) objectTransform.position += _grabSettings.OffsetFromSurface * cellRayHit.HitNormal;
- ObjectSurfaceInfo surfaceInfo = new ObjectSurfaceInfo();
- surfaceInfo.SurfacePlane = surfacePlane;
- surfaceInfo.SitPoint = sitPoint;
- SetObjectSurfaceInfo(grabbedObject, surfaceInfo);
- }
- }
- }
- else
- if (_state == State.Rotating)
- {
- GameObjectExtensions.RecordObjectTransformsForUndo(_grabbedObjects);
- float rotationSensitivity = _grabSettings.RotationSensitivity;
- foreach (var grabbedObject in _grabbedObjects)
- {
- if (!_objectToSurfaceInfo.ContainsKey(grabbedObject)) continue;
- var surfaceInfo = _objectToSurfaceInfo[grabbedObject];
- OrientedBox worldOOBB = grabbedObject.GetHierarchyWorldOrientedBox();
- grabbedObject.RotateHierarchyBoxAroundPoint(MouseCursor.Instance.OffsetSinceLastMouseMove.x * rotationSensitivity, _grabSettings.AlignAxis ? surfaceInfo.SurfacePlane.normal : Vector3.up, worldOOBB.Center);
- }
- }
- else
- if(_state == State.Scaling)
- {
- GameObjectExtensions.RecordObjectTransformsForUndo(_grabbedObjects);
- Vector2 currentCursorPos = MouseCursor.Instance.Position;
- Vector2 cursorOffsetFromScaleBegin = currentCursorPos - _cursorPosAtScaleBegin;
- float scaleFactor = 1.0f + _grabSettings.ScaleSensitivity * cursorOffsetFromScaleBegin.x;
- foreach (var grabbedObject in _grabbedObjects)
- {
- if (!_objectToSurfaceInfo.ContainsKey(grabbedObject) ||
- !_objectToWorldScale.ContainsKey(grabbedObject)) continue;
- var surfaceInfo = _objectToSurfaceInfo[grabbedObject];
- grabbedObject.SetHierarchyWorldScaleByPivotPoint(_objectToWorldScale[grabbedObject] * scaleFactor, surfaceInfo.SitPoint);
- }
- }
- }
- }
- private void SetObjectSurfaceInfo(GameObject gameObject, ObjectSurfaceInfo surfaceInfo)
- {
- if (gameObject == null) return;
- if (_objectToSurfaceInfo.ContainsKey(gameObject)) _objectToSurfaceInfo[gameObject] = surfaceInfo;
- else _objectToSurfaceInfo.Add(gameObject, surfaceInfo);
- }
- private MouseCursorRayHit GetCursorRayHit()
- {
- MouseCursor.Instance.PushObjectPickMaskFlags(MouseCursorObjectPickFlags.ObjectBox | MouseCursorObjectPickFlags.ObjectSprite);
- MouseCursor.Instance.PushObjectMask(_rayHitMask);
- MouseCursorRayHit cursorRayHit = MouseCursor.Instance.GetRayHit();
- MouseCursor.Instance.PopObjectPickMaskFlags();
- MouseCursor.Instance.PopObjectMask();
- return cursorRayHit;
- }
- }
- }
- #endif
|