Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- using System;
- using System.Collections;
- using System.Collections.Generic;
- using UnityEngine;
- using Valve.VR;
- using Valve.VR.InteractionSystem;
- public class Scaleable : MonoBehaviour
- {
- private GameObject middleMan;
- private bool stoppingResize;
- private SteamVR_Action_Boolean grabBoolean = SteamVR_Input.GetAction<SteamVR_Action_Boolean>("GrabGrip");
- public SteamVR_Skeleton_JointIndexEnum fingerJointHover = SteamVR_Skeleton_JointIndexEnum.indexTip;
- protected MeshRenderer[] highlightRenderers;
- protected MeshRenderer[] existingRenderers;
- protected GameObject highlightHolder;
- protected SkinnedMeshRenderer[] highlightSkinnedRenderers;
- protected SkinnedMeshRenderer[] existingSkinnedRenderers;
- protected static Material highlightMat;
- [Tooltip("An array of child gameObjects to not render a highlight for. Things like transparent parts, vfx, etc.")]
- public GameObject[] hideHighlight;
- private bool isResizing;
- public SteamVR_Action_Boolean rightGrab;
- public Hand rightHand;
- private bool rightGrabbing;
- private Collider[] rightOverlappingColliders;
- public LayerMask rightHoverLayerMask = -1;
- public SteamVR_Action_Boolean leftGrab;
- public Hand leftHand;
- private bool hovering;
- private bool wasHovering;
- private bool leftGrabbing;
- private Collider[] leftOverlappingColliders;
- public LayerMask leftHoverLayerMask = -1;
- public int hoverPriority;
- private int prevOverlappingColliders = 0;
- private bool attachedToHand;
- private float initialDistance;
- private Vector3 initialScale;
- private Quaternion initialRot;
- private Vector3 offsetPos;
- private Hand currentMain;
- private List<MeshRenderer> flashingRenderers = new List<MeshRenderer>();
- public Color hintColor;
- public GameObject grabHintPrefab;
- private GameObject rightTextHint;
- private GameObject leftTextHint;
- void OnEnable()
- {
- rightGrab.AddOnChangeListener(SetRightGrab, rightHand.handType);
- leftGrab.AddOnChangeListener(SetLeftGrab, leftHand.handType);
- }
- void Start()
- {
- highlightMat = (Material)Resources.Load("SteamVR_HoverHighlight", typeof(Material));
- if (highlightMat == null)
- {
- 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);
- }
- if (rightHand.gameObject.layer == 0)
- 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);
- else
- rightHoverLayerMask &= ~(1 << rightHand.gameObject.layer); //ignore self for hovering
- if (leftHand.gameObject.layer == 0)
- 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);
- else
- leftHoverLayerMask &= ~(1 << leftHand.gameObject.layer); //ignore self for hovering
- // allocate array for colliders
- rightOverlappingColliders = new Collider[32];
- leftOverlappingColliders = new Collider[32];
- foreach (Hand hand in Player.instance.hands)
- {
- hand.HideController();
- }
- }
- void SetRightGrab(SteamVR_Action_Boolean fromAction, SteamVR_Input_Sources fromSource, bool newState)
- {
- float scaledHoverRadius = 0.075f * Mathf.Abs(SteamVR_Utils.GetLossyScale(rightHand.transform));
- float closestDistance = float.MaxValue;
- Scaleable closestInteractable = null;
- if (rightHand.mainRenderModel != null)
- CheckHoveringForTransform(rightHand, rightOverlappingColliders, rightHand.mainRenderModel.GetBonePosition((int)rightHand.fingerJointHover), ref closestDistance, ref closestInteractable, Color.blue);
- if (this.Equals(closestInteractable))
- {
- if (newState)
- {
- wasHovering = hovering;
- hovering = false;
- GrabHintOff(rightHand);
- }
- else
- {
- wasHovering = hovering;
- hovering = true;
- if (isResizing)
- {
- stoppingResize = true;
- isResizing = false;
- EndScale(rightHand, leftGrabbing);
- }
- }
- rightGrabbing = newState;
- SetResizing(rightHand);
- SetPickup(newState, rightHand);
- }
- }
- void SetLeftGrab(SteamVR_Action_Boolean fromAction, SteamVR_Input_Sources fromSource, bool newState)
- {
- float scaledHoverRadius = 0.075f * Mathf.Abs(SteamVR_Utils.GetLossyScale(leftHand.transform));
- float closestDistance = float.MaxValue;
- Scaleable closestInteractable = null;
- if (leftHand.mainRenderModel != null)
- CheckHoveringForTransform(leftHand, leftOverlappingColliders, leftHand.mainRenderModel.GetBonePosition((int)leftHand.fingerJointHover), ref closestDistance, ref closestInteractable, Color.blue);
- if (this.Equals(closestInteractable))
- {
- if (newState)
- {
- wasHovering = hovering;
- hovering = false;
- GrabHintOff(leftHand);
- }
- else
- {
- wasHovering = hovering;
- hovering = true;
- if (isResizing)
- {
- stoppingResize = true;
- isResizing = false;
- EndScale(leftHand, rightGrabbing);
- }
- }
- leftGrabbing = newState;
- SetResizing(leftHand);
- SetPickup(newState, leftHand);
- }
- }
- void EndScale(Hand hand, bool grabbing)
- {
- transform.SetParent(null);
- if (grabbing)
- {
- transform.SetParent(hand.otherHand.transform);
- }
- }
- // Update is called once per frame
- void Update()
- {
- float rightClosestDistance = float.MaxValue;
- Scaleable rightClosestInteractable = null;
- if (rightHand.mainRenderModel != null)
- CheckHoveringForTransform(rightHand, rightOverlappingColliders, rightHand.mainRenderModel.GetBonePosition((int)rightHand.fingerJointHover), ref rightClosestDistance, ref rightClosestInteractable, Color.blue);
- float leftClosestDistance = float.MaxValue;
- Scaleable leftClosestInteractable = null;
- if (leftHand.mainRenderModel != null)
- CheckHoveringForTransform(leftHand, leftOverlappingColliders, leftHand.mainRenderModel.GetBonePosition((int)leftHand.fingerJointHover), ref leftClosestDistance, ref leftClosestInteractable, Color.blue);
- if (this.Equals(leftClosestInteractable) || this.Equals(rightClosestInteractable))
- {
- if (this.Equals(leftClosestInteractable))
- {
- if (transform.parent == null)
- {
- GrabHintOn(leftHand, "Grab");
- }
- else if (transform.parent.Equals(rightHand.transform))
- {
- GrabHintOn(leftHand, "Scale");
- }
- }
- else
- {
- GrabHintOff(leftHand);
- }
- if (this.Equals(rightClosestInteractable))
- {
- if (transform.parent == null)
- {
- GrabHintOn(rightHand, "Grab");
- }
- else if (transform.parent.Equals(leftHand.transform))
- {
- GrabHintOn(rightHand, "Scale");
- }
- }
- else
- {
- GrabHintOff(rightHand);
- }
- wasHovering = hovering;
- hovering = true;
- }
- else
- {
- wasHovering = hovering;
- hovering = false;
- GrabHintOff(rightHand);
- GrabHintOff(leftHand);
- }
- if (hovering && !wasHovering)
- {
- CreateHighlightRenderers();
- }
- else if (!hovering || !wasHovering)
- {
- UnHighlight();
- }
- UpdateHighlightRenderers();
- if (isResizing)
- {
- SetScale();
- }
- foreach (MeshRenderer r in flashingRenderers)
- {
- 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)));
- 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)));
- }
- if (rightTextHint != null)
- {
- rightTextHint.transform.LookAt(Camera.main.transform);
- }
- if (leftTextHint != null)
- {
- leftTextHint.transform.LookAt(Camera.main.transform);
- }
- }
- private void GrabHintOn(Hand hand, string text)
- {
- hand.ShowController();
- hand.HideSkeleton();
- // hand.GetComponent<HandPhysics>().enabled = false;
- SteamVR_RenderModel model = hand.GetComponentInChildren<SteamVR_RenderModel>();
- if (model != null)
- {
- string gripName = grabBoolean.GetRenderModelComponentName(hand.handType);
- Dictionary<string, Transform> componentTransformMap = new Dictionary<string, Transform>();
- for (int childIndex = 0; childIndex < model.transform.childCount; childIndex++)
- {
- Transform child = model.transform.GetChild(childIndex);
- if (!componentTransformMap.ContainsKey(child.name))
- {
- componentTransformMap.Add(child.name, child);
- }
- }
- Transform buttonTransform = componentTransformMap[gripName];
- if (hand.Equals(rightHand))
- {
- if (rightTextHint == null)
- {
- rightTextHint = GameObject.Instantiate(grabHintPrefab, buttonTransform.position, buttonTransform.rotation);
- rightTextHint.transform.SetParent(buttonTransform);
- rightTextHint.transform.localPosition += new Vector3(-0.05349f, 0.01587f, -0.16261f);
- }
- rightTextHint.GetComponent<HintText>().text.text = text;
- }
- else
- {
- if (leftTextHint == null)
- {
- leftTextHint = GameObject.Instantiate(grabHintPrefab, buttonTransform.position, buttonTransform.rotation);
- leftTextHint.transform.SetParent(buttonTransform);
- leftTextHint.transform.localPosition += new Vector3(0.05349f, -0.01587f, -0.16261f);
- }
- leftTextHint.GetComponent<HintText>().text.text = text;
- }
- foreach (MeshRenderer r in buttonTransform.GetComponentsInChildren<MeshRenderer>())
- {
- if (!flashingRenderers.Contains(r))
- flashingRenderers.Add(r);
- r.material.EnableKeyword("_EMISSION");
- }
- }
- }
- private void GrabHintOff(Hand hand)
- {
- if (flashingRenderers.Count > 0)
- {
- SteamVR_RenderModel model = hand.GetComponentInChildren<SteamVR_RenderModel>();
- if (model != null)
- {
- string gripName = grabBoolean.GetRenderModelComponentName(hand.handType);
- Debug.Log($"gripName: {gripName}");
- Dictionary<string, Transform> componentTransformMap = new Dictionary<string, Transform>();
- for (int childIndex = 0; childIndex < model.transform.childCount; childIndex++)
- {
- Transform child = model.transform.GetChild(childIndex);
- if (!componentTransformMap.ContainsKey(child.name))
- {
- componentTransformMap.Add(child.name, child);
- }
- }
- Transform buttonTransform = componentTransformMap[gripName];
- foreach (MeshRenderer r in buttonTransform.GetComponentsInChildren<MeshRenderer>())
- {
- flashingRenderers.Remove(r);
- r.material.DisableKeyword("_EMISSION");
- }
- }
- if (hand.Equals(rightHand) && rightTextHint != null)
- {
- Destroy(rightTextHint);
- }
- else if (hand.Equals(leftHand) && leftTextHint != null)
- {
- Destroy(leftTextHint);
- }
- }
- if (flashingRenderers.Count == 0)
- {
- hand.HideController();
- hand.ShowSkeleton();
- // hand.GetComponent<HandPhysics>().enabled = true;
- }
- }
- private void UnHighlight()
- {
- Destroy(highlightHolder);
- GrabHintOff(rightHand);
- GrabHintOff(leftHand);
- }
- void SetResizing(Hand mainHand)
- {
- if (leftGrabbing && rightGrabbing)
- {
- isResizing = true;
- attachedToHand = true;
- Debug.Log($"attached to {mainHand.handType}");
- UnHighlight();
- initialDistance = Vector3.Distance(mainHand.transform.position, mainHand.otherHand.transform.position);
- middleMan = new GameObject();
- Transform midpoint = middleMan.transform;
- midpoint.position = (mainHand.otherHand.transform.position + mainHand.transform.position) / 2;
- midpoint.rotation = FindRot(mainHand.transform, mainHand.otherHand.transform);
- currentMain = mainHand;
- transform.SetParent(midpoint);
- midpoint.SetParent(null);
- offsetPos = transform.localPosition;
- }
- }
- void SetScale()
- {
- Vector3 mainPos = currentMain.transform.position;
- Vector3 otherPos = currentMain.otherHand.transform.position;
- float scale = Vector3.Distance(mainPos, otherPos) / initialDistance;
- middleMan.transform.localScale = new Vector3(scale, scale, scale);
- middleMan.transform.rotation = FindRot(currentMain.transform, currentMain.otherHand.transform);
- middleMan.transform.position = (mainPos + otherPos) / 2;
- }
- public void ScaleAround(GameObject target, Vector3 pivot, Vector3 newScale)
- {
- Vector3 A = target.transform.localPosition;
- Vector3 B = pivot;
- Vector3 C = A - B; // diff from object pivot to desired pivot/origin
- float RS = newScale.x / target.transform.localScale.x; // relataive scale factor
- // calc final position post-scale
- Vector3 FP = B + C * RS;
- // finally, actually perform the scale/translation
- target.transform.localScale = newScale;
- target.transform.localPosition = FP;
- }
- //find rotation between two points to add to initialrot
- private Quaternion FindRot(Transform t1, Transform t2)
- {
- Quaternion rot1 = t1.rotation;
- Quaternion rot2 = t2.rotation;
- Vector3 pos1 = t1.position;
- Vector3 pos2 = t2.position;
- Vector3 axis1to2 = (pos2 - pos1);
- Vector3 up1 = t1.up;
- Vector3 up2 = t2.up;
- Vector3 averageUp = (up1 + up2) / 2;
- Vector3 forward = Vector3.Cross(averageUp, axis1to2);
- Vector3 finalUp = Vector3.Cross(forward, axis1to2);
- Quaternion rot = Quaternion.LookRotation(forward, finalUp);
- return rot;
- }
- void SetPickup(bool newState, Hand hand)
- {
- if (isResizing || stoppingResize)
- {
- if (stoppingResize)
- stoppingResize = false;
- return;
- }
- else if (newState)
- {
- transform.SetParent(hand.transform);
- attachedToHand = true;
- UnHighlight();
- return;
- }
- else
- {
- transform.SetParent(null);
- attachedToHand = false;
- UnHighlight();
- CreateHighlightRenderers();
- return;
- }
- }
- protected virtual bool CheckHoveringForTransform(Hand hand, Collider[] overlappingColliders, Vector3 hoverPosition, ref float closestDistance, ref Scaleable closestInteractable, Color debugColor)
- {
- bool foundCloser = false;
- // null out old vals
- for (int i = 0; i < overlappingColliders.Length; ++i)
- {
- overlappingColliders[i] = null;
- }
- int numColliding = Physics.OverlapSphereNonAlloc(hoverPosition, hand.controllerHoverRadius, overlappingColliders, hand.hoverLayerMask.value);
- if (numColliding >= 32)
- 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");
- // DebugVar
- int iActualColliderCount = 0;
- // Pick the closest hovering
- for (int colliderIndex = 0; colliderIndex < overlappingColliders.Length; colliderIndex++)
- {
- Collider collider = overlappingColliders[colliderIndex];
- if (collider == null)
- continue;
- Scaleable contacting = collider.GetComponentInParent<Scaleable>();
- // Yeah, it's null, skip
- if (contacting == null)
- continue;
- // Ignore this collider for hovering
- IgnoreHovering ignore = collider.GetComponent<IgnoreHovering>();
- if (ignore != null)
- {
- if (ignore.onlyIgnoreHand == null || ignore.onlyIgnoreHand == hand)
- {
- continue;
- }
- }
- // Can't hover over the object if it's attached
- bool hoveringOverAttached = false;
- for (int attachedIndex = 0; attachedIndex < hand.AttachedObjects.Count; attachedIndex++)
- {
- if (hand.AttachedObjects[attachedIndex].attachedObject == contacting.gameObject)
- {
- hoveringOverAttached = true;
- break;
- }
- }
- if (hoveringOverAttached)
- continue;
- // Best candidate so far...
- float distance = Vector3.Distance(contacting.transform.position, hoverPosition);
- //float distance = Vector3.Distance(collider.bounds.center, hoverPosition);
- bool lowerPriority = false;
- if (closestInteractable != null)
- { // compare to closest interactable to check priority
- lowerPriority = contacting.hoverPriority < closestInteractable.hoverPriority;
- }
- bool isCloser = (distance < closestDistance);
- if (isCloser && !lowerPriority)
- {
- closestDistance = distance;
- closestInteractable = contacting;
- foundCloser = true;
- }
- iActualColliderCount++;
- }
- if (iActualColliderCount > 0 && iActualColliderCount != prevOverlappingColliders)
- {
- prevOverlappingColliders = iActualColliderCount;
- }
- return foundCloser;
- }
- protected virtual void CreateHighlightRenderers()
- {
- existingSkinnedRenderers = this.GetComponentsInChildren<SkinnedMeshRenderer>(true);
- if (highlightHolder == null)
- highlightHolder = new GameObject("Highlighter");
- highlightSkinnedRenderers = new SkinnedMeshRenderer[existingSkinnedRenderers.Length];
- for (int skinnedIndex = 0; skinnedIndex < existingSkinnedRenderers.Length; skinnedIndex++)
- {
- SkinnedMeshRenderer existingSkinned = existingSkinnedRenderers[skinnedIndex];
- if (ShouldIgnoreHighlight(existingSkinned))
- continue;
- GameObject newSkinnedHolder = new GameObject("SkinnedHolder");
- newSkinnedHolder.transform.parent = highlightHolder.transform;
- SkinnedMeshRenderer newSkinned = newSkinnedHolder.AddComponent<SkinnedMeshRenderer>();
- Material[] materials = new Material[existingSkinned.sharedMaterials.Length];
- for (int materialIndex = 0; materialIndex < materials.Length; materialIndex++)
- {
- materials[materialIndex] = highlightMat;
- }
- newSkinned.sharedMaterials = materials;
- newSkinned.sharedMesh = existingSkinned.sharedMesh;
- newSkinned.rootBone = existingSkinned.rootBone;
- newSkinned.updateWhenOffscreen = existingSkinned.updateWhenOffscreen;
- newSkinned.bones = existingSkinned.bones;
- highlightSkinnedRenderers[skinnedIndex] = newSkinned;
- }
- MeshFilter[] existingFilters = this.GetComponentsInChildren<MeshFilter>(true);
- existingRenderers = new MeshRenderer[existingFilters.Length];
- highlightRenderers = new MeshRenderer[existingFilters.Length];
- for (int filterIndex = 0; filterIndex < existingFilters.Length; filterIndex++)
- {
- MeshFilter existingFilter = existingFilters[filterIndex];
- MeshRenderer existingRenderer = existingFilter.GetComponent<MeshRenderer>();
- if (existingFilter == null || existingRenderer == null || ShouldIgnoreHighlight(existingFilter))
- continue;
- GameObject newFilterHolder = new GameObject("FilterHolder");
- newFilterHolder.transform.parent = highlightHolder.transform;
- MeshFilter newFilter = newFilterHolder.AddComponent<MeshFilter>();
- newFilter.sharedMesh = existingFilter.sharedMesh;
- MeshRenderer newRenderer = newFilterHolder.AddComponent<MeshRenderer>();
- Material[] materials = new Material[existingRenderer.sharedMaterials.Length];
- for (int materialIndex = 0; materialIndex < materials.Length; materialIndex++)
- {
- materials[materialIndex] = highlightMat;
- }
- newRenderer.sharedMaterials = materials;
- highlightRenderers[filterIndex] = newRenderer;
- existingRenderers[filterIndex] = existingRenderer;
- }
- }
- protected virtual void UpdateHighlightRenderers()
- {
- if (highlightHolder == null)
- return;
- for (int skinnedIndex = 0; skinnedIndex < existingSkinnedRenderers.Length; skinnedIndex++)
- {
- SkinnedMeshRenderer existingSkinned = existingSkinnedRenderers[skinnedIndex];
- SkinnedMeshRenderer highlightSkinned = highlightSkinnedRenderers[skinnedIndex];
- if (existingSkinned != null && highlightSkinned != null && attachedToHand == false)
- {
- highlightSkinned.transform.position = existingSkinned.transform.position;
- highlightSkinned.transform.rotation = existingSkinned.transform.rotation;
- highlightSkinned.transform.localScale = existingSkinned.transform.lossyScale;
- highlightSkinned.localBounds = existingSkinned.localBounds;
- highlightSkinned.enabled = hovering && existingSkinned.enabled && existingSkinned.gameObject.activeInHierarchy;
- int blendShapeCount = existingSkinned.sharedMesh.blendShapeCount;
- for (int blendShapeIndex = 0; blendShapeIndex < blendShapeCount; blendShapeIndex++)
- {
- highlightSkinned.SetBlendShapeWeight(blendShapeIndex, existingSkinned.GetBlendShapeWeight(blendShapeIndex));
- }
- }
- else if (highlightSkinned != null)
- highlightSkinned.enabled = false;
- }
- for (int rendererIndex = 0; rendererIndex < highlightRenderers.Length; rendererIndex++)
- {
- MeshRenderer existingRenderer = existingRenderers[rendererIndex];
- MeshRenderer highlightRenderer = highlightRenderers[rendererIndex];
- if (existingRenderer != null && highlightRenderer != null && attachedToHand == false)
- {
- highlightRenderer.transform.position = existingRenderer.transform.position;
- highlightRenderer.transform.rotation = existingRenderer.transform.rotation;
- highlightRenderer.transform.localScale = existingRenderer.transform.lossyScale;
- highlightRenderer.enabled = hovering && existingRenderer.enabled && existingRenderer.gameObject.activeInHierarchy;
- }
- else if (highlightRenderer != null)
- {
- highlightRenderer.enabled = false;
- GrabHintOff(rightHand);
- GrabHintOff(leftHand);
- }
- }
- }
- protected virtual bool ShouldIgnoreHighlight(Component component)
- {
- return ShouldIgnore(component.gameObject);
- }
- protected virtual bool ShouldIgnore(GameObject check)
- {
- for (int ignoreIndex = 0; ignoreIndex < hideHighlight.Length; ignoreIndex++)
- {
- if (check == hideHighlight[ignoreIndex])
- return true;
- }
- return false;
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement