Search Unity

Showcase Two-hand Scaling script

Discussion in 'VR' started by miloszecket, Jul 24, 2020.

  1. miloszecket

    miloszecket

    Joined:
    Feb 4, 2019
    Posts:
    7
    (could use some optimization, but I've been looking for this for *so long*)
    Code (CSharp):
    1.  
    2. using System;
    3. using System.Collections;
    4. using System.Collections.Generic;
    5. using UnityEngine;
    6. using Valve.VR;
    7. using Valve.VR.InteractionSystem;
    8.  
    9. public class Scaleable : MonoBehaviour
    10. {
    11.     private GameObject middleMan;
    12.     private bool stoppingResize;
    13.     private SteamVR_Action_Boolean grabBoolean = SteamVR_Input.GetAction<SteamVR_Action_Boolean>("GrabGrip");
    14.     public SteamVR_Skeleton_JointIndexEnum fingerJointHover = SteamVR_Skeleton_JointIndexEnum.indexTip;
    15.     protected MeshRenderer[] highlightRenderers;
    16.     protected MeshRenderer[] existingRenderers;
    17.     protected GameObject highlightHolder;
    18.     protected SkinnedMeshRenderer[] highlightSkinnedRenderers;
    19.     protected SkinnedMeshRenderer[] existingSkinnedRenderers;
    20.     protected static Material highlightMat;
    21.     [Tooltip("An array of child gameObjects to not render a highlight for. Things like transparent parts, vfx, etc.")]
    22.     public GameObject[] hideHighlight;
    23.     private bool isResizing;
    24.     public SteamVR_Action_Boolean rightGrab;
    25.     public Hand rightHand;
    26.     private bool rightGrabbing;
    27.     private Collider[] rightOverlappingColliders;
    28.     public LayerMask rightHoverLayerMask = -1;
    29.     public SteamVR_Action_Boolean leftGrab;
    30.     public Hand leftHand;
    31.  
    32.     private bool hovering;
    33.     private bool wasHovering;
    34.  
    35.     private bool leftGrabbing;
    36.     private Collider[] leftOverlappingColliders;
    37.     public LayerMask leftHoverLayerMask = -1;
    38.     public int hoverPriority;
    39.     private int prevOverlappingColliders = 0;
    40.     private bool attachedToHand;
    41.     private float initialDistance;
    42.     private Vector3 initialScale;
    43.     private Quaternion initialRot;
    44.     private Vector3 offsetPos;
    45.     private Hand currentMain;
    46.     private List<MeshRenderer> flashingRenderers = new List<MeshRenderer>();
    47.     public Color hintColor;
    48.     public GameObject grabHintPrefab;
    49.     private GameObject rightTextHint;
    50.     private GameObject leftTextHint;
    51.  
    52.     void OnEnable()
    53.     {
    54.         rightGrab.AddOnChangeListener(SetRightGrab, rightHand.handType);
    55.         leftGrab.AddOnChangeListener(SetLeftGrab, leftHand.handType);
    56.     }
    57.     void Start()
    58.     {
    59.         highlightMat = (Material)Resources.Load("SteamVR_HoverHighlight", typeof(Material));
    60.  
    61.         if (highlightMat == null)
    62.         {
    63.             Debug.LogError("<b>[SteamVR Interaction]</b> Hover Highlight Material is missing. Please create a material named 'SteamVR_HoverHighlight' and place it in a Resources folder", this);
    64.         }
    65.         if (rightHand.gameObject.layer == 0)
    66.             Debug.LogWarning("<b>[SteamVR Interaction]</b> Hand is on default layer. This puts unnecessary strain on hover checks as it is always true for hand colliders (which are then ignored).", this);
    67.         else
    68.             rightHoverLayerMask &= ~(1 << rightHand.gameObject.layer); //ignore self for hovering
    69.  
    70.         if (leftHand.gameObject.layer == 0)
    71.             Debug.LogWarning("<b>[SteamVR Interaction]</b> Hand is on default layer. This puts unnecessary strain on hover checks as it is always true for hand colliders (which are then ignored).", this);
    72.         else
    73.             leftHoverLayerMask &= ~(1 << leftHand.gameObject.layer); //ignore self for hovering
    74.  
    75.         // allocate array for colliders
    76.         rightOverlappingColliders = new Collider[32];
    77.         leftOverlappingColliders = new Collider[32];
    78.         foreach (Hand hand in Player.instance.hands)
    79.         {
    80.             hand.HideController();
    81.         }
    82.     }
    83.  
    84.     void SetRightGrab(SteamVR_Action_Boolean fromAction, SteamVR_Input_Sources fromSource, bool newState)
    85.     {
    86.         float scaledHoverRadius = 0.075f * Mathf.Abs(SteamVR_Utils.GetLossyScale(rightHand.transform));
    87.         float closestDistance = float.MaxValue;
    88.         Scaleable closestInteractable = null;
    89.         if (rightHand.mainRenderModel != null)
    90.             CheckHoveringForTransform(rightHand, rightOverlappingColliders, rightHand.mainRenderModel.GetBonePosition((int)rightHand.fingerJointHover), ref closestDistance, ref closestInteractable, Color.blue);
    91.  
    92.         if (this.Equals(closestInteractable))
    93.         {
    94.             if (newState)
    95.             {
    96.                 wasHovering = hovering;
    97.                 hovering = false;
    98.                 GrabHintOff(rightHand);
    99.             }
    100.             else
    101.             {
    102.                 wasHovering = hovering;
    103.                 hovering = true;
    104.                 if (isResizing)
    105.                 {
    106.                     stoppingResize = true;
    107.                     isResizing = false;
    108.                     EndScale(rightHand, leftGrabbing);
    109.                 }
    110.             }
    111.             rightGrabbing = newState;
    112.             SetResizing(rightHand);
    113.             SetPickup(newState, rightHand);
    114.         }
    115.     }
    116.     void SetLeftGrab(SteamVR_Action_Boolean fromAction, SteamVR_Input_Sources fromSource, bool newState)
    117.     {
    118.         float scaledHoverRadius = 0.075f * Mathf.Abs(SteamVR_Utils.GetLossyScale(leftHand.transform));
    119.         float closestDistance = float.MaxValue;
    120.         Scaleable closestInteractable = null;
    121.         if (leftHand.mainRenderModel != null)
    122.             CheckHoveringForTransform(leftHand, leftOverlappingColliders, leftHand.mainRenderModel.GetBonePosition((int)leftHand.fingerJointHover), ref closestDistance, ref closestInteractable, Color.blue);
    123.  
    124.         if (this.Equals(closestInteractable))
    125.         {
    126.             if (newState)
    127.             {
    128.                 wasHovering = hovering;
    129.                 hovering = false;
    130.                 GrabHintOff(leftHand);
    131.             }
    132.             else
    133.             {
    134.                 wasHovering = hovering;
    135.                 hovering = true;
    136.  
    137.                 if (isResizing)
    138.                 {
    139.                     stoppingResize = true;
    140.                     isResizing = false;
    141.                     EndScale(leftHand, rightGrabbing);
    142.                 }
    143.             }
    144.             leftGrabbing = newState;
    145.             SetResizing(leftHand);
    146.             SetPickup(newState, leftHand);
    147.         }
    148.     }
    149.     void EndScale(Hand hand, bool grabbing)
    150.     {
    151.         transform.SetParent(null);
    152.         if (grabbing)
    153.         {
    154.             transform.SetParent(hand.otherHand.transform);
    155.         }
    156.     }
    157.  
    158.  
    159.     // Update is called once per frame
    160.     void Update()
    161.     {
    162.         float rightClosestDistance = float.MaxValue;
    163.         Scaleable rightClosestInteractable = null;
    164.         if (rightHand.mainRenderModel != null)
    165.             CheckHoveringForTransform(rightHand, rightOverlappingColliders, rightHand.mainRenderModel.GetBonePosition((int)rightHand.fingerJointHover), ref rightClosestDistance, ref rightClosestInteractable, Color.blue);
    166.         float leftClosestDistance = float.MaxValue;
    167.         Scaleable leftClosestInteractable = null;
    168.         if (leftHand.mainRenderModel != null)
    169.             CheckHoveringForTransform(leftHand, leftOverlappingColliders, leftHand.mainRenderModel.GetBonePosition((int)leftHand.fingerJointHover), ref leftClosestDistance, ref leftClosestInteractable, Color.blue);
    170.         if (this.Equals(leftClosestInteractable) || this.Equals(rightClosestInteractable))
    171.         {
    172.             if (this.Equals(leftClosestInteractable))
    173.             {
    174.                 if (transform.parent == null)
    175.                 {
    176.                     GrabHintOn(leftHand, "Grab");
    177.                 }
    178.                 else if (transform.parent.Equals(rightHand.transform))
    179.                 {
    180.                     GrabHintOn(leftHand, "Scale");
    181.                 }
    182.             }
    183.             else
    184.             {
    185.  
    186.                 GrabHintOff(leftHand);
    187.             }
    188.             if (this.Equals(rightClosestInteractable))
    189.             {
    190.                 if (transform.parent == null)
    191.                 {
    192.                     GrabHintOn(rightHand, "Grab");
    193.                 }
    194.                 else if (transform.parent.Equals(leftHand.transform))
    195.                 {
    196.                     GrabHintOn(rightHand, "Scale");
    197.                 }
    198.             }
    199.             else
    200.             {
    201.  
    202.                 GrabHintOff(rightHand);
    203.             }
    204.             wasHovering = hovering;
    205.             hovering = true;
    206.  
    207.         }
    208.         else
    209.         {
    210.             wasHovering = hovering;
    211.             hovering = false;
    212.             GrabHintOff(rightHand);
    213.             GrabHintOff(leftHand);
    214.         }
    215.         if (hovering && !wasHovering)
    216.         {
    217.             CreateHighlightRenderers();
    218.         }
    219.         else if (!hovering || !wasHovering)
    220.         {
    221.             UnHighlight();
    222.         }
    223.         UpdateHighlightRenderers();
    224.  
    225.  
    226.         if (isResizing)
    227.         {
    228.             SetScale();
    229.         }
    230.         foreach (MeshRenderer r in flashingRenderers)
    231.         {
    232.             r.material.SetColor("_EmissionColor", Color.Lerp(Color.black, hintColor, Util.RemapNumberClamped(Mathf.Cos((Time.realtimeSinceStartup) * Mathf.PI * 2.0f), -1.0f, 1.0f, 0.0f, 1.0f)));
    233.             r.material.SetFloat("_EmissionScaleUI", Mathf.Lerp(0.0f, 10.0f, Util.RemapNumberClamped(Mathf.Cos((Time.realtimeSinceStartup) * Mathf.PI * 2.0f), -1.0f, 1.0f, 0.0f, 1.0f)));
    234.         }
    235.         if (rightTextHint != null)
    236.         {
    237.             rightTextHint.transform.LookAt(Camera.main.transform);
    238.         }
    239.         if (leftTextHint != null)
    240.         {
    241.             leftTextHint.transform.LookAt(Camera.main.transform);
    242.         }
    243.     }
    244.  
    245.     private void GrabHintOn(Hand hand, string text)
    246.     {
    247.         hand.ShowController();
    248.         hand.HideSkeleton();
    249.         // hand.GetComponent<HandPhysics>().enabled = false;
    250.         SteamVR_RenderModel model = hand.GetComponentInChildren<SteamVR_RenderModel>();
    251.         if (model != null)
    252.         {
    253.             string gripName = grabBoolean.GetRenderModelComponentName(hand.handType);
    254.             Dictionary<string, Transform> componentTransformMap = new Dictionary<string, Transform>();
    255.             for (int childIndex = 0; childIndex < model.transform.childCount; childIndex++)
    256.             {
    257.                 Transform child = model.transform.GetChild(childIndex);
    258.  
    259.                 if (!componentTransformMap.ContainsKey(child.name))
    260.                 {
    261.                     componentTransformMap.Add(child.name, child);
    262.                 }
    263.  
    264.             }
    265.             Transform buttonTransform = componentTransformMap[gripName];
    266.             if (hand.Equals(rightHand))
    267.             {
    268.                 if (rightTextHint == null)
    269.                 {
    270.                     rightTextHint = GameObject.Instantiate(grabHintPrefab, buttonTransform.position, buttonTransform.rotation);
    271.                     rightTextHint.transform.SetParent(buttonTransform);
    272.                     rightTextHint.transform.localPosition += new Vector3(-0.05349f, 0.01587f, -0.16261f);
    273.                 }
    274.                 rightTextHint.GetComponent<HintText>().text.text = text;
    275.             }
    276.             else
    277.             {
    278.                 if (leftTextHint == null)
    279.                 {
    280.                     leftTextHint = GameObject.Instantiate(grabHintPrefab, buttonTransform.position, buttonTransform.rotation);
    281.                     leftTextHint.transform.SetParent(buttonTransform);
    282.                     leftTextHint.transform.localPosition += new Vector3(0.05349f, -0.01587f, -0.16261f);
    283.                 }
    284.                 leftTextHint.GetComponent<HintText>().text.text = text;
    285.             }
    286.  
    287.             foreach (MeshRenderer r in buttonTransform.GetComponentsInChildren<MeshRenderer>())
    288.             {
    289.                 if (!flashingRenderers.Contains(r))
    290.                     flashingRenderers.Add(r);
    291.                 r.material.EnableKeyword("_EMISSION");
    292.             }
    293.         }
    294.  
    295.  
    296.     }
    297.  
    298.     private void GrabHintOff(Hand hand)
    299.     {
    300.         if (flashingRenderers.Count > 0)
    301.         {
    302.             SteamVR_RenderModel model = hand.GetComponentInChildren<SteamVR_RenderModel>();
    303.             if (model != null)
    304.             {
    305.                 string gripName = grabBoolean.GetRenderModelComponentName(hand.handType);
    306.                 Debug.Log($"gripName: {gripName}");
    307.                 Dictionary<string, Transform> componentTransformMap = new Dictionary<string, Transform>();
    308.                 for (int childIndex = 0; childIndex < model.transform.childCount; childIndex++)
    309.                 {
    310.                     Transform child = model.transform.GetChild(childIndex);
    311.  
    312.                     if (!componentTransformMap.ContainsKey(child.name))
    313.                     {
    314.                         componentTransformMap.Add(child.name, child);
    315.                     }
    316.  
    317.                 }
    318.                 Transform buttonTransform = componentTransformMap[gripName];
    319.                 foreach (MeshRenderer r in buttonTransform.GetComponentsInChildren<MeshRenderer>())
    320.                 {
    321.                     flashingRenderers.Remove(r);
    322.                     r.material.DisableKeyword("_EMISSION");
    323.                 }
    324.             }
    325.             if (hand.Equals(rightHand) && rightTextHint != null)
    326.             {
    327.                 Destroy(rightTextHint);
    328.             }
    329.             else if (hand.Equals(leftHand) && leftTextHint != null)
    330.             {
    331.                 Destroy(leftTextHint);
    332.             }
    333.  
    334.         }
    335.         if (flashingRenderers.Count == 0)
    336.         {
    337.             hand.HideController();
    338.             hand.ShowSkeleton();
    339.             // hand.GetComponent<HandPhysics>().enabled = true;
    340.         }
    341.     }
    342.  
    343.     private void UnHighlight()
    344.     {
    345.         Destroy(highlightHolder);
    346.         GrabHintOff(rightHand);
    347.         GrabHintOff(leftHand);
    348.     }
    349.  
    350.     void SetResizing(Hand mainHand)
    351.     {
    352.         if (leftGrabbing && rightGrabbing)
    353.         {
    354.             isResizing = true;
    355.             attachedToHand = true;
    356.             Debug.Log($"attached to {mainHand.handType}");
    357.             UnHighlight();
    358.             initialDistance = Vector3.Distance(mainHand.transform.position, mainHand.otherHand.transform.position);
    359.             middleMan = new GameObject();
    360.             Transform midpoint = middleMan.transform;
    361.             midpoint.position = (mainHand.otherHand.transform.position + mainHand.transform.position) / 2;
    362.             midpoint.rotation = FindRot(mainHand.transform, mainHand.otherHand.transform);
    363.             currentMain = mainHand;
    364.             transform.SetParent(midpoint);
    365.             midpoint.SetParent(null);
    366.             offsetPos = transform.localPosition;
    367.         }
    368.     }
    369.     void SetScale()
    370.     {
    371.         Vector3 mainPos = currentMain.transform.position;
    372.         Vector3 otherPos = currentMain.otherHand.transform.position;
    373.         float scale = Vector3.Distance(mainPos, otherPos) / initialDistance;
    374.         middleMan.transform.localScale = new Vector3(scale, scale, scale);
    375.         middleMan.transform.rotation = FindRot(currentMain.transform, currentMain.otherHand.transform);
    376.         middleMan.transform.position = (mainPos + otherPos) / 2;
    377.     }
    378.     public void ScaleAround(GameObject target, Vector3 pivot, Vector3 newScale)
    379.     {
    380.         Vector3 A = target.transform.localPosition;
    381.         Vector3 B = pivot;
    382.  
    383.         Vector3 C = A - B; // diff from object pivot to desired pivot/origin
    384.  
    385.         float RS = newScale.x / target.transform.localScale.x; // relataive scale factor
    386.  
    387.         // calc final position post-scale
    388.         Vector3 FP = B + C * RS;
    389.  
    390.         // finally, actually perform the scale/translation
    391.         target.transform.localScale = newScale;
    392.         target.transform.localPosition = FP;
    393.     }
    394.     //find rotation between two points to add to initialrot
    395.     private Quaternion FindRot(Transform t1, Transform t2)
    396.     {
    397.         Quaternion rot1 = t1.rotation;
    398.         Quaternion rot2 = t2.rotation;
    399.         Vector3 pos1 = t1.position;
    400.         Vector3 pos2 = t2.position;
    401.         Vector3 axis1to2 = (pos2 - pos1);
    402.         Vector3 up1 = t1.up;
    403.         Vector3 up2 = t2.up;
    404.         Vector3 averageUp = (up1 + up2) / 2;
    405.         Vector3 forward = Vector3.Cross(averageUp, axis1to2);
    406.         Vector3 finalUp = Vector3.Cross(forward, axis1to2);
    407.         Quaternion rot = Quaternion.LookRotation(forward, finalUp);
    408.  
    409.         return rot;
    410.     }
    411.     void SetPickup(bool newState, Hand hand)
    412.     {
    413.         if (isResizing || stoppingResize)
    414.         {
    415.             if (stoppingResize)
    416.                 stoppingResize = false;
    417.             return;
    418.         }
    419.         else if (newState)
    420.         {
    421.             transform.SetParent(hand.transform);
    422.             attachedToHand = true;
    423.             UnHighlight();
    424.             return;
    425.         }
    426.         else
    427.         {
    428.             transform.SetParent(null);
    429.             attachedToHand = false;
    430.  
    431.             UnHighlight();
    432.             CreateHighlightRenderers();
    433.             return;
    434.         }
    435.     }
    436.     protected virtual bool CheckHoveringForTransform(Hand hand, Collider[] overlappingColliders, Vector3 hoverPosition, ref float closestDistance, ref Scaleable closestInteractable, Color debugColor)
    437.     {
    438.         bool foundCloser = false;
    439.  
    440.         // null out old vals
    441.         for (int i = 0; i < overlappingColliders.Length; ++i)
    442.         {
    443.             overlappingColliders[i] = null;
    444.         }
    445.  
    446.         int numColliding = Physics.OverlapSphereNonAlloc(hoverPosition, hand.controllerHoverRadius, overlappingColliders, hand.hoverLayerMask.value);
    447.  
    448.         if (numColliding >= 32)
    449.             Debug.LogWarning("<b>[SteamVR Interaction]</b> This hand is overlapping the max number of colliders: " + 32 + ". Some collisions may be missed. Increase 32 on Hand.cs");
    450.  
    451.         // DebugVar
    452.         int iActualColliderCount = 0;
    453.  
    454.         // Pick the closest hovering
    455.         for (int colliderIndex = 0; colliderIndex < overlappingColliders.Length; colliderIndex++)
    456.         {
    457.             Collider collider = overlappingColliders[colliderIndex];
    458.             if (collider == null)
    459.                 continue;
    460.  
    461.             Scaleable contacting = collider.GetComponentInParent<Scaleable>();
    462.  
    463.             // Yeah, it's null, skip
    464.             if (contacting == null)
    465.                 continue;
    466.  
    467.             // Ignore this collider for hovering
    468.             IgnoreHovering ignore = collider.GetComponent<IgnoreHovering>();
    469.             if (ignore != null)
    470.             {
    471.                 if (ignore.onlyIgnoreHand == null || ignore.onlyIgnoreHand == hand)
    472.                 {
    473.                     continue;
    474.                 }
    475.             }
    476.  
    477.             // Can't hover over the object if it's attached
    478.             bool hoveringOverAttached = false;
    479.             for (int attachedIndex = 0; attachedIndex < hand.AttachedObjects.Count; attachedIndex++)
    480.             {
    481.                 if (hand.AttachedObjects[attachedIndex].attachedObject == contacting.gameObject)
    482.                 {
    483.                     hoveringOverAttached = true;
    484.                     break;
    485.                 }
    486.             }
    487.  
    488.             if (hoveringOverAttached)
    489.                 continue;
    490.  
    491.             // Best candidate so far...
    492.             float distance = Vector3.Distance(contacting.transform.position, hoverPosition);
    493.             //float distance = Vector3.Distance(collider.bounds.center, hoverPosition);
    494.             bool lowerPriority = false;
    495.             if (closestInteractable != null)
    496.             { // compare to closest interactable to check priority
    497.                 lowerPriority = contacting.hoverPriority < closestInteractable.hoverPriority;
    498.             }
    499.             bool isCloser = (distance < closestDistance);
    500.             if (isCloser && !lowerPriority)
    501.             {
    502.                 closestDistance = distance;
    503.                 closestInteractable = contacting;
    504.                 foundCloser = true;
    505.             }
    506.             iActualColliderCount++;
    507.         }
    508.  
    509.  
    510.         if (iActualColliderCount > 0 && iActualColliderCount != prevOverlappingColliders)
    511.         {
    512.             prevOverlappingColliders = iActualColliderCount;
    513.         }
    514.  
    515.         return foundCloser;
    516.     }
    517.     protected virtual void CreateHighlightRenderers()
    518.     {
    519.         existingSkinnedRenderers = this.GetComponentsInChildren<SkinnedMeshRenderer>(true);
    520.         if (highlightHolder == null)
    521.             highlightHolder = new GameObject("Highlighter");
    522.         highlightSkinnedRenderers = new SkinnedMeshRenderer[existingSkinnedRenderers.Length];
    523.  
    524.         for (int skinnedIndex = 0; skinnedIndex < existingSkinnedRenderers.Length; skinnedIndex++)
    525.         {
    526.             SkinnedMeshRenderer existingSkinned = existingSkinnedRenderers[skinnedIndex];
    527.  
    528.             if (ShouldIgnoreHighlight(existingSkinned))
    529.                 continue;
    530.  
    531.             GameObject newSkinnedHolder = new GameObject("SkinnedHolder");
    532.             newSkinnedHolder.transform.parent = highlightHolder.transform;
    533.             SkinnedMeshRenderer newSkinned = newSkinnedHolder.AddComponent<SkinnedMeshRenderer>();
    534.             Material[] materials = new Material[existingSkinned.sharedMaterials.Length];
    535.             for (int materialIndex = 0; materialIndex < materials.Length; materialIndex++)
    536.             {
    537.                 materials[materialIndex] = highlightMat;
    538.             }
    539.  
    540.             newSkinned.sharedMaterials = materials;
    541.             newSkinned.sharedMesh = existingSkinned.sharedMesh;
    542.             newSkinned.rootBone = existingSkinned.rootBone;
    543.             newSkinned.updateWhenOffscreen = existingSkinned.updateWhenOffscreen;
    544.             newSkinned.bones = existingSkinned.bones;
    545.  
    546.             highlightSkinnedRenderers[skinnedIndex] = newSkinned;
    547.         }
    548.  
    549.         MeshFilter[] existingFilters = this.GetComponentsInChildren<MeshFilter>(true);
    550.         existingRenderers = new MeshRenderer[existingFilters.Length];
    551.         highlightRenderers = new MeshRenderer[existingFilters.Length];
    552.  
    553.         for (int filterIndex = 0; filterIndex < existingFilters.Length; filterIndex++)
    554.         {
    555.             MeshFilter existingFilter = existingFilters[filterIndex];
    556.             MeshRenderer existingRenderer = existingFilter.GetComponent<MeshRenderer>();
    557.  
    558.             if (existingFilter == null || existingRenderer == null || ShouldIgnoreHighlight(existingFilter))
    559.                 continue;
    560.  
    561.             GameObject newFilterHolder = new GameObject("FilterHolder");
    562.             newFilterHolder.transform.parent = highlightHolder.transform;
    563.             MeshFilter newFilter = newFilterHolder.AddComponent<MeshFilter>();
    564.             newFilter.sharedMesh = existingFilter.sharedMesh;
    565.             MeshRenderer newRenderer = newFilterHolder.AddComponent<MeshRenderer>();
    566.  
    567.             Material[] materials = new Material[existingRenderer.sharedMaterials.Length];
    568.             for (int materialIndex = 0; materialIndex < materials.Length; materialIndex++)
    569.             {
    570.                 materials[materialIndex] = highlightMat;
    571.             }
    572.             newRenderer.sharedMaterials = materials;
    573.  
    574.             highlightRenderers[filterIndex] = newRenderer;
    575.             existingRenderers[filterIndex] = existingRenderer;
    576.         }
    577.     }
    578.  
    579.     protected virtual void UpdateHighlightRenderers()
    580.     {
    581.         if (highlightHolder == null)
    582.             return;
    583.  
    584.         for (int skinnedIndex = 0; skinnedIndex < existingSkinnedRenderers.Length; skinnedIndex++)
    585.         {
    586.             SkinnedMeshRenderer existingSkinned = existingSkinnedRenderers[skinnedIndex];
    587.             SkinnedMeshRenderer highlightSkinned = highlightSkinnedRenderers[skinnedIndex];
    588.  
    589.             if (existingSkinned != null && highlightSkinned != null && attachedToHand == false)
    590.             {
    591.                 highlightSkinned.transform.position = existingSkinned.transform.position;
    592.                 highlightSkinned.transform.rotation = existingSkinned.transform.rotation;
    593.                 highlightSkinned.transform.localScale = existingSkinned.transform.lossyScale;
    594.                 highlightSkinned.localBounds = existingSkinned.localBounds;
    595.                 highlightSkinned.enabled = hovering && existingSkinned.enabled && existingSkinned.gameObject.activeInHierarchy;
    596.  
    597.                 int blendShapeCount = existingSkinned.sharedMesh.blendShapeCount;
    598.                 for (int blendShapeIndex = 0; blendShapeIndex < blendShapeCount; blendShapeIndex++)
    599.                 {
    600.                     highlightSkinned.SetBlendShapeWeight(blendShapeIndex, existingSkinned.GetBlendShapeWeight(blendShapeIndex));
    601.                 }
    602.             }
    603.             else if (highlightSkinned != null)
    604.                 highlightSkinned.enabled = false;
    605.  
    606.         }
    607.  
    608.         for (int rendererIndex = 0; rendererIndex < highlightRenderers.Length; rendererIndex++)
    609.         {
    610.             MeshRenderer existingRenderer = existingRenderers[rendererIndex];
    611.             MeshRenderer highlightRenderer = highlightRenderers[rendererIndex];
    612.  
    613.             if (existingRenderer != null && highlightRenderer != null && attachedToHand == false)
    614.             {
    615.                 highlightRenderer.transform.position = existingRenderer.transform.position;
    616.                 highlightRenderer.transform.rotation = existingRenderer.transform.rotation;
    617.                 highlightRenderer.transform.localScale = existingRenderer.transform.lossyScale;
    618.                 highlightRenderer.enabled = hovering && existingRenderer.enabled && existingRenderer.gameObject.activeInHierarchy;
    619.             }
    620.             else if (highlightRenderer != null)
    621.             {
    622.                 highlightRenderer.enabled = false;
    623.                 GrabHintOff(rightHand);
    624.                 GrabHintOff(leftHand);
    625.             }
    626.         }
    627.     }
    628.     protected virtual bool ShouldIgnoreHighlight(Component component)
    629.     {
    630.         return ShouldIgnore(component.gameObject);
    631.     }
    632.  
    633.     protected virtual bool ShouldIgnore(GameObject check)
    634.     {
    635.         for (int ignoreIndex = 0; ignoreIndex < hideHighlight.Length; ignoreIndex++)
    636.         {
    637.             if (check == hideHighlight[ignoreIndex])
    638.                 return true;
    639.         }
    640.  
    641.         return false;
    642.     }
    643. }
    644.  
     
  2. miloszecket

    miloszecket

    Joined:
    Feb 4, 2019
    Posts:
    7
    The text hint prefab is a gameobject with a canvas child with a TMPro object, where the gameobject has a simple `HintText` component that solely accesses the TMPro object. I can post it if needed but it shouldn't be too hard to make

    edit: here it is
     
    Last edited: Jul 24, 2020
  3. tlskillman

    tlskillman

    Joined:
    Dec 12, 2015
    Posts:
    16
    Hi @miloszecket, I too have been looking for this functionality for a long time. I was excited to see your code but ran into some incompatibilites with the Unity XR environment I'm working in for a standalone Quest 2 app. Any chance you've already been down that rode and have an XR version of you code to share? Thanks.