[파이썬을 이용한 Ray Tracing 구현] 3. xml 파싱 및 클래스 생성
그림으로 나타내기 위한 정보들을 xml을 통해 넘겨받았습니다. xml에는 camera, image, shader, surface, light에 관한 정보들이 들어있습니다.
다음은 하나의 구를 저장하는 xml의 예시입니다.
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
|
<?xml version="1.0" encoding="UTF-8" ?>
<!-- Test scene with a single sphere.
-->
<scene>
<camera>
<viewPoint>5 4 3</viewPoint>
<viewDir>-5 -4 -3</viewDir>
<projNormal>5 4 3</projNormal>
<viewUp>0 1 0</viewUp>
<projDistance>5</projDistance>
<viewWidth>2.5</viewWidth>
<viewHeight>2.5</viewHeight>
</camera>
<image>
300 300
</image>
<shader name="blue" type="Phong">
<diffuseColor>.2 .3 .8</diffuseColor>
<specularColor>1 1 0</specularColor>
<exponent>50</exponent>
</shader>
<surface type="Sphere">
<shader ref="blue" />
<!--shader type="ShowNormal"/-->
<center>0 0 0</center>
<radius>1</radius>
</surface>
<light>
<position>3 4 5</position>
<intensity>1 1 1</intensity>
</light>
</scene>
|
cs |
xml parsing을 쉽게 하기 위해 ElementTree를 사용해보았습니다. 우리에게 필요한 객체 중 하나인 camera를 생성해보았습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
|
for c in root.findall('camera'):
if (c.findtext('projNormal')):
if (c.findtext('projDistance')):
view = View(viewPoint, viewDir, viewUp, viewProjNormal, viewWidth, viewHeight, projDistance, intensity)
|
미리 저장 받은 root에서 camera에 관련된 정보를 모두 찾습니다. findall과 findtext를 적절히 사용하여 view 객체를 생성할 수 있습니다. camera와 마찬가지로 surface별로 객체를 생성해주었습니다. surface 객체는 Sphere와 Box 객체로 나누어 list에 한번에 저장해주었습니다. 이 때 주의해주어야 할 점은 shader의 개수와 surface의 개수가 같지 않다는 점 입니다. 다른 surface더라도 shader를 공유할 수 있으니 큰 for문에서 surface를 지정해주고 그 surface에 맞는 shader를 찾아주었습니다. xml안의 ref는 tag를 통해 접근할 수 있습니다. light에 관한 정보도 클래스로 만들어 list로 관리해주었습니다.
사용한 클래스의 형태는 다음과 같습니다. 먼저 색상을 정하기 위한 color class가 있습니다.
1
2
3
4
5
6
7
8
9
10
|
class Color:
def __init__(self, R, G, B):
def gammaCorrect(self, gamma):
inverseGamma = 1.0 / gamma;
def toUINT8(self):
|
gammaCorrection을 제공합니다. 기본값으로 쓰이는 2.2를 나중에 넣어서 이미지를 저장해주었습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
class Shader:
def __init__(self, type):
self.t = type
class ShaderPhong(Shader):
def __init__(self, diffuse, specular, exponent):
self.d = diffuse
self.s = specular
self.e = exponent
class ShaderLambertian(Shader):
def __init__(self, diffuse):
self.d = diffuse
|
shader 클래스는 상속을 사용하여 만들어보았습니다. sphere와 box 모두 shader를 갖지만 그 shader가 phong일지 lambertian일지 정해지지 않았습니다. 그래서 상속 구조를 사용하였고, 클래스 내 함수는 따로 존재하지 않습니다.
나머지 클래스들은 모두 기본변수만 갖는 클래스로 구성하였습니다. box 클래스는 parsing 과정에서 미리 normal vector를 구하여 list로 넣어주었습니다. 매번 계산하게되면 속도 지연이 일어나기 때문입니다.