6) cub3D - Raycaster 구현 (3)

sorikikikim·2021년 6월 8일
0

cub3D

목록 보기
6/6

참고한 링크

lodev tutorial - wall

변수 선언 (t_wall_info)

typedef struct		s_wall_info
{
	double		camera_x;
	double		raydir_x;
	double		raydir_y;
	double		side_dist_x;
	double		side_dist_y;
	double		delta_dist_x;
	double		delta_dist_y;
	double		perp_wall_dist;
	double		wall_x;
	double		step;
	double		tex_pos;
	int		map_x;
	int		map_y;
	int		step_x;
	int		step_y;
	int		hit;
	int		side;
	int		line_height;
	int		draw_start;
	int		draw_end;
	int		tex_num;
	int		tex_x;
	int		tex_y;
	int		color;
	int		x;
	int		y;
}			t_wall_info;

t_wall_info	*wall;

wall->wall_x
: 벽의 정확히 어디에 부딪혔는지 나타낸다.
  texture을 적용할 때 어떤 x좌표를 사용해야 하는지 판단하는데 사용한다. 
wall->tex_x, wall->tex_y 
: 텍스처의 x, y 좌표

변수 선언(t_texture)

typedef struct		s_texture
{
	t_xy		size; // int x,y
	int		*data;
}			t_texture;

t_texture	*texture;

texture->size.x, texture->size.y
: texture의 텍셀(texel)이 갖는 width와 height 크기

나중에 벽의 방향에 따라 다른 texture로 설정해주기 위해 구조체를 모아놓은 구조체 t_cub에 texture의 배열을 선언해줘야 한다.
ex) t_texture texture[4];

set_wall()

(5) 벽의 x값 texture 설정

if (wall->side == 0)
	wall->wall_x = player->pos_y + wall->perp_wall_dist * wall->raydir_y;
else
	wall->wall_x = player->pos_x + wall->perp_wall_dist * wall->raydir_x;
wall->wall_x -= floor((wall->wall_x));
wall->tex_x = (int)(wall->wall_x * (double)texture->size.x);
if (wall->side == 0 && wall->raydir_x > 0)
	wall->tex_x = texture->size.x - wall->tex_x - 1;
if (wall->side == 1 && wall->raydir_y < 0)
	wall->tex_x = texture->size.x - wall->tex_x - 1;

1) wall_x로 벽의 정확히 어디에 부딪혔는지 알 수 있다.
2) 부딪힌 곳의 정확한 x, y값(double)에서 벽의 x, y값(int)을 빼서 판단할 수 있다.
3) 광선이 x면과 부딪힌 경우(side == 0)에 wall_x는 벽의 x좌표이지만, y면에 부딪힌 경우(side == 1)에 wall_x는 벽의 y좌표가 된다.
4) 이러나 저러나 텍스처를 적용할 때 wall_x의 값은 텍스처의 x좌표에 사용된다.
5) 텍스처의 x좌표를 나타내는 tex_x는 wall_x로 계산해줄 수 있다.

(6) 벽의 y값 texture 설정

wall->step = 1.0 * texture->size.y / wall->line_height;
wall->tex_pos = (wall->draw_start - HEIGHT / 2 + wall->line_height / 2) * wall->step;
wall->y = wall->draw_start - 1;
while (++wall->y < wall->draw_end)
{
	wall->tex_y = (int)wall->tex_pos;
	wall->tex_pos += wall->step;
	wall->color = texture->data[texture->size.x * wall->tex_y + wall->tex_x];
	if (wall->side == 1)
		wall->color = (wall->color >> 1) & 8355711;
	info->buf[wall->y][wall->x] = wall->color;
}

1) 수직선 상 각 픽셀이 텍스처의 어떤 y좌표 tex_y를 갖게 할건지 정해주기 위해 y방향 반복문을 돌린다. 반복문을 돌면서 최종적으로 구한 값 wall->color을 화면 버퍼 buffer[wall->y][wall->x]에 하나하나 넣어주면 된다.
2)step은 텍스처의 좌표를 수직선 상에 있는 좌표에 대해 얼마나 늘려야 할지에 따라 결정된다. 그리고 부동소수점 수인 double형에서 int형으로 캐스팅해주어 텍셀값을 선택할 수 있도록 한다.
3) tex_y의 값은 step의 크기만큼 증가하면서 계산된다.
4) 광선이 벽의 y면에 부딪힌 경우(side == 1)에 색상값은 좀 더 어둡게 표현해준다. (그렇게 해야 좀 더 자연스러운 조명표현이 되기 때문이다.)
5) 십진수를 10으로 나누면 마지막 자리를 없앨 수 있는 것처럼 (300 / 10 하면 30으로 마지막 숫자 0이 제거됨) 이진수를 2로 나누는 것은 마지막 비트를 제거하는 것과 같다. 여기서는 비트연산 중 오른쪽 시프트연산 >>1 을 사용해서 마지막 비트를 제거해주었다.
6) 따라서 시프트연산 후, 모든 바이트의 첫 번째 비트는 0으로 설정해주어야 하고, 방법은 이진수 01111111 01111111 01111111(10진수로는 8355711)를 AND연산해주면 실제보다 어두운 색으로 설정된다.
7) 최종적으로 계산된 color 의 값이 현재 버퍼픽셀의 색상으로 설정되면 반복문의 한 사이클을 마치고 다음 y로 넘어간다.

참고 : 여기서 step을 사용한 방식은 아핀 텍스처매핑 방법이다. 각 픽셀에 대해 각각 나눗셈을 하지않고 두 점 사이를 (일정한 비율로) 선형보간하는 방식이다. 이 방법은 일반적으로 원근법을 정확하게 표현해주지 못하지만 지금처럼 완벽하게 수직인 벽(그리고 완벽하게 수평인 천장과 바닥)인 경우에는 올바르게 나타난다.

!!!!!!!!!~!!!!~!!!!

Hits

0개의 댓글

관련 채용 정보