From d56490e6c2542c9f8a9d4f9e3b5d7590606e01f5 Mon Sep 17 00:00:00 2001 From: Charles Phillips Date: Thu, 5 Mar 2020 18:05:11 -0800 Subject: [PATCH 1/4] [model ui api] Painting support for both hands --- Painting.cs | 60 +++++++++++++++++++++++++++++++---------------------- Program.cs | 1 + 2 files changed, 36 insertions(+), 25 deletions(-) diff --git a/Painting.cs b/Painting.cs index c18f6a5..a09e963 100644 --- a/Painting.cs +++ b/Painting.cs @@ -8,12 +8,21 @@ namespace StereoKitPaintTutorial class Painting { Pose _pose = new Pose(new Vec3(0, 0, -0.3f), Quat.Identity); - List _activeStroke = new List(); + Dictionary> _activeStroke = new Dictionary> { + { Handed.Left, new List() }, + { Handed.Right, new List() } + }; List _strokeList = new List(); Stack _undoStack = new Stack(); - Vec3 _prevFingertip; - bool _isDrawing; + Dictionary _prevFingertip = new Dictionary { + { Handed.Left, new Vec3() }, + { Handed.Right, new Vec3() } + }; + Dictionary _isDrawing = new Dictionary { + { Handed.Left, false }, + { Handed.Right, false } + }; public void Step(Handed handed, Color color, float thickness) { @@ -60,41 +69,42 @@ void UpdateInput(Handed handed, Color color, float thickness) Hand hand = Input.Hand(handed); Vec3 fingertip = hand[FingerId.Index, JointId.Tip].position; fingertip = Hierarchy.ToLocal(fingertip); - fingertip = Vec3.Lerp(_prevFingertip, fingertip, 0.3f); + fingertip = Vec3.Lerp(_prevFingertip[handed], fingertip, 0.3f); // If the user just made a pinching motion, and is not interacting // with the UI, we'll begin a paint stroke! if (hand.IsJustPinched && !UI.IsInteracting(handed)) { - BeginStroke(fingertip, color, thickness); - _isDrawing = true; + BeginStroke(handed, fingertip, color, thickness); + _isDrawing[handed] = true; } // If we're drawing a paint stroke, then lets update it with the current // steps information! - if (_isDrawing) - UpdateStroke(fingertip, color, thickness); + if (_isDrawing[handed]) + UpdateStroke(handed, fingertip, color, thickness); // And when they cease the pinching motion, we'll end whatever stroke // we started. - if (_isDrawing && hand.IsJustUnpinched) + if (_isDrawing[handed] && hand.IsJustUnpinched) { - EndStroke(); - _isDrawing = false; + EndStroke(handed); + _isDrawing[handed] = false; } - _prevFingertip = fingertip; + _prevFingertip[handed] = fingertip; } void Draw() { // Draw the unfinished stroke the user may be drawing - Lines.Add(_activeStroke.ToArray()); + Lines.Add(_activeStroke[Handed.Left].ToArray()); + Lines.Add(_activeStroke[Handed.Right].ToArray()); // Then draw all the other strokes that are part of the painting! for (int i = 0; i < _strokeList.Count; i++) Lines.Add(_strokeList[i]); } - void BeginStroke(Vec3 at, Color32 color, float thickness) + void BeginStroke(Handed handed, Vec3 at, Color32 color, float thickness) { // Start with two points! The first one begins at the point provided, // and the second one will always be updated to the current fingertip @@ -103,38 +113,38 @@ void BeginStroke(Vec3 at, Color32 color, float thickness) // a popping effect when points are simply added at distance intervals. // The extra point that directly follows the fingertip will nicely // prevent this 'popping' artifact! - _activeStroke.Add(new LinePoint(at, color, thickness)); - _activeStroke.Add(new LinePoint(at, color, thickness)); - _prevFingertip = at; + _activeStroke[handed].Add(new LinePoint(at, color, thickness)); + _activeStroke[handed].Add(new LinePoint(at, color, thickness)); + _prevFingertip[handed] = at; } - void UpdateStroke(Vec3 at, Color32 color, float thickness) + void UpdateStroke(Handed handed, Vec3 at, Color32 color, float thickness) { // Calculate the current distance from the last point, as well as the // speed at which the hand is traveling. - Vec3 prevLinePoint = _activeStroke[_activeStroke.Count - 2].pt; + Vec3 prevLinePoint = _activeStroke[handed][_activeStroke[handed].Count - 2].pt; float dist = Vec3.Distance(prevLinePoint, at); - float speed = Vec3.Distance(at, _prevFingertip) / Time.Elapsedf; + float speed = Vec3.Distance(at, _prevFingertip[handed]) / Time.Elapsedf; // Create a point at the current location, using speed as the thickness // of the stroke! The last point in the stroke should always be at the current // fingertip location to prevent 'popping' when adding a new point. LinePoint here = new LinePoint(at, color, Math.Max(1 - speed * 0.5f, 0.1f) * thickness); - _activeStroke[_activeStroke.Count - 1] = here; + _activeStroke[handed][_activeStroke[handed].Count - 1] = here; // If we're more than a centimeter away from our last point, we'll add // a new point! This is simple, but effective enough. A higher quality // implementation might use an error/change function that also factors // into account the change in angle. if (dist > 1 * Units.cm2m) - _activeStroke.Add(here); + _activeStroke[handed].Add(here); } - void EndStroke() + void EndStroke(Handed handed) { // Add the active stroke to the painting, and clear it out for the next one! - _strokeList.Add(_activeStroke.ToArray()); - _activeStroke.Clear(); + _strokeList.Add(_activeStroke[handed].ToArray()); + _activeStroke[handed].Clear(); } #region File Load and Save diff --git a/Program.cs b/Program.cs index 02692d0..31e503d 100644 --- a/Program.cs +++ b/Program.cs @@ -48,6 +48,7 @@ static void Main(string[] args) { // Send input information to the painting, it will handle this info to create // brush strokes. This will also draw the painting too! + activePainting.Step(Handed.Left, paletteMenu.PaintColor, paletteMenu.PaintSize); activePainting.Step(Handed.Right, paletteMenu.PaintColor, paletteMenu.PaintSize); // Step our palette UI! From 51944e317d1bc472f5fe35993f26fce0b67a1488 Mon Sep 17 00:00:00 2001 From: Charles Phillips Date: Fri, 6 Mar 2020 07:51:32 -0800 Subject: [PATCH 2/4] [model ui] each Hand gets its own Palette --- Program.cs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/Program.cs b/Program.cs index 31e503d..da8e0e4 100644 --- a/Program.cs +++ b/Program.cs @@ -8,7 +8,8 @@ namespace StereoKitPaintTutorial class Program { static Painting activePainting = new Painting(); - static PaletteMenu paletteMenu; + static PaletteMenu paletteMenuLeft; + static PaletteMenu paletteMenuRight; static Pose menuPose = new Pose(new Vec3(0.4f, 0, -0.4f), Quat.LookDir(-1,0,1)); static string defaultFolder = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments); @@ -39,7 +40,8 @@ static void Main(string[] args) // Initialize the palette menu, see PaletteMenu.cs! This class manages the palette // UI object for manipulating our brush stroke size and color. - paletteMenu = new PaletteMenu(); + paletteMenuLeft = new PaletteMenu(); + paletteMenuRight = new PaletteMenu(); // Step the application each frame, until StereoKit is told to exit! The callback // code here is called every frame after input and system events, but before the @@ -48,11 +50,12 @@ static void Main(string[] args) { // Send input information to the painting, it will handle this info to create // brush strokes. This will also draw the painting too! - activePainting.Step(Handed.Left, paletteMenu.PaintColor, paletteMenu.PaintSize); - activePainting.Step(Handed.Right, paletteMenu.PaintColor, paletteMenu.PaintSize); + activePainting.Step(Handed.Left, paletteMenuLeft.PaintColor, paletteMenuLeft.PaintSize); + activePainting.Step(Handed.Right, paletteMenuRight.PaintColor, paletteMenuRight.PaintSize); // Step our palette UI! - paletteMenu.Step(); + paletteMenuLeft.Step(); + paletteMenuRight.Step(); // Step our application's menu! This includes Save/Load Clear and Quit commands. StepMenuWindow(); From 311e97910cccfdf208c306a97a163cf575a543f0 Mon Sep 17 00:00:00 2001 From: Charles Phillips Date: Fri, 6 Mar 2020 07:52:12 -0800 Subject: [PATCH 3/4] [api] allow Pose of Palette to be set externally --- PaletteMenu.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/PaletteMenu.cs b/PaletteMenu.cs index dc88fa9..9ae85cf 100644 --- a/PaletteMenu.cs +++ b/PaletteMenu.cs @@ -17,6 +17,7 @@ class PaletteMenu // These properties are public, so back in Program.cs, we can get access to // these values! + public Pose Pose { get{ return _pose; } set{ _pose = value; } } public Color PaintColor { get{ return _color; } private set{ _color = value; } } public float PaintSize { get{ return _size; } private set{ _size = value; } } From 55333d85b30afb4e6968ef87fc147af60a51c659 Mon Sep 17 00:00:00 2001 From: Charles Phillips Date: Fri, 6 Mar 2020 07:52:37 -0800 Subject: [PATCH 4/4] [ui] set Palette for right Hand to the right --- Program.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Program.cs b/Program.cs index da8e0e4..8909cfd 100644 --- a/Program.cs +++ b/Program.cs @@ -42,6 +42,7 @@ static void Main(string[] args) // UI object for manipulating our brush stroke size and color. paletteMenuLeft = new PaletteMenu(); paletteMenuRight = new PaletteMenu(); + paletteMenuRight.Pose = new Pose(new Vec3(0.1f, 0, -0.4f), Quat.LookDir(-0.25f, 0, 1)); // Step the application each frame, until StereoKit is told to exit! The callback // code here is called every frame after input and system events, but before the