0414 cinemachine/coroutine/IK pivot

2021. 4. 14. 12:19unity

글로벌 일루미네이션 (GI)
물체의 표면에 직접 들어오는 빛뿐만 아니라
다른 물체의 표면에 반사되어 들어온 간접광까지 표현하는 것

 

angluar drag 회전할 때의 마찰력

apply root motion
게임 오브젝트의 위치와 모션을 애니메이션이 제어하도록 한다.

 

cinemachine

deadzone (중앙)
soft zone (파랑)
hard limit (빨강)

dead zone: 주시하는 물체가 게임 화면 밖으로 벗어나지 않게 추적의 세기를 단계별로 설정
카메라가 주시하는 물체가 화면의 데드존에 있는 동안 카메라가 회전하지 않는다.
soft zone: 주시하는 물체가 화면의 소프트존에 있다면 물체가 화면의 조준점에 오도록 카메라가 부드럽게 회전한다.
hard limit: 만약 물체가 너무 빠르게 움직여 화면의 소프트존을 벗어나 하드 리밋에 도달하려 한다면 카메라가 격하게 회전한다.

카메라가 주시하는 물체는 화면의 소프트존을 벗어나지 않는다.

데드존과 소프트존의 크기를 줄이면 물체가 조금이라도 화면 중앙을 벗어나러 할 때
지연 시간 없이 카메라가 즉시 물체를 향해 회전, 화면의 움직임이 딱딱하게 느껴질 수도 있다.

반대로 데드존과 소프트존의 크기를 늘리면 물체를 좇는 화면의 움직임이 느리게 느껴질 수 있다.

damping: 카메라의 회전 속도 결정 (수치가 높을 수록 격하게 움직임)


Coroutine

docs.unity3d.com/kr/530/Manual/Coroutines.html

실행을 중지하여 Unity에 제어권을 돌려주고, 그러나 계속할 때는 다음 프레임에서 중지한 곳부터 실행을 계속할 수 있는 기능
코루틴을 실행하려면 StartCoroutine 함수를 사용합니다.

Fade 함수의 루프 카운터는 코루틴의 라이프 사이클을 통해 올바른 값을 유지합니다. 
yield 중에 모든 변수 또는 파라미터가 올바르게 보존됩니다.

기본적으로 코루틴은 yield 한 직후의 프레임에서 재개되지만, 지연했다가 
다시 시작하려면 WaitForSeconds 함수를 사용합니다.

이 방법으로 효과를 일정한 시간 범위에서 펼칠 수 있지만, 최적화 방법으로 해도 편리합니다. 

IEnumerator Fade() {
    for (float f = 1f; f >= 0; f -= 0.1f) {
        Color c = renderer.material.color;
        c.a = f;
        renderer.material.color = c;
        yield return new WaitForSeconds(.1f);
    }
}

작업이 너무 자주 반복할 필요가 없는 경우, 코루틴에 넣어 매 프레임 실행하지 않고 정기적으로 업데이트 할 수 있습니다. 
예를 들자면, 적이 근처에 있는 것을 플레이어에게 알리는 알람입니다.
적이 많은 경우에 이 함수를 매 프레임 호출하여 현저한 오버 헤드를 초래할 지도 모릅니다. 그러나 코루틴을 사용하여 1/10 초 간격으로 호출할 수 있습니다

Coroutine 변수로 받아서

StopCoroutine(변수)로 코루틴 멈춤 가능

using UnityEngine;
using UnityEngine.AI;

public class App : MonoBehaviour
{
    public Transform point;
    public NavMeshAgent agent;
    public Zombie zombie;
    // Start is called before the first frame update
    void Start()
    {
        this.zombie.Init();
    }

