VR Development Framework
v 1.0.0
 All Classes Namespaces Functions Variables Enumerations Enumerator Properties Events Pages
AVR_PoseAssumer.cs
1 using System.Collections;
2 using System.Collections.Generic;
3 using UnityEngine;
4 #if UNITY_EDITOR
5 using UnityEditor;
6 #endif
7 
8 namespace AVR.Avatar {
9  /// <summary>
10  /// Applies a pose provided by an AVR_PosePorvider to a rigged 3d model with an avatar.
11  /// </summary>
12  [RequireComponent(typeof(Animator))]
13  [AVR.Core.Attributes.DocumentationUrl("class_a_v_r_1_1_avatar_1_1_a_v_r___pose_assumer.html")]
14  public class AVR_PoseAssumer : AVR.Core.AVR_Component
15  {
16  /// <summary>
17  /// PoseProvider to get pose information from
18  /// </summary>
19  public AVR_PoseProvider provider;
20 
21  /// <summary>
22  /// 3d models' transform of the head
23  /// </summary>
24  public Transform headTransform;
25 
26  /// <summary>
27  /// 3d models' transform of the neck
28  /// </summary>
29  public Transform neckTransform;
30 
31  /// <summary>
32  /// Swap the X and Y axes of the head and neck. (If the head is inverted on your avatar, toggle this)
33  /// </summary>
34  public bool switchAxisXZ = true;
35 
36  /// <summary>
37  /// Swap left and right feet targets. (If the avatar consistently has crossed legs, toggle this)
38  /// </summary>
39  public bool swap_feet = false;
40 
41  private Animator animator;
42  private bool IKPass_is_enabled = false;
43 
44  /// <summary>
45  /// If true, we automatically blend the weight of the IK layer to inverse proportion of the playerRigs' speed
46  /// </summary>
47  public bool autoLayerBlend = false;
48 
49  /// <summary>
50  /// The animation parameter in the animation controller we set to the playerrigs speed when the rig is teleporting
51  /// </summary>
52  [AVR.Core.Attributes.ConditionalHideInInspector("autoLayerBlend", true)]
53  public string speedAnimationParameter = "Speed";
54 
55  /// <summary>
56  /// Speed of how quickly we blend in and out of the IK layer (if autoLayerBlend is true)
57  /// </summary>
58  [AVR.Core.Attributes.ConditionalHideInInspector("autoLayerBlend", true)]
59  public float layerBlend_speed = 5.0f;
60  private float layerBlend = 1.0f;
61 
63  public float lookAtWeight_body = 0.0f;
65  public float lookAtWeight_head = 1.0f;
67  public float lookAtWeight_eyes = 1.0f;
69  public float lookAtWeight_clamp = 0.0f;
71  public float lookAtWeight = 1.0f;
73  public float HandPosWeight = 1.0f;
75  public float HandRotWeight = 0.5f;
77  public float FootPosWeight = 1.0f;
79  public float FootRotWeight = 1.0f;
80 
81  protected override void Start() {
82  base.Start();
83  animator = GetComponent<Animator>();
84  if(!animator.avatar) {
85  AVR.Core.AVR_DevConsole.warn("AVR_PoseAssumer requires an Animator component WITH an Avatar set. " + animator.name + " has none.");
86  }
87  Invoke("CheckIKPass", 3.0f);
88 
89  animator.logWarnings = false; //TODO: This disables warning-spam if parameters (like "Speed") dont exist. Perhaps this should be optional based on a setting.
90  }
91 
92  void CheckIKPass() {
93  if(!IKPass_is_enabled) {
94  AVR.Core.AVR_DevConsole.warn("The OnAnimatorIK() method of AVR_PoseAssumer " + gameObject.name + " is not being called. Does the respective Animator have IKPass enabled on any layers?");
95  }
96  }
97 
98  void LateUpdate() {
99  if(!headTransform || !neckTransform) {
100  AVR.Core.AVR_DevConsole.cwarn("headTransform and neckTransform are not set!", this);
101  return;
102  }
103  // Head linkage
104  Vector3 headAng = headTransform.eulerAngles;
105  Vector3 neckAng = neckTransform.eulerAngles;
106  float ang = Mathf.DeltaAngle(360.0f, provider.eyeRot.eulerAngles.z);
107  if (switchAxisXZ)
108  {
109  headAng.x = ang;
110  neckAng.x = ang * 0.5f;
111  }
112  else
113  {
114  headAng.z = ang;
115  neckAng.z = ang * 0.5f;
116  }
117  headTransform.eulerAngles = headAng;
118  neckTransform.eulerAngles = neckAng;
119  }
120 
121  void Update() {
122  #if AVR_NET
123  if (!playerRig) return; // Sometimes this happens on MP for 1 frame.
124  #endif
125 
126 
127  if(autoLayerBlend) {
128  layerBlend = Mathf.Lerp(layerBlend, Mathf.SmoothStep(1.0f, 0.0f, playerRig.AvgMotion.magnitude), layerBlend_speed * Time.deltaTime);
129  }
130  }
131 
132  protected void setWeights(int layerIndex) {
133  float layerWeight = animator.GetLayerWeight(layerIndex);
134 
135  animator.SetLookAtWeight(lookAtWeight*layerWeight, lookAtWeight_body*layerWeight, lookAtWeight_head*layerWeight, lookAtWeight_eyes*layerWeight, lookAtWeight_clamp*layerWeight);
136  animator.SetIKPositionWeight(AvatarIKGoal.LeftHand, HandPosWeight*layerWeight);
137  animator.SetIKRotationWeight(AvatarIKGoal.LeftHand, HandRotWeight*layerWeight);
138  animator.SetIKPositionWeight(AvatarIKGoal.RightHand, HandPosWeight*layerWeight);
139  animator.SetIKRotationWeight(AvatarIKGoal.RightHand, HandRotWeight*layerWeight);
140  animator.SetIKPositionWeight(AvatarIKGoal.LeftFoot, FootPosWeight*layerWeight);
141  animator.SetIKRotationWeight(AvatarIKGoal.LeftFoot, FootRotWeight*layerWeight);
142  animator.SetIKPositionWeight(AvatarIKGoal.RightFoot, FootPosWeight*layerWeight);
143  animator.SetIKRotationWeight(AvatarIKGoal.RightFoot, FootRotWeight*layerWeight);
144  }
145 
146  protected void setPosRot(int layerIndex) {
147  float layerWeight = animator.GetLayerWeight(layerIndex);
148 
149  {
150  animator.SetLookAtPosition(transform.TransformPoint(provider.lookAtPos));
151  }
152  {
153  animator.bodyPosition = transform.TransformPoint(provider.bodyPos);
154  animator.bodyRotation = transform.rotation * provider.bodyRot;
155  }
156  if(playerRig.leftHandController!=null)
157  {
158  animator.SetIKPosition(AvatarIKGoal.LeftHand, transform.TransformPoint(provider.leftHandPos));
159  animator.SetIKRotation(AvatarIKGoal.LeftHand, transform.rotation * provider.leftHandRot);
160  }
161  if(playerRig.rightHandController != null)
162  {
163  animator.SetIKPosition(AvatarIKGoal.RightHand, transform.TransformPoint(provider.rightHandPos));
164  animator.SetIKRotation(AvatarIKGoal.RightHand, transform.rotation * provider.rightHandRot);
165  }
166  if(!swap_feet)
167  {
168  animator.SetIKPosition(AvatarIKGoal.LeftFoot, transform.TransformPoint(provider.leftFootPos));
169  animator.SetIKRotation(AvatarIKGoal.LeftFoot, transform.rotation * provider.leftFootRot);
170  animator.SetIKPosition(AvatarIKGoal.RightFoot, transform.TransformPoint(provider.rightFootPos));
171  animator.SetIKRotation(AvatarIKGoal.RightFoot, transform.rotation * provider.rightFootRot);
172  }
173  else {
174  animator.SetIKPosition(AvatarIKGoal.LeftFoot, transform.TransformPoint(provider.rightFootPos));
175  animator.SetIKRotation(AvatarIKGoal.LeftFoot, transform.rotation * provider.rightFootRot);
176  animator.SetIKPosition(AvatarIKGoal.RightFoot, transform.TransformPoint(provider.leftFootPos));
177  animator.SetIKRotation(AvatarIKGoal.RightFoot, transform.rotation * provider.leftFootRot);
178  }
179  }
180 
181  void OnAnimatorIK(int layerIndex)
182  {
183  IKPass_is_enabled = true;
184 
185  #if AVR_NET
186  if (!playerRig) return; // Sometimes this happens on MP for one frame.
187  #endif
188 
189  setPosRot(layerIndex);
190 
191  // This paragraph handles everything regarding basic movement animations and stuff
192  if(autoLayerBlend) {
193  animator.SetFloat(speedAnimationParameter, playerRig.AvgMotion.magnitude);
194  animator.SetLayerWeight(layerIndex, layerBlend);
195  Vector3 defaultBodyPos = transform.TransformPoint(provider.pivotPos + Vector3.up * 1.0f);
196  animator.bodyPosition = Vector3.Lerp(defaultBodyPos, animator.bodyPosition, layerBlend);
197  animator.bodyRotation = Quaternion.Lerp(
198  // The 0.0001*forward is to avoid quaternion zero-look errors. These don't actually break anything, but they do spam the debug output.
199  transform.rotation * Quaternion.LookRotation(playerRig.AvgMotion + 0.0001f*Vector3.forward, Vector3.up),
200  animator.bodyRotation,
201  layerBlend
202  );
203  }
204 
205  setWeights(layerIndex);
206  }
207  }
208 }
Applies a pose provided by an AVR_PosePorvider to a rigged 3d model with an avatar.
Estimates the pose of a player from the locations of VR controllers and HMD
void setPosRot(int layerIndex)
void setWeights(int layerIndex)
void OnAnimatorIK(int layerIndex)
Sets the documentation html file inside of Packages/com.avr.core/Documentation/html of a given class...
Assigns given attributes to a foldout group in the inspector. The way these are drawn is determined b...
Allows for simple hiding of properties in the UnityEditor depending on certain conditions. For instance, in the following example the "type" field will only be displayed in the inspector if the "tracking" field is set to true: