You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			90 lines
		
	
	
		
			3.3 KiB
		
	
	
	
		
			C#
		
	
			
		
		
	
	
			90 lines
		
	
	
		
			3.3 KiB
		
	
	
	
		
			C#
		
	
using UnityEngine;
 | 
						|
using System.Collections;
 | 
						|
using RootMotion.FinalIK;
 | 
						|
 | 
						|
namespace RootMotion.FinalIK {
 | 
						|
	
 | 
						|
	/// <summary>
 | 
						|
	/// Prevents body parts from penetrating scene geometry by offsetting effectors away from the colliders.
 | 
						|
	/// </summary>
 | 
						|
	public class PenetrationAvoidance : OffsetModifier {
 | 
						|
		
 | 
						|
		/// <summary>
 | 
						|
		/// Definition of avoidance and raycasting info.
 | 
						|
		/// </summary>
 | 
						|
		[System.Serializable]
 | 
						|
		public class Avoider {
 | 
						|
			
 | 
						|
			/// <summary>
 | 
						|
			/// Linking this to an effector
 | 
						|
			/// </summary>
 | 
						|
			[System.Serializable]
 | 
						|
			public class EffectorLink {
 | 
						|
				[Tooltip("Effector to apply the offset to.")] public FullBodyBipedEffector effector;
 | 
						|
				[Tooltip("Multiplier of the offset value, can be negative.")] public float weight;
 | 
						|
			}
 | 
						|
			
 | 
						|
			[Tooltip("Bones to start the raycast from. Multiple raycasts can be used by assigning more than 1 bone.")] public Transform[] raycastFrom;
 | 
						|
			[Tooltip("The Transform to raycast towards. Usually the body part that you want to keep from penetrating.")] public Transform raycastTo;
 | 
						|
			[Tooltip("If 0, will use simple raycasting, if > 0, will use sphere casting (better, but slower).")] [Range(0f, 1f)] public float raycastRadius;
 | 
						|
			[Tooltip("Linking this to FBBIK effectors.")] public EffectorLink[] effectors;
 | 
						|
			[Tooltip("The time of smooth interpolation of the offset value to avoid penetration.")] public float smoothTimeIn = 0.1f;
 | 
						|
			[Tooltip("The time of smooth interpolation of the offset value blending out of penetration avoidance.")] public float smoothTimeOut = 0.3f;
 | 
						|
			[Tooltip("Layers to keep penetrating from.")] public LayerMask layers;
 | 
						|
			
 | 
						|
			private Vector3 offset;
 | 
						|
			private Vector3 offsetTarget;
 | 
						|
			private Vector3 offsetV;
 | 
						|
			
 | 
						|
			public void Solve(IKSolverFullBodyBiped solver, float weight) {
 | 
						|
				// Get the offset to interpolate to
 | 
						|
				offsetTarget = GetOffsetTarget(solver);
 | 
						|
				
 | 
						|
				// Interpolating the offset value
 | 
						|
				float smoothDampTime = offsetTarget.sqrMagnitude > offset.sqrMagnitude? smoothTimeIn: smoothTimeOut;
 | 
						|
				offset = Vector3.SmoothDamp(offset, offsetTarget, ref offsetV, smoothDampTime);
 | 
						|
				
 | 
						|
				// Apply offset to the FBBIK effectors
 | 
						|
				foreach (EffectorLink link in effectors) {
 | 
						|
					solver.GetEffector(link.effector).positionOffset += offset * weight * link.weight;
 | 
						|
				}
 | 
						|
			}
 | 
						|
			
 | 
						|
			// Multiple raycasting to accumulate the offset
 | 
						|
			private Vector3 GetOffsetTarget(IKSolverFullBodyBiped solver) {
 | 
						|
				Vector3 t = Vector3.zero;
 | 
						|
				
 | 
						|
				foreach (Transform from in raycastFrom) {
 | 
						|
					t += Raycast(from.position, raycastTo.position + t);
 | 
						|
				}
 | 
						|
				
 | 
						|
				return t;
 | 
						|
			}
 | 
						|
			
 | 
						|
			// Raycast, return the offset that would not penetrate any colliders
 | 
						|
			private Vector3 Raycast(Vector3 from, Vector3 to) {
 | 
						|
				Vector3 direction = to - from;
 | 
						|
				float distance = direction.magnitude;
 | 
						|
				RaycastHit hit;
 | 
						|
				
 | 
						|
				if (raycastRadius <= 0f) {
 | 
						|
					Physics.Raycast(from, direction, out hit, distance, layers);
 | 
						|
				} else {
 | 
						|
					Physics.SphereCast(from, raycastRadius, direction, out hit, distance, layers);
 | 
						|
				}
 | 
						|
				
 | 
						|
				if (hit.collider == null) return Vector3.zero;
 | 
						|
				
 | 
						|
				return Vector3.Project(-direction.normalized * (distance - hit.distance), hit.normal);
 | 
						|
			}
 | 
						|
		}
 | 
						|
		
 | 
						|
		[Tooltip("Definitions of penetration avoidances.")] public Avoider[] avoiders;
 | 
						|
		
 | 
						|
		// Called by IKSolverFullBody before updating
 | 
						|
		protected override void OnModifyOffset() {
 | 
						|
			foreach (Avoider avoider in avoiders) avoider.Solve(ik.solver, weight);
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 |