Skip to content

Commit 4381709

Browse files
RogPodgeZee2
andauthored
Remove allocs from idle and selecting ray interactor (#11344)
* Line visual now only applies compression effect when the ray interactor has hit an object * adjusted gradient compress algorithm to be more compact and efficient * added deadzone parameter to the input simulator so axis values would reach 0 or 1 * reorganized line visuals script, made adjustments to minimize color utilities calls when not needed * adjusted prefab values to be less aggressive with the compression effect * removing unused perf marker Co-authored-by: Finn Sinclair <finnnorth@gmail.com>
1 parent e6d50d0 commit 4381709

File tree

4 files changed

+73
-63
lines changed

4 files changed

+73
-63
lines changed

com.microsoft.mrtk.core/Utilities/ColorUtilities.cs

Lines changed: 15 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -56,38 +56,26 @@ public static Gradient GradientCompress(Gradient a, float p1, float p2)
5656
return a;
5757
}
5858

59-
// List of all the unique key times
60-
cachedKeyTimes.Clear();
61-
62-
for (int i = 0; i < a.colorKeys.Length; i++)
59+
float compressionRatio = p2 - p1;
60+
if (p1 == 0.0f && compressionRatio == 1.0f)
6361
{
64-
float k = a.colorKeys[i].time;
65-
if (!cachedKeyTimes.Contains(k))
66-
cachedKeyTimes.Add(k);
62+
return a;
6763
}
6864

69-
for (int i = 0; i < a.alphaKeys.Length; i++)
65+
// This call will alloc because .colorKeys and .alphaKeys creates copies of the underlying arrays
66+
GradientColorKey[] clrs = a.colorKeys;
67+
GradientAlphaKey[] alphas = a.alphaKeys;
68+
69+
for (int i = 0; i < clrs.Length; i++)
7070
{
71-
float k = a.alphaKeys[i].time;
72-
if (!cachedKeyTimes.Contains(k))
73-
cachedKeyTimes.Add(k);
71+
var newTime = p1 + compressionRatio * clrs[i].time;
72+
clrs[i].time = newTime;
7473
}
7574

76-
GradientColorKey[] clrs = new GradientColorKey[cachedKeyTimes.Count];
77-
GradientAlphaKey[] alphas = new GradientAlphaKey[cachedKeyTimes.Count];
78-
int gradientIdx = 0;
79-
80-
float compressionRatio = p2 - p1;
81-
82-
// Pick colors of both gradients at key times and lerp them
83-
foreach (float time in cachedKeyTimes)
75+
for (int i = 0; i < alphas.Length; i++)
8476
{
85-
var newTime = p1 + compressionRatio * time;
86-
87-
var clr = a.Evaluate(time);
88-
clrs[gradientIdx] = new GradientColorKey(clr, newTime);
89-
alphas[gradientIdx] = new GradientAlphaKey(clr.a, newTime);
90-
gradientIdx++;
77+
var newTime = p1 + compressionRatio * alphas[i].time;
78+
alphas[i].time = newTime;
9179
}
9280

9381
var g = new Gradient();
@@ -97,8 +85,8 @@ public static Gradient GradientCompress(Gradient a, float p1, float p2)
9785
}
9886

