Search
Duplicate
🌏

miniRT

Holy Graph
2Circle
간략한 내용
주어진 좌표와 데이터값으로 3차원 공간 그리기
적정 기간
2weeks
제작에 참여한 사람
진행 중인 사람
최종 편집일
Jul 10
통과한 사람
1 more property
민희알티

1. miniRT 과제 목표

miniRT는 기초적인 컴퓨터 그래픽스 과제를 해결하는 것이다.
평면, 구, .....

2. MiniLibX 사용하기

1) Mninilibx란?

MiniLibX는 X-Window 및 Cocoa에 대한 지식 없이도 화면에서 무언가를 렌더링하기위한 가장 기본적인 작업을 수행 할 수있는 작은 그래픽 라이브러리이다. 그것은 간단한 창 생성, 그리기 도구, 이미지 기능 및 이벤트 관리 시스템을 제공합니다.
아래에 대한 내용은 해외의 카뎃이 열심히 MiniLibX에 대한 사용법을 문서화 해둔 것을 번역한 내용이다. 본문을 보고 싶다면 아래 링크를 참고하자.

X-Window란?

X-Window는 유닉스 용 네트워크 지향 그래픽 시스템이다. 이것은 예입니다. 원격 데스크톱에 연결할 때 사용된다. 이러한 구현의 가장 일반적인 예 중 하나는 TeamViewer이다.

MacOS

MacOS는 화면에 대한 그래픽 액세스를 처리하지만 이에 액세스하려면 화면, 윈도우 시스템, 키보드 및 마우스를 처리하는 기본 MacOS 그래픽 프레임 워크에 애플리케이션을 등록해야한다.

2) Colors

색상은 int형식으로 표현된다. 우리는 ARGB값을 포함하는 int를 얻으려면 몇가지 규칙이 필요하다.
우리는 TRGB 형식을 사용하기 위해 비트연산을 활용한다. 색상을 표현하기 위현 형식은 0xTTRRGGBB와 같이 초기화해서 사용한다. 각 코드는 다음을 의미한다.
T Transparency;
R Red color;
G Green color;
B Blue color.
RGB 는 위와같이 초기화 할 수 있고, 몇 가지 예시는 아래와 같다.
Red: 0x00FF0000;
Green: 0x0000FF00;
Blue: 0x000000FF;
각 바이트는 2 ^ 8 개의 값을 포함하고 rgb 값의 범위는 0에서 255까지이므로 정수를 완벽하게 맞출 수 있다. (int가 4 바이트이므로). 프로그래밍 방식으로 값을 설정하기 위해 비트 시프 팅을 사용한다. 우리를 위해 정확하게하는 함수를 만들어 보자.
int create_trgb(int t, int r, int g, int b) { return(t << 24 | r << 16 | g << 8 | b); }
C
복사
비트연산을 활용하면 이렇게 인코딩된 TRGB값을 활용해서 다시 각 코드의 값을 뽑아낼 수 있다.
int get_t(int trgb) { return (trgb & (0xFF << 24)); } int get_r(int trgb) { return (trgb & (0xFF << 16)); } int get_g(int trgb) { return (trgb & (0xFF << 8)); } int get_b(int trgb) { return (trgb & 0xFF); }
C
복사

3) Getting Started

mlx 초기화 하기

mlx.h 파일에 선언되어 있는 mlx_init함수를 활용해서 포인터를 초기화할 수 있다. 이제 mlx_ptr은 mlx_init()함수가 리턴하는 주소를 가리키게 된다.
#include <mlx.h> int main(void) { void *mlx_ptr; mlx_ptr = mlx_init(); return (0); }
C
복사

창 생성하기

이제 초기화된 포인터를 활용해서 창을 띄워보자!
#include <mlx.h> int main() { void *mlx_ptr; void *win_ptr; // 생성할 윈도우를 가리키는 포인터 mlx_ptr = mlx_init(); win_ptr = mlx_new_window(mlx_ptr, 500, 500, "Hellow World!"); mlx_loop(mlx_ptr); // 생성한 윈도우가 있는 mlx_ptr을 rendering한다. return (0); }
C
복사
창을 생성하는 함수의 prototype은 아래와 같다.
void mlx_new_window(void mlx_ptr, int size_x, int size_y, char *title)
C
복사
mlx_ptr : mlx_init이 반환한 연결 식별자
size_x : 창의 가로 사이즈
size_y : 창의 세로 사이즈
title : 타이틀 바에 표시될 문자열
return value :
만약 초기화 하지 않은 mlx_ptrmlx_new_window함수로 전달된다면 segfault를 발생한다.
이 함수는 창을 생성하는 것 까지만 작동하고 실제로 모니터상에 창을 띄우진 않는다. mlx_loop 함수를 주석처리해보면 실행파일을 실행했을 때, 아무것도 보이지 않는 것을 알 수 있다.
이벤트를 받는 함수의 prototype은 아래와 같다.
int mlx_loop(void *mlx_ptr)
C
복사
mlx_ptr : 디스플레이에 연결되어 있는 mlx_ptr
return value : no return
이벤트를 받기 위해서 꼭 사용해야 한다고 나와있지만, 실제로 이 함수를 사용하지 않으면 윈도우 자체가 뜨지 않는다.

