유니티에서 raycast
유니티에서 Ray 클래스가 존재하며 unityengine.dll에 구현되어 있다
Ray ray = new ray(origin, direction, length)
로 ray의 시작점과 방향, 그리고 ray가 뻣어나가는 길이 등을 설정해 줄 수 있음
è Ray 클래스는 단순 광선 성분을 나타내는 클래스에 불과하다
Raycast를 쓰기 위해서 유니티의 physics 엔진을 불러와야함
유니티에서 물리 엔진은 Nvidia PhysX를 사용하며 PhysX의 raycast 검출 알고리즘을 사용함
1. Input action에서 마우스 왼쪽 클릭시 이벤트를 생성
2. 이벤트 클릭 되었을 때 Click = true가 되도록 설정
3. Click 시 raycast 검출 알고리즘 실행(Physics.Raycast(ray, out RaycastHit, length)
Out 부분은 PhysX에서 충돌된 오브젝트중 가장 가까운 거리에 있는 오브젝트에 대한 정보의 결과값을 반환하는 부분임.
문제점
1. 1인칭으로 카메라 확인 시 카메라랑 player의 거리가 가까워서 player에 닿는 문제가 발생함
Player 오브젝트를 raycast 검출시에 비트 마스킹 하여 처리하도록 설정
2. Ray의 길이를 내가 임의로 설정했는데 이렇게 되면 상호작용시 상황에 따라서 변칙적임
è 게임 디자인적 요소 고려해야 함
플레이의 손 길이 등을 반영해서 ray의 길이를 두어야 함
-> 월드 공간에서 오브젝트 등을 배치할 때 scale 단위를 잘 고려해야 함
Rigidbody collider 등은 unit 기반으로 동작하기 때문에 1Unity Unit = 1m를 기준으로 해서 개발할때 항상 체크할 수 있도록 함
캐릭터 등은 1 unit -> 1m 의 기준에 따라서 보통 1.7 unit ~ 2 unit으로 스케일 설정하기 등
Raycast 클래스 등의 사용 과정, 심화
유니티 c#에서 PhysX을 사용할때는 유니티 c# 스크립트에서 각각의 정보를 가져와 Wrapper를 통해 c++기반 PhysX 엔진에 값을 전달하여 값을 다시 unity 엔진에 반환해 준다
유니티는
IL2CPP
Mono
방식의 스크립트에서
è Native c++ 로 바인딩 되는 구조로 되어 있음
물리 엔진 연산시 SIMD VPU를 사용해야 하기 때문에 GPU단에서 동작 안하고 CPU에서 처리됨
è 즉 CPU 성능이 좋아야 물리 연산이 빠르게 처리될 수 있다
Wrapping -> unity c#에서는 physX c++ 함수를 직접 바로 호출할 수 없음
유니티 엔진에서 물리엔진과 같은 c++기반 함수를 c#에서 사용할수 있게 감싸서 인터페이스에 API로 노출시킴
Native c++ -> native란 운영체제가 직접 실행할 수 있는 바이너리 코드를 의미함
Native code -> 다른말로 unmanaged language를 의미함, native Code는 컴파일 시 어셈블리어로 바로 번역됨, IL을 만들지 않고 컴파일 이후 바로 실행이 가능함
Ex) c, c++
이와 대비되는 개념으로 Managed Language가 있음
è 중간 언어 IL(intermediate language)로 우선 먼저 컴파일 됨
Ex) c# java python
보통 어플리케이션에서는 개발의 생산성이 높은 managed Language로 개발됨
따라서 native binding이 필요함
Unmanaged language로 작성된 PhysX를 Managed Language로 스크립트 만드는 유니티 c#에 서로 연결 glue 하기 위한 작업
Physics.Raycast()를 통해 PhysX의 raycast 기능을 호출하도록 c#에서 프런트 엔드(인터페이스) 형태로 만들어 놓음
è 개발하기 쉽게 + 블랙박스로 가려져 있는 PhysX 내부까지 접근할 필요 없게 하도록
Marshal의 의미
서로 다른 언어 환경 간에 데이터 형식을 변환하는 것을 의미함
Ex)
C# vector3 -> c++ Vec3
C# 배열 -> c++ 포인터
C# 구조체 -> c++ 클래스 등으로 메모리 데이터 복사
등의 과정을 marshalling 이라고 한다
유니티에서 월드 공간에 오브젝트 생성시 엔진에서 오브젝트의 정보를 관리하는 것 뿐만 아니라 물리 엔진에서 collider rigidbody등 또한 PhysX 에서 actor로 데이터를 등록함
è physX 단에서 등록되어 있는 actor에 대해 BVH 기반으로 계산함
API(application programming interface)
기능을 사용하기 위한 공개된 함수, 클래스 등의 집합을 의미함
è 기존에 기능이 구현된 로우 레벨 코드가 있고 이를 사용하기 위해서 외부에 친절하게 인터페이스 방식으로 사용 가능하게끔 간략화 해놓음
è
SDK(software development kit)
Api+도구+라이브러리+문서 등을 전체 포괄한 패키지
API를 포함해서 기능개발에 필요한 모든 도구를 모아둔 세트를 의미한다
Ex) Android sdk, Windows sdk
유니티를 예시를 들면
특정 함수나 클래스 메소드 등을 사용할 때 미리 정의되어 있는 문법등을 API라 하고
유니티 엔진 자체와 같이 개발 전체 환경을 SDK 라고 함
API로 감싼다는 말은 만들어 놓은 특정 기능들을 쉽게 호출하고 사용할 수 있도록 적절한 함수 형태(interface)로 감싼다 라는 의미임
Library
특정 기능을 모아둔 도구 상자, 기능 묶음, 내가 필요할 때 해당 라이브러리(기능 모음집) 안에 있는 일부들을 뽑아다가 씀
Framework
프로그램 구조 등의 흐름을 미리 결정해 놓아서 개발자는 해당 방식대로 따라가기만 하도록 해 놓은 형태
전체 흐름을 주도하고 개발자는 해당 부분 안에 필요한 코드만 채우면 됨
Ex) collab에 쓰는 미리 만들어져 있는 AI 툴들이나 유니티 c# 스크립트 등이 framework
개발자가 모든 흐름을 제어하는 것이 아니라 프레임워크 흐름을 따라서 개발자가 개발하는 틀을 의미함
Raycast
Ray: 광선
Cast: 투사
선을 쏘아서 닿는 물체에 대해서 검사( 복수 물체 존재 가능)
직선을 나타내는데 있어서는
1. 방향벡터 d
2. 위치벡터 v
가 필요
특정 위치의 벡터를 v라 하고 초기에 광선을 쏘는 위치벡터를 v0라 하고 방향벡터를 d라 하자
V = (x0, y0, z0) + (dx, dy, dz) * t
여기서 t는 이동 거리를 의미(변수)
t값에 따라서 구하고자 하는 위치 벡터의 값을 도출할 수 있다.
레이캐스팅 -> 광선을 쏘아 해당 방향에 닿는 오브젝트 등을 판별하기 위함
레이트레이싱 -> 광선을 재귀적으로 쏘아 반사되어 GI 등에 활용
유니티에서는 Raycast를 Ray type을 통해 제공하고 있음
UnityEngine.dll에 해당 타입을 구조체로 선언해져 있다.
Ray 외에도
Vector3, Quaternion, Transform, Physics 등등이 UnityEngine에 속해 있음
Raycast는 유니티 엔진에서 사용하는 PhysX 엔진에서 해당 정보를 호출받는다.
Raycast -> 오브젝트의 collision 처리
오브젝트 메쉬에 대해서 히트박스 등을 다음과 같은 방식으로 오브젝트를 감싸서 평면들에 대해서 충돌 검출을 진행함
대부분 충돌 검출 시스템은
분할 축 정리(SAT, separating axis theorem)을 사용함 (AABB보다는 OBB에서 주로 사용)
è 두 볼록형상을 한 축에 투영했을 때 투영된 구간이 서로 겹치지 않는 조건이 하나라도 존재한다면 두 물체는 교차하지(intersection) 않은 것이다.
형상이 convex(볼록)하냐, concave(오목) 하냐에 따라서도 충돌 검출에 대한 조건 등이 달라짐
è 임의의 두 점을 연결했을 때 형상안의 집합에 대한 반직선이 오직 한번만 형상을 통과하면 볼록, 두번 이상이면 오목하다
AABB(axis aligned bounding box)
월드 공간의 x,y,z 정규 직교에 대해서 평행하게 정렬된 직육면체 형태
회전하지 않음 -> axis aligned
두점을 통해서 bounding box를 정의할 수 있음 (min ,max)
가장 빠르고 간편하게 사용되는 처리 방식, 메모리 사용량 적음,
오브젝트 기울어지거나 평행한 축 아니면 빈공간 많이 생김 -> 오차가 커짐
OBB(oriented bounding box)
객체 회전 방향에 맞춰서 회전된 직육면체 박스
오브젝트의 local space를 기준으로 축이 회전됨
OBB는 AABB보다 더 정확한 형상을 직육면체로 감싸준다.
따라서 world공간에 축정렬이 안되어 있기 때문에 SAT를 통한 검출을 해야 함
더욱 정밀한 BroadPhase 검사가 가능함
DOP -> AABB + OBB, Discrete Oriented Polytope
더 많은 평면을 가진 다면체를 사용하여 경계 볼륨을 만듬
k-dop
면이 많을수록 메쉬를 감싸는 형태로 충돌 경계가 만들어짐
공간 계층 분할 방식(spatial portioning) 의 종류
Octree, BSP(binary space partitioning, kd tree, sphere tree)
BVH (Bounding Volume Hierarchy)
Bounding volume을 계층적으로 공간 분할하여 처리
점차 bvh 트리를 root에서 자식 노드로 따라 내려가면서 충돌 형상을 잘게 분할
기하 개체를 3차원 공간에서 구조화 하는 spatial data structure를 주로 사용함
Tree의 형태
Root node
Leaf node
Broad phase에서는
AABB사용
Middle Phase 에서는
BVH(bound volume hierarchy)를 통해 검출 단계를 잘게 나눔
Narrow Phase 에서는
OBB 사용
DOP는 realtime 게임 엔진에서 잘 쓰이지는 않는다.
메모리 점유 + 게산량이 많아서 시스템 리소스에 영향이 크다.
World space에는 무수히 많은 object가 존재하기 때문에 DOP로 검출하면 상당히 느리다.
AABB는 계산이 단순하고 조건 분기 없으며 CPU에서 SIMD 친화적이기 때문에 리얼타임이 중요한 게임에서는 AABB로 검출함
SIMD -> single instruct multiple data
한번 명령으로 여러 데이터 처리 -> CPU의 핵심
VPU 연산 , vector processing unit
한번에 여러 개의 부동소수 연산을 처리 가능(FPU, 과거 foating point Unit 의 발전된 형태)
AABB는 3차원에서 6개의 floating point를 사용
Min(xmin, ymin, zmin)
Max(xmax, ymax, zmax)
6개의 부동소수 연산을 하는것과 달리 DOP(disrete oriented polytope) 은 k dop 등으로 쪼개질 시 연산 처리가 복잡해짐
캐시 친화적
Cpu 안에 있는 임시 메모리에서 데이터가 많이 처리될수록 더욱 많은 수학 연산 등이 빠르게 처리될 수 있음
근데 데이터 크기가 커지면 cache안에 수용 가능한 데이터 량이 적어져서 cache miss 빈번하게 발생함
è AABB는 world공간과 축이 평행하기 때문에 데이터를 바로 불러서 처리할 수 있음
è 동일한 크기에 여러 연속된 float array로 데이터를 읽어드리기 때문에 연속된 메모리 블록을 한번에 불러와서 처리 가능함
è 반면 OBB, DOP는 로컬 공간에 맞게 선형 변환, 혹은 데이터 량이 매우 많아 cache 안에 파편화 되어 적재됨 (일부만)
è 메모리가 흩어져서 cache miss 발생 확률이 커지므로 그만큼 속도 지연 발생함
DOP는 R&D 분석이나 포인트 클라우드, 정밀 가공 CAD 등의 분야에서 충돌 검출 등에 주로 사용됨(정밀한 결과를 필요로 하는 분야, 리얼타임 프로세싱 분야 x)
Raycast의 처리 과정으로
1. Broad Phase(넓은 단계 충돌 검출), 충돌 가능성이 있는 후보를 먼저 추려냄, 교차 가능성이 있는 충돌체들
2. MidPhase(중간단계 충돌 검출), 계층적 경계 볼륨 구조, tree형태로 처리
3. Narrow Phase(좁은 단계 충돌 검출), 개ㅕㄹ적인 충돌 단위들로 교차 테스트 진행, 정확한 충돌 여부 판정
로 세분화 되어 처리됨
Broad phase에서 충돌 검출 할 시에 만약 월드 공간에 n개의 rigidbody 가 존재한다 했을 때 각각 충돌했는지 등의 검사를 할때는 단순하게 O(n^2)의 시간 복잡도를 가지게 됨
è 데이터 구조의 최적화를 위해서 SAP(Sweep and Prune) 방법을 사용하게 됨
핵심은 충돌 여부를 판별하는 객체의 수를 줄여 시간 복잡도를 줄이는 것이 목표임
유니티 raycast 구현
실습
유니티 raycast 구현,
오브젝트 판별,
선택 로그 출력,
움직임 로직 코드 리펙토링
마우스 커서 중앙 표시
raycast 구현 카메라 3인칭
Player 비트 마스킹
게임 공간 scaling 기준 척도 통일하기
마우스 커서 화면 중앙에 표시하기(오버레이)
다음에 알아볼 내용
SAP
KD TREE, octree, bsptree, sphere tree etc 의 공간 분할 트리
'Unity Study' 카테고리의 다른 글
| 2025-11-22 3rd person camera (0) | 2025.11.24 |
|---|---|
| 2025-11-21 Project prefab (0) | 2025.11.24 |
| 2025-11-19 Jumping (0) | 2025.11.24 |
| 2025-11-17 running (0) | 2025.11.24 |
| 2025-11-15 Camera Rotation (0) | 2025.11.24 |