init thumb trackballer

This commit is contained in:
spatialfree 2022-10-02 08:36:20 -04:00
parent 3291571152
commit 673efeba58
7 changed files with 189 additions and 225 deletions

View file

@ -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();

View file

@ -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);

View file

@ -1,12 +0,0 @@
namespace Oriels;
class StretchFinger : dof {
// Pose p0, p1
public void Init() {
}
public void Frame() {
}
}

View file

@ -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)
);
}
}
}

View file

@ -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)
);
}
}
}

View file

@ -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);