Raycasting

·2023년 4월 11일
0

Unity

목록 보기
11/22

📌Raycasting


광선을 쏘다?
레이저를 쏴서 그 레이저랑 부딪히는 물체가 있는지 판단하는 기술

Raycast

 void Update()
    {
        //레이캐스트 눈에 보이게
        Debug.DrawRay(transform.position, Vector3.forward, Color.red);

        //플레이어위치, 단방향으로 쏘기
        if (Physics.Raycast(transform.position, Vector3.forward);
        {
            Debug.Log($"Raycast !");
        }
    }

바닥에서 나가는 이유는 유니티짱의 기준좌표가 발바닥 기준이라서
Vector3.forward(0,0,1) 이라서 짧게 나감

Raycast(거리추가)

void Update()
    {
        //레이캐스트 눈에 보이게
        Debug.DrawRay(transform.position + Vector3.up, Vector3.forward * 10, Color.red);

        //플레이어위치, 단방향으로 쏘기, 최대 위치
        if (Physics.Raycast(transform.position + Vector3.up, Vector3.forward, 10))
        {
            Debug.Log($"Raycast !");
        }
    }

Raycast(맞은물체확인+플레이어위치)

유니티짱이 움직일때마다 레이캐스팅을 변하게 하고싶다

void Update()
    {
        //로컬에서 월드로 변환
        Vector3 look = transform.TransformDirection(Vector3.forward);
        //레이캐스트 눈에 보이게
        Debug.DrawRay(transform.position + Vector3.up, look * 10, Color.red);

        RaycastHit hit;
        //플레이어위치, 단방향으로 쏘기, 최대 위치
        if (Physics.Raycast(transform.position + Vector3.up, look, out hit, 10))
        {
            Debug.Log($"Raycast {hit.collider.gameObject.name}");
        }
    }

Vector3.up을 더해준 이유는 지금 발바닥에서 나가서 위로 더 올리려고

RaycastAll

기존의 레이캐스팅은 앞에 있는것만 확인한다
여러개 레이캐스팅할려면 이걸 쓴다

 void Update()
    {

        //로컬에서 월드로 변환
        Vector3 look = transform.TransformDirection(Vector3.forward);
        //레이캐스트 눈에 보이게
        Debug.DrawRay(transform.position + Vector3.up, look * 10, Color.red);

        RaycastHit[] hits;
        hits = Physics.RaycastAll(transform.position + Vector3.up, look, 10);
        
        foreach(RaycastHit hit in hits)
        {
            Debug.Log($"Raycast {hit.collider.gameObject.name}");
        }
    }

📌화면


local <-> world <-> Viewport <-> Screen(화면)

스크린좌표

픽셀좌표

Debug.Log(Input.mousePosition); //Screen

컴퓨터 해상도 1920 * 1080이라고 하면 그만큼의 픽셀이 있는것처럼 표시함

뷰포트좌표

스크린과 유사한데 비율로 표시해줌

Debug.Log(Camera.main.ScreenToViewportPoint(Input.mousePosition)); //Viewport

메인카메라

카메라는 피라미드 형태로 비춰준다

Near은 피라미드 꼭대기에서 카메라까지의 길이
Far은 피라미드 밑부분까지의 길이

3D화면에서 2D좌표로 넘어올때는 좌표 하나가 없어진다(Z : 깊이가 없어진다)

카메라 레이캐스팅

if (Input.GetMouseButtonDown(0))     //마우스 입력있을때만
        {
            //마우스 위치 screen 에서 world로 바꿔줌
            Vector3 mousePos = Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, Camera.main.nearClipPlane));
            //마우스 위치 - 카메라위치 
            Vector3 dir = mousePos - Camera.main.transform.position;
            //노말라이즈해줌
            dir = dir.normalized;

            Debug.DrawRay(Camera.main.transform.position, dir * 100.0f, Color.red, 1.0f);

            RaycastHit hit;
            if (Physics.Raycast(Camera.main.transform.position, dir, out hit, 100.0f))
            {
                Debug.Log($"RayCast Camera @ {hit.collider.gameObject.name}");
            }
        }

카메라에서 Near위치까지 가는 방향벡터가 나오게된다 = 마우스 위치 - 카메라위치
크기는 1이 아니라서 normalized로 맞춰준다(방향유지, 크기를 1로)

위의 코드를 더 간단히 표현

 void Update()
    {
        // Local <-> World <-> Viewport <-> Screen(화면)

        if (Input.GetMouseButtonDown(0))     //마우스 입력있을때만
        {
            Ray ray = Camera.main.ScreenPointToRay( Input.mousePosition );

            Debug.DrawRay(Camera.main.transform.position, ray.direction * 100.0f, Color.red, 1.0f);

            RaycastHit hit;
            
            if (Physics.Raycast(ray, out hit, 100.0f))
            {
                Debug.Log($"RayCast Camera @ {hit.collider.gameObject.name}");
            }
        }
    }

어디에 사용할까?
디아블로같은 쿼터뷰 게임 이동 구현 할때?


📌Raycasting의 최적화


성능이 무겁기 때문에 잘 사용해야한다.

충돌전용메쉬

충돌을 구현할때 충돌전용 메쉬를 하나 더 만들어서 안보이는 상태로 중복배치해서 그 Collider를 사용해서 연산한다 -> 이 방법도 부하가 심하다고 한다

레이어설정

연산하고 싶은 애들만 raycasting하기

총 레이어는 32개 비트 플래그(바이트의 개별 비트)를 사용해서 표현한다

Layer를 사용한 Raycasting최적화

중요하다

void Update()
    {
        // Local <-> World <-> Viewport <-> Screen(화면)

        if (Input.GetMouseButtonDown(0))     //마우스 입력있을때만
        {
            Ray ray = Camera.main.ScreenPointToRay( Input.mousePosition );

            int mask = (1 << 6) | (1 << 7); //Monster + Wall

            Debug.DrawRay(Camera.main.transform.position, ray.direction * 100.0f, Color.red, 1.0f);
            
            RaycastHit hit; 
            //Monster만 걸리는 raycasting
            if (Physics.Raycast(ray, out hit, 100.0f, mask))
            {
                Debug.Log($"RayCast Camera @ {hit.collider.gameObject.name}");
            }
        }
    }

Cube를 Monster로 바닥을 Wall Layer로 설정하고 실행
Layer로 등록된 큐브와 바닥만 찍히고 유니티짱을 찍으면 지나가서 바닥을 찍게된다

int mask = (1 << 6) | (1 << 7); //Monster + Wall
부분을 아래와 같이 표시도 가능하다
LayerMask mask = LayerMask.GetMask("Monster") | LayerMask.GetMask("Wall");

태그

태그를 사용해서도 물체 구분 가능

태그와 레이어의 차이는 비트연산?
Tag는 비트연산이 없다


참고자료


Part3: 유니티 엔진
섹션 4.Collision(충돌)

비트플래그

profile
개인공부저장용(하루의 기록)

0개의 댓글