카메라 이동 연습 2(draw gizmos, 선형 보간과 구면 선형 보간)
2023. 8. 18.

OnDrawGizmos

-매 프레임 호출된다.

https://gist.github.com/luisparravicini/50d044a20c67f0615fdd28accd939df4

 

Method to draw an arc with Unity's Gizmos

Method to draw an arc with Unity's Gizmos. GitHub Gist: instantly share code, notes, and snippets.

gist.github.com

노란색 선은 카메라의 방향을 의미한다.

카메라의 위치를 구하기 위해 카메라의 방향이 필요하므로 Gizmo로 그려 보았다.

카메라의 위치 = 타겟의 위치 +(타깃의 뒤쪽 방향 *떨어질 거리)+(y축 방향*높이);이다.

초록색 화살표가 가리키는 곳이 카메라의 위치이다. 회전해도 따라다닌다.
카메라 코드 수정

선형 보간과 구면 선형 보간

-시작점과 끝점 사이의 특정 위치를 추정할 때 사용한다.

유니티에서는 Lerp 선형 보간 함수를 제공하며 Vector3, Mathf, Quanternion, Color 구조에서 사용할 수 있다.

구면 선형 보간은 주로 회전 로직에 사용된다. 

https://docs.unity3d.com/ScriptReference/Vector3.Slerp.html

 

Unity - Scripting API: Vector3.Slerp

Interpolates between a and b by amount t. The difference between this and linear interpolation (aka, "lerp") is that the vectors are treated as directions rather than points in space. The direction of the returned vector is interpolated by the angle and it

docs.unity3d.com

선형보간차트, 구면 선형 보간

+) Time.deltaTime은 프레임과 프레임 사이의 시간이다.

 

보간 연습

Quaternion에는 좌표가 아니라 각도가 들어간다.

Vector3.SmoothDamp를 사용해도 부드럽게 이동시킬 수 있다.

이 함수를 사용하려면 ref 키워드를 알아야하는데, 인수가 값이 아니라 참조로 전달됨을 나타낸다. 지역 변수에서 참조 변수를 선언한다. 참조형식(클래스)가 아니다. ref키워드를 사용하면 원본이 변한다.

 

위와 반대로 damping이 작아져야 빠르게 움직인다.

 

방향벡터는 크기와 뱡항만 가지고있다. 위치가 필요없다. LookAt하는 위치에 방향벡터를 offset으로 더해줬다.

 

offset으로 카메라가 머리를 바라보도록 조정

 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;

public class PlayerController : MonoBehaviour
{
    public Vector3 cameraPosition;

    private Vector3 moveDir;
    private Vector3 aPosition;
    private Animation anim;
    //변수
    [SerializeField]private float moveSpeed = 1f;
    [SerializeField] private float turnSpeed =80f;
    private void Start()
    {
        this.anim = GetComponent<Animation>();
        anim.Play("Idle");//시작 시 Idle
    }
    private void Update()
    {
        //키보드 이동
        float h = Input.GetAxis("Horizontal");
        float v = Input.GetAxis("Vertical");
        float r = Input.GetAxis("Mouse X");//마우스를 왼쪽으로 움직이면 음수, 오른쪽 양수 반환
        moveDir = (Vector3.forward * v) + Vector3.right * h;
        this.transform.Translate(moveDir.normalized * this.moveSpeed * Time.deltaTime);//이동
        //   Debug.LogFormat("{0} , {1}", moveDir, moveDir.normalized);
        //  DrawArrow.ForDebug(this.transform.position, moveDir, 5f, Color.red);
        Vector3 angle = Vector3.up * turnSpeed * Time.deltaTime * r;
       // Vector3 angle2 = Vector3.up * turnSpeed * r;//Time.deltaTime을 빼보았다.
      //  Debug.LogFormat("angle2:{0},r:{1}",angle2,r );
        this.transform.Rotate(angle);//Vector3.up을 축으로 회전
        PlayAnim(h,v);
        
    }
    private void OnDrawGizmos()
    {
        DrawArrow.ForGizmo(this.transform.position, this.transform.forward , Color.red);
        Gizmos.color = Color.white;
        GizmosExtensions.DrawWireArc(this.transform.position, this.transform.forward, 360, 1);
        DrawArrow.ForGizmo(this.transform.position, -this.transform.forward * 3, Color.yellow);
        this.aPosition = this.transform.position + (-this.transform.forward * 3);//a지점의 위치
        DrawArrow.ForGizmo(this.aPosition, Vector3.up * 2, Color.green);//카메라의 위치를 의미한다.
        this.cameraPosition = this.aPosition+ (Vector3.up*2);
    }
    private void PlayAnim(float h,float v)//키보드 입력값을 기준으로 애니메이션 play
    {
        if (v >= 0.1f)//x축 : 전,후
        {
            anim.CrossFade("RunF", 0.25f);//전진
        }
        else if (v <= -0.1f)
        {
            anim.CrossFade("RunB", 0.25f);//후진
        }
        else if (h >= 0.1f)//z축 : 좌, 우
        {
            anim.CrossFade("RunR", 0.25f);
        }
        else if (h <= -0.1f)
        {
            anim.CrossFade("RunL", 0.25f);
        }
        else
        {
            anim.CrossFade("Idle", 0.25f);//정지 시 Idle
        }
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayCam : MonoBehaviour
{
    [Range(0.0f, 20.0f)] public float distance = 10.0f;
    [Range(0.0f, 10.0f)] public float height = 2.0f;
    [SerializeField]private float damping = 10.0f;
    private Vector3 velocity = Vector3.zero;
    [SerializeField] private Transform targetTr;//카메라가 따라가야할 대상
    [SerializeField]private float targetOffset = 2.0f;
    // Start is called before the first frame update
    void Start()
    {
          
     }

    // Update is called once per frame
    void LateUpdate()
    {     
        Vector3 pos = targetTr.position + (-targetTr.transform.forward * distance)+(Vector3.up*height);
       // this.transform.position = Vector3.Slerp(this.transform.position,pos,Time.deltaTime*damping);
        //구면 선형 보간 함수를 사용해 부드럽게 위치를 변경
        this.transform.position = Vector3.SmoothDamp(this.transform.position,pos,ref velocity,damping);
        //smoothdamp를 이용한 위치 보간
        this.transform.LookAt(targetTr.position + (targetTr.up*targetOffset));//카메라를 타겟의 좌표를 향해 회전
        //targetOffset으로 바라볼 위치 조정

    }
}
myoskin