본문 바로가기
프로그래밍/유니티

Unity의 RayCast/BoxCast/SphereCast/CapsuleCast 정리

by 넋두리- 2021. 4. 5.

오늘은 유니티의 RayCast와 관련된 내용을 살펴보려고 합니다.

 

RayCast는 직선 상에 가상의 빔을 쏘아서 충돌하는 Collider가 있는 지 체크하는 함수입니다.

이와 비슷한 기능으로 BoxCast, SphereCast, CapsuleCast가 있는데요, 이것도 모두 RayCast의 일종입니다.

앞에 있는 Box, Sphere, Capsule의 형태로 RayCast를 한다고 보면 됩니다.

가시적인 형태를 한 번 먼저 살펴볼까요?

 

Unity - 위에서부터 RayCast, BoxCast, SphereCast, CapsuleCast

왼쪽에 있는 객체에서 Ray를 쏘아 오른쪽 객체에 충돌한 상태입니다.

 

그럼 이렇게 충돌하는 Collider가 있는 지 체크해서 어디에 쓰냐구요?

 

사정 거리 내에 적이 있는 지 확인을 할 때,

내가 올라설 수 있는 바닥 혹은 객체가 있는 지,

공격을 했을 때 타격 지점(무기나 주먹, 발 등)에 충돌이 되는 객체가 있는 지,

다른 물체로 인해서 길이 막히거나 공격이 불가능한 지

등등등... 수 많은 곳에서 응용이 되고 있습니다.

 

그럼 어떻게 RayCast가 되고 있는 지 가시적으로 보면서

함수 작동 원리를 이해하고 추후 디버깅 등에서도 많이 유용하게 사용해봅시다!

Gizmo API를 이용해 에디터 상에서 가시적인 거리를 표시를 하려고해요.

 

그럼 RayCast, BoxCast, SphereCast, CapsuleCast를 차례로 살펴봅시다.

 

1. RayCast

 

RayCastTest.cs

using UnityEngine;

/// <summary>
/// 직선으로 충돌하는 객체가 있는 지 RayCast를 한다.
/// </summary>
public class RayCastTest : MonoBehaviour
{
    // ray의 길이
    [SerializeField]
    private float _maxDistance = 20.0f;

    // ray의 색상
    [SerializeField]
    private Color _rayColor = Color.red;

    void OnDrawGizmos()
    {
        Gizmos.color = _rayColor;

        // 함수 파라미터 : 현재 위치, Ray의 방향, RaycastHit 결과, Raycast를 진행할 거리
        if (true == Physics.Raycast(transform.position, transform.forward, out RaycastHit hit, _maxDistance))
        {
            // Hit된 지점까지 ray를 그려준다.
            Gizmos.DrawRay(transform.position, transform.forward * hit.distance);
        }
        else
        {
            // Hit가 되지 않았으면 최대 검출 거리로 ray를 그려준다.
            Gizmos.DrawRay(transform.position, transform.forward * _maxDistance);
        }
    }
}

 

GameObject -> 3D Object -> Cube 메뉴로 큐브를 두 개 생성했어요.

큐브 중 z좌표가 더 작은 큐브에 RayCastTest.cs 스크립트를 붙여서 테스트했습니다.

z축으로 9m만큼 떨어진 큐브에 있는 box collider에 hit 되어서 해당 좌표까지 Ray가 그려졌네요.

 

Unity - RayCast 충돌된 객체 있음

큐브를 그럼 옮겨볼까요?

Unity - RayCast 충돌된 객체 없음

충돌된 객체가 없어서 일직선 상으로 쭉 뻗어 최대 거리로 세팅한 20m까지 그려지는군요.

직선 상에 충돌된 객체만 찾기 때문에 아마 속도적인 측면에서 제일 빠를 것으로 보입니다.

 

2. BoxCast

 

BoxCastTest.cs

using UnityEngine;

/// <summary>
/// 직선으로 충돌하는 객체가 있는 지 박스 모양으로 RayCast를 한다.
/// </summary>
public class BoxCastTest : MonoBehaviour
{
    // ray의 길이
    [SerializeField]
    private float _maxDistance = 20.0f;

    // ray의 색상
    [SerializeField]
    private Color _rayColor = Color.red;

    void OnDrawGizmos()
    {
        Gizmos.color = _rayColor;

        // 함수 파라미터 : 현재 위치, Box의 절반 사이즈, Ray의 방향, RaycastHit 결과, Box의 회전값, BoxCast를 진행할 거리
        if (true == Physics.BoxCast(transform.position, transform.lossyScale / 2.0f, transform.forward, out RaycastHit hit, transform.rotation, _maxDistance))
        {
            // Hit된 지점까지 ray를 그려준다.
            Gizmos.DrawRay(transform.position, transform.forward * hit.distance);

            // Hit된 지점에 박스를 그려준다.
            Gizmos.DrawWireCube(transform.position + transform.forward * hit.distance, transform.lossyScale);
        }
        else
        {
            // Hit가 되지 않았으면 최대 검출 거리로 ray를 그려준다.
            Gizmos.DrawRay(transform.position, transform.forward * _maxDistance);
        }
    }
}

 

이전과 동일하게 큐브를 두 개 생성하고,

큐브 중 z좌표가 더 작은 큐브에 BoxCastTest.cs 스크립트를 붙여서 테스트했습니다.

아까 방향 벡터로만 체크하는 RayCast와 다르게 BoxCast는 방향 벡터를 기준으로 Box 크기만큼 체크를 합니다!

