치춘짱베리굿나이스

[Rank 4] Cub3D - Raycasting 구현 ① 변수 설명 본문

42/42s Cursus

[Rank 4] Cub3D - Raycasting 구현 ① 변수 설명

치춘 2022. 3. 31. 23:04

변수 설명

posX, posY

  • 플레이어의 좌표를 나타내는 벡터
  • 원점 (0, 0) 을 시작점으로, 플레이어의 좌표를 끝점으로 하는 벡터이다
  • 단도직입적으로 플레이어의 위치 좌표라고 생각하는게 편하다

dirX, dirY

  • 플레이어의 시선을 나타내는 벡터
  • 길이는 1로 고정된다
  • 플레이어가 보고 있는 방향을 나타낸다
  • 플레이어의 눈에서 레이저가 나온다고 가정할 때 해당 레이저의 이동 방향이라 생각하면 쉽다

planeX, planeY

  • 카메라 평면을 나타내는 벡터
  • 카메라 평면이라는 개념이 생소할 수 있는데, 이 벡터와 반대방향 벡터 (-plane) 를 합친 만큼에 비춰지는 게임 오브젝트들이 화면상에 그려진다고 생각하면 된다
  • 쉽게 말해, 실제 플레이어가 컴퓨터로 보는 화면의 가로 길이와 1대1 대응된다
  • 따라서 시야와는 무조건 수직이다 (플레이어가 모니터를 수직으로 보고 게임을 진행하므로)

dir과 plane의 길이

  • 이미지에는 dir의 크기가 상관없다고 적혀있지만, dirplane간의 길이 비율이 시야각을 결정하므로 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 등) 과 함께 계산하여 소수부분을 구하는 데에 사용된다

sideDistX, sideDistY, deltaDistX, deltaDistY

  • x면은 x축에 수직인 면이고, y면은 y축에 수직인 면이다
  • sideDistX의 초기값: 시작점에서 첫 번째 x면을 만나는 점까지의 거리
  • sideDistY의 초기값: 시작점에서 첫 번째 y면을 만나는 점까지의 거리
  • sideDistXsideDistY는 광선이 이동하면서 계속 갱신된다
    • 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) 등을 선언해서 사용
Comments