유니티3D – 구면좌표계를 활용한 3인칭 카메라
- 삽질 정보/C#
- 2021. 12. 11.
구면좌표계(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);
}
}
- Start 이벤트가 실행될 때, controllingCamera가 없으면 차일드에서 컴포넌트를 얻는다.
- 이후, 카메라 ↔ 플레이어 간의 상대 위치를 얻어옴. (Vector3)
- 여기에서 ‘magnitude’ 를 사용해, 벡터의 크기를 얻음 → radius
- 방위각(azimuth)은 ϕ를 구하는 것 이므로, 𝑥 = 𝑟 sin 𝜃 cosϕ, 𝑧 = 𝑟 sin 𝜃 sinϕ 로 계산된 𝑥 및 𝑧를 활용해 atan2 계산.
- 어차피 나누기 계산이라 𝑟 sin 𝜃 를 따로 나눠줄 필요는 없는 듯.
- 앙각(elevation)은 𝜃 를 구하는 것 이므로, 𝑦 = 𝑟 cos 𝜃 를 반대로 계산함. (𝑟을 나누고, 아크코사인)
- UpdateCameraAsCartesian 함수에 위 로직을 넣어서, 카메라 위치와 회전을 재계산 하게끔 함.
- Input.GetButton 함수로, Fire2 버튼이 클릭될 동안에 Update 로직 실행.
- Fire2 버튼은 기본적으로 마우스 우클릭에 할당.
- 상하 좌우로 이동된 만큼을 Input.GetAxisRaw 함수로 얻어서, 해당 수치 만큼 방위각 및 앙각에 더함.
- 구면좌표계(3D 극좌표계) → 3D 왼손 직교 좌표계로 변환하는 공식을 사용해 상대 좌표를 계산.
- DirectX, Unity 3D, Unreal Engine은 좌표계로 왼손 좌표계를 사용한다.
- OpenGL 등은 오른손 좌표계 사용.
- 마찬가지로 계산 후 UpdateCameraAsCartesian 함수를 호출해 카메라 위치 및 회전을 재계산.
개잘됨.