창에 이미지 넣기

mlx_new_image()는 메모리에 새 이미지를 만든다. 나중에 이 이미지를 조작할 수 있다. 생성할 이미지의 크기 만 필요하다.
void *mlx_new_image(void *mlx_ptr, int width, int height)
C
복사
mlx_ptr : 디스플레이에 연결되어 있는 mlx_ptr
width : 이미지의 너비
height : 이미지의 높이
mlx_get_data_addr()는 생성된 이미지에 대한 정보를 리턴한다.
char *mlx_get_data_addr(void *img_ptr, int *bits_per_pixel, \ int *size_line, int *endian);
C
복사
img_ptr : 사용할 이미지를 지정한다
bits_per_pixel : 픽셀 색상을 나타내는데 필요한 비트 수
size_line : 이미지 한 줄을 메모리에 저장하는데 사용되는 바이트 수. 이 정보는 이미지의 한 줄에서 다른 줄로 이동하는 데 필요하다.
endian : 이미지의 픽셀 색상 저장 방식(little endian = 0, big endian = 1)
endian이란? 엔디언(Endianness)은 컴퓨터의 메모리와 같은 1차원의 공간에 여러 개의 연속된 대상을 배열하는 방법을 뜻하며, 바이트를 배열하는 방법을 특히 바이트 순서(Byte order)라 한다. endian에 대해 자세히 알고싶다면?
mlx_put_image_to_window()는 생성한 이미지를 원하는 윈도우에 넣어주는 함수이다.
int mlx_put_image_to_window(void *mlx_ptr, void *win_ptr, void *img_ptr, \ int x, int y);
C
복사
mlx_ptr : 디스플레이에 연결되어 있는 mlx_ptr
win_ptr : 사용할 윈도우
img_ptr : 사용할 이미지
x, y : 이미지가 위치할 좌표
return value : ?????

예시코드

아래는 화면에 빨간색 대각선을 보여주는 두가지 방법이 나와있다. mlx.h에 선언되어있는 mlx_pixel_put()을 활용해서 출력하는 방법과 이미지를 생성해서 생성한 이미지를 화면에 올리는 방법이다. 아래 코드는 첫번째 방법으로 화면이 출력되고 있고 주석 처리된 부분을 모두 지우면 두번째 방법을 활용해서 출력할 수 있다.
#include <unistd.h> #include <mlx.h> typedef struct s_data { void *img; char *addr; int bits_per_pixel; int line_length; int endian; } t_data; void my_mlx_pixel_put(t_data *data, int x, int y, int color) { char *dst; dst = data->addr + (y * data->line_length + x * (data->bits_per_pixel / 8)); *(unsigned int*)dst = color; } int main() { void *mlx_ptr; void *win_ptr; t_data image; mlx_ptr = mlx_init(); win_ptr = mlx_new_window(mlx_ptr, 1920, 1080, "Hellow World!"); image.img = mlx_new_image(mlx_ptr, 1920, 1080); // 이미지 객체 생성 image.addr = mlx_get_data_addr(image.img, &image.bits_per_pixel, &image.line_length, &image.endian); // 이미지 주소 할당 for (int i = 0 ; i < 200 ; i++) { mlx_pixel_put (mlx_ptr, win_ptr, i, i, 0x00FF0000); //my_mlx_pixel_put(&image, i, i, 0x00FF0000); } //mlx_put_image_to_window(mlx_ptr, win_ptr, image.img, 0, 0); mlx_loop(mlx_ptr); return (0); }
C
복사

4) Hooks

