본문 바로가기

컴퓨터 그래픽스

[파이썬을 이용한 Ray Tracing 구현] 4. ray vector 구하기와 intersect 판정

ray vector는 half line을 사용하여 구현하였습니다. 시작점인 viewpoint를 p라고 하고, view direction을 d라고 하였을 때 ray vector r(t) = p + t*d로 나타낼 수 있습니다. 이 때 구해야 할 값은 t값이 됩니다. t값을 구하기에 앞서 먼저 각 픽셀별로 view direction을 구해주어야 합니다. view direction을 구하기 위해서는 pixel-to-image mapping 방법을 사용해 주었습니다. 

 

u = l + (r-l)(i+0.5)/n_x

v = b + (t-b)(j+0.5)/n_y

 

위는 pixel-to-image mapping 방법에 대한 이해를 도와주는 그림입니다. 주어진 직사각형이 image plane이 되고 우리는 그 image plane 속의 픽셀에 각각 ray vector를 만들어 주어야 합니다. 좌표를 이용하는 방법 보다는 vector의 합을 이용하여 구하는 것이 편리합니다. 

 

먼저 image plane의 중점으로 가는 vector w는 normal vector를 사용하여 구하였습니다. 그 후  u벡터와 v벡터를 view up vector를 사용하여 구해주었습니다. 

 

1
2
3
= view.viewDir

그리고 이 벡터들을 이용하여 (0,0)의 위치로 가는 start vector를 구해주었고 이중 for문을 돌며 image plane의 width와 height을 픽셀 수로 나누어준 길이 즉 픽셀 하나의 가로 세로 크기만큼 더해주며 픽셀별 ray vector를 구해주었습니다.

 

1
2
3
4
5
 for x in np.arange(imgSize[0]):
        for y in np.arange(imgSize[1]):
            ray = start + u_unit * x * pixel_x + pixel_y * y * v_unit
            tmp = raytrace(list, ray, view.viewPoint)
            img[y][x] = shade(tmp[0], ray, view, list, tmp[1], light)

이렇게 구해준 ray vector를 raytrace에 인자로 넘겨주어 도형 list를 돌며 결과값을 반환해주었습니다. 이 결과값은 추후에 설명하겠습니다.

 

raytrace 함수에서는 어떤 도형이 가장 view point와 가까운지와 그 도형과의 거리를 return합니다. 가장 가까운지 판별하는 방법은 sphere와 box가 다른 방법을 사용하고 있습니다. 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
    for i in list:
        if i.__class__.__name__ == 'Sphere':
 
            a = np.sum(ray * ray)
            b = np.sum((viewPoint - i.c) * ray)
            c = np.sum((viewPoint - i.c) ** 2- i.r ** 2
 
            if b ** 2 - a * c >= 0:
                if -+ np.sqrt(b ** 2 - a * c) >= 0:
                    if m >= (-+ np.sqrt(b ** 2 - a * c)) / a:
                        m = (-+ np.sqrt(b ** 2 - a * c)) / a
                        idx = cnt
 
                if -- np.sqrt(b ** 2 - a * c) >= 0:
                    if m >= (-- np.sqrt(b ** 2 - a * c)) / a:
                        m = (-- np.sqrt(b ** 2 - a * c)) / a
                        idx = cnt
 
        elif i.__class__.__name__ == 'Box':
            result = 1
 
            txmin = (i.minPt[0]-viewPoint[0])/ray[0]
            txmax = (i.maxPt[0]-viewPoint[0])/ray[0]
 
            if txmin > txmax:
                txmin, txmax = txmax, txmin
 
            tymin = (i.minPt[1]-viewPoint[1])/ray[1]
            tymax = (i.maxPt[1]-viewPoint[1])/ray[1]
 
            if tymin > tymax:
                tymin, tymax = tymax, tymin
 
            if txmin > tymax or tymin > txmax:
                result = 0
 
            if tymin > txmin:
                txmin = tymin
            if tymax < txmax:
                txmax = tymax
 
            tzmin = (i.minPt[2]-viewPoint[2])/ray[2]
            tzmax = (i.maxPt[2]-viewPoint[2])/ray[2]
 
            if tzmin > tzmax:
                tzmin, tzmax = tzmax, tzmin
 
            if txmin > tzmax or tzmin > txmax:
                result = 0
 
            if tzmin >= txmin:
                txmin = tzmin
            if tzmax < txmax:
                txmax = tzmax
 
            if result == 1:
                if m >= txmin:
                    m = txmin
                    idx = cnt
 
        cnt = cnt + 1
 

intersect 거리를 구하는 방법은 다음 두 페이지를 참조하였습니다.

 

https://pjreddie.com/media/files/Redmon_Thesis.pdf

https://www.scratchapixel.com/lessons/3d-basic-rendering/minimal-ray-tracer-rendering-simple-shapes/ray-box-intersection

 

A Minimal Ray-Tracer: Rendering Simple Shapes (Sphere, Cube, Disk, Plane, etc.) (Ray-Box Intersection)

A Minimal Ray-Tracer: Rendering Simple Shapes (Sphere, Cube, Disk, Plane, etc.)Ray-Box Intersection Figure 1: equation of a line. The equation of a line can be written as y=mx+b. For the oblique line which equation is y=x-1 we have m=1 and b=-1. In the fol

www.scratchapixel.com