campfire/Assets/SteamVR/InteractionSystem/Core/Scripts/HandCollider.cs
2020-04-29 20:40:05 +03:00

284 lines
9.8 KiB
C#

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace Valve.VR.InteractionSystem
{
public class HandCollider : MonoBehaviour
{
private new Rigidbody rigidbody;
[HideInInspector]
public HandPhysics hand;
public LayerMask collisionMask;
Collider[] colliders;
public FingerColliders fingerColliders;
[System.Serializable]
public class FingerColliders
{
[Tooltip("Starting at tip and going down. Max 2.")]
public Transform[] thumbColliders = new Transform[1];
[Tooltip("Starting at tip and going down. Max 3.")]
public Transform[] indexColliders = new Transform[2];
[Tooltip("Starting at tip and going down. Max 3.")]
public Transform[] middleColliders = new Transform[2];
[Tooltip("Starting at tip and going down. Max 3.")]
public Transform[] ringColliders = new Transform[2];
[Tooltip("Starting at tip and going down. Max 3.")]
public Transform[] pinkyColliders = new Transform[2];
public Transform[] this[int finger]
{
get
{
switch (finger)
{
case 0:
return thumbColliders;
case 1:
return indexColliders;
case 2:
return middleColliders;
case 3:
return ringColliders;
case 4:
return pinkyColliders;
default:
return null;
}
}
set
{
switch (finger)
{
case 0:
thumbColliders = value; break;
case 1:
indexColliders = value; break;
case 2:
middleColliders = value; break;
case 3:
ringColliders = value; break;
case 4:
pinkyColliders = value; break;
}
}
}
}
private static PhysicMaterial physicMaterial_lowfriction;
private static PhysicMaterial physicMaterial_highfriction;
private void Awake()
{
rigidbody = GetComponent<Rigidbody>();
rigidbody.maxAngularVelocity = 50;
}
private void Start()
{
colliders = GetComponentsInChildren<Collider>();
if (physicMaterial_lowfriction == null)
{
physicMaterial_lowfriction = new PhysicMaterial("hand_lowFriction");
physicMaterial_lowfriction.dynamicFriction = 0;
physicMaterial_lowfriction.staticFriction = 0;
physicMaterial_lowfriction.bounciness = 0;
physicMaterial_lowfriction.bounceCombine = PhysicMaterialCombine.Minimum;
physicMaterial_lowfriction.frictionCombine = PhysicMaterialCombine.Minimum;
}
if (physicMaterial_highfriction == null)
{
physicMaterial_highfriction = new PhysicMaterial("hand_highFriction");
physicMaterial_highfriction.dynamicFriction = 1f;
physicMaterial_highfriction.staticFriction = 1f;
physicMaterial_highfriction.bounciness = 0;
physicMaterial_highfriction.bounceCombine = PhysicMaterialCombine.Minimum;
physicMaterial_highfriction.frictionCombine = PhysicMaterialCombine.Average;
}
SetPhysicMaterial(physicMaterial_lowfriction);
scale = SteamVR_Utils.GetLossyScale(hand.transform);
}
void SetPhysicMaterial(PhysicMaterial mat)
{
if (colliders == null) colliders = GetComponentsInChildren<Collider>();
for (int i = 0; i < colliders.Length; i++)
{
colliders[i].sharedMaterial = mat;
}
}
float scale;
public void SetCollisionDetectionEnabled(bool value)
{
rigidbody.detectCollisions = value;
}
public void MoveTo(Vector3 position, Quaternion rotation)
{
targetPosition = position;
targetRotation = rotation;
//rigidbody.MovePosition(position);
//rigidbody.MoveRotation(rotation);
ExecuteFixedUpdate();
}
public void TeleportTo(Vector3 position, Quaternion rotation)
{
targetPosition = position;
targetRotation = rotation;
MoveTo(position, rotation);
rigidbody.position = position;
if (rotation.x != 0 || rotation.y != 0 || rotation.z != 0 || rotation.w != 0)
rigidbody.rotation = rotation;
//also update transform in case physics is disabled
transform.position = position;
transform.rotation = rotation;
}
public void Reset()
{
TeleportTo(targetPosition, targetRotation);
}
public void SetCenterPoint(Vector3 newCenter)
{
center = newCenter;
}
private Vector3 center;
private Vector3 targetPosition = Vector3.zero;
private Quaternion targetRotation = Quaternion.identity;
protected const float MaxVelocityChange = 10f;
protected const float VelocityMagic = 6000f;
protected const float AngularVelocityMagic = 50f;
protected const float MaxAngularVelocityChange = 20f;
public bool collidersInRadius;
protected void ExecuteFixedUpdate()
{
collidersInRadius = Physics.CheckSphere(center, 0.2f, collisionMask);
if (collidersInRadius == false)
{
//keep updating velocity, just in case. Otherwise you get jitter
rigidbody.velocity = Vector3.zero;
rigidbody.angularVelocity = Vector3.zero;
/*
rigidbody.velocity = (targetPosition - rigidbody.position) / Time.fixedDeltaTime;
float angle; Vector3 axis;
(targetRotation * Quaternion.Inverse(rigidbody.rotation)).ToAngleAxis(out angle, out axis);
rigidbody.angularVelocity = axis.normalized * angle / Time.fixedDeltaTime;
*/
rigidbody.MovePosition(targetPosition);
rigidbody.MoveRotation(targetRotation);
}
else
{
Vector3 velocityTarget, angularTarget;
bool success = GetTargetVelocities(out velocityTarget, out angularTarget);
if (success)
{
float maxAngularVelocityChange = MaxAngularVelocityChange * scale;
float maxVelocityChange = MaxVelocityChange * scale;
rigidbody.velocity = Vector3.MoveTowards(rigidbody.velocity, velocityTarget, maxVelocityChange);
rigidbody.angularVelocity = Vector3.MoveTowards(rigidbody.angularVelocity, angularTarget, maxAngularVelocityChange);
}
}
}
protected bool GetTargetVelocities(out Vector3 velocityTarget, out Vector3 angularTarget)
{
bool realNumbers = false;
float velocityMagic = VelocityMagic;
float angularVelocityMagic = AngularVelocityMagic;
Vector3 positionDelta = (targetPosition - rigidbody.position);
velocityTarget = (positionDelta * velocityMagic * Time.deltaTime);
if (float.IsNaN(velocityTarget.x) == false && float.IsInfinity(velocityTarget.x) == false)
{
realNumbers = true;
}
else
velocityTarget = Vector3.zero;
Quaternion rotationDelta = targetRotation * Quaternion.Inverse(rigidbody.rotation);
float angle;
Vector3 axis;
rotationDelta.ToAngleAxis(out angle, out axis);
if (angle > 180)
angle -= 360;
if (angle != 0 && float.IsNaN(axis.x) == false && float.IsInfinity(axis.x) == false)
{
angularTarget = angle * axis * angularVelocityMagic * Time.deltaTime;
realNumbers &= true;
}
else
angularTarget = Vector3.zero;
return realNumbers;
}
const float minCollisionEnergy = 0.1f;
const float maxCollisionEnergy = 1.0f;
const float minCollisionHapticsTime = 0.2f;
private float lastCollisionHapticsTime;
private void OnCollisionEnter(Collision collision)
{
bool touchingDynamic = false;
if (collision.rigidbody != null)
{
if (collision.rigidbody.isKinematic == false) touchingDynamic = true;
}
// low friction if touching static object, high friction if touching dynamic
SetPhysicMaterial(touchingDynamic ? physicMaterial_highfriction : physicMaterial_lowfriction);
float energy = collision.relativeVelocity.magnitude;
if(energy > minCollisionEnergy && Time.time - lastCollisionHapticsTime > minCollisionHapticsTime)
{
lastCollisionHapticsTime = Time.time;
float intensity = Util.RemapNumber(energy, minCollisionEnergy, maxCollisionEnergy, 0.3f, 1.0f);
float length = Util.RemapNumber(energy, minCollisionEnergy, maxCollisionEnergy, 0.0f, 0.06f);
hand.hand.TriggerHapticPulse(length, 100, intensity);
}
}
}
}