본문 바로가기

컴퓨터 그래픽스

[파이썬을 이용한 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'):
        viewPoint = np.array(c.findtext('viewPoint').split()).astype(np.float)
        viewDir = np.array(c.findtext('viewDir').split()).astype(np.float)
        if (c.findtext('projNormal')):
            viewProjNormal = np.array(c.findtext('projNormal').split()).astype(np.float)
        viewUp = np.array(c.findtext('viewUp').split()).astype(np.float)
        if (c.findtext('projDistance')):
            projDistance = np.array(c.findtext('projDistance').split()).astype(np.float)
        viewWidth = np.array(c.findtext('viewWidth').split()).astype(np.float)
        viewHeight = np.array(c.findtext('viewHeight').split()).astype(np.float)
 
    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):
        return (np.clip(self.color, 01* 255).astype(np.uint8)

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로 넣어주었습니다. 매번 계산하게되면 속도 지연이 일어나기 때문입니다.