Search Unity

  1. We are migrating the Unity Forums to Unity Discussions. On July 12, the Unity Forums will become read-only. On July 15, Unity Discussions will become read-only until July 18, when the new design and the migrated forum contents will go live. Read our full announcement for more information and let us know if you have any questions.

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.