9987
// Caching the key times to not create a new HashSet every time this is called.
100-
static HashSet<float> cachedKeyTimes = new HashSet<float>();
101-
static Gradient GradientLerp(Gradient a, Gradient b, float t, bool noAlpha, bool noColor)
88+
private static HashSet<float> cachedKeyTimes = new HashSet<float>();
89+
private static Gradient GradientLerp(Gradient a, Gradient b, float t, bool noAlpha, bool noColor)
10290
{
10391
if (t == 0.0f)
10492
{

com.microsoft.mrtk.input/Assets/Prefabs/MRTK LeftHand Controller.prefab

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -410,7 +410,7 @@ MonoBehaviour:
410410
m_Mode: 0
411411
m_NumColorKeys: 2
412412
m_NumAlphaKeys: 2
413-
maxGradientLength: 0.1
413+
maxGradientLength: 0.3
414414
lineWidth:
415415
serializedVersion: 2
416416
m_Curve:

com.microsoft.mrtk.input/Interactors/InteractorVisuals/MRTKLineVisual.cs

Lines changed: 47 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -70,12 +70,12 @@ public Gradient SelectActiveColorGradient
7070
}
7171

7272
[SerializeField]
73-
[Tooltip("Controls the length of the visual that the gradient is applied relative to the ray interactor's max raycast distance")]
73+
[Tooltip("On hit, the gradient will be applied evenly along the line renderer until it's total length is longer than this value multiplied by the ray interactor's max raycast distance")]
7474
[Range(0.01f, 1)]
75-
float maxGradientLength = 0.1f;
75+
float maxGradientLength = 0.3f;
7676

7777
/// <summary>
78-
/// Controls the length of the visual that the gradient is applied relative to the ray interactor's max raycast distance
78+
/// On hit, the gradient will be applied evenly along the line renderer until it's total length is longer than this value multiplied by the ray interactor's max raycast distance.
7979
/// </summary>
8080
public float MaxGradientLength
8181
{
@@ -268,6 +268,9 @@ protected void OnDisable()
268268

269269
private static readonly ProfilerMarker UpdateLinePerfMarker = new ProfilerMarker("[MRTK] MRTKLineVisual.UpdateLineVisual");
270270

271+
// Cached value of the current gradient. Used to avoid making calls to lineRenderer.colorGradient, which allocs
272+
private Gradient cachedGradient = new Gradient();
273+
271274
[BeforeRenderOrder(XRInteractionUpdateOrder.k_BeforeRenderLineVisual)]
272275
private void UpdateLineVisual()
273276
{
@@ -307,21 +310,18 @@ private void UpdateLineVisual()
307310
// Finally enable the line renderer if we pass the other checks
308311
lineRenderer.enabled = rayInteractor.isHoverActive;
309312

310-
// Assign the first point to the ray origin
311-
lineDataProvider.FirstPoint = rayPositions[0];
312-
313-
IVariableSelectInteractor variableSelectInteractor = rayInteractor as IVariableSelectInteractor;
314-
315-
if (variableSelectInteractor != null)
313+
// Exit early if the line renderer is ultimately disabled
314+
if (!lineRenderer.enabled)
316315
{
317-
lineRenderer.GetPropertyBlock(propertyBlock);
318-
propertyBlock.SetFloat("_Shift_", variableSelectInteractor.SelectProgress);
319-
lineRenderer.colorGradient = ColorUtilities.GradientLerp(ValidColorGradient, SelectActiveColorGradient, variableSelectInteractor.SelectProgress);
320-
lineRenderer.SetPropertyBlock(propertyBlock);
316+
ClearLineRenderer();
317+
return;
321318
}
322319

320+
// Assign the first point to the ray origin
321+
lineDataProvider.FirstPoint = rayPositions[0];
322+
323323
// If the interactor is currently selecting, lock the end of the ray to the selected object
324-
if (rayInteractor.interactablesSelected.Count > 0)
324+
if (rayInteractor.hasSelection)
325325
{
326326
// Assign the last point to the one saved by the callback
327327
lineDataProvider.LastPoint = hitTargetTransform.TransformPoint(targetLocalHitPoint);
@@ -355,26 +355,6 @@ private void UpdateLineVisual()
355355

356356
// Assign the last point to last point in the data structure
357357
lineDataProvider.LastPoint = rayPositions[rayPositionsCount - 1];
358-
359-
// If we are hovering over a valid object, lerp the color based on pinchedness if applicable
360-
if (rayHasHit)
361-
{
362-
if (variableSelectInteractor != null)
363-
{
364-
lineRenderer.colorGradient = ColorUtilities.GradientLerp(ValidColorGradient, SelectActiveColorGradient, variableSelectInteractor.SelectProgress);
365-
}
366-
else
367-
{
368-
lineRenderer.colorGradient = ColorUtilities.GradientLerp(ValidColorGradient, SelectActiveColorGradient, rayInteractor.hasSelection ? 1 : 0);
369-
}
370-
}
371-
else
372-
{
373-
lineRenderer.colorGradient = NoTargetColorGradient;
374-
}
375-
376-
var compressionAmount = Mathf.Clamp(rayInteractor.maxRaycastDistance * MaxGradientLength / hitDistance, 0.0f, 1.0f);
377-
lineRenderer.colorGradient = ColorUtilities.GradientCompress(lineRenderer.colorGradient, 0.0f, compressionAmount);
378358
}
379359

380360
// Project forward based on pointer direction to get an 'expected' position of the first control point if we've hit an object
@@ -407,6 +387,39 @@ private void UpdateLineVisual()
407387
rendererPositions[i] = lineDataProvider.GetPoint(normalizedDistance);
408388
}
409389
lineRenderer.SetPositions(rendererPositions);
390+
391+
// Now handle coloring the line visual
392+
// If our interactor is a variable select interactor, change the material property based on select progress
393+
IVariableSelectInteractor variableSelectInteractor = rayInteractor as IVariableSelectInteractor;
394+
if (variableSelectInteractor != null)
395+
{
396+
lineRenderer.GetPropertyBlock(propertyBlock);
397+
propertyBlock.SetFloat("_Shift_", variableSelectInteractor.SelectProgress);
398+
lineRenderer.SetPropertyBlock(propertyBlock);
399+
}
400+
401+
// If we are hovering over a valid object or are currently selecting one, lerp the color based on selectedness
402+
if (rayHasHit || rayInteractor.hasSelection)
403+
{
404+
if (variableSelectInteractor != null)
405+
{
406+
cachedGradient = ColorUtilities.GradientLerp(ValidColorGradient, SelectActiveColorGradient, variableSelectInteractor.SelectProgress);
407+
}
408+
else
409+
{
410+
cachedGradient = ColorUtilities.GradientLerp(ValidColorGradient, SelectActiveColorGradient, rayInteractor.hasSelection ? 1 : 0);
411+
}
412+
413+
// apply the compression effect
414+
var compressionAmount = Mathf.Clamp(rayInteractor.maxRaycastDistance * MaxGradientLength / hitDistance, 0.0f, 1.0f);
415+
cachedGradient = ColorUtilities.GradientCompress(cachedGradient, 0.0f, compressionAmount);
416+
}
417+
else
418+
{
419+
cachedGradient = NoTargetColorGradient;
420+
}
421+
422+
lineRenderer.colorGradient = cachedGradient;
410423
}
411424
}
412425

