배 타다 개발자

[Unity] Raycasting 본문

Graphics/Unity 3D

[Unity] Raycasting

노 아 2021. 12. 9. 23:41

Raycast란?

레이캐스트

어떤 물체에서 광선을 발사하여 그 광선에 닿는 물체가 있는지 없는지 검사하는 하는 함수이다.

Vector3 Phisics.raycast(position, direction, distance);

환경세팅

유니티 스탠다드 에셋[클릭] 하여서 에셋을 다운받는다. 참고로
(2019.1 unity version 에서 import 가능하였다.

Standard Asset -> Chracters -> FirstPersonChracter -> Prefabs 에서 FPSController 프리팹을 Hierarchy창에 올리고 바닥(Plane) 감지할 대상(Cube)를 만든다.

1차 구현 목표 : 레이캐스트롤 통해 물체감지

1차 구현

플레이어 스크립트 컴포넌트를 하나 추가한다.

2차 구현 목표 : 감지한 객체를 선택하여 옮기기

raycast 광선 상에 있는 오브젝트를 클릭하여,

이 상태로 변하고, 원하는 곳에서 클릭을 해제하면, 물체가 이동한다

2차 구현

DrawRay, ray : 개발자용 광선, ray 객체만들기.

Update(){
Ray ray = new Ray(rayOrigin, rayDir);
Debug.DrawRay(ray.origin, ray.direction * 100f, Color.red);
        }

먼저 업데트 함수에 광선의 시작지점과, 방향을 가지는 ray 클래스를 하나 만들어 준다.

개발자용 DrawRay 함수를 통해서, 테스트시 개발자만 볼 수 있는 빨간 광선을 그려준다.

그러면 이렇게 빨간 실선으로 카메라의 방향에 따른 광선의 변화를 볼 수 있다.

layer setting : 바닥이 아닌 큐브만 일치하게 하기


물리적인 효과는 층(layer)를 통해서 감지한다.
큐브에 임의의 layer를 interactable 을 만들어 지정해주고,

public LayerMask whatIsTarget;

을 public 접근제어자로 LayerMask를 선언해준 후에


GUI를 통해 컴포넌트에 감지할 레이어를 interactable만으로 설정한다.

if (Physics.Raycast(ray,out hit, distance, whatIsTarget))

이후 Physics.Raycast의 매개변수에 whatIsTarget이라는 레이어를 전달해주어 Interactable 레이어만을 감지할 수 있도록 한다.

RaycastHit, 레이캐스트로 감지한 객체에 관한 모든 것

 RaycastHit hit;

if (Physics.Raycast(ray,out hit, distance, whatIsTarget))
             {
             ...
             }

여기서 out hit 은 무엇일까?
RaycastHit클래스를 통해서 레이캐스트의 광선에 맞은 객체를 담는 컨테이너로 hit을 뽑아 낼 수 있다.

 GameObject hitTarget = hit.collider.gameObject;

물리적으로 감지된 hit의 콜라이더를 통해 접근한 게임오브젝트를
새로운 hitTarget에 초기화 시키면 비로소 hitTarget은 광선에 맞은 객체이다.

소스원본


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

public class RayInterection : MonoBehaviour
{

    //카메라의 정중장에서 광선을 쏘아서 일정거리내에 무언가가 있으면 감지해주는 스크립


    public LayerMask whatIsTarget;
    private Camera playerCam;
    // 위치를 감지하기 위해서는 우선 카메라의 위치를 알고 있어야함

    public float distance = 100f;
    // 카메라로 부터 감지할 거리

    private Transform moveTarget;
    private float targetDistance;



    void Start()
    {
        playerCam = Camera.main;
        // 게임이 시작 되면 현재 활성화된 메인 카메라를 가져온다. 
    }


    void Update()
    {


        Vector3 rayOrigin = playerCam.ViewportToWorldPoint(new Vector3(0.5f,0.5f,0f));
        // rayOrigin : 광선이 날아갈 정중앙위치 
        // ViewportToWolrdPoint : 카메라의 한 지점의 위치가 게임상에서
        // 어느 위치(가로 중앙, 세로 중, 카메라의 깊이(0))를 리턴
        Vector3 rayDir = playerCam.transform.forward;
        // 광선의 방향 = 카메라의 앞


        Ray ray = new Ray(rayOrigin, rayDir);
        Debug.DrawRay(ray.origin, ray.direction * 100f, Color.red);




        if(Input.GetMouseButtonDown(0))
        {

            RaycastHit hit; // 레이캐스트 광선에 맞은 객체의 정보르 담는 컨테이너


            if (Physics.Raycast(ray,out hit, distance, whatIsTarget))
                // 레이캐스트는 물리처리 이므로 Phisics의 함수
                // Raycast(광선 시작지점, 방향, 거리)
            {

                GameObject hitTarget = hit.collider.gameObject;
                // hit에 부딪힌 콜라이더의 게임오브젝트를 가져온다.
                hitTarget.GetComponent<Renderer>().material.color = Color.red;

                moveTarget = hitTarget.transform;
                targetDistance = hit.distance;


                Debug.Log(hit.collider.gameObject.name);
                Debug.Log("무엇인가 광선에 감지되었다.");
            }
        }


         if(Input.GetMouseButtonUp(0)) // 좌클릭 해제시
        {
            if(moveTarget != null)
            {
                moveTarget.GetComponent<Renderer>().material.color = Color.white;
                // 원래 색인 흰색으로 돌린다. 
            }
            moveTarget = null;  
            // 
        }

         if(moveTarget != null)
        {
            moveTarget.position = ray.origin + ray.direction * targetDistance;
// 무브타겟의 위치는 광선 발사 지점에서 ray 방향으로 targetDistance 앞으로 설정한다. 
        }
    }
}