Guest User

Untitled

a guest
Mar 17th, 2018
270
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 8.41 KB | None | 0 0
  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using System;
  4. using UnityEngine;
  5. using Oculus.Avatar;
  6.  
  7. // Smoothly tween between the "real" hand pose that comes out of the
  8. // Oculus Avatar SDK and a custom grip pose.
  9. //
  10. // ## Why?
  11. // The SDK doesn't natively do this so we have to do it manually here.
  12. // We can't just naively lerp from the current hand pose to our target because
  13. // ovr doesn't update bones unless the C layer says they changed - so there's
  14. // no consistent FROM state, and thus no real control over how far through
  15. // the lerp you want to be
  16. // (i.e. you can't say "lerp 50% please" because the next frame the from
  17. // state will have moved to 50% so the request for 50% is now really for 75%
  18. // and so you'll always tend towards the TO state no matter how much you
  19. // actually want to lerp.)
  20. //
  21. // ## Overview
  22. // Roughtly we:
  23. // - Make a copy of the hand skeleton
  24. // - When the OvrAvatar updates, update our copy to match.
  25. // - Use our copy as the FROM version in a lerp TO our custom pose
  26. // - Set the rendered skeleton to whatever our lerped versions are
  27. //
  28. // ## TODO / Known Issues
  29. // - Not tested with OvrAvatarSkinnedMeshRenderPBSComponent
  30. // - Multiple target poses or some sort of blend tree would be nice.
  31. // - Limit tweens to specific fingers to allow it to play nice with other hand
  32. // poses (e.g. index finger trigger should only effect index finger).
  33. //
  34. // ## Contact
  35. // Any questions or bug reports - email me!
  36. // Chris McLaughlin - chris@vitei.com
  37.  
  38. public class OVRAvatarHandPoseOverrider : MonoBehaviour {
  39.  
  40. [Range(0,1)]
  41. public float m_tweenAmount;
  42. public OvrAvatar m_avatar;
  43. public enum Handedness { Right, Left }
  44. public Handedness m_hand;
  45. public Transform m_gripPose;
  46. OvrAvatarHand m_ovrHand;
  47. OvrAvatarRenderComponent m_ovrHandRenderer;
  48. Transform[] m_bonesTruePose;
  49. IntPtr m_ovrRenderPart = IntPtr.Zero;
  50.  
  51. [System.Serializable]
  52. public class BoneSet {
  53. public Transform m_rendered;
  54. public Transform m_base;
  55. public Transform m_target;
  56. }
  57. List<BoneSet> m_boneSets;
  58.  
  59. #if UNITY_EDITOR
  60. Transform m_lastGripPose;
  61. private void OnValidate() {
  62. // if the game is runnnign and the user changes the pose in editor,
  63. // then we want to make sure to update everything so that's what
  64. // they see!
  65. if(Application.isPlaying && m_lastGripPose != m_gripPose) {
  66. SetupBoneSets();
  67. }
  68. m_lastGripPose = m_gripPose;
  69. }
  70. #endif
  71.  
  72. protected virtual void Start() {
  73. // Get all the relevant components that we're gonna need later on
  74. this.Fetch(out m_avatar);
  75. m_ovrHand = (m_hand == Handedness.Left) ? m_avatar.HandLeft : m_avatar.HandRight;
  76. }
  77.  
  78. protected virtual void Update() {
  79.  
  80. // we need a renderpart before we can do anything else. This doesn't
  81. // exist until the SDK tries to render the hand, so we have to keep
  82. // testing here in update until we can get it.
  83. if (m_ovrRenderPart == IntPtr.Zero){
  84. GetNativeRenderPartPtr();
  85. return;
  86. }
  87.  
  88. // we need the bonesets setup otherwise there's nothing to actually do
  89. // the work on. Again we need the rendered data before we can do
  90. // this setup.
  91. if (m_boneSets == null) {
  92. SetupBoneSets();
  93. return;
  94. }
  95.  
  96. // Use the renderpart to look into the avatar sdk adn find out what bones have changed.
  97. // Update our TRUE bones to whatever the sdk says they should be
  98. // We can't use the meshrenderer's bones as the FROM in our lerp
  99. // because the SDK doesn't update them unless _it_ thinks that they
  100. // changed.
  101. ulong dirtyJoints = CAPI.ovrAvatarSkinnedMeshRender_GetDirtyJoints(m_ovrRenderPart);
  102. for (UInt32 i = 0; i < m_bonesTruePose.Length; i++) {
  103. UInt64 dirtyMask = (ulong)1 << (int)i;
  104. // We need to make sure that we fully update the initial position of
  105. // Skinned mesh renderers, then, thereafter, we can only update dirty joints
  106. if ((dirtyMask & dirtyJoints) != 0) {
  107. //This joint is dirty and needs to be updated
  108. Transform targetBone = m_ovrHandRenderer.bones[i];
  109. if (m_bonesTruePose != null && m_bonesTruePose[i] != null) {
  110. m_bonesTruePose[i].localPosition = targetBone.localPosition;
  111. m_bonesTruePose[i].localRotation = targetBone.localRotation;
  112. m_bonesTruePose[i].localScale = targetBone.localScale;
  113. }
  114. }
  115. }
  116.  
  117. // Loop through all our bones based on how much the trigger is pulled and put them into the right positions!
  118. for (int i = 0; i < m_boneSets.Count; i++) {
  119. // Not lerping POSITION or SCALE because hand bones don't need to, but if you want to do that for some reason, then add it here!
  120.  
  121. // You could use a SLERP here, but I didn't see any difference in action, so went with the cheaper LERP instead.
  122. m_boneSets[i].m_rendered.localRotation = Quaternion.Lerp(m_boneSets[i].m_base.localRotation, m_boneSets[i].m_target.localRotation, m_tweenAmount);
  123. }
  124. }
  125.  
  126. //-------------------------------------------------------
  127.  
  128. // Dive into the avatar sdk and pull out a reference to what I guess is
  129. // the thing that renders a hand. we can then use it to look up how
  130. // dirty it is later on.
  131. void GetNativeRenderPartPtr() {
  132. if (m_avatar.sdkAvatar != IntPtr.Zero) { // null check, otherwise the next line will hard crash the game.
  133. UInt32 componentCount = CAPI.ovrAvatarComponent_Count(m_avatar.sdkAvatar);
  134. for (UInt32 i = 0; i < componentCount; i++) {
  135. IntPtr ptr = CAPI.ovrAvatarComponent_Get_Native(m_avatar.sdkAvatar, i);
  136. ovrAvatarComponent component = (ovrAvatarComponent)System.Runtime.InteropServices.Marshal.PtrToStructure(ptr, typeof(ovrAvatarComponent));
  137. if (component.name == (m_hand == Handedness.Left ? "hand_left" : "hand_right")) {
  138. m_ovrRenderPart = OvrAvatar.GetRenderPart(component, 0); //magic 0
  139. }
  140. }
  141. }
  142. }
  143.  
  144. // Make a copy of all the bones in the OvrAvatarSkinnedMeshRenderComponent, these will represent the position as the avatar sdk thinks is should be
  145. void CreateTrueBoneArray() {
  146. Transform[] bones = m_ovrHandRenderer.bones;
  147. m_bonesTruePose = new Transform[bones.Length];
  148. for (int i = 0; i < bones.Length; i++) {
  149. m_bonesTruePose[i] = new GameObject(bones[i].name + " (true pose)").transform;
  150. }
  151. List<Transform> bonesAsList = new List<Transform>(bones);
  152. for (int i = 0; i < bones.Length; i++) {
  153. int parentIdx = bonesAsList.IndexOf(bones[i].parent);
  154. if (parentIdx >= 0) {
  155. m_bonesTruePose[i].parent = m_bonesTruePose[parentIdx];
  156. }
  157. else {
  158. m_bonesTruePose[i].parent = bones[i].parent;
  159. }
  160. m_bonesTruePose[i].transform.localPosition = bones[i].transform.localPosition;
  161. m_bonesTruePose[i].transform.localRotation = bones[i].transform.localRotation;
  162. m_bonesTruePose[i].transform.localScale = bones[i].transform.localScale;
  163. }
  164. }
  165.  
  166. // Make sets of corresponding bones that we'll lerp between.
  167. void SetupBoneSets() {
  168. if(m_ovrHand == null) {
  169. return;
  170. }
  171.  
  172. // Get the skinnedmeshrenderer because it has all the bone data we need
  173. m_ovrHandRenderer = m_ovrHand.GetComponentInChildren<OvrAvatarRenderComponent>();
  174. if (m_ovrHandRenderer == null) {
  175. return;
  176. }
  177.  
  178. // Make our copy of the bones to use as the TRUTH
  179. CreateTrueBoneArray();
  180.  
  181. // Make our bonesets that allow us to lerp between TRUTH and m_gripPose;
  182. m_boneSets = new List<BoneSet>();
  183. for (int i = 0; i < m_ovrHandRenderer.bones.Length; i++) {
  184. BoneSet bs = new BoneSet();
  185. bs.m_rendered = m_ovrHandRenderer.bones[i];
  186. bs.m_base = m_bonesTruePose[i];
  187. bs.m_target = m_gripPose.FindChildRecursive(m_ovrHandRenderer.bones[i].name);
  188.  
  189. // don't add any that have incomplete data as it will cause errors later on ehwn we're interpolating
  190. if (bs.m_rendered != null && bs.m_base != null && bs.m_target != null) {
  191. m_boneSets.Add(bs);
  192. }
  193. }
  194. }
  195. }
Add Comment
Please, Sign In to add comment