티스토리 뷰
로데브 中 텍스쳐를 이해하는 페이지.
이해했던 흐름 그대로의 정리라서 로데브 원본과 살짝 차이가 있습니다.
1. 벽 텍스쳐 (affine texture mapping)
2. 천장, 바닥 텍스쳐
3. 텍스쳐에 투명도 넣기
1. 벽 텍스쳐 (affine texture mapping)
광선으로 벽의 높이를 구한 다음부터의 내용
int texNum = worldMap[mapX][mapY] - 1;
double obj_x = (ray.side == 0) ? posY + perpWallDist * rayDirY : posX + perpWallDist * rayDistX;
int img_x = (int)(img_width * (obj_x - floor(obj_x)));
if (wall->type == SOUTH || wall->type == WEST)
img_x = img_width - img_x - 1;
double obj_y = 0;
if (draw_start == 0)
obj_y = wall_height / 2 - win_h / 2;
y = draw_start;
while (y < draw_end)
{
int img_y = (int)(img_height * obj_y / wall_height);
int tex_point = size_l / (bpp / 8) * img_y + img_x;
buf[y][x] = data[texNum][tex_point];
obj_y++;
y++;
}
전체적인 흐름은 x좌표를 잡은 상태에서 수직으로 내려오면서 텍스쳐(이미지)를 가져오는 것이다.
obj_x: 벽에 부딪혔을 때 가로 좌표
obj_y: 그 위치에서 수직으로 올린 벽 시작점
(img_x, img_y): 그 때 텍스쳐에 해당하는 위치
img_height, img_width: 텍스쳐 각각의 가로세로 (각 텍스쳐 크기가 다른 경우 위 코드에서 보완 필요)
예시를 보면서 이해해보자.
왼쪽 벽에 오른쪽 4 * 2 사이즈의 텍스쳐를 넣을 것이다.
가로 과정
1. 광선이 벽에 부딪혔을 때 x 좌표를 구한다. (왼쪽 갈색별) (값은 레이캐스팅 과정에서 구해진다.)
ex) obj_x = 44.23
2. 벽 가로에 대한 obj_x의 상대적 위치를 구한다. 가로가 1이기 때문에 정수부분을 빼서 소수부분으로 상대적 위치를 구할 수 있다.
ex) obj_x - floor(obj_x) = 44.23 - 44 = 0.23
3. 상대적 위치를 원본 텍스쳐 width에 적용한다.
ex) img_x = (int)(4 * 0.23) = (int) (0.92) = 0
4. [img_x = 0]이 실제 텍스쳐에서 가져올 가로 위치. (오른쪽 갈색별 위치를 int로 변환)
세로 과정
wall_height = 64라고 가정하자 (실제 구현에서는 texture 단계 이전에 wall_height를 구하는 과정이 있다.)
1. obj_x에서 수직으로 올라와 벽 시작점 obj_y를 잡는다. (왼쪽 파란별)
(일단 스크린에 벽 전체가 보일 경우로 가정했다. 이때 obj_y는 0이다)
ex) obj_y = 0
2. 벽 세로에 대한 obj_y의 상대적 위치를 구한다. 내 위치를 벽 높이로 나눠주면 상대적 위치를 구할 수 있다.
ex) obj_y / 64 = 0
3. 상대적 위치를 원본 텍스쳐 height에 적용한다.
ex) img_y = (int)(2 * 0) = 0
4. [img_y = 0]이 실제 텍스쳐에서 가져올 세로 위치. (오른쪽 흰색별 위치를 int로 변환)
종합하면 [img_x = 0, img_y = 0]으로 파란색 픽셀을 가져오게 된다.
while문을 계속 돌아서 obj_y = 40이 되었다면
1. obj_y = 40
2. obj_y의 상대적 위치는 40 / 64 = 5 / 8
3. pos_y = (int) (2 * 5 / 8) = 1
[img_x = 0, img_y = 1]으로 흰색 픽셀을 가져온다.
스킵했던 부분 설명
1.
img_x = (int)(img_width * (obj_x - floor(obj_x));
if (wall->type == SOUTH || wall->type == WEST)
img_x = img_width - img_x - 1;
2.
obj_y = 0;
if (draw_start == 0)
obj_y = wall_height / 2 - win_h / 2;
1.
스크린을 띄워보면 벽면이 가로로 뒤집혀서 그려지는 방향이 있다. (대칭이 아닌 텍스쳐를 넣어보면 바로 눈에 보인다.)
[img_x = img_width - img_x - 1] 이 찍은 위치를 다시 뒤집어서 정상적으로 돌려주는 부분이다.
(side == 0 && rayDirX > 0) || (side == 1 && rayDirY < 0) 조건문을 그대로 써도 되고, cub3d 과제 내용 중 방향을 정하는 부분이 있기 때문에 위 코드처럼 단순화할 수도 있다.
2.
[obj_y= 0]은 벽 높이가 스크린 높이보다 작아서 화면에 벽 전체가 그려지는 경우를 가정한 것이었다. (멀리서 벽을 바라볼 때)
하지만 아래 그림처럼 벽 높이가 노란색 스크린보다 커지는 경우가 있다. (벽 바로 앞에 섰을 때)
texture 이전 단계에서 이런 경우를 draw_start = 0, draw_end = win_height로 보정해주었다.
마찬가지로 보정이 필요한데, 이때는 벽 제일 윗부분을 시작점(obj_y = 0)으로 잡으면 안되고, 화면에 그려주는 부분부터 시작해야 한다.
그 시작점이 벽 절반 높이에서 화면 절반 높이를 뺀 위치다.
그래서 draw_start == 0일 땐 [obj_y = wall_height / 2 - win_height / 2]
마지막으로, 구한 텍스쳐 위치(img_x, img_y)로 데이터에서 색상을 가져와서 버퍼에 넣어준다.
텍스쳐 위치로 색상을 가져오는 계산은 mlx_get_data_addr 페이지에 설명되어 있다.
tex_point = size_l / (bpp / 8) * img_y + img_x;
buf[y][x] = data[tex_point];
x 하나에 대해서 수직으로 전부 내려오면 아래처럼 저장되고
이 작업을 모든 x에 대해(스크린 widht만큼) 실행하면 버퍼에 화면 전체 벽이 저장된다.
'42 > cub3d' 카테고리의 다른 글
cub3d - 완성본 (0) | 2020.10.19 |
---|---|
cub3d - lodev 레이캐스팅, 카메라행렬 (0) | 2020.10.19 |
cub3d - transparency (0) | 2020.10.17 |
cub3d - mlx_get_data_addr (0) | 2020.09.23 |