컴퓨터 프로그래밍에서 Hooking이라는 용어는 소프트웨어 구성 요소간에 전달되는 함수 호출이나 메시지 또는 이벤트를 가로 채서 운영 체제, 응용 프로그램 또는 기타 소프트웨어 구성 요소의 동작을 변경하거나 강화하는 데 사용되는 다양한 기술을 포함한다. 이러한 가로채는 함수 호출, 이벤트 또는 메시지를 처리하는 코드를 Hook라고한다.
아래 세가지 함수는 모두 hooking을 도와주는 함수들입니다.
int mlx_key_hook ( void win_ptr, int (*funct_ptr)(), void *param ); int mlx_mouse_hook ( void win_ptr, int (*funct_ptr)(), void *param ); int mlx_expose_hook ( void win_ptr, int (*funct_ptr)(), void *param );
C
복사
win_ptr : 적용할 윈도우
(funct_ptr)() : 호출하고 싶은 함수 포인터
param : 필요한 매개변수를 저장하는데 사용
위 함수들과 비슷하지만 조금 더 범용적으로 사용가능한 mlx_hook함수가 있다.
int mlx_hook(void *win_ptr, int x_event, int x_mask, int (*funct)(), void *param);
C
복사
아래는 hooked 될 수 있는 MiniLibX 함수들입니다. X11/X.h의 일부 macro와 define이 요구됩니다.
int mlx_mouse_hide(); int mlx_mouse_show(); int mlx_mouse_move(void *win_ptr, int x, int y); int mlx_mouse_get_pos(void *win_ptr, int *x, int *y); int mlx_do_key_autorepeatoff(void *mlx_ptr); int mlx_do_key_autorepeaton(void *mlx_ptr); int mlx_do_sync(void *mlx_ptr);
C
복사
esc key : 53
맥 키코드 (code)

5) Events

6) Loops

7) Events

8) Loops

9) Images

10) Sync

11) Epilogue

12) Prototypes

3. Makefile 만들기

2서클 이후 과제들은 대부분 많은 양의 소스파일들을 가지고 있기 때문에 역할별로 디렉토리를 구별해 주는 것이 필요하다. 게다가 이번 과제는 컴파일을 하기위해 아래와 같이 엄청나게 긴 명령을 쳐야 하는데 매번 컴파일을 할때마다 이 라인을 칠 수는 없기 때문에 미리 Makefile을 만들어 보도록 하자!
gcc -Wextra -Werror -Wall -Lmlx -lmlx -framework OpenGL \ -framework Appkit $(SRCS) -o $(NAME)
Makefile
복사
혹시 Makefile에 대해 더 궁금하다면 여기를 참고하도록 하자. (클러스터 사파리에서는 문자가 깨지는 경우가 생겨서 크롬으로 여는 것을 추천)
# **************************************************************************** # # # # ::: :::::::: # # Makefile :+: :+: :+: # # +:+ +:+ +:+ # # By: suhshin <suhshin@student.42seoul.kr> +#+ +:+ +#+ # # +#+#+#+#+#+ +#+ # # Created: 2021/03/26 15:07:00 by suhshin #+# #+# # # Updated: 2021/03/26 15:52:35 by suhshin ### ########.fr # # # # **************************************************************************** # NAME = a.out SRCS = \ minirt.c # # # OBJS = $(SRCS:%.c=%.o) # # Compiler and flags # CC = clang CFLAGS = -Wall -Werror -Wextra CLIB = -Lmlx -lmlx -framework OpenGL -framework Appkit -Imlx # # Rules # all : $(NAME) %.o :%.c $(CC) $(CFLAGS) -c $< -o $@ $(NAME): $(OBJ) $(CC) $(CFLAGS) $(CLIB) $(SRCS) -o $(NAME) install_name_tool -change libmlx.dylib mlx/libmlx.dylib $(NAME) clean : rm -rf $(OBJS) fclean : clean rm -rf $(NAME) re : fclean all
C++
복사

4. asdf?

#include "minirt.h" void vec_print(t_vec *vec) { printf("[%.2f, %.2f, %.2f]", vec->x, vec->y, vec->z); } void vec_cross(t_vec *out, t_vec *v1, t_vec *v2) { out->x = v1->y * v2->z + v1->z * v2->y; out->y = v1->z * v2->x + v1->x * v2->z; out->z = v1->x * v2->y + v1->y * v2->x; } double vec_dot(t_vec *v1, t_vec *v2) { return (v1->x * v2->x + v1->y * v2->y + v1->z * v2->z); } double vec_length_squared(t_vec *vec) { return (vec->x * vec->x + vec->y * vec->y + vec->z * vec->z); } double vec_length(t_vec *vec) { double len; len = vec_length_squared(vec); len = sqrt(len); return (len); } void vec(t_vec *out, double x, double y, double z) { out->x = x; out->y = y; out->z = z; } void vec_unit(t_vec *out, t_vec *v) { double len; len = vec_length(v); vec(out, v->x / len ,v->y / len ,v->z / len); } void ray_at(t_vec *out, t_ray *ray, double t) { vec(out, ray->origin.x + ray->dir.x * t ,ray->origin.y + ray->dir.y * t ,ray->origin.z + ray->dir.z * t); } void vec_cal(t_vec *out, t_vec *v, double *a, int n) { vec(out, 0, 0, 0); while (n--) { out->x += v[n].x * a[n]; out->y += v[n].y * a[n]; out->z += v[n].z * a[n]; } }
C++
복사

Reference

MiniLibX
42Docs
42seoul Cadet (docs 번역 등)
mlx 정리 잘 되어 있는 곳
mlx mouse event
x11 header