@@ -40,6 +40,8 @@ private struct PoseSample
4040 public abstract bool isGrabbed { get ; }
4141 public abstract bool isChangingGrabber { get ; }
4242 public abstract GrabberBase currentGrabberBase { get ; }
43+ public abstract float minScaleOnStretch { get ; set ; }
44+ public abstract float maxScaleOnStretch { get ; set ; }
4345 public Rigidbody grabRigidbody { get ; protected set ; }
4446
4547 private Queue < PoseSample > m_poseSamples = new Queue < PoseSample > ( ) ;
@@ -63,32 +65,6 @@ protected void RecordLatestPosesForDrop(float currentTime, float recordLength)
6365 } ) ;
6466 }
6567
66- protected virtual void OnGrabRigidbody ( )
67- {
68- var currentGrabber = currentGrabberBase ;
69- var targetPose = currentGrabber . grabberOrigin * currentGrabber . grabOffset ;
70- ModifyPose ( ref targetPose , true ) ;
71-
72- RigidPose . SetRigidbodyVelocity ( grabRigidbody , grabRigidbody . position , targetPose . pos , followingDuration ) ;
73- RigidPose . SetRigidbodyAngularVelocity ( grabRigidbody , grabRigidbody . rotation , targetPose . rot , followingDuration , overrideMaxAngularVelocity ) ;
74- }
75-
76- protected virtual void OnGrabTransform ( )
77- {
78- var currentGrabber = currentGrabberBase ;
79- var targetPose = currentGrabber . grabberOrigin * currentGrabber . grabOffset ;
80- ModifyPose ( ref targetPose , true ) ;
81-
82- if ( grabRigidbody != null )
83- {
84- grabRigidbody . velocity = Vector3 . zero ;
85- grabRigidbody . angularVelocity = Vector3 . zero ;
86- }
87-
88- transform . position = targetPose . pos ;
89- transform . rotation = targetPose . rot ;
90- }
91-
9268 protected virtual void DoDrop ( )
9369 {
9470 if ( grabRigidbody != null && ! grabRigidbody . isKinematic && m_poseSamples . Count > 0 )
@@ -102,6 +78,82 @@ protected virtual void DoDrop()
10278 m_poseSamples . Clear ( ) ;
10379 }
10480 }
81+
82+ protected abstract void OnGrabRigidbody ( ) ;
83+
84+ protected abstract void OnGrabTransform ( ) ;
85+
86+ public struct StretchAnchors
87+ {
88+ // A1: first anchor
89+ // A2: second anchor
90+ // C: strethable center
91+ // P: closest point on line A1-A2 away from C
92+ private Vector3 originScale ;
93+ private float A1A2Len ;
94+ private float A1PLen ;
95+ private float PCLen ;
96+ private Quaternion originRotOffset ;
97+ private Quaternion lastRot ;
98+
99+ public void SetupStartingAnchors ( Vector3 anchor1 , Vector3 anchor2 , Vector3 originPos , Quaternion originRot , Vector3 originScale )
100+ {
101+ // FIXME: what if anchor1 == anchor2?
102+ this . originScale = originScale ;
103+
104+ var vectorS1S2 = anchor2 - anchor1 ;
105+ A1A2Len = Vector3 . Magnitude ( vectorS1S2 ) ;
106+
107+ var vectorS1C = originPos - anchor1 ;
108+ A1PLen = Vector3 . Dot ( vectorS1C , vectorS1S2 ) / A1A2Len ;
109+ PCLen = Mathf . Sqrt ( vectorS1C . sqrMagnitude - A1PLen * A1PLen ) ;
110+
111+ var normal = Vector3 . Cross ( vectorS1S2 , vectorS1C ) ;
112+ var rot = Quaternion . LookRotation ( vectorS1S2 , normal ) ;
113+ originRotOffset = Quaternion . Inverse ( rot ) * originRot ;
114+
115+ lastRot = rot ;
116+ }
117+
118+ public void UpdateAnchors ( Vector3 anchor1 , Vector3 anchor2 , out Vector3 newPos , out Quaternion newRot , out Vector3 newScale , float minScale , float maxScale )
119+ {
120+ // determin scale ratio
121+ var vectorS1S2 = anchor2 - anchor1 ;
122+ var vectorS1S2Len = vectorS1S2 . magnitude ;
123+ var vectorS1S2Norm = vectorS1S2 / vectorS1S2Len ;
124+ var posScale = vectorS1S2Len / A1A2Len ;
125+
126+ lastRot = Quaternion . FromToRotation ( lastRot * Vector3 . forward , vectorS1S2Norm ) * lastRot ;
127+ var tangent = lastRot * Vector3 . right ;
128+
129+ var transformScale = 1f ;
130+ minScale = Mathf . Abs ( minScale ) ;
131+ maxScale = Mathf . Abs ( maxScale ) ;
132+ if ( minScale < maxScale )
133+ {
134+ // FIXME: what if originScale have zero value?
135+ var originScaleAbs = new Vector3 ( Mathf . Abs ( originScale . x ) , Mathf . Abs ( originScale . y ) , Mathf . Abs ( originScale . z ) ) ;
136+ if ( originScaleAbs . x == originScaleAbs . y && originScaleAbs . y == originScaleAbs . z )
137+ {
138+ transformScale = Mathf . Clamp ( posScale , minScale / originScaleAbs . x , maxScale / originScaleAbs . x ) ;
139+ }
140+ else
141+ {
142+ // when scale is irregular, clamp the scale factor to make sure no scale value is out of min/max range
143+ var minScaleAxis = Mathf . Min ( originScaleAbs . x , originScaleAbs . y , originScaleAbs . z ) ;
144+ var maxScaleAxis = Mathf . Max ( originScaleAbs . x , originScaleAbs . y , originScaleAbs . z ) ;
145+ if ( minScaleAxis / maxScaleAxis >= minScale / maxScale )
146+ {
147+ transformScale = Mathf . Clamp ( posScale , minScale / minScaleAxis , maxScale / maxScaleAxis ) ;
148+ }
149+ }
150+ }
151+
152+ newPos = anchor1 + vectorS1S2Norm * A1PLen * posScale + tangent * PCLen * transformScale ;
153+ newRot = lastRot * originRotOffset ;
154+ newScale = originScale * transformScale ;
155+ }
156+ }
105157 }
106158
107159 public abstract class GrabbableBase < TEventData , TGrabber > : GrabbableBase where TGrabber : GrabberBase < TEventData > where TEventData : BaseEventData
@@ -119,6 +171,10 @@ public abstract class GrabbableBase<TEventData, TGrabber> : GrabbableBase where
119171 public event Action beforeGrabberReleased ; // get grabber that about to release here
120172 public event Action onGrabberDrop ; // manually change drop velocity here
121173
174+ private TGrabber anchorGabber1 ;
175+ private TGrabber anchorGabber2 ;
176+ private StretchAnchors stretchAnchors ;
177+
122178 protected bool IsGrabberExists ( TEventData eventData )
123179 {
124180 return m_grabbers . ContainsKey ( eventData ) ;
@@ -129,6 +185,35 @@ protected bool TryGetExistsGrabber(TEventData eventData, out TGrabber grabber)
129185 return m_grabbers . TryGetValue ( eventData , out grabber ) ;
130186 }
131187
188+ protected bool TryGetValidAnchors ( out TGrabber grabber1 , out TGrabber grabber2 , out Vector3 pose1 , out Vector3 pose2 )
189+ {
190+ var i = m_grabbers . Count - 1 ;
191+ if ( i >= 1 )
192+ {
193+ var g1 = m_grabbers . GetValueByIndex ( i ) ;
194+ var p1 = g1 . grabberOrigin . pos ;
195+ for ( -- i ; i >= 0 ; -- i )
196+ {
197+ var g2 = m_grabbers . GetValueByIndex ( i ) ;
198+ var p2 = g2 . grabberOrigin . pos ;
199+ if ( ! Mathf . Approximately ( ( p2 - p1 ) . magnitude , 0f ) )
200+ {
201+ grabber1 = g1 ;
202+ grabber2 = g2 ;
203+ pose1 = p1 ;
204+ pose2 = p2 ;
205+ return true ;
206+ }
207+ }
208+ }
209+
210+ grabber1 = default ( TGrabber ) ;
211+ grabber2 = default ( TGrabber ) ;
212+ pose1 = default ( Vector3 ) ;
213+ pose2 = default ( Vector3 ) ;
214+ return false ;
215+ }
216+
132217 protected abstract TGrabber CreateGrabber ( TEventData eventData ) ;
133218
134219 protected abstract void DestoryGrabber ( TGrabber grabber ) ;
@@ -146,6 +231,18 @@ protected bool AddGrabber(TEventData eventData)
146231
147232 if ( isGrabbed ) { beforeGrabberReleased ( ) ; }
148233 m_grabbers . Add ( eventData , newGrabber ) ;
234+
235+ Vector3 p1 , p2 ;
236+ if ( TryGetValidAnchors ( out anchorGabber1 , out anchorGabber2 , out p1 , out p2 ) )
237+ {
238+ stretchAnchors . SetupStartingAnchors (
239+ p1 ,
240+ p2 ,
241+ transform . position ,
242+ transform . rotation ,
243+ transform . localScale ) ;
244+ }
245+
149246 afterGrabberGrabbed ( ) ;
150247 return true ;
151248 }
@@ -177,6 +274,21 @@ protected bool RemoveGrabber(TEventData eventData)
177274 finally { ExitGrabberChangingLock ( ) ; }
178275 }
179276
277+ Vector3 p1 , p2 ;
278+ if ( TryGetValidAnchors ( out anchorGabber1 , out anchorGabber2 , out p1 , out p2 ) )
279+ {
280+ stretchAnchors . SetupStartingAnchors (
281+ p1 ,
282+ p2 ,
283+ transform . position ,
284+ transform . rotation ,
285+ transform . localScale ) ;
286+ }
287+ else if ( m_grabbers . Count > 0 )
288+ {
289+ currentGrabber . grabOffset = currentGrabber . grabberOrigin . GetInverse ( ) * new RigidPose ( transform ) ;
290+ }
291+
180292 return true ;
181293 }
182294
@@ -216,9 +328,83 @@ private void ExitGrabberChangingLock()
216328 {
217329 m_grabberChangingLock = false ;
218330 }
331+
332+ protected override void OnGrabRigidbody ( )
333+ {
334+ if ( anchorGabber1 != null && anchorGabber2 != null )
335+ {
336+ Vector3 pos ;
337+ Quaternion rot ;
338+ Vector3 scale ;
339+ stretchAnchors . UpdateAnchors (
340+ anchorGabber1 . grabberOrigin . pos ,
341+ anchorGabber2 . grabberOrigin . pos ,
342+ out pos ,
343+ out rot ,
344+ out scale ,
345+ minScaleOnStretch ,
346+ maxScaleOnStretch ) ;
347+
348+ GrabRigidbodyToPose ( new RigidPose ( pos , rot ) ) ;
349+ transform . localScale = scale ;
350+ }
351+ else
352+ {
353+ var currentGrabber = currentGrabberBase ;
354+ GrabRigidbodyToPose ( currentGrabber . grabberOrigin * currentGrabber . grabOffset ) ;
355+ }
356+ }
357+
358+ protected override void OnGrabTransform ( )
359+ {
360+ if ( anchorGabber1 != null && anchorGabber2 != null )
361+ {
362+ Vector3 pos ;
363+ Quaternion rot ;
364+ Vector3 scale ;
365+ stretchAnchors . UpdateAnchors (
366+ anchorGabber1 . grabberOrigin . pos ,
367+ anchorGabber2 . grabberOrigin . pos ,
368+ out pos ,
369+ out rot ,
370+ out scale ,
371+ minScaleOnStretch ,
372+ maxScaleOnStretch ) ;
373+
374+ GrabTransformToPose ( new RigidPose ( pos , rot ) ) ;
375+ transform . localScale = scale ;
376+ }
377+ else
378+ {
379+ var currentGrabber = currentGrabberBase ;
380+ GrabTransformToPose ( currentGrabber . grabberOrigin * currentGrabber . grabOffset ) ;
381+ }
382+ }
383+
384+ protected void GrabRigidbodyToPose ( RigidPose targetPose )
385+ {
386+ ModifyPose ( ref targetPose , true ) ;
387+
388+ RigidPose . SetRigidbodyVelocity ( grabRigidbody , grabRigidbody . position , targetPose . pos , followingDuration ) ;
389+ RigidPose . SetRigidbodyAngularVelocity ( grabRigidbody , grabRigidbody . rotation , targetPose . rot , followingDuration , overrideMaxAngularVelocity ) ;
390+ }
391+
392+ protected void GrabTransformToPose ( RigidPose targetPose )
393+ {
394+ ModifyPose ( ref targetPose , true ) ;
395+
396+ if ( grabRigidbody != null )
397+ {
398+ grabRigidbody . velocity = Vector3 . zero ;
399+ grabRigidbody . angularVelocity = Vector3 . zero ;
400+ }
401+
402+ transform . position = targetPose . pos ;
403+ transform . rotation = targetPose . rot ;
404+ }
219405 }
220406
221- [ Obsolete ( "Use GrabbableBase.Generic< TGrabber> instead" ) ]
407+ [ Obsolete ( "Use GrabbableBase<TEventData, TGrabber> instead" ) ]
222408 public abstract class GrabbableBase < TGrabber > : BasePoseTracker where TGrabber : class , GrabbableBase < TGrabber > . IGrabber
223409 {
224410 public const float MIN_FOLLOWING_DURATION = 0.02f ;
0 commit comments