42seoul:: <cub3d> 레이케스팅을 활용한 그래픽 디자인

jahlee·2023년 6월 15일
0

개인 공부

목록 보기
12/23

Subject 링크

개요

최초의 fps게임인 Wolfenstein 3D와 같은 프로그램을 레이케스팅이라는 랜더링 기술을 활용하여 그래픽 디자인을 구현해보는것이 목표이다.

레이케스팅이란 ?

플레이어를 기준으로 시야각 범위에서 무수히 많은 빛을 쏘아서 벽을 탐지하는 기법이다. 이때 벡터를 활용하여 단위길이만큼 광선의 길이를 늘려가며 주어진 맵에서 벽을 확인을 해주게된다. 단순히 광선이 포함하는 모든 점들에 대해서만 벽의 존재를 확인해주면 벽을 탐지하지 못하는 경우가 발생할 수 도있고, 연산자체도 상당히 많아져서 DDA라는 기법을 사용한다.

DDA

어안효과 방지

레이케스팅을 하여 벽과의 실제 거리, 즉 Euclid거리를 구할 수 있게된다. 이때 Euclid 거리를 사용하여 화면에 벽을 그려준다면 둥글게 그려지는 현상을 확인할 수 있게된다. 이를 방지하기위해 보정된 거리인 PerpDist를 사용하여 화면에 그려준다.

RGB, ARGB?

RGB는 색을 나타내는 방식으로 unsignedint범위 내로 표현이 되어진다. RGB의 경우 3바이트로 16진수의 방식으로 보통 표현한다.(물론 10진수값으로 넣어도 무방)

예시 ) RGB = 0xFF00FF

마찬가지로 ARGB는 RGB에서 색의 투명도를 추가로 표현해준것이다. 때문에 1바이트가 큰 4바이트이다.

예시 ) ARGB = 0x00FF00FF

텍스쳐를 비율에 맞게 그리기

간략 코드

cub3d.h

#ifndef CUB3D_H
# define CUB3D_H

# include <fcntl.h>
# include <math.h>
# include <mlx.h>
# include <stdio.h>
# include <stdlib.h>
# include <unistd.h>
# include "libft/libft.h"

# define WIDTH				1280
# define HEIGHT				920
# define FOV				0.66
# define MV_SPEED			0.1

# define X_EVENT_KEY_PRESS	2
# define X_EVENT_KEY_EXIT	17
# define KEY_ESC			53
# define KEY_W 				13
# define KEY_A 				0
# define KEY_S 				1
# define KEY_D 				2
# define KEY_LEFT			123
# define KEY_RIGHT			124

enum e_element
{
	NORTH,
	SOUTH,
	EAST,
	WEST,
	FLOOR,
	CEILING
};

enum e_side
{
	HORIZONTAL,
	VERTICAL
};

struct s_vector
{
	double	x;
	double	y;
};

struct s_img
{
	void			*img_ptr;
	unsigned int	*buffer;
	int				width;
	int				height;
	int				bits_per_pixel;
	int				size_line;
	int				endian;
};

struct s_map_info
{
	char			*north_path;
	char			*south_path;
	char			*west_path;
	char			*east_path;
	unsigned int	color_floor;
	unsigned int	color_ceiling;
	char			**map;
	int				width;
	int				height;
	int				check[6];
};

struct s_ray
{
	t_vector	side_dist;
	t_vector	delta_dist;
	t_vector	dir;
	t_side		side;
	int			map_x;
	int			map_y;
	int			dx;
	int			dy;
	int			hit;
	int			wall_height;
	int			draw_start;
	int			draw_end;
	double		wall_x;
};

struct s_player
{
	t_vector	pos;
	t_vector	dir;
	t_vector	plane;
	char		direction;
};

struct s_cub
{
	int			fd;
	int			error;
	void		*mlx_ptr;
	void		*win_ptr;
	t_player	player;
	t_map_info	map_info;
	t_img		*background;
	t_img		*texture[4];
};
#endif

main.c

#include "../cub3d.h"

int	main(int argc, char **argv)
{
	t_cub	cub;

	ft_memset(&cub, 0, sizeof(t_cub));
	if (argc != 2)
		cub_error(&cub, "Invalid number of arguments");
	init_map(&cub, argv[1]);
	start_game(&cub);
	return (0);
}

raycast.c

void	raycast(t_cub *cub)
{
	t_img	img;
	t_ray	ray;
	int		idx;

	img.img_ptr = mlx_new_image(cub->mlx_ptr, WIDTH, HEIGHT);
	img.buffer = (unsigned int *)mlx_get_data_addr(img.img_ptr, \
		&(img.bits_per_pixel), &(img.size_line), &(img.endian));
	set_transparent_img(img.buffer);
	idx = -1;
	while (++idx < WIDTH)
	{
		init_ray(cub, &ray, idx);//초기화
		dda(cub, &ray);// DDA
		set_wall_element(cub, &ray);//화면에 출력해주기 위해 필요한 인자를 구함
		draw_vertical_pixel(cub, &ray, &img, idx);//수직으로 img.buffer의 ARGB 데이터를 값에 맞게 변경
	}
	mlx_put_image_to_window(cub->mlx_ptr, cub->win_ptr, \
		cub->background->img_ptr, 0, 0);//천장 바닥 이미지 출력
	mlx_put_image_to_window(cub->mlx_ptr, cub->win_ptr, img.img_ptr, 0, 0);// 벽이미지 출력
}

후기

직접 그래픽 디자인을 통해 2차원 맵을 3차원으로 확장하여 화면에 출력해주는 것을 구현하였는데, 이와 같은 과제를 해보지 않았다면 알기 어려웠던 여러 알고리즘과 기법들에 대해 공부할 수 있었던 시간이었다.

참조

레이케스팅 예시
텍스쳐 관련 예시

0개의 댓글