치춘짱베리굿나이스

[Rank 4] Cub3D - Raycasting 심화 - 텍스쳐 입히기 본문

42/42s Cursus

[Rank 4] Cub3D - Raycasting 심화 - 텍스쳐 입히기

치춘 2022. 4. 1. 19:04

텍스쳐 입히기

  • 직전에는 벽에 단색을 입혔지만 이번엔 텍스쳐를 입혀보자
  • 벽이 왜곡되어 보여야 하므로 어느 높이에 어떤 텍스쳐 색을 넣어야 할 지 계산해야 한다

동서남북 텍스쳐 저장하기

  • .xpm 또는 .png 파일을 불러와서 포인터 배열 또는 구조체에 저장해둔다

perpWallDist 구하기

Raycasting 구현 - 화면에 벽 그리기 의 방법으로 perpWallDist를 구한다

벽이 바라보는 위치 구하기

  • 벽이 바라보는 방향이 어느 쪽인지 (동서남북) 에 따라 다른 텍스쳐를 적용해야 하므로, 부딪힌 광선의 방향을 가진rayDirXrayDirY, 벽이 위치한 축 (x 또는 y)을 담은 side 변수를 사용하여 벽의 방향을 구한다

벽의 x축 거리의 비율 구하기

  • 광선이 벽의 어느 지점에 닿았는지 구해야 텍스쳐상의 어떤 픽셀 색을 사용할 지 알 수 있다
  • 벽이 1*1 크기라고 가정했을 때의 비율로 계산한다 (텍스쳐의 크기에 비례해서 어느 지점의 색을 가져와야 하는지 계산하기 쉽기 때문)

벽의 방향이 x면일 경우 (x축에 수직, side = x)

wallX = posY + perpWallDist * rayDirY;
wallX -= floor(wallX);
  • wallX를 구하는 방법으로, wallX가 우리가 구하고자 하는 벽 상에서 광선이 닿은 곳까지의 거리이다

벽의 방향이 y면일 경우 (y축에 수직, side = y)

wallX = posX + perpWallDist * rayDirX;
wallX -= floor(wallX);
  • wallX를 구하는 방법으로, wallX가 우리가 구하고자 하는 벽 상에서 광선이 닿은 곳까지의 x축 거리이다
  • 벽에서 광선이 닿은 곳까지의 높이 (y거리) 를 구하는 것이 아니므로 wallY가 아니다 (헷갈리지 않도록 주의)

실제 텍스쳐상에서의 거리 구하기

  • 방금 구한 것은 벽이 1 * 1 크기일 때 광선이 닿은 지점까지의 거리이다
  • 이번에는 실제 텍스쳐 (32 * 32 또는 64 * 64 등...) 상에서 광선이 닿은 지점까지의 거리를 구한다

textureX = (int)(wallX * (double)TEXTURE_WIDTH);

texture_x 보정하기

  • 광선의 방향이 음수일 경우, 거리를 텍스쳐상 x = 0인 지점부터 계산한 것이 아닌 x = TEXTURE_WIDTH인 지점부터 거꾸로 계산되므로 조건문을 이용하여 이를 보정한다

벽의 방향이 x면일 경우 (x축에 수직, side = x)

if (벽이 x면이고 rayDirX가 음수)
    textureX = TEXTURE_WIDTH - textureX - 1;

벽의 방향이 y면일 경우 (y축에 수직, side = y)

if (벽이 y면이고 rayDirY가 음수)
    texture_x = TEXTURE_WIDTH - texture_x - 1;

실제로 텍스쳐 그리기

  • 화면에 그려질 텍스쳐의 높이 (lineHeight) 와 실제 텍스쳐의 높이 (TEXTURE_HEIGHT) 가 다르기 때문에, 텍스쳐를 늘이거나 줄이기 위해 높이의 비율을 구한다

  • 이때 사용할 비율이 step으로, 텍스쳐상에서 몇 칸씩 이동하면서 픽셀의 색을 가져올지 나타내는 변수이다

  • 텍스쳐상에서 어떤 픽셀의 색을 가져올 지에 대한 y좌표는 texture_pos에 담는다
    • 과제 진행시의 모든 변수명은 snake case로 통일하였으나, 원본 로데브 자료가 camel case를 따르므로, 본 자료에서 변수명 서식이 통일이 안 된 부분이 있다
    • 처음에는 팀원이랑 둘이서만 보려고 했던 자료라 + 나도 사람인지라 헷갈려서 그랬습니다 쏴리
  • 벽을 위에서 아래로 색칠하면서 서로 다른 픽셀을 가져와야 하기 때문에, texture_posstep만큼 증가하며 서로 다른 픽셀을 가리킨다
  • 텍스쳐상의 x좌표는 아까 계산한 textureX이다
  • 이 두 좌표를 가지고 텍스쳐상에서 색상을 뽑아낼 것이다

  • 한 루프당 화면상의 start_point 지점부터 end_point 지점까지 텍스쳐를 그려낼 것이다
  • Raycasting 구현 - 화면에 벽 그리기 에서 구했던 startPointendPoint를 사용하면 된다 (또 통일성없이 필기했지요?)
  • 화면상의 x좌표는 while (x < width) 반복문에서의 x를 사용하며, 해당 반복문을 한 번 반복할 때마다 안에서 계산하는 모든 좌표는 전부 특정 x좌표 상에서의 y좌표 및 거리라고 생각하면 된다

while (벽의 시작지점부터 끝지점까지)
{
    textureY = (int)texture_pos & (TEXTURE_HEIGHT - 1);
    texture_pos += step;
    픽셀 가져와서 색칠하는 함수;
    벽의 세로 좌표++;
}
  • 예시로 텍스쳐의 전체 크기가 64 * 64라 하자 (TEXTURE_WIDTH = TEXTURE_HEIGHT = 64)
  • 미리 구했던 textureX가 32이고, texture_pos가 30.5라고 가정하면, 실제 픽셀 좌표는 정수형이므로 texture_pos를 int형으로 변환한다
    • texture_pos의 정수형 값이 textureY이다 ⇒ textureY = 30
    • textureY를 구할 때 texture_posTEXTURE_HEIGHT - 1을 and 연산 취해주는 이유는 오버플로우를 방지하기 위함이다
    • texture_posTEXTURE_HEIGHT와 일치할 경우 텍스쳐에서 인덱스를 이용하여 픽셀 색상을 가져올 때 textureY = TEXTURE_HEIGHT가 되어 오버플로우로 프로그램이 터지기 때문
  • 따라서 텍스쳐상 해당 좌표의 색상은 [textureY][textureX] = [30][32] 에서의 흰색이다
Comments