z축으로 9m만큼 떨어진 큐브에 있는 box collider에 hit 되어서 해당 좌표까지 Ray가 그려지고,

hit 지점을 중심으로 WireCube가 그려졌습니다.

 

Unity - BoxCast 충돌된 객체 있음

 

큐브를 옮기면

Unity - BoxCast 충돌된 객체 없음

 

이렇게 됩니다.

 

3. SphereCast

 

SphereCastTest.cs

using UnityEngine;

/// <summary>
/// 직선으로 충돌하는 객체가 있는 지 원 모양으로 RayCast를 한다.
/// </summary>
public class SphereCastTest : MonoBehaviour
{
    // ray의 길이
    [SerializeField]
    private float _maxDistance = 20.0f;

    // ray의 색상
    [SerializeField]
    private Color _rayColor = Color.red;

    void OnDrawGizmos()
    {
        Gizmos.color = _rayColor;
        float sphereScale = Mathf.Max(transform.lossyScale.x, transform.lossyScale.y, transform.lossyScale.z);

        // 함수 파라미터 : 현재 위치, Sphere의 크기(x,y,z 중 가장 큰 값이 크기가 됨), Ray의 방향, RaycastHit 결과, Sphere의 회전값, SphereCast를 진행할 거리
        if (true == Physics.SphereCast(transform.position, sphereScale / 2.0f, transform.forward, out RaycastHit hit, _maxDistance))
        {
            // Hit된 지점까지 ray를 그려준다.
            Gizmos.DrawRay(transform.position, transform.forward * hit.distance);

            // Hit된 지점에 Sphere를 그려준다.
            Gizmos.DrawWireSphere(transform.position + transform.forward * hit.distance, sphereScale / 2.0f);
        }
        else
        {
            // Hit가 되지 않았으면 최대 검출 거리로 ray를 그려준다.
            Gizmos.DrawRay(transform.position, transform.forward * _maxDistance);
        }
    }
}

 

GameObject -> 3D Object -> Sphere 메뉴로 구를 두 개 생성하고,

구 중 z좌표가 더 작은 구에 SphereCastTest.cs 스크립트를 붙여서 테스트했습니다.

SphereCast도 방향 벡터를 기준으로 Sphere의 크기만큼 체크를 합니다!

z축으로 9m만큼 떨어진 구에 있는 Sphere Collider에 hit 되어서 해당 좌표까지 Ray가 그려지고,

hit 지점을 중심으로 WireSphere가 그려졌습니다.

 

Unity - SphereCast 충돌된 객체 있음

 

구를 조금씩 옮겨보면

Unity - SphereCast 충돌된 객체 있음2

 

이렇게 충돌된 위치가 다르다는 것을 확인할 수 있어요!

이것도 마찬가지로 충돌되지 않는 위치까지 옮기면 최대 거리까지 Ray를 그려주도록 스크립팅 되어있습니다.

 

4. CapsuleCast

 

CapsuleCastTest.cs

using UnityEngine;

/// <summary>
/// 직선으로 충돌하는 객체가 있는 지 캡슐 모양으로 RayCast를 한다.
/// </summary>
public class CapsuleCastTest : MonoBehaviour
{
    // ray의 길이
    [SerializeField]
    private float _maxDistance = 20.0f;

    // ray의 색상
    [SerializeField]
    private Color _rayColor = Color.red;

    void OnDrawGizmos()
    {
        Gizmos.color = _rayColor;
        float capsuleScale = Mathf.Max(transform.lossyScale.x, transform.lossyScale.z);

        // 함수 파라미터 : Capsule의 시작점, Capsule의 끝점, Capsule의 크기(x, z 중 가장 큰 값이 크기가 됨), Ray의 방향, RaycastHit 결과, Capsule의 회전값, CapsuleCast를 진행할 거리
        if (true == Physics.CapsuleCast(transform.position, transform.position, capsuleScale / 2.0f, transform.forward, out RaycastHit hit, _maxDistance))
        {
            // Hit된 지점까지 ray를 그려준다.
            Gizmos.DrawRay(transform.position, transform.forward * hit.distance);

            MeshFilter meshFilter = GetComponent<MeshFilter>();

            // Hit된 지점에 Capsule를 그려준다.
            Gizmos.DrawWireMesh(meshFilter.sharedMesh, transform.position + transform.forward * hit.distance);
        }
        else
        {
            // Hit가 되지 않았으면 최대 검출 거리로 ray를 그려준다.
            Gizmos.DrawRay(transform.position, transform.forward * _maxDistance);
        }
    }
}

 

GameObject -> 3D Object -> Capsule 메뉴로 캡슐을 두 개 생성하고,

캡슐 중 z좌표가 더 작은 캡슐CapsuleCastTest.cs 스크립트를 붙여서 테스트했습니다.

CapsuleCast도 방향 벡터를 기준으로 Capsule의 크기만큼 체크를 합니다!

z축으로 9m만큼 떨어진 캡슐에 있는 Capsule Collider에 hit 되어서 해당 좌표까지 Ray가 그려지고,

hit 지점을 중심으로 WireCapsule을 그리기 위해서 DrawWireMesh 함수를 썼습니다..

따로 제공되는 것은 아쉽지만 없네요 ㅜㅜ

 

마지막 CapsuleCast 같은 경우에는 position 파라미터 쪽에서 좀 더 확인할 부분이 있어서 추후에 수정하겠습니다..

 

본 포스팅은 아래 포스팅 내용을 참고했습니다.

(참고 : theeye.pe.kr/archives/2764)

 

 

댓글