diff --git a/app/Mono.cs b/app/Mono.cs index 0986046..763e7f3 100644 --- a/app/Mono.cs +++ b/app/Mono.cs @@ -67,7 +67,7 @@ public class Mono { matHolo = Material.Default.Copy(); matHolo.Transparency = Transparency.Add; matHolo.DepthWrite = false; - matHolo.DepthTest = DepthTest.Always; + // matHolo.DepthTest = DepthTest.Always; matHolo.FaceCull = Cull.None; // matHolo.SetTexture("diffuse", Tex.DevTex); matHolo.Wireframe = true; @@ -93,6 +93,8 @@ public class Mono { compositor.Frame(); + // Input.Subscribe(InputSource.Hand, BtnState.Any, Action); + // ------------------------------------------------- // // dof.Frame(); @@ -109,6 +111,8 @@ public class Mono { lwc.Demo(ltb.ori); rwc.Demo(rtb.ori); + rtb.Demo(); + // rBlock.Step(); lBlock.Step(); // cubicCon.Step(); @@ -123,9 +127,15 @@ public class Mono { ShowWindowButton(); } - Pose windowPoseButton = new Pose(0, 0, 0.75f, Quat.Identity); + Pose windowPoseButton = new Pose(-0.5f, 1.3f, 0, Quat.FromAngles(0, -90f, 0)); + TextStyle style = Text.MakeStyle(Font.FromFile("add/fonts/DM-Mono.ttf"), 1f * U.cm, Color.White); + Vec2 fieldSize = new Vec2(6f * U.cm, 3f * U.cm); void ShowWindowButton() { - UI.WindowBegin("Window Button", ref windowPoseButton); + UI.WindowBegin("design vars", ref windowPoseButton); + UI.SetThemeColor(UIColor.Background, new Color(0f, 0f, 0f)); + UI.SetThemeColor(UIColor.Primary, new Color(0.5f, 0.5f, 0.5f)); + UI.PushTextStyle(style); + // if (UI.Button("Draw Oriel Axis")) { oriel.drawAxis = !oriel.drawAxis; } @@ -139,29 +149,49 @@ public class Mono { // UI.Label("pos.y"); // UI.HSlider("pos.y", ref playerY, -1f, 1f, 0.1f); - // UI.Label("trail.length"); - // UI.HSlider("trail.length", ref trailLen, 0.1f, 1f, 0.1f); - - // UI.Label("trail.scale"); - // UI.HSlider("trail.str", ref trailScl, 0.1f, 2f, 0.1f); - - // UI.Label("str"); - // UI.HSlider("str", ref stretchStr, 0.1f, 1f, 0.1f); - + UI.Label("wavecursor."); + UI.Input("wavecursor.reach", ref wcReach, fieldSize, TextContext.Number); + UI.SameLine(); UI.Label("reach"); + UI.Input("wavecursor.length", ref wcLength, fieldSize, TextContext.Number); + UI.SameLine(); UI.Label("length"); + UI.Input("wavecursor.scale", ref wcScale, fieldSize, TextContext.Number); + UI.SameLine(); UI.Label("scale"); + UI.Label("trackballer."); + UI.Input("trackballer.compliance", ref tbCompliance, fieldSize, TextContext.Number); + UI.SameLine(); UI.Label("compliance"); + UI.Input("trackballer.x", ref tbX, fieldSize, TextContext.Number); + UI.SameLine(); UI.Label("x"); + UI.Input("trackballer.y", ref tbY, fieldSize, TextContext.Number); + UI.SameLine(); UI.Label("y"); + UI.Input("trackballer.z", ref tbZ, fieldSize, TextContext.Number); + UI.SameLine(); UI.Label("z"); // flipIndex // flipGrip - - UI.WindowEnd(); } - public float trailLen = 0.666f; - public float trailScl = 0.333f; - public float stretchStr = 0.5f; - public float playerY = 0; + public string wcReach = "1.0"; + public string wcLength = "0.666"; + public string wcScale = "0.333"; + + public string tbCompliance = "0.0"; + public string tbX = "1.0"; + public string tbY = "2.0"; + public string tbZ = "-4.0"; + + + // public float playerY = 0; + +} + +// convert into a class +class Design { + public string txt; + public int integer; + public float floating; } diff --git a/app/PullRequest.cs b/app/PullRequest.cs index 0518a74..22c1840 100644 --- a/app/PullRequest.cs +++ b/app/PullRequest.cs @@ -67,6 +67,11 @@ public static class PullRequest { return (to * delta * to.Inverse).Normalized; } + // ? + public static Vec3 Relative(Quat to, Vec3 delta) { + return to * delta * to.Inverse; + } + // public static void LookDirection(this ref Quat q, Vec3 dir) { // Vec3 up = Vec3.Up; @@ -284,10 +289,27 @@ public static class PullRequest { return MathF.Max(min, MathF.Min(max, v)); } + public static float ToFloat( + ref string s, + float min = float.NegativeInfinity, + float max = float.PositiveInfinity + ) { + try { + float value = Clamp(float.Parse(s), min, max); + // if clamped, update string + if (value != float.Parse(s)) { + s = value.ToString(); + } + return value; + } catch { + return 0; + } + } + public class PID { public float p, i; - float integral = 0f; - float value = 0f; + public float value; + float integral; // float scalar = 1f; public PID(float p = 1, float i = 0.1f) { @@ -303,6 +325,18 @@ public static class PullRequest { } } + public class Vec3PID { + public Vec3 value, integral; + // float scalar = 1f; + + public Vec3 Update(Vec3 target, float p = 1, float i = 0.1f) { + Vec3 error = value - target; + integral += error; + Vec3 delta = ((p * error) + (i * integral)); + return value -= delta * Time.Elapsedf; + } + } + public class Lerper { public float t = 0; public float spring = 1; diff --git a/app/Rig/Rig.cs b/app/Rig/Rig.cs index ba360ef..fb07a86 100644 --- a/app/Rig/Rig.cs +++ b/app/Rig/Rig.cs @@ -5,13 +5,7 @@ public class Rig { public Vec3 pos = new Vec3(0, 0, 0); public Quat ori = Quat.Identity; - public Rig() { - if (World.HasBounds) { - // pos.XZ = World.BoundsPose.position.XZ; - // pos.y = World.BoundsPose.position.y; - // ori = World.BoundsPose.orientation; - } - } + public Rig() {} // public Vec3 center; // public void Recenter() { @@ -44,12 +38,19 @@ public class Rig { public Vec3 LocalPos(Vec3 p) { - return ori.Inverse * (p - (pos + Vec3.Up * Mono.inst.playerY)); + return ori.Inverse * (p - (pos)); } + bool gotBounds = false; + public void Step() { + Matrix bounds = Matrix.T(0, 1.3f, 0); + if (!gotBounds && World.HasBounds) { + gotBounds = true; + bounds = World.BoundsPose.ToMatrix(); + // Renderer.CameraRoot = World.BoundsPose.ToMatrix(); + } - public void Step() { - Renderer.CameraRoot = Matrix.TR((pos + Vec3.Up * Mono.inst.playerY), ori); + Renderer.CameraRoot = Matrix.TR(pos, ori) * bounds; // Controllers rCon.Step(true); diff --git a/app/Space.cs b/app/Space.cs index 31ba70a..b88dae1 100644 --- a/app/Space.cs +++ b/app/Space.cs @@ -76,7 +76,7 @@ public class Space { // World.BoundsPose.position.y - shed.Draw(Matrix.TRS(new Vec3(0, -1.6f, 0), Quat.Identity, Vec3.One)); + shed.Draw(Matrix.Identity); // draw a grid of cube pillars spaced out evenly along the XZ plane diff --git a/app/_Init.cs b/app/_Init.cs index 3662d3b..4b80087 100644 --- a/app/_Init.cs +++ b/app/_Init.cs @@ -20,7 +20,7 @@ Renderer.ClearColor = new Color(0f, 0f, 0f); Oriels.Mono mono = Oriels.Mono.inst; mono.Init(); -while (SK.Step(() => { +SK.Run(() => { mono.Frame(); -})); -SK.Shutdown(); \ No newline at end of file +}); +// SK.Shutdown(); \ No newline at end of file diff --git a/app/dofs/stretch-cursor/wave/WaveCursor.cs b/app/dofs/stretch-cursor/wave/WaveCursor.cs index 1729dfd..3c56f59 100644 --- a/app/dofs/stretch-cursor/wave/WaveCursor.cs +++ b/app/dofs/stretch-cursor/wave/WaveCursor.cs @@ -31,8 +31,8 @@ class WaveCursor : dof { hand.Get(FingerId.Index, JointId.Tip).position, hand.Get(FingerId.Index, JointId.KnuckleMajor).position ); - - cursor.raw = hand.Get(FingerId.Index, JointId.Tip).position + dir * stretch * strength * Mono.inst.stretchStr; + + cursor.raw = hand.Get(FingerId.Index, JointId.Tip).position + dir * stretch * strength; cursor.pos.x = (float)xF.Filter(cursor.raw.x, (double)Time.Elapsedf); cursor.pos.y = (float)yF.Filter(cursor.raw.y, (double)Time.Elapsedf); cursor.pos.z = (float)zF.Filter(cursor.raw.z, (double)Time.Elapsedf); @@ -45,7 +45,9 @@ class WaveCursor : dof { } public float deadzone = 0.3f; - public float strength = 3f; + public float strength { + get { return PullRequest.ToFloat(ref Mono.inst.wcReach, 0); } // 3f + } public Handed handed = Handed.Left; @@ -85,23 +87,24 @@ class WaveCursor : dof { } void Trail(Vec3[] points, Vec3 nextPos) { - while (Vec3.Distance(points[0], nextPos) > 0.03f * Mono.inst.trailScl) { + float scale = PullRequest.ToFloat(ref Mono.inst.wcScale, 0.001f); + while (Vec3.Distance(points[0], nextPos) > 0.03f * scale) { for (int i = points.Length - 1; i > 0; i--) { points[i] = points[i - 1]; } - points[0] += Vec3.Direction(nextPos, points[0]) * 0.02f * Mono.inst.trailScl; + points[0] += Vec3.Direction(nextPos, points[0]) * 0.02f * scale; } // points[0] = nextPos; - int len = (int)(points.Length * Mono.inst.trailLen); + int len = (int)(points.Length * PullRequest.ToFloat(ref Mono.inst.wcLength, 0f, 1f)); 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; + // // points[i] = points[i - 1] + dir * 0.02f * scale; // } Vec3 from = i > 0 ? points[i - 1] : nextPos; @@ -109,9 +112,9 @@ class WaveCursor : dof { Mesh.Cube.Draw( Mono.inst.matHolo, Matrix.TRS( - points[i] + ori * new Vec3(0, 0, 0.01f) * Mono.inst.trailScl, + points[i] + ori * new Vec3(0, 0, 0.01f) * scale, ori, - new Vec3(0.01f, 0.01f, 0.02f) * Mono.inst.trailScl + new Vec3(0.01f, 0.01f, 0.02f) * scale ), Color.HSV(i / (float)len, 1, 1) ); diff --git a/app/dofs/trackballer/Trackballer.cs b/app/dofs/trackballer/Trackballer.cs index fc6133a..b98c619 100644 --- a/app/dofs/trackballer/Trackballer.cs +++ b/app/dofs/trackballer/Trackballer.cs @@ -4,10 +4,16 @@ class Trackballer : dof { // data public Btn btnIn, btnOut; + bool onTheBall; public Quat ori = Quat.Identity; + Quat momentum = Quat.Identity; - Quat delta = Quat.Identity; - Matrix oldMeshMatrix = Matrix.Identity; + Quat delta = Quat.Identity; + Matrix pad = Matrix.Identity; + Matrix oldPad = Matrix.Identity; + int lastClosestIndex; + + PullRequest.Vec3PID compliance = new PullRequest.Vec3PID(); PullRequest.OneEuroFilter xF = new PullRequest.OneEuroFilter(0.0001f, 0.1f); PullRequest.OneEuroFilter yF = new PullRequest.OneEuroFilter(0.0001f, 0.1f); @@ -23,115 +29,161 @@ class Trackballer : dof { public void Frame() { Hand hand = Input.Hand(handed); if (hand.tracked.IsActive() && !hand.tracked.IsJustActive()) { - Vec3 anchor = hand.Get(FingerId.Index, JointId.KnuckleMajor).position; - anchor = anchor + hand.palm.orientation * new Vec3(handed == Handed.Left ? -0.006f : 0.006f, 0.01f, -0.04f); - Matrix mAnchor = Matrix.TR(anchor, hand.palm.orientation); - Matrix mAnchorInv = mAnchor.Inverse; - - Vec3 thumbTip = hand.Get(FingerId.Thumb, JointId.Tip).position; - // Vec3 tipDelta = mAnchorInv.Transform(thumbTip) - mAnchorInv.Transform(oldTip); - // oldTip = thumbTip; - Vec3 thumbKnuckle = hand.Get(FingerId.Thumb, JointId.KnuckleMinor).position; - - Quat thumbRot = hand.Get(FingerId.Thumb, JointId.Tip).orientation; - Matrix mMesh = Matrix.TRS( - thumbTip, - thumbRot, - new Vec3(handed == Handed.Left ? -1f : 1f, 1f, 1f) * 0.1666f - ); - mesh.Draw(Mono.inst.matHolo, mMesh, new Color(0, 1, 1)); - - // closest to anchor - float closest = 100000f; - int closestIndex = -1; - Vertex[] verts = mesh.GetVerts(); - for (int i = 0; i < verts.Length; i++) { - Vec3 v = mMesh.Transform(verts[i].pos); - float d = (v - anchor).LengthSq; - if (d < closest) { - closest = d; - closestIndex = i; - } - } - - Vec3 localPad = mAnchorInv.Transform(mMesh.Transform(verts[closestIndex].pos)); - Vec3 oldPad = mAnchorInv.Transform(oldMeshMatrix.Transform(verts[closestIndex].pos)); - - oldMeshMatrix = mMesh; - - // - // Vec3 pad = anchor.SnapToLine( - // thumbKnuckle, thumbTip, - // true, - // out float t, 0f, 1f - // ); - // // t = 1 - t; - // // scale to 0.666f - 1f - // // t = (t - 0.666f) / 0.334f; - // t = t * t; - // t = 1 - t; - // pad += hand.Get(FingerId.Thumb, JointId.Tip).orientation * -Vec3.Up * 0.00666f * t; - - - // Vec3 localPad = mAnchorInv.Transform(pad); - // Vec3 localPad = mAnchorInv.Transform(thumbTip); - - // ? - // localPad.x = (float)xF.Filter(localPad.x, (double)Time.Elapsedf); - // localPad.y = (float)yF.Filter(localPad.y, (double)Time.Elapsedf); - // localPad.z = (float)zF.Filter(localPad.z, (double)Time.Elapsedf); - - - - // Lines.Add(thumbTip, thumbKnuckle, Color.White, 0.002f); - Mesh.Sphere.Draw(Mono.inst.matHolo, Matrix.TRS(mAnchor.Transform(localPad), hand.palm.orientation, 0.002f), new Color(0, 1, 1)); - - - // if (btnIn.held) { - // btnIn.Step(localPad.Length < layer[1]); - // } else { - // btnIn.Step(localPad.Length < layer[0]); - // } - float inT = btnIn.held ? 1 : 0.333f; - - if (btnOut.held) { - btnOut.Step(localPad.Length > layer[1]); - } else { - btnOut.Step(localPad.Length > layer[2]); - } - float outT = btnOut.held ? 1 : 0.333f; - - if (btnIn.held) { - delta = momentum = Quat.Identity; - } else { - if (localPad.Length < layer[1]) { - delta = PullRequest.Relative( - hand.palm.orientation, - Quat.Delta( - oldPad.Normalized, - localPad.Normalized - ) - ).Normalized; - - momentum = Quat.Slerp(momentum, delta, Time.Elapsedf * 10f); - } - } - - // Draw - Mesh.Sphere.Draw(Mono.inst.matHolo, Matrix.TRS(anchor, ori, layer[1] * 2), new Color(inT, 0, 0)); - // Mesh.Cube.Draw(Mono.inst.matHolo, Matrix.TRS(anchor, ori, 0.04f), new Color(0, outT * 0.2f, 0)); + UpdateMomentum(hand); } - Quat newOri = momentum * ori; + Quat newOri = (momentum * ori).Normalized; if (new Vec3(newOri.x, newOri.y, newOri.z).LengthSq > 0) { ori = newOri; } } + public void UpdateMomentum(Hand hand) { + // Thumb pad + HandJoint thumbJoint = hand.Get(FingerId.Thumb, JointId.Tip); + oldPad = pad; + pad = Matrix.TRS( + thumbJoint.position, + thumbJoint.orientation, + new Vec3(handed == Handed.Left ? -1f : 1f, 1f, 1f) * 0.1666f + ); + mesh.Draw(Mono.inst.matHolo, pad, new Color(0, 1, 1)); + + // Ball anchor + HandJoint ballJoint = hand.Get(FingerId.Index, JointId.KnuckleMajor); + Vec3 anchorPos = ballJoint.position + hand.palm.orientation * new Vec3( + PullRequest.ToFloat(ref Mono.inst.tbX, -10f, 10f) * U.cm * (handed == Handed.Left ? -1 : 1), + PullRequest.ToFloat(ref Mono.inst.tbY, -10f, 10f) * U.cm, + PullRequest.ToFloat(ref Mono.inst.tbZ, -10f, 10f) * U.cm + ); + anchorPos += compliance.Update( + Vec3.Zero, + onTheBall ? 1f : 10f, + onTheBall ? 0.1f : 1f // 10x less integral when on the ball? + ); + // compliance; + // compliance = Vec3.Lerp(compliance, Vec3.Zero, Time.Elapsedf * 10f); + Matrix anchor = Matrix.TR(anchorPos, hand.palm.orientation); + Matrix anchorInv = anchor.Inverse; + + // Traction delta mesh matrix + Vertex[] verts = mesh.GetVerts(); + float oldClosest = ( + pad.Transform(verts[lastClosestIndex].pos) - anchorPos + ).LengthSq; + float closest = 100000f; + int closestIndex = lastClosestIndex; + for (int i = 0; i < verts.Length; i++) { + Vec3 v = pad.Transform(verts[i].pos); + float d = (v - anchorPos).LengthSq; + if (d < closest && d < oldClosest - 0.00002f) { + closest = d; + closestIndex = i; + } + } + lastClosestIndex = closestIndex; + + Vec3 point = anchorInv.Transform( + pad.Transform(verts[closestIndex].pos) + ); + Vec3 oldPoint = anchorInv.Transform( + oldPad.Transform(verts[closestIndex].pos) + ); + + // ? + // localPad.x = (float)xF.Filter(localPad.x, (double)Time.Elapsedf); + // localPad.y = (float)yF.Filter(localPad.y, (double)Time.Elapsedf); + // localPad.z = (float)zF.Filter(localPad.z, (double)Time.Elapsedf); + + // Lines.Add(thumbTip, thumbKnuckle, Color.White, 0.002f); + Mesh.Sphere.Draw( + Mono.inst.matHolo, + Matrix.TRS(anchor.Transform(point), hand.palm.orientation, 0.002f), + new Color(0, 1, 1) + ); + + float dist = point.Length; + // if (btnIn.held) { btnIn.Step(dist < layer[1]); } + // else { btnIn.Step(dist < layer[0]); } + float inT = btnIn.held ? 1 : 0.333f; + + if (btnOut.held) { btnOut.Step(dist > layer[1]); } + else { btnOut.Step(dist > layer[2]); } + float outT = btnOut.held ? 1 : 0.333f; + + if (btnIn.held) { + delta = momentum = Quat.Identity; + } else { + onTheBall = dist < layer[1]; + if (onTheBall) { + delta = Quat.Delta( + oldPoint.Normalized, + point.Normalized + ).Relative(hand.palm.orientation); + + momentum = Quat.Slerp(momentum, delta, Time.Elapsedf * 10f); + + Vec3 contact = point.Normalized * layer[1]; + Vec3 offset = point - contact; + + // no z axis + // offset.z = 0; + + offset = hand.palm.orientation * offset; + compliance.value += offset * PullRequest.ToFloat(ref Mono.inst.tbCompliance, 0f, 1f); + compliance.integral = Vec3.Zero; + } + } + + // Draw + Mesh.Sphere.Draw( + Mono.inst.matHolo, + Matrix.TRS(anchorPos, ori, layer[1] * 2), + new Color(inT, 0, 0) + ); + } + // design - public Handed handed = Handed.Left; + public Handed handed = Handed.Left; public float[] layer = new float[] { 0.00333f, 0.02f, 0.0666f }; + + Vec3 cursorPos = new Vec3(0f, 0f, 0f); + public void Demo() { + Matrix panel = Matrix.TR( + new Vec3( + 1.47f, + 1.145f, // - World.BoundsPose.position.y, + 1.08f), + Quat.FromAngles(-3.2f, 90f, 0) + ); + + float width = 52 * U.cm; + float height = 29f * U.cm; + Mesh.Quad.Draw( + Mono.inst.matHolo, + Matrix.S(new Vec3(width, height, 1)) * panel, + new Color(1, 1, 1) + ); + + + cursorPos.x = PullRequest.Clamp( + cursorPos.x + (delta * Vec3.Right).z * 0.1f, + width / -2f, + width / 2f + ); + cursorPos.y = PullRequest.Clamp( + cursorPos.y + (delta * Vec3.Right).y * -0.1f, + height / -2f, + height / 2f + ); + + Mesh.Quad.Draw( + Material.Unlit, + Matrix.TS(cursorPos, 1 * U.cm) * panel, + new Color(1, 1, 1) + ); + } } diff --git a/oriels.csproj b/oriels.csproj index 8c840c6..653b467 100644 --- a/oriels.csproj +++ b/oriels.csproj @@ -13,7 +13,6 @@ PreserveNewest - diff --git a/res/thumb_pad.blend b/res/thumb_pad.blend index 6c2af65..f13cd68 100644 Binary files a/res/thumb_pad.blend and b/res/thumb_pad.blend differ