    // Update is called once per frame
    void Update()
    {
        if (Input.GetMouseButtonDown(0)) 
        {
            //마우스 버튼 누른 쪽으로 raycast 생성
            var ray=Camera.main.ScreenPointToRay(Input.mousePosition);
            RaycastHit hit;
            
            if (Physics.Raycast(ray, out hit, 1000f)) 
            {
                Debug.DrawRay(ray.origin, ray.direction * 1000f, Color.red, 1f);
                NavMeshHit navHit;
                this.point.transform.position = hit.point;
                //해당 포지션이 네브메쉬 위에 있는가?
                var result=NavMesh.SamplePosition(hit.point, out navHit, 1f, NavMesh.AllAreas);
                Debug.Log(result);
                if (result) 
                {
                    agent.isStopped = false;
                    agent.SetDestination(hit.point);
                }
            };
            
        }
    }
}
using UnityEngine;

public class Zombie : MonoBehaviour
{
    public float radius= 2.0f;
    public void Init()
    {
        this.StartCoroutine(this.DetectTarget());
    }
    private IEnumerator DetectTarget() 
    {
        while (true) 
        {
            Debug.Log("detect");
            yield return new WaitForSeconds(1f);
        }
        
    }
    private void OnDrawGizmos()
    {
        Gizmos.color = Color.yellow;
        Gizmos.DrawSphere(this.transform.position,2);
    }

}

 


 

캐릭터와 총에게 IK적용

using UnityEngine;

public class PlayerShooter : MonoBehaviour
{
    private GameObject gun;
    private Transform gunPivot;
    public Transform leftHandMount;
    public Transform rightHandMount;
    public Animator playerAnim;

    private GameObject player;
    // Start is called before the first frame update
    void Start()
    {
        player = GetComponent<GameObject>();
        gun = GetComponent<GameObject>();
        playerAnim = GetComponent<Animator>();
        
    }
   

    // Update is called once per frame
    void Update()
    {
        
    }
    //애니메이터의 IK 갱신
    private void OnAnimatorIK(int layerIndex)
    {

        //IK를 사용하여 왼손의 위치와 회전을 총의 왼쪽 손잡이에
        playerAnim.SetIKPositionWeight(AvatarIKGoal.LeftHand, 1f);
        playerAnim.SetIKRotationWeight(AvatarIKGoal.LeftHand, 1f);

        playerAnim.SetIKPosition(AvatarIKGoal.LeftHand, leftHandMount.position);
        playerAnim.SetIKRotation(AvatarIKGoal.LeftHand, leftHandMount.rotation);

        //IK를 사용하여 오른손의 위치와 회전을 총의 오른쪽 손잡이에
        playerAnim.SetIKPositionWeight(AvatarIKGoal.RightHand, 1f);
        playerAnim.SetIKRotationWeight(AvatarIKGoal.RightHand, 1f);

        playerAnim.SetIKPosition(AvatarIKGoal.RightHand, rightHandMount.position);
        playerAnim.SetIKRotation(AvatarIKGoal.RightHand, rightHandMount.rotation);
    }
}

물체의 pivot은 캐릭터의 손과 되도록 가까운 위치에 맞춰야 하는 것 같다...

www.youtube.com/watch?v=7Xy7nRDdDHI&list=PL5kjuqWePlOoR6OJy8Ula_14FzMb9Zpnc&index=10

SetIKPositionWeight: IK 목표의 변환 가중치를 설정한다.
SetIKPositionWeight(AvatarIKGoal 목표, float 값)
IK 목표는 특정 신체 부위에 대한 대상 위치 및 회전
float는 IK가 조준 할 시작 위치와 목표 위치 사이의 거리

SetIKPosition:
public void SetIKPosition ( AvatarIKGoal goal , Vector3 goalPosition );
이 함수는 항상 MonoBehaviour.OnAnimatorIK 에서 호출되어야합니다 .
IK 목표는 특정 신체 부위에 대한 대상 위치 및 회전입니다.

AvatarIKGoal : IK 가중치, 위치 및 회전을 설정하고 가져온다.
AvatarIKGoal.Left/RightHand