치춘짱베리굿나이스
[Rank 4] Cub3D - Raycasting 심화 - 텍스쳐 입히기 본문
텍스쳐 입히기
- 직전에는 벽에 단색을 입혔지만 이번엔 텍스쳐를 입혀보자
- 벽이 왜곡되어 보여야 하므로 어느 높이에 어떤 텍스쳐 색을 넣어야 할 지 계산해야 한다
동서남북 텍스쳐 저장하기
.xpm
또는.png
파일을 불러와서 포인터 배열 또는 구조체에 저장해둔다
perpWallDist 구하기
Raycasting 구현 - 화면에 벽 그리기 의 방법으로 perpWallDist
를 구한다
벽이 바라보는 위치 구하기
- 벽이 바라보는 방향이 어느 쪽인지 (동서남북) 에 따라 다른 텍스쳐를 적용해야 하므로, 부딪힌 광선의 방향을 가진
rayDirX
와rayDirY
, 벽이 위치한 축 (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_pos
는step
만큼 증가하며 서로 다른 픽셀을 가리킨다 - 텍스쳐상의 x좌표는 아까 계산한
textureX
이다 - 이 두 좌표를 가지고 텍스쳐상에서 색상을 뽑아낼 것이다
- 한 루프당 화면상의
start_point
지점부터end_point
지점까지 텍스쳐를 그려낼 것이다 - Raycasting 구현 - 화면에 벽 그리기 에서 구했던
startPoint
와endPoint
를 사용하면 된다 (또 통일성없이 필기했지요?) - 화면상의 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_pos
와TEXTURE_HEIGHT - 1
을 and 연산 취해주는 이유는 오버플로우를 방지하기 위함이다texture_pos
가TEXTURE_HEIGHT
와 일치할 경우 텍스쳐에서 인덱스를 이용하여 픽셀 색상을 가져올 때textureY
=TEXTURE_HEIGHT
가 되어 오버플로우로 프로그램이 터지기 때문
- 이
- 따라서 텍스쳐상 해당 좌표의 색상은
[textureY][textureX]
=[30][32]
에서의 흰색이다
'42 > 42s Cursus' 카테고리의 다른 글
[Rank 4] CPP Module (0) | 2022.06.17 |
---|---|
[Rank 2 / 3] Minitalk / Minishell - 시그널이란 (1) | 2022.04.28 |
[Rank 4] Cub3D - Raycasting 구현 ⑤ 키 이벤트 (0) | 2022.04.01 |
[Rank 4] Cub3D - Raycasting 구현 ④ 화면에 벽 그리기 (0) | 2022.04.01 |
[Rank 4] Cub3D - Raycasting 구현 ③ 광선 이동거리 계산 및 보정 (0) | 2022.04.01 |
Comments