저의 천사 발렘 유튜버님의 영상을 후루룩 해왔습니다!!!
필요한 재료
첫 번째로 Animation Rigging이 필요합니다!
IK Foot Solver
using UnityEngine;
public class IKFootSolver : MonoBehaviour
{
public bool isMovingForward;
[SerializeField] LayerMask terrainLayer = default;
[SerializeField] Transform body = default;
[SerializeField] IKFootSolver otherFoot = default;
[SerializeField] float speed = 4;
[SerializeField] float stepDistance = .2f;
[SerializeField] float stepLength = .2f;
[SerializeField] float sideStepLength = .1f;
[SerializeField] float stepHeight = .3f;
[SerializeField] Vector3 footOffset = default;
public Vector3 footRotOffset;
public float footYPosOffset = 0.1f;
public float rayStartYOffset = 0;
public float rayLength = 1.5f;
float footSpacing;
Vector3 oldPosition, currentPosition, newPosition;
Vector3 oldNormal, currentNormal, newNormal;
float lerp;
private void Start()
{
footSpacing = transform.localPosition.x;
currentPosition = newPosition = oldPosition = transform.position;
currentNormal = newNormal = oldNormal = transform.up;
lerp = 1;
}
void Update()
{
transform.position = currentPosition + Vector3.up * footYPosOffset;
transform.localRotation = Quaternion.Euler(footRotOffset);
Ray ray = new Ray(body.position + (body.right * footSpacing) + Vector3.up * rayStartYOffset, Vector3.down);
Debug.DrawRay(body.position + (body.right * footSpacing) + Vector3.up * rayStartYOffset, Vector3.down);
if (Physics.Raycast(ray, out RaycastHit info, rayLength, terrainLayer.value))
{
if (Vector3.Distance(newPosition, info.point) > stepDistance && !otherFoot.IsMoving() && lerp >= 1)
{
lerp = 0;
Vector3 direction = Vector3.ProjectOnPlane(info.point - currentPosition,Vector3.up).normalized;
float angle = Vector3.Angle(body.forward, body.InverseTransformDirection(direction));
isMovingForward = angle < 50 || angle > 130;
if(isMovingForward)
{
newPosition = info.point + direction * stepLength + footOffset;
newNormal = info.normal;
}
else
{
newPosition = info.point + direction * sideStepLength + footOffset;
newNormal = info.normal;
}
}
}
if (lerp < 1)
{
Vector3 tempPosition = Vector3.Lerp(oldPosition, newPosition, lerp);
tempPosition.y += Mathf.Sin(lerp * Mathf.PI) * stepHeight;
currentPosition = tempPosition;
currentNormal = Vector3.Lerp(oldNormal, newNormal, lerp);
lerp += Time.deltaTime * speed;
}
else
{
oldPosition = newPosition;
oldNormal = newNormal;
}
}
private void OnDrawGizmos()
{
Gizmos.color = Color.red;
Gizmos.DrawSphere(newPosition, 0.1f);
}
public bool IsMoving()
{
return lerp < 1;
}
}
IKTargetFollowVRRig
using UnityEngine;
[System.Serializable]
public class VRMap
{
public Transform vrTarget;
public Transform ikTarget;
public Vector3 trackingPositionOffset;
public Vector3 trackingRotationOffset;
public void Map()
{
ikTarget.position = vrTarget.TransformPoint(trackingPositionOffset);
ikTarget.rotation = vrTarget.rotation * Quaternion.Euler(trackingRotationOffset);
}
}
public class IKTargetFollowVRRig : MonoBehaviour
{
[Range(0,1)]
public float turnSmoothness = 0.1f;
public VRMap head;
public VRMap leftHand;
public VRMap rightHand;
public Vector3 headBodyPositionOffset;
void LateUpdate()
{
transform.position = head.ikTarget.position + headBodyPositionOffset;
float yaw = head.vrTarget.eulerAngles.y;
transform.rotation = Quaternion.Lerp(transform.rotation,Quaternion.Euler(transform.eulerAngles.x, yaw, transform.eulerAngles.z),turnSmoothness);
head.Map();
leftHand.Map();
rightHand.Map();
}
}
AnimateOnInput
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.InputSystem;
[System.Serializable]
public class AnimationInput
{
public string animationPropertyName;
public InputActionProperty action;
}
public class AnimateOnInput : MonoBehaviour
{
public List<AnimationInput> animationInputs;
public Animator animator;
void Update()
{
foreach (var item in animationInputs)
{
float actionValue = item.action.action.ReadValue<float>();
animator.SetFloat(item.animationPropertyName, actionValue);
}
}
}
Arm, Leg IK 세팅 방법
IK 부착하는 방법은 예전 포스팅에서 다룬 적이 있습니다!
2022.11.06 - [Unity/VR(OVR SDK)] - Unity VR Arm IK
Unity VR Arm IK
패키지 매니저에 들어가서 Animation Rigging 패키지를 다운받는다 준비해둔 휴머노이드 모델에다가 Rig Builder를 추가하고 Animation을 삭제해준다 Bone Renderer를 추가해주고 모델의 Root부분부터 맨 아래
wlsdn629.tistory.com
2022.11.06 - [Unity/VR(OVR SDK)] - Unity VR Leg IK
Unity VR Leg IK
이번 시간엔 Leg Ik 설정하는 방법에 대해 알아보겠다 먼저 모델의 Animation Type을 Humanoid로 바꿔준다 그다음 믹사모같은데에서 Walk관련 애니메이션을 하나 다운받아준다 그 애니메이션 또한 휴머
wlsdn629.tistory.com
복습할 겸 처음부터 다시 적어보겠습니다!
모델을 눌러준 후 상단 [Animation Rigging] 탭을 눌러준 후 [Bone Renderer Setup]을 눌러줍니다!
자동으로 Bone Renderer 세팅이 된 것을 볼 수 있습니다!
그 다음으로 , Rig Builder 컴포넌트를 붙여줍니다!
다음으로 모델에 빈 오브젝트를 하나 생성해준 후 Rig컴포넌트를 붙여줍니다!
아까 만든 Rig builder에 드래그해서 할당시켜줍니다!
VR Rig IK 자식으로 총 5가지 종류의 IK를 만들어줍니다!
그 다음으로 Head IK을 제외한 모든 IK에 Two Bone IK Constraint 컴포넌트를 부착시켜줍니다!
Tip에 RightHand Rig을 찾아 할당시켜준 후
점 3개를 눌러준 다음 Auto Setup From Tip Transform을 눌러줍니다! 그러면 자동으로 세팅이됩니다!!!!!
다음으로
Right Arm IK Target과 RightHand을 동시에 눌러준 후 Align Transform을 눌러줍니다!
Hint같은 경우에는 팔꿈치 뒤에 위치하도록 세팅했습니다!(Hint Setting에 대해서는 아직 잘 모르겠네요!, 주로 관절쪽, 즉 굽혀지는 곳에 세팅한다는데 Valem은 이상한곳에 세팅했더라고요...이유는 잘 모르겠습니다!)
IK_Target같은 경우에는 손이 해당 지점으로 위치하게 끔 유도하는 친구이고,
IK_Hint같은 경우에는 캐릭터의 팔이 휘는 방향을 안내하는 도우미 점이라고 생각하시면 되겠습니다!
Two Bone IK Contstaint 컴포넌트 같은 경우에는 2개의 Bone을 정의할 때 사용된다고 합니다! (그럼 3개의 Bone일 때는 어떡하지..?)
오른 팔, 왼팔, 오른 발, 왼발 다 똑같이 세팅해줍시다!
마지막으로 Leg Target에는 포스팅 맨 위에 적어놨던 IK Foot Solver 스크립트를 부착해줍니다!
Head IK 세팅 방법
Head IK 에는 Multi Parent Constraint 컴포넌트를 붙여줍니다!
1. 자식 오브젝트로 Head Target을 만들어 준 다음 Head에 align시켜줍니다!
2. 그 후에 Source Object에 Head Target을 할당시켜주고 Constrained Object에는 Head을 할당해줍니다!
VR Rig에 IK 할당하기
포스팅 맨 위 재료 부분에서 작성한 IK Target Follow VR Rig와 Animate On Input 스크립트를 만든 후 컴포넌트로 부착시켜줍니다!
XR Rig에 Main Camera, LeftHand Controller, RightHand Controller 오브젝트에 각각 자식 오브젝트를 하나씩 만들어줍니다!
IK Target Follow VR Rig 컴포넌트는 위와 같이 세팅해줍니다!
VR Target은 XR Rig를 뜻하며 , IK Target은 모델 Rig를 뜻합니다!
위와 같이 세팅을 한 후에 플레이 해봤는데 XR Rig가 이상하면 본인 프로젝트에 맞게 세팅하셔야 합니다!
Animation Hand
마지막으로 Animate On Input 스크립트는 다음과 같이 세팅해줍니다!
Rig Player Animator같은 경우에는
위 파일을 다운받아 사용하시면 됩니다!
본인의 Model Rig Hand가 XR Rig에 일치하지 않는 경우 위와 같이 Transform을 변경해보시길 바랍니다!
결과 영상