치춘짱베리굿나이스

[Rank 4] Cub3D - Raycasting 구현 ② 반복문의 동작 본문

42/42s Cursus

[Rank 4] Cub3D - Raycasting 구현 ② 반복문의 동작

치춘 2022. 4. 1. 00:09

반복문의 동작

주의할 점

  • Lodev는 y가 아래에서 위로 증가하는 좌표계를 사용하였는데, 레이캐스팅 구현 시에 이 부분을 신경쓰지 않으면 이동 방향이나 회전 방향이 반대가 된다
  • 각 벡터의 용도를 확실히 알고 구현해야 플레이어의 현재 상태에서 어떤 방향 또는 값을 갖는지 명확하게 알고 디버깅할 수 있으므로 코드를 작성하기 전 각 변수의 의미를 확실히 알고 가는 것을 추천함
  • 위의 이미지 또한 어떻게 구현하는가에 따라 틀릴 수 있다

1. stepX, stepY 설정

if (rayDirX < 0)
    stepX = -1;
else
    stepX = 1;

if (rayDirY < 0)
    stepY = -1;
else
    stepY = 1;
  • 현재 광선의 방향에 따라 stepXstepY를 설정한다
  • 광선의 방향은 rayDirXrayDirY에 의해 결정된다

2. sideDistX, sideDistY 정해주기

  • 증명은 그림의 직각삼각형 닮음비를 이용한 증명을 참고

if (rayDirX < 0)
    sideDistX = (posX - mapX) * deltaDistX;
else
    sideDistX = (mapX + 1 - posX) * deltaDistX;
}

if (rayDirY < 0)
    sideDistY = (posY - mapY) * deltaDistY;
else
    sideDistY = (mapY + 1 - posY) * deltaDistY;
}

3. DDA 알고리즘 진행

  • 광선을 직선으로 이동시켜 벽을 찾기 위해 사용하는 알고리즘
  • hit가 0일 동안 (while (!hit)) DDA 알고리즘의 과정을 반복하여 벽을 찾아내고 반복문을 중단한다

1. sideDistX와 sideDistY를 비교

if (sideDistX < sideDistY)
{
  sideDistX += deltaDistX;
    mapX += stepX;
    side = WALL_X; // 0
}
else
{
    sideDistY += deltaDistY;
    mapY += stepY;
    side = WALL_Y; // 1
}
  • 기본 원리는 매번 sideDistXsideDistY를 비교하여,
    • sideDistX가 더 작을 경우
      • sideDistXdeltaDistX를 더한다
      • mapXstepX를 더한다
      • x축에 수직인 면 (x면) 에 닿았으므로 side를 0으로 설정한다
    • sideDistY가 더 작을 경우
      • sideDistYdeltaDistY를 더한다
      • mapYstepY를 더한다
      • y축에 수직인 면 (y면) 에 닿았으므로 side를 1로 설정한다

  • sideDistX, sideDistY를 계산하며 광선이 어떤 벽에 부딪혔는지 구하는 예시이다
  • 간단하게 설명하면, 다음 x좌표까지 이동했을 때의 광선의 거리와 다음 y좌표까지 이동했을 때의 광선의 거리 중 짧은 것을 선택하여 미리 구한 delta값만큼 더하여 광선을 이동시킨다

2. 구한 좌표 (mapX, mapY) 를 토대로 월드맵 체크

if (mapArr[mapY][mapX] == '1')
    hit = 1
hit = 0
  • pos (시작점) 부터 sideDistX만큼 이동한 광선과 sideDistY만큼 이동한 광선이 모두 벽과 부딪혔을 경우, 지도의 이차원 배열상 좌표 (mapX, mapY) 가 1 (벽) 일 것이므로 이 좌표에 해당하는 벽에 부딪혔다고 판정하고 반복문을 중단한다
Comments