Skip to content

Instantly share code, notes, and snippets.

@austinbhale
Last active May 2, 2023 18:06
Show Gist options
  • Save austinbhale/15037f67e446402531a309452b183b99 to your computer and use it in GitHub Desktop.
Save austinbhale/15037f67e446402531a309452b183b99 to your computer and use it in GitHub Desktop.
A workaround to get model scaling into StereoKit
public class Program
{
private static void Main(string[] _)
{
// Initialize StereoKit
SKSettings settings = new()
{
appName = "ModelScaleSK",
assetsFolder = "Assets",
};
if (!SK.Initialize(settings))
{
Environment.Exit(1);
}
Material volumeMat = Default.MaterialUIBox.Copy();
volumeMat["border_size"] = 0.0f;
volumeMat["border_affect_radius"] = 0.3f;
var model = Model.FromMesh(Mesh.GenerateSphere(15 * U.cm), Material.Default);
float modelScale = 1;
Pose modelPose = new(Input.Head.ToMatrix().Transform(Vec3.Forward * 0.3f), Quat.Identity);
SK.Run(() =>
{
Bounds modelBoundsScaled = model.Bounds * modelScale;
if (UIExtension.HandleBegin($"Test", ref modelPose, modelBoundsScaled, ref modelScale))
{
Default.MeshCube.Draw(volumeMat, Matrix.TS(modelBoundsScaled.center, modelBoundsScaled.dimensions));
}
UI.HandleEnd();
Hierarchy.Push(modelPose.ToMatrix(modelScale));
model.Draw(Matrix.Identity);
Hierarchy.Pop();
});
}
/// <summary>
/// Extends StereoKit UI capabilities.
/// </summary>
public static class UIExtension
{
/// <summary>
/// Temporary dictionary to store scale information of the model being scaled by the user.
/// </summary>
private static readonly Dictionary<string, float> s_IdScalePairs = new();
/// <summary>
/// A modification of UI.HandleBegin, that allows for scaling 3D models through
/// hand interaction.
/// </summary>
/// <param name="id">Name of the 3d model being manipulated.</param>
/// <param name="pose">Pose of the object being manipulated.</param>
/// <param name="handle">Bounds of the object being manipulated.</param>
/// <param name="scale">Current scale of the object.</param>
/// <param name="drawHandle">Flag to indicate whether to draw the bounds.</param>
/// <param name="moveType">Defines how the handle follows the user's hands.</param>
/// <returns>The original result from StereoKit's HandleBegin.</returns>
public static bool HandleBegin(string id, ref Pose pose, Bounds handle, ref float scale,
bool drawHandle = false, UIMove moveType = UIMove.Exact)
{
if (UI.HandleBegin(id, ref pose, handle, drawHandle, moveType))
{
if (moveType != UIMove.Exact)
{
return true;
}
Hand leftHand = Input.Hand(Handed.Left);
Hand rightHand = Input.Hand(Handed.Right);
if (leftHand.IsTracked && rightHand.IsTracked
&& leftHand.IsPinched && rightHand.IsPinched)
{
if (leftHand.IsJustPinched || rightHand.IsJustPinched)
{
handle.center = pose.ToMatrix().Transform(handle.center);
if (handle.Contains(leftHand.pinchPt) && handle.Contains(rightHand.pinchPt))
{
s_IdScalePairs[id] = Vec3.Distance(leftHand.pinchPt, rightHand.pinchPt) / scale;
}
}
else if (s_IdScalePairs.ContainsKey(id))
{
float currentDist = Vec3.Distance(leftHand.pinchPt, rightHand.pinchPt);
scale = currentDist / s_IdScalePairs[id];
}
}
else if (s_IdScalePairs.ContainsKey(id))
{
s_IdScalePairs.Remove(id);
}
return true;
}
if (s_IdScalePairs.ContainsKey(id))
{
s_IdScalePairs.Remove(id);
}
return false;
}
public static bool Handle(string id, ref Pose pose, Bounds handle, ref float scale,
bool drawHandle = false, UIMove moveType = UIMove.Exact)
{
bool result = HandleBegin(id, ref pose, handle, ref scale, drawHandle, moveType);
UI.HandleEnd();
return result;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment