initial upload
This commit is contained in:
BIN
Unity-Master/Assets/Plugins/RootMotion/FinalIK/_DEMOS/FBBIK/Amplifier.unity
(Stored with Git LFS)
Normal file
BIN
Unity-Master/Assets/Plugins/RootMotion/FinalIK/_DEMOS/FBBIK/Amplifier.unity
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -0,0 +1,6 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1a221864c2d4141cfab6c79846565174
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Unity-Master/Assets/Plugins/RootMotion/FinalIK/_DEMOS/FBBIK/Body Tilt.unity
(Stored with Git LFS)
Normal file
BIN
Unity-Master/Assets/Plugins/RootMotion/FinalIK/_DEMOS/FBBIK/Body Tilt.unity
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -0,0 +1,6 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 15dd3a3d1606b41ab8169e92e914a946
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Unity-Master/Assets/Plugins/RootMotion/FinalIK/_DEMOS/FBBIK/Boxing.unity
(Stored with Git LFS)
Normal file
BIN
Unity-Master/Assets/Plugins/RootMotion/FinalIK/_DEMOS/FBBIK/Boxing.unity
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -0,0 +1,6 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b85ace1101bfa4110b70af1c694c1745
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Unity-Master/Assets/Plugins/RootMotion/FinalIK/_DEMOS/FBBIK/Carry Box.unity
(Stored with Git LFS)
Normal file
BIN
Unity-Master/Assets/Plugins/RootMotion/FinalIK/_DEMOS/FBBIK/Carry Box.unity
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -0,0 +1,6 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0c1f1d575fa3e405d8214cda9f3e60ae
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Unity-Master/Assets/Plugins/RootMotion/FinalIK/_DEMOS/FBBIK/Driving.unity
(Stored with Git LFS)
Normal file
BIN
Unity-Master/Assets/Plugins/RootMotion/FinalIK/_DEMOS/FBBIK/Driving.unity
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -0,0 +1,6 @@
|
||||
fileFormatVersion: 2
|
||||
guid: eb8a7e9cae153408d8242a655f13e2ac
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Unity-Master/Assets/Plugins/RootMotion/FinalIK/_DEMOS/FBBIK/Effector Offset.unity
(Stored with Git LFS)
Normal file
BIN
Unity-Master/Assets/Plugins/RootMotion/FinalIK/_DEMOS/FBBIK/Effector Offset.unity
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -0,0 +1,6 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 56ab62ebe17334ae19eab6a1dd946afc
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Unity-Master/Assets/Plugins/RootMotion/FinalIK/_DEMOS/FBBIK/First Person Shooter (Recoil).unity
(Stored with Git LFS)
Normal file
BIN
Unity-Master/Assets/Plugins/RootMotion/FinalIK/_DEMOS/FBBIK/First Person Shooter (Recoil).unity
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6b33fdae1f2dc4c7c875a10e438ea419
|
||||
timeCreated: 1461307985
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Unity-Master/Assets/Plugins/RootMotion/FinalIK/_DEMOS/FBBIK/First Person Shooter.unity
(Stored with Git LFS)
Normal file
BIN
Unity-Master/Assets/Plugins/RootMotion/FinalIK/_DEMOS/FBBIK/First Person Shooter.unity
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -0,0 +1,6 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 133e8d48ba7914813954c2a5b5d4e8bd
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Unity-Master/Assets/Plugins/RootMotion/FinalIK/_DEMOS/FBBIK/Head Effector (Hand Controllers).unity
(Stored with Git LFS)
Normal file
BIN
Unity-Master/Assets/Plugins/RootMotion/FinalIK/_DEMOS/FBBIK/Head Effector (Hand Controllers).unity
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d67a9d6cb5f28114d8a006db1dd1860c
|
||||
timeCreated: 1456919434
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Unity-Master/Assets/Plugins/RootMotion/FinalIK/_DEMOS/FBBIK/Head Effector.unity
(Stored with Git LFS)
Normal file
BIN
Unity-Master/Assets/Plugins/RootMotion/FinalIK/_DEMOS/FBBIK/Head Effector.unity
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -0,0 +1,6 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f971715c34ef7496f930e939d65b2634
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Unity-Master/Assets/Plugins/RootMotion/FinalIK/_DEMOS/FBBIK/Hit Reaction.unity
(Stored with Git LFS)
Normal file
BIN
Unity-Master/Assets/Plugins/RootMotion/FinalIK/_DEMOS/FBBIK/Hit Reaction.unity
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -0,0 +1,6 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8777d34ec9e694f2c98e65d98922b023
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Unity-Master/Assets/Plugins/RootMotion/FinalIK/_DEMOS/FBBIK/Holding Hands.unity
(Stored with Git LFS)
Normal file
BIN
Unity-Master/Assets/Plugins/RootMotion/FinalIK/_DEMOS/FBBIK/Holding Hands.unity
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -0,0 +1,6 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 45f325b7eef7b4c3dbb04f3c83398709
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Unity-Master/Assets/Plugins/RootMotion/FinalIK/_DEMOS/FBBIK/Inertia.unity
(Stored with Git LFS)
Normal file
BIN
Unity-Master/Assets/Plugins/RootMotion/FinalIK/_DEMOS/FBBIK/Inertia.unity
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -0,0 +1,6 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8064853db60c34f9d93fc3372647e7e9
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Unity-Master/Assets/Plugins/RootMotion/FinalIK/_DEMOS/FBBIK/Interaction Character-Character.unity
(Stored with Git LFS)
Normal file
BIN
Unity-Master/Assets/Plugins/RootMotion/FinalIK/_DEMOS/FBBIK/Interaction Character-Character.unity
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -0,0 +1,6 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cbedbd696f39a46c9bd4bd5d94c55c4a
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Unity-Master/Assets/Plugins/RootMotion/FinalIK/_DEMOS/FBBIK/Interaction Pick Up 2-Handed.unity
(Stored with Git LFS)
Normal file
BIN
Unity-Master/Assets/Plugins/RootMotion/FinalIK/_DEMOS/FBBIK/Interaction Pick Up 2-Handed.unity
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -0,0 +1,6 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c8c08a518832d484b8d8de7804c18a97
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Unity-Master/Assets/Plugins/RootMotion/FinalIK/_DEMOS/FBBIK/Interaction Trigger.unity
(Stored with Git LFS)
Normal file
BIN
Unity-Master/Assets/Plugins/RootMotion/FinalIK/_DEMOS/FBBIK/Interaction Trigger.unity
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -0,0 +1,6 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 583d03f8c5b5e4b30b67347ab343a511
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Unity-Master/Assets/Plugins/RootMotion/FinalIK/_DEMOS/FBBIK/Interaction Walls.unity
(Stored with Git LFS)
Normal file
BIN
Unity-Master/Assets/Plugins/RootMotion/FinalIK/_DEMOS/FBBIK/Interaction Walls.unity
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -0,0 +1,6 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 57465d524287546bba2116eb2e39ad01
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Unity-Master/Assets/Plugins/RootMotion/FinalIK/_DEMOS/FBBIK/Interaction.unity
(Stored with Git LFS)
Normal file
BIN
Unity-Master/Assets/Plugins/RootMotion/FinalIK/_DEMOS/FBBIK/Interaction.unity
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -0,0 +1,6 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6aa7e7dc669224b66abda13816fd66e8
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Unity-Master/Assets/Plugins/RootMotion/FinalIK/_DEMOS/FBBIK/Kissing Rig.unity
(Stored with Git LFS)
Normal file
BIN
Unity-Master/Assets/Plugins/RootMotion/FinalIK/_DEMOS/FBBIK/Kissing Rig.unity
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -0,0 +1,6 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d0377e8a32b944328bf2c301c8265a73
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Unity-Master/Assets/Plugins/RootMotion/FinalIK/_DEMOS/FBBIK/Mapping To Ragdoll.unity
(Stored with Git LFS)
Normal file
BIN
Unity-Master/Assets/Plugins/RootMotion/FinalIK/_DEMOS/FBBIK/Mapping To Ragdoll.unity
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -0,0 +1,6 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 92d2f08133f9e43e3baf1be5c19efa98
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Unity-Master/Assets/Plugins/RootMotion/FinalIK/_DEMOS/FBBIK/Motion Absorb.unity
(Stored with Git LFS)
Normal file
BIN
Unity-Master/Assets/Plugins/RootMotion/FinalIK/_DEMOS/FBBIK/Motion Absorb.unity
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -0,0 +1,6 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c2e2ef913e2ad4a7ba3fdbcee7344b0b
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Unity-Master/Assets/Plugins/RootMotion/FinalIK/_DEMOS/FBBIK/Offset Effector.unity
(Stored with Git LFS)
Normal file
BIN
Unity-Master/Assets/Plugins/RootMotion/FinalIK/_DEMOS/FBBIK/Offset Effector.unity
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -0,0 +1,6 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0ef9773715d234a1c826469b246b2209
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Unity-Master/Assets/Plugins/RootMotion/FinalIK/_DEMOS/FBBIK/Penetration Avoidance.unity
(Stored with Git LFS)
Normal file
BIN
Unity-Master/Assets/Plugins/RootMotion/FinalIK/_DEMOS/FBBIK/Penetration Avoidance.unity
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 888b8015bdd29f540b676314d9b6576e
|
||||
timeCreated: 1524812697
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Unity-Master/Assets/Plugins/RootMotion/FinalIK/_DEMOS/FBBIK/Ragdoll Utility.unity
(Stored with Git LFS)
Normal file
BIN
Unity-Master/Assets/Plugins/RootMotion/FinalIK/_DEMOS/FBBIK/Ragdoll Utility.unity
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -0,0 +1,6 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 87d20d0d91268468bb51673c2d887ee2
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Unity-Master/Assets/Plugins/RootMotion/FinalIK/_DEMOS/FBBIK/Recoil.unity
(Stored with Git LFS)
Normal file
BIN
Unity-Master/Assets/Plugins/RootMotion/FinalIK/_DEMOS/FBBIK/Recoil.unity
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -0,0 +1,6 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d48f3468e9a994c9ea6cee5166cf194d
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9e79e75b388784e188c2a3b50d014ce1
|
||||
folderAsset: yes
|
||||
timeCreated: 1434626795
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,128 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using RootMotion.FinalIK;
|
||||
|
||||
namespace RootMotion.Demos {
|
||||
|
||||
/// <summary>
|
||||
/// Warping an effector from animation space to world space.
|
||||
/// The weight curve of the warp is used to add the offset from "Warp From" to "Warp To" to the effector.
|
||||
/// "Warp From" should be a Transform parented to the root of the character, hence in animation space (virtual position where a soccer player's foot hits the ball in the animation).
|
||||
/// "Warp To" should be a Transform in the world space (the actual ball).
|
||||
/// </summary>
|
||||
public class AnimationWarping : OffsetModifier {
|
||||
|
||||
/// <summary>
|
||||
/// Definition of a warp from 'warpFrom' to 'warpTo' by normalized time of the animation
|
||||
/// </summary>
|
||||
[System.Serializable]
|
||||
public struct Warp {
|
||||
[Tooltip("Layer of the 'Animation State' in the Animator.")]
|
||||
public int animationLayer;
|
||||
[Tooltip("Name of the state in the Animator to warp.")]
|
||||
public string animationState;
|
||||
[Tooltip("Warping weight by normalized time of the animation state.")]
|
||||
public AnimationCurve weightCurve;
|
||||
[Tooltip("Animated point to warp from. This should be in character space so keep this Transform parented to the root of the character.")]
|
||||
public Transform warpFrom;
|
||||
[Tooltip("World space point to warp to.")]
|
||||
public Transform warpTo;
|
||||
[Tooltip("Which FBBIK effector to use?")]
|
||||
public FullBodyBipedEffector effector;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Using effector.positionOffset or effector.position with effector.positionWeight?
|
||||
/// </summary>
|
||||
[System.Serializable]
|
||||
public enum EffectorMode {
|
||||
PositionOffset,
|
||||
Position,
|
||||
}
|
||||
|
||||
[Tooltip("Reference to the Animator component to use")]
|
||||
public Animator animator;
|
||||
[Tooltip("Using effector.positionOffset or effector.position with effector.positionWeight? " +
|
||||
"The former will enable you to use effector.position for other things, the latter will weigh in the effectors, hence using Reach and Pull in the process.")]
|
||||
public EffectorMode effectorMode;
|
||||
|
||||
[Space(10)]
|
||||
[Tooltip("The array of warps, can have multiple simultaneous warps.")]
|
||||
public Warp[] warps;
|
||||
|
||||
private EffectorMode lastMode;
|
||||
|
||||
protected override void Start() {
|
||||
base.Start();
|
||||
|
||||
lastMode = effectorMode;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current warping weight of the warp at the specified index.
|
||||
/// </summary>
|
||||
public float GetWarpWeight(int warpIndex) {
|
||||
if (warpIndex < 0) {
|
||||
Debug.LogError("Warp index out of range.");
|
||||
return 0f;
|
||||
}
|
||||
if (warpIndex >= warps.Length) {
|
||||
Debug.LogError("Warp index out of range.");
|
||||
return 0f;
|
||||
}
|
||||
if (animator == null) {
|
||||
Debug.LogError("Animator unassigned in AnimationWarping");
|
||||
return 0f;
|
||||
}
|
||||
|
||||
// Get the animator state info
|
||||
AnimatorStateInfo info = animator.GetCurrentAnimatorStateInfo(warps[warpIndex].animationLayer);
|
||||
|
||||
// If not currently playing the animation state of the warp, return
|
||||
if (!info.IsName(warps[warpIndex].animationState)) return 0f;
|
||||
|
||||
// Evaluate the weight of the warp by the current normalized time of the state
|
||||
return warps[warpIndex].weightCurve.Evaluate(info.normalizedTime - (int)info.normalizedTime);
|
||||
}
|
||||
|
||||
// Called each time before FBBIK solves
|
||||
protected override void OnModifyOffset() {
|
||||
// Go through all the warps...
|
||||
for (int i = 0; i < warps.Length; i++) {
|
||||
float warpWeight = GetWarpWeight(i);
|
||||
|
||||
// Get the offset form warpFrom to warpTo
|
||||
Vector3 offset = warps[i].warpTo.position - warps[i].warpFrom.position;
|
||||
|
||||
// Add that offset to the effector (using positionOffset additively, because it will be reset to Vector3.zero by FBBIK after each update)
|
||||
switch(effectorMode) {
|
||||
case EffectorMode.PositionOffset:
|
||||
ik.solver.GetEffector(warps[i].effector).positionOffset += offset * warpWeight * weight;
|
||||
break;
|
||||
case EffectorMode.Position:
|
||||
ik.solver.GetEffector(warps[i].effector).position = ik.solver.GetEffector(warps[i].effector).bone.position + offset;
|
||||
ik.solver.GetEffector(warps[i].effector).positionWeight = weight * warpWeight;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Switching modes safely, weighing out effector positionWeights
|
||||
if (lastMode == EffectorMode.Position && effectorMode == EffectorMode.PositionOffset) {
|
||||
foreach (Warp warp in warps) {
|
||||
ik.solver.GetEffector(warp.effector).positionWeight = 0f;
|
||||
}
|
||||
}
|
||||
|
||||
lastMode = effectorMode;
|
||||
}
|
||||
|
||||
// Set effector positionWeights to 0 if in "Position" effector mode
|
||||
void OnDisable() {
|
||||
if (effectorMode != EffectorMode.Position) return;
|
||||
|
||||
foreach (Warp warp in warps) {
|
||||
ik.solver.GetEffector(warp.effector).positionWeight = 0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 07341efad24fc425b88a57536e3a568c
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,63 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using RootMotion.FinalIK;
|
||||
|
||||
namespace RootMotion.Demos {
|
||||
|
||||
/// <summary>
|
||||
/// Basic Mecanim Animator controller for 3rd person view.
|
||||
/// </summary>
|
||||
public class AnimatorController3rdPerson : MonoBehaviour {
|
||||
|
||||
public float rotateSpeed = 7f; // Speed of rotating the character
|
||||
public float blendSpeed = 10f; // Animation blending speed
|
||||
public float maxAngle = 90f; // Max angular offset from camera direction
|
||||
public float moveSpeed = 1.5f; // The speed of moving the character with no root motion
|
||||
public float rootMotionWeight; // Crossfading between procedural movement and root motion
|
||||
|
||||
protected Animator animator; // The Animator
|
||||
protected Vector3 moveBlend, moveInput, velocity;
|
||||
|
||||
protected virtual void Start() {
|
||||
animator = GetComponent<Animator>();
|
||||
}
|
||||
|
||||
// Moving the character
|
||||
void OnAnimatorMove() {
|
||||
velocity = Vector3.Lerp (velocity, transform.rotation * Vector3.ClampMagnitude(moveInput, 1f) * moveSpeed, Time.deltaTime * blendSpeed);
|
||||
|
||||
// Crossfading between procedural movement and root motion.
|
||||
transform.position += Vector3.Lerp(velocity * Time.deltaTime, animator.deltaPosition, rootMotionWeight);
|
||||
}
|
||||
|
||||
// Move the character
|
||||
public virtual void Move(Vector3 moveInput, bool isMoving, Vector3 faceDirection, Vector3 aimTarget) {
|
||||
// Store variables that we need in other methods
|
||||
this.moveInput = moveInput;
|
||||
|
||||
// Get the facing direction relative to the character rotation
|
||||
Vector3 faceDirectionLocal = transform.InverseTransformDirection(faceDirection);
|
||||
|
||||
// Get the angle between the facing direction and character forward
|
||||
float angle = Mathf.Atan2(faceDirectionLocal.x, faceDirectionLocal.z) * Mathf.Rad2Deg;
|
||||
|
||||
// Find the rotation
|
||||
float rotation = angle * Time.deltaTime * rotateSpeed;
|
||||
|
||||
// Clamp the rotation to maxAngle
|
||||
if (angle > maxAngle) rotation = Mathf.Clamp(rotation, angle - maxAngle, rotation);
|
||||
if (angle < -maxAngle) rotation = Mathf.Clamp(rotation, rotation, angle + maxAngle);
|
||||
|
||||
// Rotate the character
|
||||
transform.Rotate(Vector3.up, rotation);
|
||||
|
||||
// Locomotion animation blending
|
||||
moveBlend = Vector3.Lerp(moveBlend, moveInput, Time.deltaTime * blendSpeed);
|
||||
|
||||
// Set Animator parameters
|
||||
animator.SetFloat("X", moveBlend.x);
|
||||
animator.SetFloat("Z", moveBlend.z);
|
||||
animator.SetBool("IsMoving", isMoving);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 898bc8d3a77f74e0b8cd466413a4b20d
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,122 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using RootMotion.FinalIK;
|
||||
|
||||
namespace RootMotion.Demos {
|
||||
|
||||
// Extends the default Animator controller for 3rd person view to add IK
|
||||
public class AnimatorController3rdPersonIK: AnimatorController3rdPerson {
|
||||
|
||||
[Range(0f, 1f)] public float headLookWeight = 1f;
|
||||
public Vector3 gunHoldOffset;
|
||||
public Vector3 leftHandOffset;
|
||||
public Recoil recoil;
|
||||
|
||||
// The IK components
|
||||
private AimIK aim;
|
||||
private FullBodyBipedIK ik;
|
||||
|
||||
private Vector3 headLookAxis;
|
||||
private Vector3 leftHandPosRelToRightHand;
|
||||
private Quaternion leftHandRotRelToRightHand;
|
||||
private Vector3 aimTarget;
|
||||
private Quaternion rightHandRotation;
|
||||
|
||||
protected override void Start() {
|
||||
base.Start();
|
||||
|
||||
// Find the IK components
|
||||
aim = GetComponent<AimIK>();
|
||||
ik = GetComponent<FullBodyBipedIK>();
|
||||
ik.solver.OnPreRead += OnPreRead;
|
||||
|
||||
// Disable the IK components to manage their updating
|
||||
aim.enabled = false;
|
||||
ik.enabled = false;
|
||||
|
||||
// Presuming head is rotated towards character forward at Start
|
||||
headLookAxis = ik.references.head.InverseTransformVector(ik.references.root.forward);
|
||||
|
||||
// Enable the upper-body aiming pose
|
||||
animator.SetLayerWeight(1, 1f);
|
||||
}
|
||||
|
||||
public override void Move(Vector3 moveInput, bool isMoving, Vector3 faceDirection, Vector3 aimTarget) {
|
||||
base.Move(moveInput, isMoving, faceDirection, aimTarget);
|
||||
|
||||
// Snatch the aim target from the Move call, it will be used by AimIK (Move is called by CharacterController3rdPerson that controls the actual motion of the character)
|
||||
this.aimTarget = aimTarget;
|
||||
|
||||
// IK procedures, make sure this updates AFTER the camera is moved/rotated
|
||||
// Sample something from the current pose of the character
|
||||
Read();
|
||||
|
||||
// AimIK pass
|
||||
AimIK();
|
||||
|
||||
// FBBIK pass - put the left hand back to where it was relative to the right hand before AimIK solved
|
||||
FBBIK();
|
||||
|
||||
// AimIK pass
|
||||
AimIK();
|
||||
|
||||
// Rotate the head to look at the aim target
|
||||
HeadLookAt(aimTarget);
|
||||
}
|
||||
|
||||
private void Read() {
|
||||
// Remember the position and rotation of the left hand relative to the right hand
|
||||
leftHandPosRelToRightHand = ik.references.rightHand.InverseTransformPoint(ik.references.leftHand.position);
|
||||
leftHandRotRelToRightHand = Quaternion.Inverse(ik.references.rightHand.rotation) * ik.references.leftHand.rotation;
|
||||
}
|
||||
|
||||
private void AimIK() {
|
||||
// Set AimIK target position and update
|
||||
aim.solver.IKPosition = aimTarget;
|
||||
aim.solver.Update(); // Update AimIK
|
||||
}
|
||||
|
||||
// Positioning the left hand on the gun after aiming has finished
|
||||
private void FBBIK() {
|
||||
// Store the current rotation of the right hand
|
||||
rightHandRotation = ik.references.rightHand.rotation;
|
||||
|
||||
// Offsetting hands, you might need that to support multiple weapons with the same aiming pose
|
||||
Vector3 rightHandOffset = ik.references.rightHand.rotation * gunHoldOffset;
|
||||
ik.solver.rightHandEffector.positionOffset += rightHandOffset;
|
||||
|
||||
if (recoil != null) recoil.SetHandRotations(rightHandRotation * leftHandRotRelToRightHand, rightHandRotation);
|
||||
|
||||
// Update FBBIK
|
||||
ik.solver.Update();
|
||||
|
||||
// Rotating the hand bones after IK has finished
|
||||
if (recoil != null) {
|
||||
ik.references.rightHand.rotation = recoil.rotationOffset * rightHandRotation;
|
||||
ik.references.leftHand.rotation = recoil.rotationOffset * rightHandRotation * leftHandRotRelToRightHand;
|
||||
} else {
|
||||
ik.references.rightHand.rotation = rightHandRotation;
|
||||
ik.references.leftHand.rotation = rightHandRotation * leftHandRotRelToRightHand;
|
||||
}
|
||||
}
|
||||
|
||||
// Final calculations before FBBIK solves. Recoil has already solved by, so we can use its calculated offsets.
|
||||
// Here we set the left hand position relative to the position and rotation of the right hand.
|
||||
private void OnPreRead() {
|
||||
Quaternion r = recoil != null? recoil.rotationOffset * rightHandRotation: rightHandRotation;
|
||||
Vector3 leftHandTarget = ik.references.rightHand.position + ik.solver.rightHandEffector.positionOffset + r * leftHandPosRelToRightHand;
|
||||
ik.solver.leftHandEffector.positionOffset += leftHandTarget - ik.references.leftHand.position - ik.solver.leftHandEffector.positionOffset + r * leftHandOffset;
|
||||
}
|
||||
|
||||
// Rotating the head to look at the target
|
||||
private void HeadLookAt(Vector3 lookAtTarget) {
|
||||
Quaternion headRotationTarget = Quaternion.FromToRotation(ik.references.head.rotation * headLookAxis, lookAtTarget - ik.references.head.position);
|
||||
ik.references.head.rotation = Quaternion.Lerp(Quaternion.identity, headRotationTarget, headLookWeight) * ik.references.head.rotation;
|
||||
}
|
||||
|
||||
// Cleaning up the delegates
|
||||
void OnDestroy() {
|
||||
if (ik != null) ik.solver.OnPreRead -= OnPreRead;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7cacab300efda4d8c8c72660683917b8
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,43 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using RootMotion.FinalIK;
|
||||
|
||||
namespace RootMotion.Demos {
|
||||
|
||||
/// <summary>
|
||||
/// Contols animation for a third person person controller.
|
||||
/// </summary>
|
||||
public class CharacterAnimationThirdPersonIK: CharacterAnimationThirdPerson {
|
||||
|
||||
private FullBodyBipedIK ik;
|
||||
|
||||
protected override void Start() {
|
||||
base.Start();
|
||||
|
||||
ik = GetComponent<FullBodyBipedIK>();
|
||||
}
|
||||
|
||||
protected override void LateUpdate() {
|
||||
base.LateUpdate();
|
||||
|
||||
// Rotate the upper body a little bit to world up vector if the character is rotated (for wall-running)
|
||||
if (Vector3.Angle(transform.up, Vector3.up) <= 0.01f) return;
|
||||
|
||||
Quaternion r = Quaternion.FromToRotation(transform.up, Vector3.up);
|
||||
|
||||
RotateEffector(ik.solver.bodyEffector, r, 0.1f);
|
||||
RotateEffector(ik.solver.leftShoulderEffector, r, 0.2f);
|
||||
RotateEffector(ik.solver.rightShoulderEffector, r, 0.2f);
|
||||
RotateEffector(ik.solver.leftHandEffector, r, 0.1f);
|
||||
RotateEffector(ik.solver.rightHandEffector, r, 0.1f);
|
||||
}
|
||||
|
||||
// Rotate an effector from the root of the character
|
||||
private void RotateEffector(IKEffector effector, Quaternion rotation, float mlp) {
|
||||
Vector3 d1 = effector.bone.position - transform.position;
|
||||
Vector3 d2 = rotation * d1;
|
||||
Vector3 offset = d2 - d1;
|
||||
effector.positionOffset += offset * mlp;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: da28f9c80db074b10842df00a4b50b12
|
||||
timeCreated: 1435755417
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,57 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
|
||||
namespace RootMotion.Demos {
|
||||
|
||||
/// <summary>
|
||||
/// Basic Mecanim character controller for 3rd person view.
|
||||
/// </summary>
|
||||
public class CharacterController3rdPerson: MonoBehaviour {
|
||||
|
||||
public CameraController cam; // The camera
|
||||
|
||||
private AnimatorController3rdPerson animatorController; // The Animator controller
|
||||
|
||||
void Start() {
|
||||
animatorController = GetComponent<AnimatorController3rdPerson>();
|
||||
|
||||
cam.enabled = false;
|
||||
}
|
||||
|
||||
void LateUpdate() {
|
||||
// Update the camera first so we always have its final translation in the frame
|
||||
cam.UpdateInput();
|
||||
cam.UpdateTransform();
|
||||
|
||||
// Read the input
|
||||
Vector3 input = inputVector;
|
||||
|
||||
// Should the character be moving?
|
||||
// inputVectorRaw is required here for not starting a transition to idle on that one frame where inputVector is Vector3.zero when reversing directions.
|
||||
bool isMoving = inputVector != Vector3.zero || inputVectorRaw != Vector3.zero;
|
||||
|
||||
// Character look at vector.
|
||||
Vector3 lookDirection = cam.transform.forward;
|
||||
|
||||
// Aiming target
|
||||
Vector3 aimTarget = cam.transform.position + (lookDirection * 10f);
|
||||
|
||||
// Move the character.
|
||||
animatorController.Move(input, isMoving, lookDirection, aimTarget);
|
||||
}
|
||||
|
||||
// Convert the input axis to a vector
|
||||
private static Vector3 inputVector {
|
||||
get {
|
||||
return new Vector3(Input.GetAxis("Horizontal"), 0f, Input.GetAxis("Vertical"));
|
||||
}
|
||||
}
|
||||
|
||||
// Convert the raw input axis to a vector
|
||||
private static Vector3 inputVectorRaw {
|
||||
get {
|
||||
return new Vector3(Input.GetAxisRaw("Horizontal"), 0f, Input.GetAxisRaw("Vertical"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2e2dfae99419b433289fb54f4c763435
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,40 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using RootMotion.FinalIK;
|
||||
|
||||
namespace RootMotion.Demos {
|
||||
|
||||
/// <summary>
|
||||
/// Demo for offsetting Effectors.
|
||||
/// </summary>
|
||||
public class EffectorOffset : OffsetModifier {
|
||||
|
||||
// If 1, The hand effectors will maintain their position relative to their parent triangle's rotation {root node, left shoulder, right shoulder}
|
||||
[Range(0f, 1f)]
|
||||
public float handsMaintainRelativePositionWeight;
|
||||
|
||||
// The offset vectors for each effector
|
||||
public Vector3 bodyOffset, leftShoulderOffset, rightShoulderOffset, leftThighOffset, rightThighOffset, leftHandOffset, rightHandOffset, leftFootOffset, rightFootOffset;
|
||||
|
||||
protected override void OnModifyOffset() {
|
||||
// How much will the hand effectors maintain their position relative to their parent triangle's rotation {root node, left shoulder, right shoulder} ?
|
||||
ik.solver.leftHandEffector.maintainRelativePositionWeight = handsMaintainRelativePositionWeight;
|
||||
ik.solver.rightHandEffector.maintainRelativePositionWeight = handsMaintainRelativePositionWeight;
|
||||
|
||||
// Apply position offsets relative to this GameObject's rotation.
|
||||
ik.solver.bodyEffector.positionOffset += transform.rotation * bodyOffset * weight;
|
||||
ik.solver.leftShoulderEffector.positionOffset += transform.rotation * leftShoulderOffset * weight;
|
||||
ik.solver.rightShoulderEffector.positionOffset += transform.rotation * rightShoulderOffset * weight;
|
||||
ik.solver.leftThighEffector.positionOffset += transform.rotation * leftThighOffset * weight;
|
||||
ik.solver.rightThighEffector.positionOffset += transform.rotation * rightThighOffset * weight;
|
||||
ik.solver.leftHandEffector.positionOffset += transform.rotation * leftHandOffset * weight;
|
||||
ik.solver.rightHandEffector.positionOffset += transform.rotation * rightHandOffset * weight;
|
||||
ik.solver.leftFootEffector.positionOffset += transform.rotation * leftFootOffset * weight;
|
||||
ik.solver.rightFootEffector.positionOffset += transform.rotation * rightFootOffset * weight;
|
||||
|
||||
// NB! effector position offsets are reset to Vector3.zero after FBBIK update is complete.
|
||||
// This enables to have more than one script modifying the position offset of effectors.
|
||||
// Therefore instead of writing effector.positionOffset = value, write effector.positionOffset += value instead.
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c96ec8ee850b44337a19453c26b170ed
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,76 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using RootMotion.FinalIK;
|
||||
|
||||
namespace RootMotion.Demos {
|
||||
|
||||
/// <summary>
|
||||
/// Demo of exploding a viking using FBBIK
|
||||
/// </summary>
|
||||
public class ExplosionDemo : MonoBehaviour {
|
||||
|
||||
public SimpleLocomotion character; // Reference to the SimpleLocomotion component
|
||||
public float forceMlp = 1f; // Explosion force
|
||||
public float upForce = 1f; // Explosion up forve
|
||||
public float weightFalloffSpeed = 1f; // The speed of explosion falloff
|
||||
public AnimationCurve weightFalloff; // Explosion weight falloff
|
||||
public AnimationCurve explosionForceByDistance; // The force of the explosion relative to character distance to the bomb
|
||||
public AnimationCurve scale; // Scaling the bomb GameObject with the explosion
|
||||
|
||||
private float weight = 0f;
|
||||
private Vector3 defaultScale = Vector3.one;
|
||||
private Rigidbody r;
|
||||
private FullBodyBipedIK ik;
|
||||
|
||||
void Start() {
|
||||
// Storing the default scale of the bomb
|
||||
defaultScale = transform.localScale;
|
||||
|
||||
r = character.GetComponent<Rigidbody>();
|
||||
ik = character.GetComponent<FullBodyBipedIK>();
|
||||
}
|
||||
|
||||
// Update is called once per frame
|
||||
void Update () {
|
||||
weight = Mathf.Clamp(weight - Time.deltaTime * weightFalloffSpeed, 0f, 1f);
|
||||
|
||||
// Exploding the bomb
|
||||
if (Input.GetKeyDown(KeyCode.E) && character.isGrounded) {
|
||||
// Set FBBIK weight to 1
|
||||
ik.solver.IKPositionWeight = 1f;
|
||||
|
||||
// Set limb effector positions to where they are at the momemt
|
||||
ik.solver.leftHandEffector.position = ik.solver.leftHandEffector.bone.position;
|
||||
ik.solver.rightHandEffector.position = ik.solver.rightHandEffector.bone.position;
|
||||
ik.solver.leftFootEffector.position = ik.solver.leftFootEffector.bone.position;
|
||||
ik.solver.rightFootEffector.position = ik.solver.rightFootEffector.bone.position;
|
||||
|
||||
weight = 1f;
|
||||
|
||||
// Add explosion force to the character rigidbody
|
||||
Vector3 direction = r.position - transform.position;
|
||||
direction.y = 0f;
|
||||
float explosionForce = explosionForceByDistance.Evaluate(direction.magnitude);
|
||||
r.velocity = (direction.normalized + (Vector3.up * upForce)) * explosionForce * forceMlp;
|
||||
}
|
||||
|
||||
if (weight < 0.5f && character.isGrounded) {
|
||||
weight = Mathf.Clamp(weight - Time.deltaTime * 3f, 0f, 1f);
|
||||
}
|
||||
|
||||
// Set effector weights
|
||||
SetEffectorWeights(weightFalloff.Evaluate(weight));
|
||||
|
||||
// Set bomb scale
|
||||
transform.localScale = scale.Evaluate(weight) * defaultScale;
|
||||
}
|
||||
|
||||
// Set FBBIK limb end-effector weights to value
|
||||
private void SetEffectorWeights(float w) {
|
||||
ik.solver.leftHandEffector.positionWeight = w;
|
||||
ik.solver.rightHandEffector.positionWeight = w;
|
||||
ik.solver.leftFootEffector.positionWeight = w;
|
||||
ik.solver.rightFootEffector.positionWeight = w;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5ee6c787adaa94deaa3c39e20323f559
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,60 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using RootMotion.FinalIK;
|
||||
|
||||
namespace RootMotion.Demos {
|
||||
|
||||
/// <summary>
|
||||
/// Manages FBBIK settings that are not visible in the FBBIK custom inspector.
|
||||
/// </summary>
|
||||
public class FBBIKSettings : MonoBehaviour {
|
||||
|
||||
/// <summary>
|
||||
/// Settings for a limb
|
||||
/// </summary>
|
||||
[System.Serializable]
|
||||
public class Limb {
|
||||
public FBIKChain.Smoothing reachSmoothing; // Smoothing of the Reach effect (since 0.2)
|
||||
public float maintainRelativePositionWeight; // Weight of maintaining the limb's position relative to the body part that it is attached to (since 0.2, used to be IKEffector.Mode.MaintainRelativePosition)
|
||||
public float mappingWeight = 1f;
|
||||
|
||||
// Apply the settings
|
||||
public void Apply(FullBodyBipedChain chain, IKSolverFullBodyBiped solver) {
|
||||
solver.GetChain(chain).reachSmoothing = reachSmoothing;
|
||||
solver.GetEndEffector(chain).maintainRelativePositionWeight = maintainRelativePositionWeight;
|
||||
solver.GetLimbMapping(chain).weight = mappingWeight;
|
||||
}
|
||||
}
|
||||
|
||||
public FullBodyBipedIK ik; // Reference to the FBBIK component
|
||||
public bool disableAfterStart; // If true, will not update after Start
|
||||
public Limb leftArm, rightArm, leftLeg, rightLeg; // The Limbs
|
||||
|
||||
public float rootPin = 0f; // Weight of pinning the root node to its animated position
|
||||
public bool bodyEffectChildNodes = true; // If true, the body effector will also drag the thigh effectors
|
||||
|
||||
// Apply all the settings to the FBBIK solver
|
||||
public void UpdateSettings() {
|
||||
if (ik == null) return;
|
||||
|
||||
leftArm.Apply(FullBodyBipedChain.LeftArm, ik.solver);
|
||||
rightArm.Apply(FullBodyBipedChain.RightArm, ik.solver);
|
||||
leftLeg.Apply(FullBodyBipedChain.LeftLeg, ik.solver);
|
||||
rightLeg.Apply(FullBodyBipedChain.RightLeg, ik.solver);
|
||||
|
||||
ik.solver.chain[0].pin = rootPin;
|
||||
ik.solver.bodyEffector.effectChildNodes = bodyEffectChildNodes;
|
||||
}
|
||||
|
||||
void Start() {
|
||||
Debug.Log("FBBIKSettings is deprecated, you can now edit all the settings from the custom inspector of the FullBodyBipedIK component.");
|
||||
|
||||
UpdateSettings();
|
||||
if (disableAfterStart) this.enabled = false;
|
||||
}
|
||||
|
||||
void Update() {
|
||||
UpdateSettings();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ed9ee7f6cba9940a183a1b13f38f3c67
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,30 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using RootMotion.FinalIK;
|
||||
|
||||
namespace RootMotion.Demos {
|
||||
|
||||
/// <summary>
|
||||
/// Bend goal for FullBodyBipedIK.
|
||||
/// </summary>
|
||||
public class FBIKBendGoal: MonoBehaviour {
|
||||
|
||||
public FullBodyBipedIK ik; // Refernce to the FBBIK component
|
||||
public FullBodyBipedChain chain; // Which limb is this bend goal for?
|
||||
|
||||
public float weight; // Bend goal weight
|
||||
|
||||
void Start() {
|
||||
Debug.Log("FBIKBendGoal is deprecated, you can now a bend goal from the custom inspector of the FullBodyBipedIK component.");
|
||||
}
|
||||
|
||||
void Update() {
|
||||
if (ik == null) return;
|
||||
|
||||
ik.solver.GetBendConstraint(chain).bendGoal = transform;
|
||||
ik.solver.GetBendConstraint(chain).weight = weight;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1a95ef1aaef9e41ef94e5cf5cb1a2491
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,57 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using RootMotion.FinalIK;
|
||||
|
||||
namespace RootMotion.Demos {
|
||||
|
||||
/// <summary>
|
||||
/// Demo script for boxing with the combination of FullBodyBipedIK and Aim IK.
|
||||
/// </summary>
|
||||
public class FBIKBoxing : MonoBehaviour {
|
||||
|
||||
[Tooltip("The target we want to hit")]
|
||||
public Transform target;
|
||||
[Tooltip("The pin Transform is used to reference the exact hit point in the animation (used by AimIK to aim the upper body to follow the target)." +
|
||||
"In Legacy and Generic modes you can just create and position a reference point in your animating software and include it in the FBX. " +
|
||||
"Then in Unity if you added a GameObject with the exact same name under the character's root, it would be animated to the required position." +
|
||||
"In Humanoid mode however, Mecanim loses track of any Transform that does not belong to the avatar, so in this case the pin point has to be manually set inside the Unity Editor.")]
|
||||
public Transform pin;
|
||||
[Tooltip("The Full Body Biped IK component")]
|
||||
public FullBodyBipedIK ik;
|
||||
[Tooltip("The Aim IK component. Aim IK is ust used for following the target slightly with the body.")]
|
||||
public AimIK aim;
|
||||
[Tooltip("The master weight")]
|
||||
public float weight;
|
||||
[Tooltip("The effector type of the punching hand")]
|
||||
public FullBodyBipedEffector effector;
|
||||
[Tooltip("Weight of aiming the body to follow the target")]
|
||||
public AnimationCurve aimWeight;
|
||||
|
||||
private Animator animator;
|
||||
|
||||
void Start() {
|
||||
animator = GetComponent<Animator>();
|
||||
}
|
||||
|
||||
void LateUpdate() {
|
||||
// Getting the weight of pinning the fist to the target
|
||||
float hitWeight = animator.GetFloat("HitWeight");
|
||||
|
||||
// Pinning the first with FBIK
|
||||
ik.solver.GetEffector(effector).position = target.position;
|
||||
ik.solver.GetEffector(effector).positionWeight = hitWeight * weight;
|
||||
|
||||
// Aiming the body with AimIK to follow the target
|
||||
if (aim != null) {
|
||||
// Make the aim transform always look at the pin. This will normalize the default aim diretion to the animated pose.
|
||||
aim.solver.transform.LookAt(pin.position);
|
||||
|
||||
// Set aim target
|
||||
aim.solver.IKPosition = target.position;
|
||||
|
||||
// Setting aim weight
|
||||
aim.solver.IKPositionWeight = aimWeight.Evaluate(hitWeight) * weight;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d2b4d13a962bb4d0e9a622c7f12937d7
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,70 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using RootMotion.FinalIK;
|
||||
|
||||
namespace RootMotion.Demos {
|
||||
|
||||
/// <summary>
|
||||
/// Maintains FBBIK hands on a 2-handed prop, regardless of position offset of the hand effectors
|
||||
/// </summary>
|
||||
public class FBIKHandsOnProp: MonoBehaviour {
|
||||
|
||||
public FullBodyBipedIK ik; // Reference to the FBBIK component
|
||||
public bool leftHanded;
|
||||
|
||||
void Awake() {
|
||||
// Add to OnPreUpdate delegate to get a call before the solver starts updating
|
||||
ik.solver.OnPreRead += OnPreRead;
|
||||
}
|
||||
|
||||
private void OnPreRead() {
|
||||
if (leftHanded) HandsOnProp(ik.solver.leftHandEffector, ik.solver.rightHandEffector);
|
||||
else HandsOnProp(ik.solver.rightHandEffector, ik.solver.leftHandEffector);
|
||||
}
|
||||
|
||||
private void HandsOnProp(IKEffector mainHand, IKEffector otherHand) {
|
||||
// Get the animated direction from the main hand to the other hand
|
||||
Vector3 toOtherHand = otherHand.bone.position - mainHand.bone.position;
|
||||
|
||||
// Get the hand direction relative to the main hand's rotation
|
||||
Vector3 otherHandRelativeDirection = Quaternion.Inverse(mainHand.bone.rotation) * toOtherHand;
|
||||
|
||||
// Get the center point of two hands
|
||||
Vector3 handsCenter = mainHand.bone.position + (toOtherHand * 0.5f);
|
||||
|
||||
// Get the other hand's rotation relative to the main hand's rotation
|
||||
Quaternion otherHandRelativeRotation = Quaternion.Inverse(mainHand.bone.rotation) * otherHand.bone.rotation;
|
||||
|
||||
// Get the direction from the main hand to the other hand that icludes effector position offsets
|
||||
Vector3 toOtherHandWithOffset = (otherHand.bone.position + otherHand.positionOffset) - (mainHand.bone.position + mainHand.positionOffset);
|
||||
|
||||
// Get the center point of two hands that includes effector position offsets
|
||||
Vector3 handsCenterWithOffset = (mainHand.bone.position + mainHand.positionOffset) + (toOtherHand * 0.5f);
|
||||
|
||||
// Main hand position
|
||||
mainHand.position = (mainHand.bone.position + mainHand.positionOffset) + (handsCenterWithOffset - handsCenter);
|
||||
mainHand.positionWeight = 1f;
|
||||
|
||||
// Main hand rotation
|
||||
Quaternion rotationOffset = Quaternion.FromToRotation(toOtherHand, toOtherHandWithOffset);
|
||||
mainHand.bone.rotation = rotationOffset * mainHand.bone.rotation;
|
||||
|
||||
// Other hand position
|
||||
otherHand.position = mainHand.position + mainHand.bone.rotation * otherHandRelativeDirection;
|
||||
otherHand.positionWeight = 1f;
|
||||
|
||||
// Other hand rotation
|
||||
otherHand.bone.rotation = mainHand.bone.rotation * otherHandRelativeRotation;
|
||||
|
||||
ik.solver.leftArmMapping.maintainRotationWeight = 1f;
|
||||
ik.solver.rightArmMapping.maintainRotationWeight = 1f;
|
||||
}
|
||||
|
||||
// Clean up delegates
|
||||
void OnDestroy() {
|
||||
if (ik != null) {
|
||||
ik.solver.OnPreRead -= OnPreRead;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ec5a53b0c81f7774aabb2eec99071ea3
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,172 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using RootMotion.FinalIK;
|
||||
|
||||
namespace RootMotion.Demos {
|
||||
|
||||
/// <summary>
|
||||
/// Basic full body FPS IK controller.
|
||||
///
|
||||
/// If aimWeight is weighed in, the character will simply use AimIK to aim his gun towards the camera forward direction.
|
||||
/// If sightWeight is weighed in, the character will also use FBBIK to pose the gun to a predefined position relative to the camera so it stays fixed in view.
|
||||
/// That position was simply defined by making a copy of the gun (gunTarget), parenting it to the camera and positioning it so that the camera would look down its sights.
|
||||
/// </summary>
|
||||
public class FPSAiming : MonoBehaviour {
|
||||
|
||||
[Range(0f, 1f)] public float aimWeight = 1f; // The weight of aiming the gun towards camera forward
|
||||
[Range(0f, 1f)] public float sightWeight = 1f; // the weight of aiming down the sight (multiplied by aimWeight)
|
||||
[Range(0f, 180f)] public float maxAngle = 80f; // The maximum angular offset of the aiming direction from the character forward. Character will be rotated to comply.
|
||||
public Vector3 aimOffset; // Can be used to adjust the aiming angle
|
||||
|
||||
public bool animatePhysics; // Is Animate Physiscs turned on for the character?
|
||||
public Transform gun; // The gun that the character is holding
|
||||
public Transform gunTarget; // The copy of the gun that has been parented to the camera
|
||||
public FullBodyBipedIK ik; // Reference to the FBBIK component
|
||||
public AimIK gunAim; // Reference to the AimIK component
|
||||
public AimIK headAim; // AimIK solver used for look-at when aimWeight < 1
|
||||
public CameraControllerFPS cam; // Reference to the FPS camera
|
||||
public Recoil recoil; // The recoil component (optional)
|
||||
[Range(0f, 1f)] public float cameraRecoilWeight = 0.5f; // How much of the recoil motion is added to the camera?
|
||||
|
||||
private Vector3 gunTargetDefaultLocalPosition;
|
||||
private Vector3 gunTargetDefaultLocalRotation;
|
||||
private Vector3 camDefaultLocalPosition;
|
||||
private Vector3 camRelativeToGunTarget;
|
||||
private bool updateFrame;
|
||||
|
||||
void Start() {
|
||||
// Remember some default local positions
|
||||
gunTargetDefaultLocalPosition = gunTarget.localPosition;
|
||||
gunTargetDefaultLocalRotation = gunTarget.localEulerAngles;
|
||||
camDefaultLocalPosition = cam.transform.localPosition;
|
||||
|
||||
// Disable the camera and IK components so we can handle their execution order
|
||||
cam.enabled = false;
|
||||
gunAim.enabled = false;
|
||||
if (headAim != null) headAim.enabled = false;
|
||||
ik.enabled = false;
|
||||
|
||||
if (recoil != null && ik.solver.iterations == 0) Debug.LogWarning("FPSAiming with Recoil needs FBBIK solver iteration count to be at least 1 to maintain accuracy.");
|
||||
}
|
||||
|
||||
void FixedUpdate() {
|
||||
// Making sure this works with Animate Physics
|
||||
updateFrame = true;
|
||||
}
|
||||
|
||||
|
||||
void LateUpdate() {
|
||||
// Making sure this works with Animate Physics
|
||||
if (!animatePhysics) updateFrame = true;
|
||||
if (!updateFrame) return;
|
||||
updateFrame = false;
|
||||
|
||||
// Put the camera back to its default local position relative to the head
|
||||
cam.transform.localPosition = camDefaultLocalPosition;
|
||||
|
||||
// Remember the camera's position relative to the gun target
|
||||
camRelativeToGunTarget = gunTarget.InverseTransformPoint(cam.transform.position);
|
||||
|
||||
// Update the camera
|
||||
cam.LateUpdate();
|
||||
|
||||
// Rotating the root of the character if it is past maxAngle from the camera forward
|
||||
RotateCharacter();
|
||||
|
||||
Aiming();
|
||||
|
||||
LookDownTheSight();
|
||||
}
|
||||
|
||||
private void Aiming()
|
||||
{
|
||||
if (aimWeight <= 0f) return;
|
||||
|
||||
// Remember the rotation of the camera because we need to reset it later so the IK would not interfere with the rotating of the camera
|
||||
Quaternion camRotation = cam.transform.rotation;
|
||||
|
||||
if (headAim != null)
|
||||
{
|
||||
// Aim head towards camera forward
|
||||
headAim.solver.IKPosition = cam.transform.position + cam.transform.forward * 10f;
|
||||
headAim.solver.IKPositionWeight = 1f - aimWeight;
|
||||
headAim.solver.Update();
|
||||
}
|
||||
|
||||
// Aim the gun towards camera forward
|
||||
gunAim.solver.IKPosition = cam.transform.position + cam.transform.forward * 10f + cam.transform.rotation * aimOffset;
|
||||
gunAim.solver.IKPositionWeight = aimWeight;
|
||||
gunAim.solver.Update();
|
||||
|
||||
cam.transform.rotation = camRotation;
|
||||
}
|
||||
|
||||
private void LookDownTheSight() {
|
||||
float sW = aimWeight * sightWeight;
|
||||
//if (sW <= 0f && recoil == null) return;
|
||||
|
||||
// Interpolate the gunTarget from the current animated position of the gun to the position fixed to the camera
|
||||
gunTarget.position = Vector3.Lerp(gun.position, gunTarget.parent.TransformPoint(gunTargetDefaultLocalPosition), sW);
|
||||
gunTarget.rotation = Quaternion.Lerp(gun.rotation, gunTarget.parent.rotation * Quaternion.Euler(gunTargetDefaultLocalRotation), sW);
|
||||
|
||||
// Get the current positions of the hands relative to the gun
|
||||
Vector3 leftHandRelativePosition = gun.InverseTransformPoint(ik.solver.leftHandEffector.bone.position);
|
||||
Vector3 rightHandRelativePosition = gun.InverseTransformPoint(ik.solver.rightHandEffector.bone.position);
|
||||
|
||||
// Get the current rotations of the hands relative to the gun
|
||||
Quaternion leftHandRelativeRotation = Quaternion.Inverse(gun.rotation) * ik.solver.leftHandEffector.bone.rotation;
|
||||
Quaternion rightHandRelativeRotation = Quaternion.Inverse(gun.rotation) * ik.solver.rightHandEffector.bone.rotation;
|
||||
|
||||
//float handWeight = aimWeight > 0 && sightWeight > 0? aimWeight * sightWeight: 0f;
|
||||
float handWeight = 1f;//aimWeight * sightWeight;
|
||||
|
||||
ik.solver.leftHandEffector.positionOffset += (gunTarget.TransformPoint(leftHandRelativePosition) - (ik.solver.leftHandEffector.bone.position + ik.solver.leftHandEffector.positionOffset)) * handWeight;
|
||||
ik.solver.rightHandEffector.positionOffset += (gunTarget.TransformPoint(rightHandRelativePosition) - (ik.solver.rightHandEffector.bone.position + ik.solver.rightHandEffector.positionOffset)) * handWeight;
|
||||
|
||||
// Make sure the head does not rotate
|
||||
ik.solver.headMapping.maintainRotationWeight = 1f;
|
||||
|
||||
if (recoil != null) recoil.SetHandRotations(gunTarget.rotation * leftHandRelativeRotation, gunTarget.rotation * rightHandRelativeRotation);
|
||||
|
||||
// Update FBBIK
|
||||
ik.solver.Update();
|
||||
|
||||
// Rotate the hand bones relative to the gun target the same way they are rotated relative to the gun
|
||||
if (recoil != null) {
|
||||
ik.references.leftHand.rotation = recoil.rotationOffset * (gunTarget.rotation * leftHandRelativeRotation);
|
||||
ik.references.rightHand.rotation = recoil.rotationOffset * (gunTarget.rotation * rightHandRelativeRotation);
|
||||
} else {
|
||||
ik.references.leftHand.rotation = gunTarget.rotation * leftHandRelativeRotation;
|
||||
ik.references.rightHand.rotation = gunTarget.rotation * rightHandRelativeRotation;
|
||||
}
|
||||
|
||||
// Position the camera to where it was before FBBIK relative to the gun
|
||||
cam.transform.position = Vector3.Lerp(cam.transform.position, Vector3.Lerp(gunTarget.TransformPoint(camRelativeToGunTarget), gun.transform.TransformPoint(camRelativeToGunTarget), cameraRecoilWeight), sW);
|
||||
}
|
||||
|
||||
// Rotating the root of the character if it is past maxAngle from the camera forward
|
||||
private void RotateCharacter() {
|
||||
if (maxAngle >= 180f) return;
|
||||
|
||||
// If no angular difference is allowed, just rotate the character to the flattened camera forward
|
||||
if (maxAngle <= 0f) {
|
||||
transform.rotation = Quaternion.LookRotation(new Vector3(cam.transform.forward.x, 0f, cam.transform.forward.z));
|
||||
return;
|
||||
}
|
||||
|
||||
// Get camera forward in the character's rotation space
|
||||
Vector3 camRelative = transform.InverseTransformDirection(cam.transform.forward);
|
||||
|
||||
// Get the angle of the camera forward relative to the character forward
|
||||
float angle = Mathf.Atan2(camRelative.x, camRelative.z) * Mathf.Rad2Deg;
|
||||
|
||||
// Making sure the angle does not exceed maxangle
|
||||
if (Mathf.Abs(angle) > Mathf.Abs(maxAngle)) {
|
||||
float a = angle - maxAngle;
|
||||
if (angle < 0f) a = angle + maxAngle;
|
||||
transform.rotation = Quaternion.AngleAxis(a, transform.up) * transform.rotation;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 343587580f6674d5e9346929324ec997
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,38 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
|
||||
namespace RootMotion.Demos {
|
||||
|
||||
/// <summary>
|
||||
/// Demo character controller for the Full Body FPS scene.
|
||||
/// </summary>
|
||||
public class FPSCharacter: MonoBehaviour {
|
||||
|
||||
[Range(0f, 1f)] public float walkSpeed = 0.5f;
|
||||
|
||||
private float sVel;
|
||||
private Animator animator;
|
||||
private FPSAiming FPSAiming;
|
||||
|
||||
void Start() {
|
||||
animator = GetComponent<Animator>();
|
||||
FPSAiming = GetComponent<FPSAiming>();
|
||||
}
|
||||
|
||||
void Update() {
|
||||
// Aiming down the sight of the gun when RMB is down
|
||||
FPSAiming.sightWeight = Mathf.SmoothDamp(FPSAiming.sightWeight, (Input.GetMouseButton(1)? 1f: 0f), ref sVel, 0.1f);
|
||||
|
||||
// Set to full values to optimize IK
|
||||
if (FPSAiming.sightWeight < 0.001f) FPSAiming.sightWeight = 0f;
|
||||
if (FPSAiming.sightWeight > 0.999f) FPSAiming.sightWeight = 1f;
|
||||
|
||||
animator.SetFloat("Speed", walkSpeed);
|
||||
}
|
||||
|
||||
void OnGUI() {
|
||||
GUI.Label(new Rect(Screen.width - 210, 10, 200, 25), "Hold RMB to aim down the sight");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c2f6cdcc8d33545af81dd246de448e9d
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,40 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using RootMotion.FinalIK;
|
||||
|
||||
namespace RootMotion.Demos {
|
||||
|
||||
/// <summary>
|
||||
/// Triggering Hit Reactions on mouse button.
|
||||
/// </summary>
|
||||
public class HitReactionTrigger: MonoBehaviour {
|
||||
|
||||
public HitReaction hitReaction;
|
||||
public float hitForce = 1f;
|
||||
|
||||
private string colliderName;
|
||||
|
||||
void Update() {
|
||||
// On left mouse button...
|
||||
if (Input.GetMouseButtonDown(0)) {
|
||||
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
|
||||
|
||||
// Raycast to find a ragdoll collider
|
||||
RaycastHit hit = new RaycastHit();
|
||||
if (Physics.Raycast(ray, out hit, 100f)) {
|
||||
|
||||
// Use the HitReaction
|
||||
hitReaction.Hit(hit.collider, ray.direction * hitForce, hit.point);
|
||||
|
||||
// Just for GUI
|
||||
colliderName = hit.collider.name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OnGUI() {
|
||||
GUILayout.Label("LMB to shoot the Dummy, RMB to rotate the camera.");
|
||||
if (colliderName != string.Empty) GUILayout.Label("Last Bone Hit: " + colliderName);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 36c4cd7e8f3ef4beca08a45c21632be2
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,42 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using RootMotion.FinalIK;
|
||||
|
||||
namespace RootMotion.Demos {
|
||||
|
||||
/// <summary>
|
||||
/// Holding hands rig.
|
||||
/// </summary>
|
||||
public class HoldingHands : MonoBehaviour {
|
||||
|
||||
public FullBodyBipedIK rightHandChar, leftHandChar; // The characters
|
||||
|
||||
public Transform rightHandTarget, leftHandTarget; // IK targets for the hands
|
||||
public float crossFade; // Which character is dominating?
|
||||
public float speed = 10f; // Speed of smoothly lerping the hands target
|
||||
|
||||
private Quaternion rightHandRotation, leftHandRotation;
|
||||
|
||||
void Start() {
|
||||
// Find the rotations of the hands target (this gameobject) in the rotation spaces of the hand bones
|
||||
rightHandRotation = Quaternion.Inverse(rightHandChar.solver.rightHandEffector.bone.rotation) * transform.rotation;
|
||||
leftHandRotation = Quaternion.Inverse(leftHandChar.solver.leftHandEffector.bone.rotation) * transform.rotation;
|
||||
}
|
||||
|
||||
void LateUpdate () {
|
||||
// Positioning the hands target
|
||||
Vector3 targetPosition = Vector3.Lerp(rightHandChar.solver.rightHandEffector.bone.position, leftHandChar.solver.leftHandEffector.bone.position, crossFade);
|
||||
transform.position = Vector3.Lerp(transform.position, targetPosition, Time.deltaTime * speed);
|
||||
|
||||
// Rotating the hands target
|
||||
transform.rotation = Quaternion.Slerp(rightHandChar.solver.rightHandEffector.bone.rotation * rightHandRotation, leftHandChar.solver.leftHandEffector.bone.rotation * leftHandRotation, crossFade);
|
||||
|
||||
// Set effector positions and rotations
|
||||
rightHandChar.solver.rightHandEffector.position = rightHandTarget.position;
|
||||
rightHandChar.solver.rightHandEffector.rotation = rightHandTarget.rotation;
|
||||
|
||||
leftHandChar.solver.leftHandEffector.position = leftHandTarget.position;
|
||||
leftHandChar.solver.leftHandEffector.rotation = leftHandTarget.rotation;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 19f36a5a29ba54779bbe13c64fd30c69
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,32 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using RootMotion.FinalIK;
|
||||
|
||||
namespace RootMotion.Demos {
|
||||
|
||||
/// <summary>
|
||||
/// Demonstrating character-character FBBIK interaction.
|
||||
/// </summary>
|
||||
public class InteractionC2CDemo : MonoBehaviour {
|
||||
|
||||
// GUI for testing
|
||||
void OnGUI() {
|
||||
if (GUILayout.Button("Shake Hands")) {
|
||||
|
||||
character1.StartInteraction(FullBodyBipedEffector.RightHand, handShake, true);
|
||||
character2.StartInteraction(FullBodyBipedEffector.RightHand, handShake, true);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public InteractionSystem character1, character2; // The InteractionSystems of the characters
|
||||
public InteractionObject handShake; // The HandShake InteractionObject
|
||||
|
||||
void LateUpdate() {
|
||||
// Positioning the handshake to the middle of the hands
|
||||
Vector3 handsCenter = Vector3.Lerp(character1.ik.solver.rightHandEffector.bone.position, character2.ik.solver.rightHandEffector.bone.position, 0.5f);
|
||||
handShake.transform.position = handsCenter;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c7e8eb3221b4c45078730c0cad5bde83
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,73 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using RootMotion.FinalIK;
|
||||
|
||||
namespace RootMotion.Demos {
|
||||
|
||||
/// <summary>
|
||||
/// Simple demo controller for the InteractionSystem.
|
||||
/// </summary>
|
||||
public class InteractionDemo : MonoBehaviour {
|
||||
|
||||
public InteractionSystem interactionSystem; // Reference to the InteractionSystem of the character
|
||||
|
||||
public bool interrupt; // Can we interrupt an interaction of an effector?
|
||||
|
||||
// The interaction objects
|
||||
public InteractionObject ball, benchMain, benchHands, button, cigarette, door;
|
||||
|
||||
private bool isSitting;
|
||||
|
||||
// GUI for calling the interactions
|
||||
void OnGUI() {
|
||||
interrupt = GUILayout.Toggle(interrupt, "Interrupt");
|
||||
|
||||
// While seated
|
||||
if (isSitting) {
|
||||
|
||||
if (!interactionSystem.inInteraction && GUILayout.Button("Stand Up")) {
|
||||
interactionSystem.ResumeAll();
|
||||
|
||||
isSitting = false;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// While standing
|
||||
|
||||
if (GUILayout.Button("Pick Up Ball")) {
|
||||
interactionSystem.StartInteraction(FullBodyBipedEffector.RightHand, ball, interrupt);
|
||||
}
|
||||
|
||||
if (GUILayout.Button("Button Left Hand")) {
|
||||
interactionSystem.StartInteraction(FullBodyBipedEffector.LeftHand, button, interrupt);
|
||||
}
|
||||
|
||||
if (GUILayout.Button("Button Right Hand")) {
|
||||
interactionSystem.StartInteraction(FullBodyBipedEffector.RightHand, button, interrupt);
|
||||
}
|
||||
|
||||
if (GUILayout.Button("Put Out Cigarette")) {
|
||||
interactionSystem.StartInteraction(FullBodyBipedEffector.RightFoot, cigarette, interrupt);
|
||||
}
|
||||
|
||||
if (GUILayout.Button("Open Door")) {
|
||||
interactionSystem.StartInteraction(FullBodyBipedEffector.LeftHand, door, interrupt);
|
||||
}
|
||||
|
||||
// This is a multiple-effector interaction
|
||||
if (!interactionSystem.inInteraction && GUILayout.Button("Sit Down")) {
|
||||
interactionSystem.StartInteraction(FullBodyBipedEffector.Body, benchMain, interrupt);
|
||||
interactionSystem.StartInteraction(FullBodyBipedEffector.LeftThigh, benchMain, interrupt);
|
||||
interactionSystem.StartInteraction(FullBodyBipedEffector.RightThigh, benchMain, interrupt);
|
||||
interactionSystem.StartInteraction(FullBodyBipedEffector.LeftFoot, benchMain, interrupt);
|
||||
|
||||
interactionSystem.StartInteraction(FullBodyBipedEffector.LeftHand, benchHands, interrupt);
|
||||
interactionSystem.StartInteraction(FullBodyBipedEffector.RightHand, benchHands, interrupt);
|
||||
|
||||
isSitting = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a6c1fe7250c0a4474b17dce2b640d1da
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,44 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using RootMotion.FinalIK;
|
||||
|
||||
namespace RootMotion.Demos {
|
||||
|
||||
/// <summary>
|
||||
/// Simple GUI for quickly testing out interactions.
|
||||
/// </summary>
|
||||
public class InteractionSystemTestGUI : MonoBehaviour {
|
||||
|
||||
[Tooltip("The object to interact to")]
|
||||
public InteractionObject interactionObject;
|
||||
[Tooltip("The effectors to interact with")]
|
||||
public FullBodyBipedEffector[] effectors;
|
||||
|
||||
private InteractionSystem interactionSystem;
|
||||
|
||||
void Awake() {
|
||||
interactionSystem = GetComponent<InteractionSystem>();
|
||||
}
|
||||
|
||||
void OnGUI() {
|
||||
if (interactionSystem == null) return;
|
||||
|
||||
if (GUILayout.Button("Start Interaction With " + interactionObject.name)) {
|
||||
if (effectors.Length == 0) Debug.Log("Please select the effectors to interact with.");
|
||||
|
||||
foreach (FullBodyBipedEffector e in effectors) {
|
||||
interactionSystem.StartInteraction(e, interactionObject, true);
|
||||
}
|
||||
}
|
||||
|
||||
if (effectors.Length == 0) return;
|
||||
|
||||
if (interactionSystem.IsPaused(effectors[0])) {
|
||||
if (GUILayout.Button("Resume Interaction With " + interactionObject.name)) {
|
||||
|
||||
interactionSystem.ResumeAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8cc0304f5a703416ebff81ad105ddf18
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,114 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using RootMotion.FinalIK;
|
||||
|
||||
namespace RootMotion.Demos {
|
||||
|
||||
/// <summary>
|
||||
/// FBBIK example rig for a kissing emote.
|
||||
/// As the IK targets of one FBBIK partner depend on the solved pose of another FBBIK partner and vice versa, the rig will have to be iterated a couple of times to make it work.
|
||||
/// </summary>
|
||||
public class KissingRig : MonoBehaviour {
|
||||
|
||||
/// <summary>
|
||||
/// A partner in the emote
|
||||
/// </summary>
|
||||
[System.Serializable]
|
||||
public class Partner {
|
||||
|
||||
public FullBodyBipedIK ik; // Reference to the FBBIK component
|
||||
public Transform mouth; // The mouth bone, should be attached to the head
|
||||
public Transform mouthTarget; // The target that we want to set the mouth bone to
|
||||
public Transform touchTargetLeftHand, touchTargetRightHand; // Touch targets for the hands
|
||||
public float bodyWeightHorizontal = 0.4f; // The body effector horizontal weight
|
||||
public float bodyWeightVertical = 1f; // The body effector vertical weight
|
||||
public float neckRotationWeight = 0.3f; // The neck rotation weight
|
||||
public float headTiltAngle = 10f; // Tilting the head
|
||||
public Vector3 headTiltAxis; // Head tilt axis
|
||||
|
||||
private Quaternion neckRotation;
|
||||
|
||||
public void Initiate() {
|
||||
// Disable the FBBIK component to manage its updating
|
||||
ik.enabled = false;
|
||||
}
|
||||
|
||||
public void Update(float weight) {
|
||||
// Set IK position and rotation weights
|
||||
ik.solver.leftShoulderEffector.positionWeight = weight;
|
||||
ik.solver.rightShoulderEffector.positionWeight = weight;
|
||||
ik.solver.leftHandEffector.positionWeight = weight;
|
||||
ik.solver.rightHandEffector.positionWeight = weight;
|
||||
ik.solver.leftHandEffector.rotationWeight = weight;
|
||||
ik.solver.rightHandEffector.rotationWeight = weight;
|
||||
ik.solver.bodyEffector.positionWeight = weight;
|
||||
|
||||
// Inverse transform the shoulder and body effectors to set them relative to the mouth bone's position in the animation
|
||||
InverseTransformEffector(FullBodyBipedEffector.LeftShoulder, mouth, mouthTarget.position, weight);
|
||||
InverseTransformEffector(FullBodyBipedEffector.RightShoulder, mouth, mouthTarget.position, weight);
|
||||
InverseTransformEffector(FullBodyBipedEffector.Body, mouth, mouthTarget.position, weight);
|
||||
|
||||
// Positioning the body effector horizontally
|
||||
ik.solver.bodyEffector.position = Vector3.Lerp(new Vector3(ik.solver.bodyEffector.position.x, ik.solver.bodyEffector.bone.position.y, ik.solver.bodyEffector.position.z), ik.solver.bodyEffector.position, bodyWeightVertical * weight);
|
||||
|
||||
// Positioning the body effector vertically
|
||||
ik.solver.bodyEffector.position = Vector3.Lerp(new Vector3(ik.solver.bodyEffector.bone.position.x, ik.solver.bodyEffector.position.y, ik.solver.bodyEffector.bone.position.z), ik.solver.bodyEffector.position, bodyWeightHorizontal * weight);
|
||||
|
||||
// Set hand effector positions to touch targets
|
||||
ik.solver.leftHandEffector.position = touchTargetLeftHand.position;
|
||||
ik.solver.rightHandEffector.position = touchTargetRightHand.position;
|
||||
ik.solver.leftHandEffector.rotation = touchTargetLeftHand.rotation;
|
||||
ik.solver.rightHandEffector.rotation = touchTargetRightHand.rotation;
|
||||
|
||||
// Store the neck rotation so we could slerp back to it after updating FBBIK
|
||||
neckRotation = neck.rotation;
|
||||
|
||||
// Update the FBBIK solver
|
||||
ik.solver.Update();
|
||||
|
||||
// Revert the neck back to its animated rotation
|
||||
neck.rotation = Quaternion.Slerp(neck.rotation, neckRotation, neckRotationWeight * weight);
|
||||
|
||||
// Head tilting
|
||||
ik.references.head.localRotation = Quaternion.AngleAxis(headTiltAngle * weight, headTiltAxis) * ik.references.head.localRotation;
|
||||
}
|
||||
|
||||
// Get the neck bone
|
||||
private Transform neck {
|
||||
get {
|
||||
return ik.solver.spineMapping.spineBones[ik.solver.spineMapping.spineBones.Length - 1];
|
||||
}
|
||||
}
|
||||
|
||||
// Placing an effector so that an arbitrary Transform (target) ends up at targetPosition
|
||||
private void InverseTransformEffector(FullBodyBipedEffector effector, Transform target, Vector3 targetPosition, float weight) {
|
||||
// Direction from the target to the effector
|
||||
Vector3 toEffector = ik.solver.GetEffector(effector).bone.position - target.position;
|
||||
|
||||
// Positioning the effector
|
||||
ik.solver.GetEffector(effector).position = Vector3.Lerp(ik.solver.GetEffector(effector).bone.position, targetPosition + toEffector, weight);
|
||||
}
|
||||
}
|
||||
|
||||
public Partner partner1, partner2; // The partners
|
||||
|
||||
[Range(0f, 1f)] public float weight; // The master weight
|
||||
[Range(1, 4)] public int iterations = 3; // The number of iterating this rig.
|
||||
// As the IK targets of one FBBIK partner depend on the solved pose of another FBBIK partner and vice versa,
|
||||
// the rig will have to be iterated a couple of times to make it work.
|
||||
|
||||
void Start() {
|
||||
// Initiating the partners
|
||||
partner1.Initiate();
|
||||
partner2.Initiate();
|
||||
}
|
||||
|
||||
void LateUpdate() {
|
||||
// Iterate the rig
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
partner1.Update(weight);
|
||||
partner2.Update(weight);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 124812fe005074e3090d2734c12bd7e9
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,130 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using RootMotion.FinalIK;
|
||||
|
||||
namespace RootMotion.Demos {
|
||||
|
||||
/// <summary>
|
||||
/// Absorbing motion on FBBIK effectors on impact. Attach this to the GameObject that receives OnCollisionEnter calls.
|
||||
/// </summary>
|
||||
public class MotionAbsorb : OffsetModifier {
|
||||
|
||||
[System.Serializable]
|
||||
public enum Mode {
|
||||
Position,
|
||||
PositionOffset
|
||||
}
|
||||
|
||||
// Manages motion absorbing for an effector
|
||||
[System.Serializable]
|
||||
public class Absorber {
|
||||
|
||||
[Tooltip("The type of effector (hand, foot, shoulder...) - this is just an enum")]
|
||||
public FullBodyBipedEffector effector;
|
||||
[Tooltip("How much should motion be absorbed on this effector")]
|
||||
public float weight = 1f;
|
||||
|
||||
private Vector3 position;
|
||||
private Quaternion rotation = Quaternion.identity;
|
||||
|
||||
private IKEffector e;
|
||||
|
||||
// Set effector position and rotation to match its bone
|
||||
public void SetToBone(IKSolverFullBodyBiped solver, Mode mode) {
|
||||
e = solver.GetEffector(effector);
|
||||
// Using world space position and rotation here for the sake of simplicity of the demo
|
||||
// Ideally we should use position and rotation relative to character's root, so we could move around while doing this.
|
||||
|
||||
switch(mode) {
|
||||
case Mode.Position:
|
||||
e.position = e.bone.position;
|
||||
e.rotation = e.bone.rotation;
|
||||
return;
|
||||
case Mode.PositionOffset:
|
||||
position = e.bone.position;
|
||||
rotation = e.bone.rotation;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Set effector position and rotation weight to match the value, multiply with the weight of this Absorber
|
||||
public void UpdateEffectorWeights(float w) {
|
||||
e.positionWeight = w * weight;
|
||||
e.rotationWeight = w * weight;
|
||||
}
|
||||
|
||||
// Set effector positionOffset to match the position, multiply with the weight of this Absorber
|
||||
public void SetPosition(float w) {
|
||||
e.positionOffset += (position - e.bone.position) * w * weight;
|
||||
}
|
||||
|
||||
// Set effector bone rotation to match the rotation, multiply with the weight of this Absorber
|
||||
public void SetRotation(float w) {
|
||||
e.bone.rotation = Quaternion.Slerp(e.bone.rotation, rotation, w * weight);
|
||||
}
|
||||
}
|
||||
|
||||
[Tooltip("Use either effector position, position weight, rotation, rotationWeight or positionOffset and rotating the bone directly.")]
|
||||
public Mode mode;
|
||||
[Tooltip("Array containing the absorbers")]
|
||||
public Absorber[] absorbers;
|
||||
[Tooltip("Weight falloff curve (how fast will the effect reduce after impact)")]
|
||||
public AnimationCurve falloff;
|
||||
[Tooltip("How fast will the impact fade away. (if 1, effect lasts for 1 second)")]
|
||||
public float falloffSpeed = 1f;
|
||||
|
||||
private float timer; // Used for fading out the effect of the impact
|
||||
private float w;
|
||||
private Mode initialMode;
|
||||
|
||||
protected override void Start() {
|
||||
base.Start();
|
||||
|
||||
ik.solver.OnPostUpdate += AfterIK;
|
||||
|
||||
initialMode = mode;
|
||||
}
|
||||
|
||||
void OnCollisionEnter(Collision c) {
|
||||
// Don't register another contact until the effect of the last one has faded
|
||||
if (timer > 0f) return;
|
||||
|
||||
// Reset timer
|
||||
timer = 1f;
|
||||
|
||||
// Set effector position and rotation to match its bone
|
||||
for (int i = 0; i < absorbers.Length; i++) absorbers[i].SetToBone(ik.solver, mode);
|
||||
}
|
||||
|
||||
// Called by IKSolverFullBody before updating
|
||||
protected override void OnModifyOffset() {
|
||||
if (timer <= 0f) return;
|
||||
mode = initialMode;
|
||||
|
||||
// Fading out the effect
|
||||
timer -= Time.deltaTime * falloffSpeed;
|
||||
|
||||
// Evaluate the absorb weight
|
||||
w = falloff.Evaluate(timer);
|
||||
|
||||
// Set the weights of the effectors
|
||||
if (mode == Mode.Position) {
|
||||
for (int i = 0; i < absorbers.Length; i++) absorbers[i].UpdateEffectorWeights(w * weight);
|
||||
} else {
|
||||
for (int i = 0; i < absorbers.Length; i++) absorbers[i].SetPosition(w * weight);
|
||||
}
|
||||
}
|
||||
|
||||
void AfterIK() {
|
||||
if (timer <= 0f) return;
|
||||
if (mode == Mode.Position) return;
|
||||
|
||||
for (int i = 0; i < absorbers.Length; i++) absorbers[i].SetRotation(w * weight);
|
||||
}
|
||||
|
||||
protected override void OnDestroy() {
|
||||
base.OnDestroy();
|
||||
if (ik != null) ik.solver.OnPostUpdate -= AfterIK;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 85872a1e4a1574355b197e878d6c3d43
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,45 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
|
||||
namespace RootMotion.Demos {
|
||||
|
||||
/// <summary>
|
||||
/// Motion Absorb demo character controller.
|
||||
/// </summary>
|
||||
public class MotionAbsorbCharacter : MonoBehaviour {
|
||||
|
||||
public Animator animator;
|
||||
public MotionAbsorb motionAbsorb;
|
||||
public Transform cube; // The cube we are hitting
|
||||
public float cubeRandomPosition = 0.1f; // Randomizing cube position after each hit
|
||||
public AnimationCurve motionAbsorbWeight;
|
||||
|
||||
private Vector3 cubeDefaultPosition;
|
||||
private AnimatorStateInfo info;
|
||||
private Rigidbody cubeRigidbody;
|
||||
|
||||
void Start() {
|
||||
// Storing the default position of the cube
|
||||
cubeDefaultPosition = cube.position;
|
||||
cubeRigidbody = cube.GetComponent<Rigidbody>();
|
||||
}
|
||||
|
||||
void Update () {
|
||||
// Set motion absorb weight
|
||||
//motionAbsorb.weight = animator.GetFloat("MotionAbsorbWeight"); // NB! Using Mecanim curves is PRO only
|
||||
|
||||
// Using an animation curve so it works with Unity Free as well
|
||||
info = animator.GetCurrentAnimatorStateInfo(0);
|
||||
motionAbsorb.weight = motionAbsorbWeight.Evaluate(info.normalizedTime - (int)info.normalizedTime);
|
||||
}
|
||||
|
||||
// Mecanim event
|
||||
void SwingStart() {
|
||||
// Reset the cube
|
||||
cubeRigidbody.MovePosition(cubeDefaultPosition + UnityEngine.Random.insideUnitSphere * cubeRandomPosition);
|
||||
cubeRigidbody.MoveRotation(Quaternion.identity);
|
||||
cubeRigidbody.velocity = Vector3.zero;
|
||||
cubeRigidbody.angularVelocity = Vector3.zero;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 278ffbe117e4c4edba3d761b55ba7bbb
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,62 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using RootMotion.FinalIK;
|
||||
|
||||
namespace RootMotion.Demos {
|
||||
|
||||
/// <summary>
|
||||
/// Custom positionOffset effector for FBBIK, could be used for example to make a spine or pelvis effector.
|
||||
/// </summary>
|
||||
public class OffsetEffector : OffsetModifier {
|
||||
|
||||
[System.Serializable]
|
||||
public class EffectorLink {
|
||||
public FullBodyBipedEffector effectorType;
|
||||
public float weightMultiplier = 1f;
|
||||
|
||||
[HideInInspector] public Vector3 localPosition;
|
||||
}
|
||||
|
||||
[Tooltip("Optional. Assign the bone Transform that is closest to this OffsetEffector to be able to call OffsetEffector.Anchor() in LateUpdate to match its position and rotation to animation.")]
|
||||
public Transform anchor;
|
||||
public EffectorLink[] effectorLinks;
|
||||
|
||||
private Vector3 posRelToAnchor;
|
||||
private Quaternion rotRelToAnchor = Quaternion.identity;
|
||||
|
||||
protected override void Start() {
|
||||
base.Start();
|
||||
|
||||
if (anchor != null)
|
||||
{
|
||||
posRelToAnchor = anchor.InverseTransformPoint(transform.position);
|
||||
rotRelToAnchor = Quaternion.Inverse(anchor.rotation) * transform.rotation;
|
||||
}
|
||||
|
||||
// Store the default positions of the effectors relative to this GameObject's position
|
||||
foreach (EffectorLink e in effectorLinks) {
|
||||
var bone = ik.solver.GetEffector(e.effectorType).bone;
|
||||
e.localPosition = transform.InverseTransformPoint(bone.position);
|
||||
if (e.effectorType == FullBodyBipedEffector.Body) ik.solver.bodyEffector.effectChildNodes = false;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnModifyOffset() {
|
||||
// Update the effectors
|
||||
foreach (EffectorLink e in effectorLinks) {
|
||||
// Using effector positionOffset
|
||||
Vector3 positionTarget = transform.TransformPoint(e.localPosition);
|
||||
|
||||
ik.solver.GetEffector(e.effectorType).positionOffset += (positionTarget - (ik.solver.GetEffector(e.effectorType).bone.position + ik.solver.GetEffector(e.effectorType).positionOffset)) * weight * e.weightMultiplier;
|
||||
}
|
||||
}
|
||||
|
||||
public void Anchor()
|
||||
{
|
||||
if (anchor == null) return;
|
||||
|
||||
transform.position = anchor.TransformPoint(posRelToAnchor);
|
||||
transform.rotation = anchor.rotation * rotRelToAnchor;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 863f1c6a1b50e40cfa321c4b7bd7b004
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,108 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using RootMotion.FinalIK;
|
||||
|
||||
namespace RootMotion.Demos {
|
||||
|
||||
/// <summary>
|
||||
/// Making a character hold on to a target and swing about it while maintaining his animation.
|
||||
/// </summary>
|
||||
public class PendulumExample : MonoBehaviour {
|
||||
|
||||
[Tooltip("The master weight of this script.")]
|
||||
[Range(0f, 1f)] public float weight = 1f;
|
||||
|
||||
[Tooltip("Multiplier for the distance of the root to the target.")]
|
||||
public float hangingDistanceMlp = 1.3f;
|
||||
|
||||
[Tooltip("Where does the root of the character land when weight is blended out?")]
|
||||
[HideInInspector] public Vector3 rootTargetPosition;
|
||||
|
||||
[Tooltip("How is the root of the character rotated when weight is blended out?")]
|
||||
[HideInInspector] public Quaternion rootTargetRotation;
|
||||
|
||||
public Transform target;
|
||||
public Transform leftHandTarget;
|
||||
public Transform rightHandTarget;
|
||||
public Transform leftFootTarget;
|
||||
public Transform rightFootTarget;
|
||||
public Transform pelvisTarget;
|
||||
public Transform bodyTarget;
|
||||
public Transform headTarget;
|
||||
public Vector3 pelvisDownAxis = Vector3.right;
|
||||
|
||||
private FullBodyBipedIK ik;
|
||||
private Quaternion rootRelativeToPelvis;
|
||||
private Vector3 pelvisToRoot;
|
||||
private float lastWeight;
|
||||
|
||||
void Start() {
|
||||
ik = GetComponent<FullBodyBipedIK>();
|
||||
|
||||
// Connect the left hand to the target
|
||||
Quaternion targetRotation = target.rotation;
|
||||
target.rotation = leftHandTarget.rotation;
|
||||
|
||||
FixedJoint j = target.gameObject.AddComponent<FixedJoint>();
|
||||
j.connectedBody = leftHandTarget.GetComponent<Rigidbody>();
|
||||
|
||||
target.GetComponent<Rigidbody>().MoveRotation(targetRotation);
|
||||
//target.rotation = targetRotation;
|
||||
|
||||
// Remember the rotation of the root relative to the pelvis
|
||||
rootRelativeToPelvis = Quaternion.Inverse(pelvisTarget.rotation) * transform.rotation;
|
||||
|
||||
// Remember the position of the root relative to the pelvis
|
||||
pelvisToRoot = Quaternion.Inverse(ik.references.pelvis.rotation) * (transform.position - ik.references.pelvis.position);
|
||||
|
||||
rootTargetPosition = transform.position;
|
||||
rootTargetRotation = transform.rotation;
|
||||
|
||||
lastWeight = weight;
|
||||
}
|
||||
|
||||
void LateUpdate() {
|
||||
// Set effector weights
|
||||
if (weight > 0f) {
|
||||
ik.solver.leftHandEffector.positionWeight = weight;
|
||||
ik.solver.leftHandEffector.rotationWeight = weight;
|
||||
} else {
|
||||
rootTargetPosition = transform.position;
|
||||
rootTargetRotation = transform.rotation;
|
||||
|
||||
if (lastWeight > 0f) {
|
||||
ik.solver.leftHandEffector.positionWeight = 0f;
|
||||
ik.solver.leftHandEffector.rotationWeight = 0f;
|
||||
}
|
||||
}
|
||||
|
||||
lastWeight = weight;
|
||||
if (weight <= 0f) return;
|
||||
|
||||
// Position the character relative to the ragdoll pelvis
|
||||
transform.position = Vector3.Lerp(rootTargetPosition, pelvisTarget.position + pelvisTarget.rotation * pelvisToRoot * hangingDistanceMlp, weight);
|
||||
|
||||
// Rotate the character to the ragdoll pelvis
|
||||
transform.rotation = Quaternion.Lerp(rootTargetRotation, pelvisTarget.rotation * rootRelativeToPelvis, weight);
|
||||
|
||||
// Set ik effector positions
|
||||
ik.solver.leftHandEffector.position = leftHandTarget.position;
|
||||
ik.solver.leftHandEffector.rotation = leftHandTarget.rotation;
|
||||
|
||||
// Get the normal hanging direction
|
||||
Vector3 dir = ik.references.pelvis.rotation * pelvisDownAxis;
|
||||
|
||||
// Rotating the limbs
|
||||
// Get the rotation from normal hangind direction to the right arm ragdoll direction
|
||||
Quaternion rightArmRot = Quaternion.FromToRotation(dir, rightHandTarget.position - headTarget.position);
|
||||
// Rotate the right arm by that offset
|
||||
ik.references.rightUpperArm.rotation = Quaternion.Lerp(Quaternion.identity, rightArmRot, weight) * ik.references.rightUpperArm.rotation;
|
||||
|
||||
Quaternion leftLegRot = Quaternion.FromToRotation(dir, leftFootTarget.position - bodyTarget.position);
|
||||
ik.references.leftThigh.rotation = Quaternion.Lerp(Quaternion.identity, leftLegRot, weight) * ik.references.leftThigh.rotation;
|
||||
|
||||
Quaternion rightLegRot = Quaternion.FromToRotation(dir, rightFootTarget.position - bodyTarget.position);
|
||||
ik.references.rightThigh.rotation = Quaternion.Lerp(Quaternion.identity, rightLegRot, weight) * ik.references.rightThigh.rotation;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a4e2a7601da0546edbfe147eb9f95826
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,159 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using RootMotion;
|
||||
using RootMotion.FinalIK;
|
||||
|
||||
namespace RootMotion.Demos {
|
||||
|
||||
/// <summary>
|
||||
/// Picking up an arbitrary object with both hands.
|
||||
/// </summary>
|
||||
public abstract class PickUp2Handed : MonoBehaviour {
|
||||
|
||||
// GUI for testing
|
||||
public int GUIspace;
|
||||
|
||||
void OnGUI() {
|
||||
GUILayout.BeginHorizontal();
|
||||
GUILayout.Space(GUIspace);
|
||||
|
||||
if (!holding) {
|
||||
|
||||
if (GUILayout.Button("Pick Up " + obj.name)) {
|
||||
interactionSystem.StartInteraction(FullBodyBipedEffector.LeftHand, obj, false);
|
||||
interactionSystem.StartInteraction(FullBodyBipedEffector.RightHand, obj, false);
|
||||
}
|
||||
|
||||
} else {
|
||||
GUILayout.BeginVertical();
|
||||
if (holdingRight)
|
||||
{
|
||||
if (GUILayout.Button("Release Right"))
|
||||
{
|
||||
interactionSystem.ResumeInteraction(FullBodyBipedEffector.RightHand);
|
||||
}
|
||||
}
|
||||
if (holdingLeft)
|
||||
{
|
||||
if (GUILayout.Button("Release Left"))
|
||||
{
|
||||
interactionSystem.ResumeInteraction(FullBodyBipedEffector.LeftHand);
|
||||
}
|
||||
}
|
||||
if (GUILayout.Button("Drop " + obj.name)) {
|
||||
interactionSystem.ResumeAll();
|
||||
}
|
||||
GUILayout.EndVertical();
|
||||
}
|
||||
|
||||
GUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
protected abstract void RotatePivot();
|
||||
|
||||
public InteractionSystem interactionSystem; // The InteractionSystem of the character
|
||||
public InteractionObject obj; // The object to pick up
|
||||
public Transform pivot; // The pivot point of the hand targets
|
||||
public Transform holdPoint; // The point where the object will lerp to when picked up
|
||||
public float pickUpTime = 0.3f; // Maximum lerp speed of the object. Decrease this value to give the object more weight
|
||||
|
||||
private float holdWeight, holdWeightVel;
|
||||
private Vector3 pickUpPosition;
|
||||
private Quaternion pickUpRotation;
|
||||
|
||||
void Start() {
|
||||
// Listen to interaction events
|
||||
interactionSystem.OnInteractionStart += OnStart;
|
||||
interactionSystem.OnInteractionPause += OnPause;
|
||||
interactionSystem.OnInteractionResume += OnDrop;
|
||||
}
|
||||
|
||||
// Called by the InteractionSystem when an interaction is paused (on trigger)
|
||||
private void OnPause(FullBodyBipedEffector effectorType, InteractionObject interactionObject) {
|
||||
if (effectorType != FullBodyBipedEffector.LeftHand) return;
|
||||
if (interactionObject != obj) return;
|
||||
|
||||
// Make the object inherit the character's movement
|
||||
obj.transform.parent = interactionSystem.transform;
|
||||
|
||||
// Make the object kinematic
|
||||
var r = obj.GetComponent<Rigidbody>();
|
||||
if (r != null) r.isKinematic = true;
|
||||
|
||||
// Set object pick up position and rotation to current
|
||||
pickUpPosition = obj.transform.position;
|
||||
pickUpRotation = obj.transform.rotation;
|
||||
holdWeight = 0f;
|
||||
holdWeightVel = 0f;
|
||||
}
|
||||
|
||||
// Called by the InteractionSystem when an interaction starts
|
||||
private void OnStart(FullBodyBipedEffector effectorType, InteractionObject interactionObject) {
|
||||
if (effectorType != FullBodyBipedEffector.LeftHand) return;
|
||||
if (interactionObject != obj) return;
|
||||
|
||||
// Rotate the hold point so it matches the current rotation of the object
|
||||
holdPoint.rotation = obj.transform.rotation;
|
||||
|
||||
// Rotate the pivot of the hand targets
|
||||
RotatePivot();
|
||||
}
|
||||
|
||||
// Called by the InteractionSystem when an interaction is resumed from being paused
|
||||
private void OnDrop(FullBodyBipedEffector effectorType, InteractionObject interactionObject) {
|
||||
if (holding) return;
|
||||
if (interactionObject != obj) return;
|
||||
|
||||
// Make the object independent of the character
|
||||
obj.transform.parent = null;
|
||||
|
||||
// Turn on physics for the object
|
||||
if (obj.GetComponent<Rigidbody>() != null) obj.GetComponent<Rigidbody>().isKinematic = false;
|
||||
}
|
||||
|
||||
void LateUpdate() {
|
||||
if (holding) {
|
||||
// Smoothing in the hold weight
|
||||
holdWeight = Mathf.SmoothDamp(holdWeight, 1f, ref holdWeightVel, pickUpTime);
|
||||
|
||||
// Interpolation
|
||||
obj.transform.position = Vector3.Lerp(pickUpPosition, holdPoint.position, holdWeight);
|
||||
obj.transform.rotation = Quaternion.Lerp(pickUpRotation, holdPoint.rotation, holdWeight);
|
||||
}
|
||||
}
|
||||
|
||||
// Are we currently holding the object?
|
||||
private bool holding {
|
||||
get {
|
||||
return holdingLeft || holdingRight;
|
||||
}
|
||||
}
|
||||
|
||||
// Are we currently holding the object with left hand?
|
||||
private bool holdingLeft
|
||||
{
|
||||
get
|
||||
{
|
||||
return interactionSystem.IsPaused(FullBodyBipedEffector.LeftHand) && interactionSystem.GetInteractionObject(FullBodyBipedEffector.LeftHand) == obj;
|
||||
}
|
||||
}
|
||||
|
||||
// Are we currently holding the object with right hand?
|
||||
private bool holdingRight
|
||||
{
|
||||
get
|
||||
{
|
||||
return interactionSystem.IsPaused(FullBodyBipedEffector.RightHand) && interactionSystem.GetInteractionObject(FullBodyBipedEffector.RightHand) == obj;
|
||||
}
|
||||
}
|
||||
|
||||
// Clean up delegates
|
||||
void OnDestroy() {
|
||||
if (interactionSystem == null) return;
|
||||
|
||||
interactionSystem.OnInteractionStart -= OnStart;
|
||||
interactionSystem.OnInteractionPause -= OnPause;
|
||||
interactionSystem.OnInteractionResume -= OnDrop;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 15d5147941ecd4e3d9c2d98b880da82b
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,34 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using RootMotion;
|
||||
using RootMotion.FinalIK;
|
||||
|
||||
namespace RootMotion.Demos {
|
||||
|
||||
/// <summary>
|
||||
/// Picking up a box shaped object with both hands.
|
||||
/// </summary>
|
||||
public class PickUpBox : PickUp2Handed {
|
||||
|
||||
// Rotate the pivot of the hand targets by 90 degrees so we could grab the object from any direction
|
||||
protected override void RotatePivot() {
|
||||
// Get the flat direction towards the character
|
||||
Vector3 characterDirection = (pivot.position - interactionSystem.transform.position).normalized;
|
||||
characterDirection.y = 0f;
|
||||
|
||||
// Convert the direction to local space of the object
|
||||
Vector3 characterDirectionLocal = obj.transform.InverseTransformDirection(characterDirection);
|
||||
|
||||
// QuaTools.GetAxis returns a 90 degree ortographic axis for any direction
|
||||
Vector3 axis = QuaTools.GetAxis(characterDirectionLocal);
|
||||
Vector3 upAxis = QuaTools.GetAxis(obj.transform.InverseTransformDirection(interactionSystem.transform.up));
|
||||
|
||||
// Rotate towards axis and upAxis
|
||||
pivot.localRotation = Quaternion.LookRotation(axis, upAxis);
|
||||
|
||||
// Match rotation of pivot to character rotation (added in v2.2)
|
||||
Quaternion q = RootMotion.QuaTools.FromToRotation(pivot.rotation, interactionSystem.transform.rotation);
|
||||
holdPoint.rotation = q * holdPoint.rotation;
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user