치춘짱베리굿나이스
[Rank 4] Cub3D - Raycasting 구현 ① 변수 설명 본문
변수 설명
posX, posY
- 플레이어의 좌표를 나타내는 벡터
- 원점 (0, 0) 을 시작점으로, 플레이어의 좌표를 끝점으로 하는 벡터이다
- 단도직입적으로 플레이어의 위치 좌표라고 생각하는게 편하다
dirX, dirY
- 플레이어의 시선을 나타내는 벡터
- 길이는 1로 고정된다
- 플레이어가 보고 있는 방향을 나타낸다
- 플레이어의 눈에서 레이저가 나온다고 가정할 때 해당 레이저의 이동 방향이라 생각하면 쉽다
planeX, planeY
- 카메라 평면을 나타내는 벡터
- 카메라 평면이라는 개념이 생소할 수 있는데, 이 벡터와 반대방향 벡터 (
-plane
) 를 합친 만큼에 비춰지는 게임 오브젝트들이 화면상에 그려진다고 생각하면 된다 - 쉽게 말해, 실제 플레이어가 컴퓨터로 보는 화면의 가로 길이와 1대1 대응된다
- 따라서 시야와는 무조건 수직이다 (플레이어가 모니터를 수직으로 보고 게임을 진행하므로)
dir과 plane의 길이
- 이미지에는
dir
의 크기가 상관없다고 적혀있지만,dir
과plane
간의 길이 비율이 시야각을 결정하므로dir
의 길이를 고정하면plane
의 길이는 시야각에 따라 정해진다 - 반대로 얘기하면,
plane
의 길이가 결정되면dir
의 길이 또한 시야각에 따라 정해지므로 엄밀히 말하면 서로가 서로에 종속적이다
w, h
- 게임이 진행되는 창의 폭과 높이 (해상도)이다
- 과제 개편 전에는 화면 해상도를 입력값으로 받아야 했으나 지금은 고정 해상도를 사용해도 상관없다
- 실제 코드상에선 변수 개수 제한과 전역변수 사용 금지 이슈 (Norminette) 때문에 힙 영역에 할당한 구조체 내에 저장해서 사용하였다
간략한 반복문 구조
mlx_loop
- 이번 과제에서 사용하게 될 그래픽 라이브러리이다
- 프로그램의 그래픽 화면이 켜져있는 동안 무한 반복되며, 키보드 / 마우스 이벤트와 그래픽 그리는 등의 작업을 여기서 진행한다
- 콘솔과 관계없이 화면이 켜져 있을 때에만 무한 반복되므로, 맵 파싱 중에 에러가 있거나 맵이 유효하지 않다면 화면이 켜지지 않기 때문에 진입하지 않는다
while (x < width)
x
는 0부터width
(스크린의 폭) 까지 증가한다x
가 현재 창에서의x
좌표를 의미하며, 반복 1회마다 해당x
좌표를 갖는 모든 좌표 (x, 0
~x, height
)를 탐색하며 픽셀 색을 계산하고 그려낸다- 따라서 화면상에 이미지는
x
가 이동하는 방향과 같은 좌측 → 우측 방향으로 그려진다
while (!hit)
hit
은 광선이 벽에 부딪혔는지 여부를 나타내는 변수이다hit
이 1이면 벽에 부딪힌 것이므로,hit
이 0일 때만 벽을 찾아 광선을 앞으로 이동시킨다
반복문 내에서 사용되는 변수들
cameraX
cameraX = 2 * x / w - 1;
- 앞서 설명했듯 카메라 평면은 실제 창의 너비에 1대 1으로 대응된다
- 카메라평면의 중앙을 0, 양 끝 점을 -1과 1이라 할 때,
- 왼쪽 끝 (
cameraX
= -1) 은 실제 화면상에서x
= 0에 대응 - 중앙 (
cameraX
= 0) 은 실제 화면상에서x
=width
/ 2에 대응 - 오른쪽 끝 (cameraX = 1) 은 실제 화면상에서 x =
width
에 대응
- 왼쪽 끝 (
- 따라서, 위와 같은 방법으로 좌표를 대응시킨다 :
rayDir
rayDirX = dirX + cameraX * planeX;
rayDirY = dirY + cameraX * planeY;
- 위에서 설명한 벡터의 합을 이용하여
rayDir
을 구할 수 있다 (dir
+plane
*가중치) - 이때 cameraX는 plane의 길이가 1이라 가정했을 때 분수로 표현되므로, 가중치로 사용가능하다
- 따라서, rayDir은 다음과 같이 계산할 수 있다 :
map
mapX = (int)posX;
mapY = (int)posY;
- 플레이어의 현재 좌표의 정수형 값으로 초기화되며, 광선의 이동방향과 거리 등을 계산할 때 조정된다
- cub3D에서 지도는 이차원 배열로 들어오며, 따라서 (
mapX
,mapY
) 의 초기값은 지도 배열 상에서 플레이어의 인덱스를 나타낸다 - 초기화된
mapX
,mapY
변수는 DDA 알고리즘을 통해 광선을 이동시킬 때, 광선이 부딪힌 벽의 정수 좌표를 담는 변수로 이용된다 - 정수형 값이기 때문에, 다른 부동소수 값들 (
posX
,posY
등) 과 함께 계산하여 소수부분을 구하는 데에 사용된다
- cub3D에서 지도는 이차원 배열로 들어오며, 따라서 (
sideDistX, sideDistY, deltaDistX, deltaDistY
- x면은 x축에 수직인 면이고, y면은 y축에 수직인 면이다
sideDistX
의 초기값: 시작점에서 첫 번째 x면을 만나는 점까지의 거리sideDistY
의 초기값: 시작점에서 첫 번째 y면을 만나는 점까지의 거리sideDistX
와sideDistY
는 광선이 이동하면서 계속 갱신된다sideDistX
는 시작점부터 현재 x면을 만나는 점까지의 거리sideDistY
는 시작점부터 현재 y면을 만나는 점까지의 거리
deltaDistX
:n - 1
번째 x면을 만나는 점부터 에서n
번째 x면과 만나는 점까지 광선의 이동 거리deltaDistY
:n - 1
번째 y면을 만나는 점부터 에서n
번째 y면과 만나는 점까지 광선의 이동 거리
deltaDist 공식 유도
deltaDistX = abs(1 / rayDirX);
deltaDistY = abs(1 / rayDirY);
rayDirX
,rayDirY
로 나눠지는 부분이 있어, 해당 변수들이 0이 될 경우 문제가 발생한다- 따라서 조건문 (lodev 자료에선 삼항연산자) 을 이용하여 값을 보정한다
perpWallDist
- 이후의 벽 높이 구하는 계산식에서 자세히 다룰 예정이지만, 플레이어와 벽 사이 거리와 그려지는 벽의 높이는 서로 반비례한다 (플레이어와 벽 사이 거리가 멀 수록, 그려지는 벽의 높이가 줄어든다)
- 플레이어의 위치 (
posX
,posY
) 기준으로 벽의 거리를 계산할 경우, 멀리 있는 벽일수록 계산되는 벽의 높이가 큰 폭으로 줄어드므로, 결국 같은 높이의 벽도 화면상에선 왜곡되어 보일 수밖에 없다 - 이를 보정하기 위해 플레이어의 위치 대신 플레이어의 위치에 카메라 평면이 존재한다고 가정하여 벽부터 카메라 평면의 거리를 계산하는데, 이때의 거리가 담기는 변수가
perpWallDist
이다 - 플레이어의 위치 (점) 대신 카메라 평면 (선) 을 사용하면, 카메라상에서 같은 거리에 해당하는 벽은 모두 높이가 같게 보이기 때문에 왜곡이 없다
stepX, stepY
- 광선이 나아가는 방향 (↖ ↗ ↘ ↙) 에 따라 결정된다
stepX
: x방향으로 이동할 때의 방향 (1 or -1) 을 담은 변수stepY
: y방향으로 이동할 때의 방향 (1 or -1) 을 담은 변수
hit, side
hit
은 광선이 벽과 부딪혔는지 나타내는 변수- side는 충돌한 벽이 x축과 수직인 벽 (x면) 인지 y축과 수직인 벽 (y면) 인지 나타내는 변수
side
가 1일 때 y면과 충돌side
가 0일 때 x면과 충돌- 0과 1로는 명료하지 않으므로, 매크로 변수 (
WALL_X
,WALL_Y
) 등을 선언해서 사용
'42 > 42s Cursus' 카테고리의 다른 글
[Rank 4] Cub3D - Raycasting 구현 ③ 광선 이동거리 계산 및 보정 (0) | 2022.04.01 |
---|---|
[Rank 4] Cub3D - Raycasting 구현 ② 반복문의 동작 (0) | 2022.04.01 |
[Rank 4] Cub3D - Raycasting 기초 (2) | 2022.03.31 |
[Rank 4] Cub3D (0) | 2022.03.31 |
[Rank 3] Minishell - 사용가능 함수 정리 (0) | 2022.02.03 |
Comments