Ray Casting - soo:bak
작성일 :
개념
Ray Casting
은 가상의 카메라에서 특정 방향으로 ‘레이, (빛)’ 또는 ‘선’ 을 발사하여,
그 레이가 어떤 물체와 만나는지를 계산하여 다양한 시각적 처리를 할 수 있는 기법이다.
레이는 기본적으로 시작점과 방향으로 정의가 되는데, 둘 모두 벡터를 통해 계산하며, 레이를 수학적으로 표현하면 다음과 같다.
Ray(t) = Origin + t * Direction
여기서,
- Origin 은 레이의 시작점
- Direction 은 레이의 방향
- t 는 레이가 얼마나 “멀리” 확장될지에 대한 스칼라값
활용 사례
Ray Casting
은 다양하게 활용할 수 있다.
특히 현대 게임에서는 물체 간의 충돌 감지, 시야 판별, 그림자 및 반사 효과 구현,
사용자의 입력이 물체와 접촉했는지에 대한 판별, FPS 게임에서 총알의 피격 여부 등등
정말 다양한 방법으로 활용이 가능한 기법이다.
모든 활용은 위의 기본적인 레이의 수식으로부터 시작된다.
예를 들어, 레이를 통해 가상의 구를 그리거나, 구와와의 상호작용 여부 등을 판별하려면 다음과 같이 수식을 풀어나간다.
(P - C) ⋅ (P - C) = r2
여기서,
- P 는 레이 위의 임의의 점
- C 는 구의 중심
- r 은 구의 반지름
으로 표현했을 때, 레이 위의 어떤 점 P 가 구와 부딪혔는지, 혹은 구의 밖에 있는지, 아니면 구의 안에 있는지 등등을 다음과 같이 계산할 수 있다.
(Origin + t * Direction - C) ⋅ (Origin + t * Direction - C) = r2
이 때, (Origin + t * Direction - C) 벡터를 Diff(t) = Origin + t * DIrection - C 라 하면,
내적의 정의에 따라 Diff(t) ⋅ Diff(t) = |Diff(t)|2 이 되므로,
(Direction ⋅ Direction) * t2 + 2 * (Direction ⋅ (Origin - C)) * t + (Origin - C) ⋅ (Origin - C) 가 되며,
이를 t 에 대한 2차 방정식
at2 + bt + c = 0 으로 간단하게 표현할 수 있다.
여기서,
- a = Direction ⋅ Direction
- b = 2(Direction ⋅ (Origin - C))
- c = (Origin - C) ⋅ (Origin - C) - r2
따라서, 레이의 길이 t 에 따라서 구를 활용한 다양한 처리들을 할 수 있게 된다.
구 이외에도 하나의 레이만으로도 다양한 처리들을 할 수 있으며, 활용 사례는 무궁무진하다.
Unity 게임 엔진에서는 API 를 통해 직접 자료형을 제공해주며, 쉽게 사용이 가능하도록 되어있다.
예시 (Unity)
[ 코드 ]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UIElements;
public class RayCastingFOV : MonoBehaviour {
public int numberOfRays = 720;
public float fov = 60f;
public float rayDistance = 1f;
public LayerMask wallMask;
public Color visibleColor = Color.yellow;
public Color nonVisibleColor = Color.black;
private void Update() {
foreach (Transform child in transform) {
Destroy(child.gameObject);
}
for (int i = 0; i < numberOfRays; i++) {
float angle = (i / (float)numberOfRays) * 360 - 180;
Vector3 rayDirection = Quaternion.Euler(0, angle, 0) * transform.forward;
Ray ray = new Ray(transform.position, rayDirection);
RaycastHit hit;
Color rayColor = nonVisibleColor;
if (angle >= -fov / 2 && angle <= fov / 2)
rayColor = visibleColor;
LineRenderer line = CreateLineRenderer(rayColor);
line.SetPosition(0, transform.position);
if (Physics.Raycast(ray, out hit, rayDistance, wallMask))
line.SetPosition(1, hit.point);
else
line.SetPosition(1, transform.position + rayDirection * rayDistance);
}
}
private LineRenderer CreateLineRenderer(Color color) {
GameObject lineObject = new GameObject("Line");
lineObject.transform.SetParent(transform);
LineRenderer line = lineObject.AddComponent<LineRenderer>();
line.material = new Material(Shader.Find("UI/Default"));
line.startColor = color;
line.endColor = color;
line.startWidth = 0.01f;
line.endWidth = 0.1f;
line.positionCount = 2;
return line;
}
}
추가 - C언어와 Ray Casting 을 활용한 DOOM 모작 프로젝트 - soo:bak