From 673efeba58b6a5ff4b27cbb15c6c57605ad38b6d Mon Sep 17 00:00:00 2001 From: spatialfree Date: Sun, 2 Oct 2022 08:36:20 -0400 Subject: [PATCH] init thumb trackballer --- app/Mono.cs | 13 +- app/PullRequest.cs | 30 +++- .../stretch-cursor/finger/StretchFinger.cs | 12 -- app/dofs/stretch-cursor/og/StretchCursor.cs | 114 +-------------- app/dofs/stretch-cursor/wave/WaveCursor.cs | 133 ++++++++++++++++++ app/dofs/stretch-cursor/{finger => wave}/⧉ | 0 app/dofs/trackballer/Trackballer.cs | 112 +++------------ 7 files changed, 189 insertions(+), 225 deletions(-) delete mode 100644 app/dofs/stretch-cursor/finger/StretchFinger.cs create mode 100644 app/dofs/stretch-cursor/wave/WaveCursor.cs rename app/dofs/stretch-cursor/{finger => wave}/⧉ (100%) diff --git a/app/Mono.cs b/app/Mono.cs index 3c929e0..2bb2e3e 100644 --- a/app/Mono.cs +++ b/app/Mono.cs @@ -42,9 +42,11 @@ public class Mono { dofs = new dof[] { // new StretchFinger(), - // new Trackballer(rGlove.virtualGlove, anchor), - new StretchCursor() { handId = 0, deadzone = 0.01f, strength = 3f }, // can override design variables - new StretchCursor() { handId = 1, deadzone = 0.01f, strength = 3f }, // can override design variables + // new Trackballer(), + new WaveCursor() { handId = 0, deadzone = 0.01f, strength = 3f }, + new WaveCursor() { handId = 1, deadzone = 0.01f, strength = 3f }, + // new StretchCursor() { deadzone = 0.01f, strength = 3f }, + // new StretchCursor() { deadzone = 0.01f, strength = 3f }, }; } Pose anchor = Pose.Identity; @@ -77,6 +79,11 @@ public class Mono { // ------------------------------------------------- + // THE BACK BREAKING PROBLEM WITH THE CURRENT DOF SYSTEM + // is that I can't pass input to it in a dynamic way + // a pointer would solve this problem but c# doesn't have pointers + // except for unsafe code, which opens up a whole new can of worms + // dof.Frame(); dofs[0].Frame(); dofs[1].Frame(); diff --git a/app/PullRequest.cs b/app/PullRequest.cs index 3ed1e84..c0363ba 100644 --- a/app/PullRequest.cs +++ b/app/PullRequest.cs @@ -49,15 +49,31 @@ public static class PullRequest { } } - public static void LookDirection(this ref Quat q, Vec3 dir) { - Vec3 up = Vec3.Up; - - // using AxisAngle - Vec3 axis = Vec3.Cross(up, dir); - float angle = MathF.Atan2(Vec3.Dot(up, dir), axis.Length); - q = FromAxisAngle(axis.Normalized, angle); + // construct the quaternion that rotates one vector to another + // uses the usual trick to get the half angle + public static Quat Delta(Vec3 to, Vec3 from) { + Vec3 vec = Vec3.Cross(from, to); + return new Quat( + vec.x, + vec.y, + vec.z, + 1 + Vec3.Dot(to, from ) + ).Normalized; } + public static Quat Relative(Quat to, Quat delta) { + return (to * delta * to.Inverse).Normalized; + } + + // public static void LookDirection(this ref Quat q, Vec3 dir) { + // Vec3 up = Vec3.Up; + + // // using AxisAngle + // Vec3 axis = Vec3.Cross(up, dir); + // float angle = MathF.Atan2(Vec3.Dot(up, dir), axis.Length); + // q = FromAxisAngle(axis.Normalized, angle); + // } + public static Quat FromAxisAngle(Vec3 axis, float angle) { float halfAngle = angle * 0.5f; float sin = (float)Math.Sin(halfAngle); diff --git a/app/dofs/stretch-cursor/finger/StretchFinger.cs b/app/dofs/stretch-cursor/finger/StretchFinger.cs deleted file mode 100644 index 84aa2ba..0000000 --- a/app/dofs/stretch-cursor/finger/StretchFinger.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace Oriels; - -class StretchFinger : dof { - // Pose p0, p1 - public void Init() { - - } - - public void Frame() { - - } -} \ No newline at end of file diff --git a/app/dofs/stretch-cursor/og/StretchCursor.cs b/app/dofs/stretch-cursor/og/StretchCursor.cs index b56a8f0..a980071 100644 --- a/app/dofs/stretch-cursor/og/StretchCursor.cs +++ b/app/dofs/stretch-cursor/og/StretchCursor.cs @@ -11,122 +11,18 @@ class StretchCursor : dof { } - bool isTracking = false; public void Frame() { - Hand hand = Input.Hand(handId); + Vec3 vec = p0.position - p1.position; + float len = vec.Length; + float stretch = Math.Max(len - deadzone, 0f); + Vec3 dir = backhand ? vec / len : p0.orientation * Vec3.Forward; - if (hand.tracked.IsActive() && !hand.tracked.IsJustActive()) { - p0.position = hand.Get(FingerId.Index, JointId.KnuckleMajor).position; - p1.position = hand.Get(FingerId.Index, JointId.Tip).position; - - isTracking = true; - } - - - // Vec3 vec = p0.position - p1.position; - // float len = vec.Length; - // float stretch = Math.Max(len - deadzone, 0f); - // Vec3 dir = backhand ? vec / len : p0.orientation * Vec3.Forward; - - - - float fI = Flexion(hand, FingerId.Index); - float fM = Flexion(hand, FingerId.Middle); - float fR = Flexion(hand, FingerId.Ring); - float fL = Flexion(hand, FingerId.Little); - - float stretch = (fI + fI + fM + fM + fM + fR + fR + fL) / 8f; // based on finger length - - Vec3 dir = PullRequest.Direction( - hand.Get(FingerId.Index, JointId.Tip).position, - hand.Get(FingerId.Index, JointId.KnuckleMajor).position - ); - - cursor.position = hand.Get(FingerId.Index, JointId.Tip).position + dir * stretch * strength * Mono.inst.stretchStr; + cursor.position = p0.position + dir * stretch * strength; // * Mono.inst.stretchStr; Mesh.Cube.Draw(Material.Default, Matrix.TS(cursor.position, 0.01f)); - - - - // thumb trackballer - float d = Vec3.Distance( - hand.Get(FingerId.Index, JointId.KnuckleMid).position, - hand.Get(FingerId.Index, JointId.KnuckleMajor).position - ); - Vec3 anchor = hand.Get(FingerId.Index, JointId.KnuckleMajor).position; - anchor = anchor + hand.palm.orientation * Vec3.Forward * d; - Mesh.Cube.Draw(Material.Default, Matrix.TS(anchor, 0.01f)); - - - - - if (isTracking) { Demo(); } } public bool backhand = true; public float deadzone = 0.1f; public float strength = 3f; - public int handId = 0; - - - float Flexion(Hand hand, FingerId finger) { - float flexion = (Vec3.Dot( - PullRequest.Direction( - hand.Get(finger, JointId.Tip).position, - hand.Get(finger, JointId.KnuckleMinor).position - ), - PullRequest.Direction( - hand.Get(finger, JointId.KnuckleMid).position, - hand.Get(finger, JointId.KnuckleMajor).position - ) - ) + 1f) / 2; - - return Math.Max(flexion - deadzone, 0f) / (1 - deadzone); - } - - - - - - - - - - - - Vec3 smoothPos; - Vec3[] points = new Vec3[64]; - void Demo() { - - smoothPos = Vec3.Lerp(smoothPos, cursor.position, Time.Elapsedf * 6f); - - // while (Vec3.Distance(points[0], smoothPos) > 0.03f) { - // for (int i = points.Length - 1; i > 0; i--) { - // points[i] = points[i - 1]; - // } - // points[0] += PullRequest.Direction(smoothPos, points[0]) * 0.02f; - // } - - - points[0] = smoothPos; - - int len = (int)(points.Length * Mono.inst.trailLen); - for (int i = 0; i < len; i++) { - if (i > 0) { - Vec3 dir = Vec3.Forward; - if (points[i].v != points[i - 1].v) { - dir = PullRequest.Direction(points[i], points[i - 1]); - } - points[i] = points[i - 1] + dir * 0.02f * Mono.inst.trailScl; - } - - Vec3 from = i > 0 ? points[i - 1] : smoothPos; - - Mesh.Cube.Draw( - Material.Default, - Matrix.TRS(points[i], Quat.LookDir(PullRequest.Direction(points[i], from)), 0.01f * Mono.inst.trailScl), - Color.HSV(i / (float)len, 1, 1) - ); - } - } } diff --git a/app/dofs/stretch-cursor/wave/WaveCursor.cs b/app/dofs/stretch-cursor/wave/WaveCursor.cs new file mode 100644 index 0000000..9956518 --- /dev/null +++ b/app/dofs/stretch-cursor/wave/WaveCursor.cs @@ -0,0 +1,133 @@ +namespace Oriels; + +class WaveCursor : dof { + public WaveCursor() { + + } + + Vec3 oldLocalPad; + public Pose cursor = Pose.Identity; + public void Init() { + + } + + bool isTracking = false; + public void Frame() { + Hand hand = Input.Hand(handId); + + if (hand.tracked.IsActive() && !hand.tracked.IsJustActive()) { + // p0.position = hand.Get(FingerId.Index, JointId.KnuckleMajor).position; + // p1.position = hand.Get(FingerId.Index, JointId.Tip).position; + + isTracking = true; + } + + float fI = Flexion(hand, FingerId.Index); + float fM = Flexion(hand, FingerId.Middle); + float fR = Flexion(hand, FingerId.Ring); + float fL = Flexion(hand, FingerId.Little); + + float stretch = (fI + fI + fM + fM + fM + fR + fR + fL) / 8f; // based on finger length + + Vec3 dir = PullRequest.Direction( + hand.Get(FingerId.Index, JointId.Tip).position, + hand.Get(FingerId.Index, JointId.KnuckleMajor).position + ); + + cursor.position = hand.Get(FingerId.Index, JointId.Tip).position + dir * stretch * strength * Mono.inst.stretchStr; + + + // thumb trackballer + float d = Vec3.Distance( + hand.Get(FingerId.Index, JointId.KnuckleMid).position, + hand.Get(FingerId.Index, JointId.KnuckleMajor).position + ); + Vec3 anchor = hand.Get(FingerId.Index, JointId.KnuckleMajor).position; + anchor = anchor + hand.palm.orientation * Vec3.Forward * d; + Matrix mAnchor = Matrix.TR(anchor, hand.palm.orientation); + Matrix mAnchorInv = mAnchor.Inverse; + + + Vec3 pad = Vec3.Lerp( + hand.Get(FingerId.Thumb, JointId.Tip).position, + hand.Get(FingerId.Thumb, JointId.KnuckleMinor).position, + 0.5f + ); + Color color = Color.White; + if (Vec3.Distance(pad, anchor) < 0.02f) { + color = new Color(1, 0, 0); + } + + Vec3 localPad = mAnchorInv.Transform(pad); + if (Vec3.Distance(pad, anchor) < 0.04f && Time.Totalf > 3f) { // localPad.Length < 0.04f + cursor.orientation = PullRequest.Relative( + hand.palm.orientation, + PullRequest.Delta(localPad.Normalized, oldLocalPad.Normalized) + ) * cursor.orientation; + } + // Lines.Add( + // mAnchor.Transform(padIn), + // mAnchor.Transform(padOut), + // new Color(1, 1, 1), 0.004f + // ); + + + + oldLocalPad = localPad; + + + + Mesh.Sphere.Draw(Material.Default, Matrix.TS(anchor, 0.02f), color); + Mesh.Cube.Draw(Material.Default, Matrix.TRS(anchor, cursor.orientation, 0.02f)); + + + if (isTracking) { Demo(); } + } + + public bool backhand = true; + public float deadzone = 0.1f; + public float strength = 3f; + public int handId = 0; + + + float Flexion(Hand hand, FingerId finger) { + float flexion = (Vec3.Dot( + PullRequest.Direction( + hand.Get(finger, JointId.Tip).position, + hand.Get(finger, JointId.KnuckleMinor).position + ), + PullRequest.Direction( + hand.Get(finger, JointId.KnuckleMid).position, + hand.Get(finger, JointId.KnuckleMajor).position + ) + ) + 1f) / 2; + + return Math.Max(flexion - deadzone, 0f) / (1 - deadzone); + } + + + Vec3 smoothPos; + Vec3[] points = new Vec3[64]; + void Demo() { + points[0] = smoothPos = Vec3.Lerp(smoothPos, cursor.position, Time.Elapsedf * 6f); + + int len = (int)(points.Length * Mono.inst.trailLen); + for (int i = 0; i < len; i++) { + if (i > 0) { + Vec3 dir = Vec3.Forward; + if (points[i].v != points[i - 1].v) { + dir = PullRequest.Direction(points[i], points[i - 1]); + } + points[i] = points[i - 1] + dir * 0.02f * Mono.inst.trailScl; + } + + Vec3 from = i > 0 ? points[i - 1] : smoothPos; + + Mesh.Cube.Draw( + Material.Default, + Matrix.TRS(points[i], Quat.LookDir(PullRequest.Direction(points[i], from)), 0.01f * Mono.inst.trailScl), + Color.HSV(i / (float)len, 1, 1) + ); + } + } +} \ No newline at end of file diff --git a/app/dofs/stretch-cursor/finger/⧉ b/app/dofs/stretch-cursor/wave/⧉ similarity index 100% rename from app/dofs/stretch-cursor/finger/⧉ rename to app/dofs/stretch-cursor/wave/⧉ diff --git a/app/dofs/trackballer/Trackballer.cs b/app/dofs/trackballer/Trackballer.cs index 560e0a7..a1466ad 100644 --- a/app/dofs/trackballer/Trackballer.cs +++ b/app/dofs/trackballer/Trackballer.cs @@ -1,109 +1,34 @@ namespace Oriels; class Trackballer : dof { - public Pose p0, anchor = Pose.Identity; - public Trackballer(Pose p0, Pose anchor) { - this.p0 = p0; - this.anchor = anchor; - } + Pose anchor = Pose.Identity; + Quat ori = Quat.Identity; + Quat qDelta = Quat.Identity; + Vec2 oldMouse; - - Vec3 pos = new Vec3(0, 0, -1); - Vec3 vel = new Vec3(0, 0, 0); - - - public Quat ori = Quat.Identity; public void Init() { } - // Vec3 pos, oldPos; - Quat qDelta = Quat.Identity; public void Frame() { - p0 = Mono.inst.rGlove.virtualGlove; - - // Vec3 vA = PullRequest.Direction(oldPos, anchor.position); - // Vec3 vB = PullRequest.Direction(p0.position, anchor.position); - - // if (Vec3.Distance(p0.position, oldPos) > 0.2f) { // (p0.position.v != oldPos.v) { - // // Vec3 delta = (p0.position - oldPos); - // float angle = Vec3.AngleBetween(vA, vB); - // Console.WriteLine("angle: " + angle); - // if (angle > 1f) { - // Vec3 v = PullRequest.Slerp(vA, vB, 1 / angle).Normalized; - // // Vec3 delta -> Quat delta - // Quat a = Quat.LookDir(vA).Normalized; - // Quat b = Quat.LookDir(v).Normalized; - // // when converting from vec to quat, the up axis can get flipped causing issues with reliably scaling the qDelta by vector angle - - - // qDelta = Quat.Difference(a, b).Normalized; - - // // qDelta scaled to one degree - // // qDelta = Quat.Slerp(Quat.Identity, qDelta, 1 / angle).Normalized; - - // // ori = Quat.Slerp(Quat.Identity, Quat.FromAngles(1, 0, 0), 6 * Time.Elapsedf) * ori; - - // // and use the velocity magnitude - // float test = MathF.Tau * 0.05f; - // } - - // oldPos = p0.position; - // } - // ori = Quat.Slerp(Quat.Identity, qDelta, 60 * Time.Elapsedf).Normalized * ori; - // ori.Normalize(); - - - - - - - // Vec3 newPos = pos + vel * Time.Elapsedf; - // if (newPos.v != pos) { - // newPos = PullRequest.Direction(newPos, anchor.position).Normalized * 1f; - // vel = PullRequest.Direction(newPos, pos) * vel.Length; - // pos = newPos; - // } - - if (Input.Key(Key.Space).IsJustActive()) { - fromMouse = Input.Mouse.pos; - } - - if (Input.Key(Key.Space).IsJustInactive()) { - Vec2 delta = (Input.Mouse.pos - fromMouse) / 32f; - vel = new Vec3(delta.x, -delta.y, 0); - - pos = new Vec3(0, 0, 1); - // ori = (Quat.LookDir(pos).Normalized * ori).Normalized; - } - - // ori.LookDirection(pos); - - // ori = Quat.FromAngles(0, MathF.Sin(Time.Totalf) * 180, 0); - // float angle; Vec3 axis; - // ori.ToAxisAngle(out axis, out angle); - // ori = PullRequest.FromAxisAngle(axis, angle); - - - - - - // pivot to just Quat.FromAngles(x, 0, 0) * Quat.FromAngles(0, y, 0) for the delta - Quat qDelta = ( - Quat.FromAngles(-vel.y * 60 * Time.Elapsedf, 0, 0) - * Quat.FromAngles(0, vel.x * 60 * Time.Elapsedf, 0) - // * Quat.FromAngles(0, 0, -vel.z * 60 * Time.Elapsedf) - ); // apply the qDelta to the current orientation relative to the head orientation - Quat headOri = Input.Head.orientation; - ori = (headOri * qDelta * headOri.Inverse * ori).Normalized; - // ori = qDelta * ori; + // Quat headOri = Input.Head.orientation; + // ori = (headOri * qDelta * headOri.Inverse * ori).Normalized; + // PullRequest.Relative(headOri, qDelta) * ori; - - + Vec2 mouse = Input.Mouse.pos; + mouse = new Vec2( + (mouse.x / 1280 * 2) - 1f, + (mouse.y / 720 * 2) - 1f + ) * 4f; + ori = PullRequest.Delta( + new Vec3(mouse.x, mouse.y, 1).Normalized, + new Vec3(oldMouse.x, oldMouse.y, 1).Normalized + ) * ori; + + oldMouse = mouse; - // Lines.Add(anchor.position, pos, new Color(1, 0, 0), 0.01f); Lines.Add( anchor.position - ori * new Vec3(-1, 0, 0) * 0.1f, @@ -121,7 +46,6 @@ class Trackballer : dof { new Color(0, 0, 1), 0.002f ); Mesh.Cube.Draw(Material.Default, Matrix.TRS(anchor.position, ori, 0.04f)); - // Mesh.Cube.Draw(Material.Default, Matrix.TS(p0.position, new Vec3(0.04f, 0.01f, 0.04f))); } Vec2 fromMouse = new Vec2(0, 0);