[miniRT] #8 Object 구조체

sham·2022년 3월 31일
0

[miniRT]

목록 보기
8/19

역시 실습 자료와 동일하다. 원본 자료를 찾아보는 걸 추천한다.

현재 코드에서는 하나의 물체만 배치한 채 렌더링하고 있지만, 이제는 여러 물체를 배치해서 광선을 쏘고 가장 먼저 마추진 물체에 대해서 렌더링을 해주어야 한다.

여러가지 물체들을 배치하고 연결리스트로 하나하나 훑어가며 감지를 체크해보자.

구조체 생성

코드

ray_color.c

//광선이 최종적으로 얻게된 픽셀의 색상 값을 리턴.
t_color3    ray_color(t_ray *ray, t_object *world)
{
    t_hit_record    rec;

    rec.tmin = 0;
    rec.tmax = MAX;

    if (hit(world, ray, &rec)) // 모든 구조체에 대한 정보를 담은 연결리스트 world로 광선과의 충돌을 테스트한다.
        return (vmult(vplus(rec.normal, color3(1, 1, 1)), 0.5));
    else
    {
        // (1-t) * 흰색 + t * 하늘색
            return (color3(0.5, 0.5, 0.5));
    }
}

hit.c

#include "trace.h"

t_bool hit(t_object *world, t_ray *ray, t_hit_record *rec)
{
    t_bool  hit_anything;
    t_hit_record *temp_rec;

    temp_rec = rec;
    hit_anything = FALSE;
    while (world) // world->next로 훑어가며 등록된 구조체를 전부 체크함
    {
        if (hit_obj(world, ray, temp_rec))
        {
            hit_anything = TRUE;
            temp_rec->tmax = temp_rec->t;
            rec = temp_rec;
        }
        world = world->next;
    }
    return (hit_anything);
}

t_bool hit_obj(t_object *world, t_ray *ray, t_hit_record *rec)
{
    t_bool hit_result;

    hit_result = FALSE;
    if (world->type == SP)
        hit_result = hit_sphere(world, ray, rec);
    return (hit_result);
}

hit_sphere.c

#include "structures.h"
#include "utils.h"
#include "trace.h"

static void print_vec(t_vec3 vec3)
{
    printf ("x : %f, y : %f, z : %f\n", vec3.x, vec3.y, vec3.z);
}

t_bool      hit_sphere(t_object *world, t_ray *ray, t_hit_record *rec)
{
    t_sphere *sp = world->element;
    t_vec3  oc; // 0에서부터 벡터로 나타낸 구의 중심. 
    t_vec3 normal; // 법선 벡터, 표준 벡터가 아니다!

    //a, b, c는 각각 t에 관한 근의 공식 2차 방정식의 계수
    double  a;
		double  half_b;    // b가 half_b로
    double  c;
    double  discriminant; // 판별식
    double sqrtd;
    double root;

    oc = vminus(ray->orig, sp->center);
    a = vlength2(ray->dir);
    half_b = vdot(oc, ray->dir);
    c = vlength2(oc) - sp->radius2;
    discriminant = half_b * half_b - a * c;

    // printf ("a : %f, b: %f, c : %f, 판별식 : %f", a, half_b, c, discriminant);

    if (discriminant < 0) 
        return (FALSE);
    // 이 시점에서 판별식이 참이 나왔기에 근이 존재한다고 판단한다.

    sqrtd = sqrt(discriminant); // 판별식에 루트를 씌움.
    root = (-half_b - sqrtd) / a; // 근의 공식 해, 작은 근부터 고려.
    // 해당 광선과 교점까지의 거리 사이에 다른 물체가 있거나 너무 멀리 있는 경우를 체크
    if (root < rec->tmin || rec->tmax < root)
    {
        root = (-half_b + sqrtd) / a; // 큰 근 역시 tmin, tmax와의 비교
        if (root < rec->tmin || rec->tmax < root) //  큰 근조차 tmin보다 작다면 hit하지 않은 것이므로 FALSE를 반환.
        return (FALSE);
    }
    
    // 조건문을 통과 == 현재까지 해당 광선이 충돌한 물체 중 가장 가까운 물체임을 의미

    rec->t = root; // 광선의 원점과 교점까지의 거리를 rec에 저장한다.
    rec->p = ray_at(ray, root); // 교점의 좌표를 rec에 저장한다.
  
    normal = vminus(rec->p, sp->center); // 법선 벡터
    
    printf ("원의 중심 - 교점 -> 법선 벡터 : ");
    print_vec(normal);
    rec->normal = vdivide(normal, sp->radius);
    // 해당 교점의 법선 벡터를 정규화하는 함수.
    // 단위 백터를 구하려면 벡터의 각 요소를 벡터의 길이로 나누어주면 된다.
    // vunit을 써줄 필요까지 없이 반지름이 곧 벡터의 길이이자 스칼라이므로 반지름으로 나누면 표준벡터가 된다.
    printf ("정규화된 법선 벡터 : ");
    print_vec(rec->normal);
    printf ("표준 벡터 : %f %f\n", vlength(rec->normal), vlength(ray->dir));

    set_face_normal(ray, rec); // 카메라가 구의 안쪽에 있을 경우 광선과 법선은 같은 방향을 향하게 된다. 법선과 광선이 반대방향을 향햐도록 확인하는 함수를 추가했다.
    return (TRUE);
}

레퍼런스

(7) Raytracing One Weekend 식 이해하기! 4

mini_raytracing_in_c/07.object.md at main · GaepoMorningEagles/mini_raytracing_in_c

Surface Normals and Multiple Objects

profile
씨앗 개발자

0개의 댓글