유니티3D – 구면좌표계를 활용한 3인칭 카메라

 

구면 좌표계

구면좌표계 = 3D 극좌표계 3D (왼손) 직교좌표계에서 구면좌표계 𝑥 = 𝑟 sin 𝜃 cosϕ 𝑦 = 𝑟 cos 𝜃 𝑧 = 𝑟 sin 𝜃 sinϕ P ( 𝑟, 𝜃, ϕ ) = ( 𝑟 sin 𝜃 cosϕ , 𝑟 cos 𝜃 , 𝑟 sin 𝜃 sinϕ) 1. 𝑥 먼

tensiya.tistory.com

 

구면좌표계(3D 극좌표계)를 사용한 간단한 3인칭 카메라.

  • 적당히 위와 같이 바닥이랑 캡슐을 하나 만들고, Main Camera를 캡슐의 차일드로 옮겨서 적당히 플레이어 객체와의 상대 위치(localPosition)을 설정.
  • Rotation은, 어차피 나중에 LookAt 함수를 활용해서 카메라를 회전 시킬 것이기 때문에, 따로 회전시키지 않음.

 


  • 대충 만든 Third Person Script 에서 Controlling Camera 필드에 카메라 할당.
    • 사실 카메라가 없으면 자동으로 차일드 중에서 카메라를 얻어오게끔 만들긴 했음.

 


ThirdPersonScript.cs

using UnityEngine;

public class ThirdPersonScript : MonoBehaviour
{
    public float azimuth;
    public float elevation;
    public float radius;
    public float speed = 0.5f;

    public Camera controllingCamera;

    void Start()
    {
        if (controllingCamera == null)
            controllingCamera = GetComponentInChildren<Camera>();
        var pos = controllingCamera.transform.localPosition;
        radius = pos.magnitude;
        azimuth = Mathf.Atan2(pos.z, pos.x);
        elevation = Mathf.Acos(pos.y / radius);
        UpdateCameraAsCartesian();
    }

    void Update()
    {
        if (!Input.GetButton("Fire2"))
            return;
        azimuth += Input.GetAxisRaw("Mouse X") * speed;
        elevation += Input.GetAxisRaw("Mouse Y") * speed;
        UpdateCameraAsCartesian();
    }

    private void UpdateCameraAsCartesian()
    {
        var t = radius * Mathf.Sin(elevation);
        var x = t * Mathf.Cos(azimuth);
        var y = radius * Mathf.Cos(elevation);
        var z = t * Mathf.Sin(azimuth);
        controllingCamera.transform.localPosition = new Vector3(x, y, z);
        controllingCamera.transform.LookAt(transform);
    }
}
  1. Start 이벤트가 실행될 때, controllingCamera가 없으면 차일드에서 컴포넌트를 얻는다.
  2. 이후, 카메라 ↔ 플레이어 간의 상대 위치를 얻어옴. (Vector3)
    1. 여기에서 ‘magnitude’ 를 사용해, 벡터의 크기를 얻음 → radius
    2. 방위각(azimuth)은 ϕ를 구하는 것 이므로, 𝑥 = 𝑟 sin 𝜃 cosϕ, 𝑧 = 𝑟 sin 𝜃 sinϕ 로 계산된 𝑥 및 𝑧를 활용해 atan2 계산.
      1. 어차피 나누기 계산이라 𝑟 sin 𝜃 를 따로 나눠줄 필요는 없는 듯.
    3. 앙각(elevation)은 𝜃 를 구하는 것 이므로, 𝑦 = 𝑟 cos 𝜃 를 반대로 계산함. (𝑟을 나누고, 아크코사인)
  3. UpdateCameraAsCartesian 함수에 위 로직을 넣어서, 카메라 위치와 회전을 재계산 하게끔 함.
  4. Input.GetButton 함수로, Fire2 버튼이 클릭될 동안에 Update 로직 실행.
    1. Fire2 버튼은 기본적으로 마우스 우클릭에 할당.
    2. 상하 좌우로 이동된 만큼을 Input.GetAxisRaw 함수로 얻어서, 해당 수치 만큼 방위각 및 앙각에 더함.
  5. 구면좌표계(3D 극좌표계) → 3D 왼손 직교 좌표계로 변환하는 공식을 사용해 상대 좌표를 계산.
    1. DirectX, Unity 3D, Unreal Engine은 좌표계로 왼손 좌표계를 사용한다.
    2. OpenGL 등은 오른손 좌표계 사용.
  6. 마찬가지로 계산 후 UpdateCameraAsCartesian 함수를 호출해 카메라 위치 및 회전을 재계산.

 

 

개잘됨.

댓글

Designed by JB FACTORY