우리는 3차원 공간을 구현할 때에 점의 위치, 방향을 수학적으로 계산하기 위해 벡터를 사용할 것이다. 벡터를 이용하면 여러가지 도형, 빛의 위치, 방향을 쉽게 다룰 수 있다. 따라서 벡터의 개념을 잘 이해하지 못했다면 벡터에 대해 간단하게 공부를 하고 오기 바란다. 벡터 공부
write_color함수 만들기.
3차원 벡터 구조체 만들기.
3차원 벡터 유틸리티 함수 만들기.
우리가 만들 레이 트레이서 프로그램은 3차원 유클리드 좌표계(익히 알고 있는 x, y, z 3축으로 된 좌표계)를 사용할 것이다..
이번 단원에서는 우리가 생성하게 될 카메라, 광선, 구체 등의 점, 벡터, 색상 정보를 저장하기 위한 3차원 벡터 구조체를 만들고 벡터 연산을 위한 유틸리티 함수 세트를 만들 것이다.
#ifndef PRINT_H
# define PRINT_H
# include "stdio.h"
# include "structures.h"
void write_color(t_color3 pixel_color);
#endif
Code1 : [/include/print.h]
ppm에 color를 출력하는 함수를 넣어줬다.
#include "print.h"
// [0,1] 로 되어있는 rgb 값을 각각 [0,255]에 맵핑 해서 출력.
void write_color(t_color3 pixel_color)
{
printf("%d %d %d\n", (int)(255.999 * pixel_color.x),
(int)(255.999 * pixel_color.y),
(int)(255.999 * pixel_color.z));
}
Code2 : [/src/print/print.c]
rgb값을 출력하는 함수.
#include <stdio.h>
/* * * * 추가 * * * */
#include "structures.h"
#include "utils.h"
#include "print.h"
/* * * * 추가 끝 * * * */
int main(void)
{
int i;
int j;
/* * * * 수정 * * * */
t_color3 pixel_color;
/* * * * 수정 끝 * * * */
...
while (i < canvas_width)
{
/* * * * 수정 * * * */
pixel_color.x = (double)i / (canvas_width - 1);
pixel_color.y = (double)j / (canvas_height - 1);
pixel_color.z = 0.25;
write_color(pixel_color);
/* * * * 수정 끝 * * * */
++i;
}
...
Code3 : [/src/main.c]
rgb값을 출력하는 함수를 아래에 write_color함수로 따로 만들었기 때문에 변수 rgb값을 출력하는 부분을 제거해줬다.
#ifndef STRUCTURES_H
# define STRUCTURES_H
typedef struct s_vec3 t_vec3;
typedef struct s_vec3 t_point3;
typedef struct s_vec3 t_color3;
struct s_vec3
{
double x;
double y;
double z;
};
#endif
Code4 : [/include/structures.h]
구조체는 모두 structure.h에 넣기로 약속하고 벡터가 아닌 점의 위치, color 또한 세개의 변수가 필요하기 때문에 같은 t_vec3 구조체에 이름만 t_point3, t_color3로 정해두었다.
#ifndef UTILS_H
# define UTILS_H
# include <math.h>
# include <stdlib.h>
# include <stdio.h>
# include "structures.h"
t_vec3 vec3(double x, double y, double z);
t_point3 point3(double x, double y, double z);
t_point3 color3(double r, double g, double b);
void vset(t_vec3 *vec, double x, double y, double z);
double vlength2(t_vec3 vec);
double vlength(t_vec3 vec);
t_vec3 vplus(t_vec3 vec, t_vec3 vec2);
t_vec3 vplus_(t_vec3 vec, double x, double y, double z);
t_vec3 vminus(t_vec3 vec, t_vec3 vec2);
t_vec3 vminus_(t_vec3 vec, double x, double y, double z);
t_vec3 vmult(t_vec3 vec, double t);
t_vec3 vmult_(t_vec3 vec, t_vec3 vec2);
t_vec3 vdivide(t_vec3 vec, double t);
double vdot(t_vec3 vec, t_vec3 vec2);
t_vec3 vcross(t_vec3 vec, t_vec3 vec2);
t_vec3 vunit(t_vec3 vec);
t_vec3 vmin(t_vec3 vec1, t_vec3 vec2);
#endif
Code5 : [/include/utils.h]
우리가 만든 벡터구조체에 대한 연산 방법이 정해져있지 않기 때문에 연산함수를 구현해야 한다.
#include "utils.h"
//벡터3 생성자
t_vec3 vec3(double x, double y, double z)
{
t_vec3 vec;
vec.x = x;
vec.y = y;
vec.z = z;
return (vec);
}
//포인트3 생성자
t_point3 point3(double x, double y, double z)
{
t_point3 point;
point.x = x;
point.y = y;
point.z = z;
return (point);
}
//색상3 생성자
t_point3 color3(double r, double g, double b)
{
t_color3 color;
color.x = r;
color.y = g;
color.z = b;
return (color);
}
// 벡터 값 설정
void vset(t_vec3 *vec, double x, double y, double z)
{
vec->x = x;
vec->y = y;
vec->z = z;
}
// 벡터 길이 제곱
double vlength2(t_vec3 vec)
{
return (vec.x * vec.x + vec.y * vec.y + vec.z * vec.z);
}
// 벡터 길이
double vlength(t_vec3 vec)
{
return (sqrt(vlength2(vec)));
}
// 벡터합
t_vec3 vplus(t_vec3 vec, t_vec3 vec2)
{
vec.x += vec2.x;
vec.y += vec2.y;
vec.z += vec2.z;
return (vec);
}
// 벡터합2
t_vec3 vplus_(t_vec3 vec, double x, double y, double z)
{
vec.x += x;
vec.y += y;
vec.z += z;
return (vec);
}
// 벡터차
t_vec3 vminus(t_vec3 vec, t_vec3 vec2)
{
vec.x -= vec2.x;
vec.y -= vec2.y;
vec.z -= vec2.z;
return (vec);
}
t_vec3 vminus_(t_vec3 vec, double x, double y, double z)
{
vec.x -= x;
vec.y -= y;
vec.z -= z;
return (vec);
}
// 벡터 * 스칼라 곱연산
t_vec3 vmult(t_vec3 vec, double t)
{
vec.x *= t;
vec.y *= t;
vec.z *= t;
return (vec);
}
// 벡터 축 값끼리 곱연산
t_vec3 vmult_(t_vec3 vec, t_vec3 vec2)
{
vec.x *= vec2.x;
vec.y *= vec2.y;
vec.z *= vec2.z;
return (vec);
}
// 벡터 스칼라 나누기
t_vec3 vdivide(t_vec3 vec, double t)
{
vec.x *= 1 / t;
vec.y *= 1 / t;
vec.z *= 1 / t;
return vec;
}
// 벡터 내적
double vdot(t_vec3 vec, t_vec3 vec2)
{
return (vec.x * vec2.x + vec.y * vec2.y + vec.z * vec2.z);
}
// 벡터 외적
t_vec3 vcross(t_vec3 vec, t_vec3 vec2)
{
t_vec3 new;
new.x = vec.y * vec2.z - vec.z * vec2.y;
new.y = vec.z * vec2.x - vec.x * vec2.z;
new.z = vec.x * vec2.y - vec.y * vec2.x;
return (new);
}
// 단위 벡터
t_vec3 vunit(t_vec3 vec)
{
double len = vlength(vec);
if (len == 0)
{
printf("Error\n:Devider is 0");
exit(0);
}
vec.x /= len;
vec.y /= len;
vec.z /= len;
return (vec);
}
// 두 벡터의 원소를 비교하여 작은 값들만 반환
t_vec3 vmin(t_vec3 vec1, t_vec3 vec2)
{
if (vec1.x > vec2.x)
vec1.x = vec2.x;
if (vec1.y > vec2.y)
vec1.y = vec2.y;
if (vec1.z > vec2.z)
vec1.z = vec2.z;
return (vec1);
}
Code6 : [/src/utils/vec3_utils.c]
각 벡터연산의 개념은 벡터의 개념에 대해 이해하면 쉽게 이해할 것이라 믿는다. 여기서 vec3, color3, point3는 같아보이지만 개념적으로 다르다고 생각했기에 다른이름으로 분류해두었다. 단위벡터는 길이가 1인 벡터를 의미하는데 이는 방향벡터를 다룰 때에 편리하기 때문에 사용한다.