com.microsoft.mrtk.input/Simulation/InputSimulator.cs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,9 @@ public ControllerSimulationSettings RightControllerSettings
310310
// TODO: Drive from inspector/simulator options.
311311
private float triggerSmoothTime = 0.1f;
312312

313+
// TODO: Drive from inspector/simulator options.
314+
private float triggerSmoothDeadzone = 0.005f;
315+
313316
/// <summary>
314317
/// Enables the simulated controller.
315318
/// </summary>
@@ -500,11 +503,17 @@ private void UpdateSimulatedController(Handedness handedness)
500503
// TODO: Currently triggerAxis is driven only from ctrlSettings.TriggerButton.action.
501504
// We will eventually drive this from the ctrlSettings.TriggerAxis.action as well.
502505
// Needs work to be able to intuitively combine trigger axis from sim input with click.
506+
float targetValue = ctrlSettings.TriggerButton.action.IsPressed() ? 1 : 0;
507+
503508
controls.TriggerAxis = Mathf.SmoothDamp(controls.TriggerAxis,
504-
ctrlSettings.TriggerButton.action.IsPressed() ? 1 : 0,
509+
targetValue,
505510
ref triggerSmoothVelocity,
506511
triggerSmoothTime);
507512

513+
if(Mathf.Abs(controls.TriggerAxis - targetValue) < triggerSmoothDeadzone)
514+
{
515+
controls.TriggerAxis = targetValue;
516+
}
508517
#if LATER
509518
// TODO: mappings need to be sorted out for these
510519
// Axes available to hands and controllers

0 commit comments

Comments
 (0)