├── .gitignore ├── README.md ├── TODO ├── build.sh ├── data ├── cone.obj ├── cornellBox.json ├── cube.obj ├── dragon.json ├── dragon.obj ├── dragon_low.obj ├── dragon_superlow.obj ├── earth.ppm ├── example_dumps.json ├── outScene.json ├── texture.json ├── torus.obj ├── transform.json ├── uvcube.obj ├── uvtorus.obj └── uvtorus2.obj ├── rayhs.cabal ├── src ├── Bitmap.hs ├── Color.hs ├── ColorMap.hs ├── Descriptors.hs ├── Geometry.hs ├── Image.hs ├── JSON.hs ├── KDTree.hs ├── Light.hs ├── Mat.hs ├── Material.hs ├── MaterialDescriptors.hs ├── Math.hs ├── Mesh.hs ├── Projection.hs ├── RandomSamples.hs ├── RayHs.hs ├── Scene.hs ├── Setup.hs ├── Transform.hs ├── Vec.hs └── test.hs ├── test.sh └── testAll.sh /.gitignore: -------------------------------------------------------------------------------- 1 | # emacs backup things 2 | *~ 3 | /**/*~ 4 | 5 | # Haskell intermediate things 6 | *.hi 7 | *.o 8 | 9 | # Output 10 | *.ppm 11 | 12 | # Build things 13 | dist/ 14 | rayhs -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # RayHs 2 | A raytracer written in Haskell 3 | 4 | RayHS is a raytracer written in Haskell, this project's goal is maily to learn Haskell with a practical application but the goal is also to implement a full-featured physicaly based renderer. 5 | The current implementation is a simple raytracer with support for basic shapes and triangle meshes. 6 | 7 | More details and screenshots can be found on the project page: http://www.orouiller.net/projects/ray-hs 8 | 9 | ## Building 10 | 11 | Building the project requires a Haskell compiler such as GHC. 12 | There are a few dependencies that can be installed via Cabal. 13 | 14 | cabal install --only-dependencies 15 | 16 | The project should build with cabal build but I provided a script build.sh with some additional compilation flags (until this is done in the cabal configuration...). 17 | 18 | There is an aditional script test.sh that builds the program, runs it and opens the output image. 19 | Currently only ppm file format is suported for output, these files can be opened by The Gimp for example. 20 | 21 | ## Usage 22 | 23 | The executable takes a filename as input. The parameter shoud point to a JSON file describing a rendering to perform. 24 | Examples of scenes can be found in the data folder. 25 | The path to the ouput ppm image can be specified as an option. 26 | 27 | ex: 28 | 29 | ./rayhs -ocornell.ppm data/cornellBox.json -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | -Mesh without normals, has uv? 2 | -Correct Projections 3 | -Allow camera and object transformations 4 | -Correct transmitted radiance 5 | -Multisampling 6 | -Texture loading 7 | -Texture antialiasing 8 | -ior modulate 9 | -kDTree 10 | 11 | -Transparent shadows 12 | -Glossy BRDFs 13 | -Path Tracing 14 | -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | ghc -isrc -O2 -funbox-strict-fields -threaded -rtsopts src/RayHs.hs -o rayhs 2 | -------------------------------------------------------------------------------- /data/cone.obj: -------------------------------------------------------------------------------- 1 | # Blender v2.73 (sub 0) OBJ File: '' 2 | # www.blender.org 3 | v 0.000000 -1.000000 -1.000000 4 | v 0.195090 -1.000000 -0.980785 5 | v 0.382683 -1.000000 -0.923880 6 | v 0.555570 -1.000000 -0.831470 7 | v 0.707107 -1.000000 -0.707107 8 | v 0.831470 -1.000000 -0.555570 9 | v 0.923880 -1.000000 -0.382683 10 | v 0.980785 -1.000000 -0.195090 11 | v 1.000000 -1.000000 -0.000000 12 | v 0.000000 1.000000 0.000000 13 | v 0.980785 -1.000000 0.195090 14 | v 0.923880 -1.000000 0.382683 15 | v 0.831470 -1.000000 0.555570 16 | v 0.707107 -1.000000 0.707107 17 | v 0.555570 -1.000000 0.831470 18 | v 0.382683 -1.000000 0.923880 19 | v 0.195090 -1.000000 0.980785 20 | v -0.000000 -1.000000 1.000000 21 | v -0.195091 -1.000000 0.980785 22 | v -0.382684 -1.000000 0.923879 23 | v -0.555571 -1.000000 0.831469 24 | v -0.707107 -1.000000 0.707106 25 | v -0.831470 -1.000000 0.555570 26 | v -0.923880 -1.000000 0.382683 27 | v -0.980785 -1.000000 0.195089 28 | v -1.000000 -1.000000 -0.000001 29 | v -0.980785 -1.000000 -0.195091 30 | v -0.923879 -1.000000 -0.382684 31 | v -0.831469 -1.000000 -0.555571 32 | v -0.707106 -1.000000 -0.707108 33 | v -0.555569 -1.000000 -0.831470 34 | v -0.382682 -1.000000 -0.923880 35 | v -0.195089 -1.000000 -0.980786 36 | vn -0.259900 0.445500 -0.856700 37 | vn 0.087800 0.445500 -0.891000 38 | vn -0.422000 0.445500 -0.789600 39 | vn -0.568000 0.445500 -0.692100 40 | vn -0.692100 0.445500 -0.568000 41 | vn -0.789600 0.445500 -0.422000 42 | vn -0.856700 0.445500 -0.259900 43 | vn -0.891000 0.445500 -0.087800 44 | vn -0.891000 0.445500 0.087800 45 | vn -0.856700 0.445500 0.259900 46 | vn -0.789600 0.445500 0.422000 47 | vn -0.692100 0.445500 0.568000 48 | vn -0.568000 0.445500 0.692100 49 | vn -0.422000 0.445500 0.789600 50 | vn -0.259900 0.445500 0.856700 51 | vn -0.087800 0.445500 0.891000 52 | vn 0.087800 0.445500 0.891000 53 | vn 0.259900 0.445500 0.856700 54 | vn 0.422000 0.445500 0.789600 55 | vn 0.568000 0.445500 0.692100 56 | vn 0.692100 0.445500 0.568000 57 | vn 0.789600 0.445500 0.422000 58 | vn 0.856700 0.445500 0.259900 59 | vn 0.891000 0.445500 0.087800 60 | vn 0.891000 0.445500 -0.087800 61 | vn 0.856700 0.445500 -0.259900 62 | vn 0.789600 0.445500 -0.422000 63 | vn 0.692100 0.445500 -0.568000 64 | vn 0.568000 0.445500 -0.692100 65 | vn 0.422000 0.445500 -0.789600 66 | vn -0.087800 0.445500 -0.891000 67 | vn 0.259900 0.445500 -0.856700 68 | vn 0.000000 -1.000000 0.000000 69 | f 32//1 10//1 33//1 70 | f 1//2 10//2 2//2 71 | f 31//3 10//3 32//3 72 | f 30//4 10//4 31//4 73 | f 29//5 10//5 30//5 74 | f 28//6 10//6 29//6 75 | f 27//7 10//7 28//7 76 | f 26//8 10//8 27//8 77 | f 25//9 10//9 26//9 78 | f 24//10 10//10 25//10 79 | f 23//11 10//11 24//11 80 | f 22//12 10//12 23//12 81 | f 21//13 10//13 22//13 82 | f 20//14 10//14 21//14 83 | f 19//15 10//15 20//15 84 | f 18//16 10//16 19//16 85 | f 17//17 10//17 18//17 86 | f 16//18 10//18 17//18 87 | f 15//19 10//19 16//19 88 | f 14//20 10//20 15//20 89 | f 13//21 10//21 14//21 90 | f 12//22 10//22 13//22 91 | f 11//23 10//23 12//23 92 | f 9//24 10//24 11//24 93 | f 8//25 10//25 9//25 94 | f 7//26 10//26 8//26 95 | f 6//27 10//27 7//27 96 | f 5//28 10//28 6//28 97 | f 4//29 10//29 5//29 98 | f 3//30 10//30 4//30 99 | f 33//31 10//31 1//31 100 | f 2//32 10//32 3//32 101 | f 1//33 9//33 11//33 102 | f 30//33 33//33 1//33 103 | f 30//33 31//33 32//33 104 | f 28//33 29//33 30//33 105 | f 26//33 27//33 28//33 106 | f 18//33 25//33 26//33 107 | f 22//33 23//33 24//33 108 | f 20//33 21//33 22//33 109 | f 18//33 19//33 20//33 110 | f 14//33 17//33 18//33 111 | f 17//33 15//33 16//33 112 | f 12//33 13//33 14//33 113 | f 1//33 11//33 12//33 114 | f 1//33 8//33 9//33 115 | f 5//33 6//33 7//33 116 | f 7//33 4//33 5//33 117 | f 4//33 2//33 3//33 118 | f 30//33 32//33 33//33 119 | f 26//33 28//33 30//33 120 | f 22//33 24//33 25//33 121 | f 25//33 20//33 22//33 122 | f 14//33 15//33 17//33 123 | f 18//33 12//33 14//33 124 | f 1//33 2//33 8//33 125 | f 7//33 2//33 4//33 126 | f 18//33 30//33 1//33 127 | f 18//33 20//33 25//33 128 | f 1//33 12//33 18//33 129 | f 8//33 2//33 7//33 130 | f 18//33 26//33 30//33 131 | -------------------------------------------------------------------------------- /data/cornellBox.json: -------------------------------------------------------------------------------- 1 | { 2 | "width":512, 3 | "height":512, 4 | "maxDepth":3, 5 | "camera":{ 6 | "position":{"x":0, "y":0, "z":-2}, 7 | "target":{"x":0, "y":0, "z":0}, 8 | "up":{"x":0, "y":1, "z":0}, 9 | "projection":{ 10 | "type":"perspective", 11 | "fovy":0.9272952180016123, 12 | "width":2, 13 | "height":2, 14 | "near": 0.1 15 | } 16 | }, 17 | "scene":{ 18 | "objects":[ 19 | { 20 | "material":{ 21 | "ior":1.9, 22 | "cd":{ 23 | "color":{ 24 | "g":0.0, 25 | "b":0.0, 26 | "r":1 27 | }, 28 | "type":"flat" 29 | }, 30 | "type":"plastic" 31 | }, 32 | "geometry":{ 33 | "radius":0.4, 34 | "center":{ 35 | "z":1, 36 | "x":0.5, 37 | "y":-0.6 38 | }, 39 | "type":"sphere" 40 | } 41 | }, 42 | { 43 | "material":{ 44 | "ior":0.1, 45 | "type":"mirror" 46 | }, 47 | "geometry":{ 48 | "radius":0.22, 49 | "center":{ 50 | "z":1.7, 51 | "x":0.7, 52 | "y":0.7 53 | }, 54 | "type":"sphere" 55 | } 56 | }, 57 | { 58 | "material":{ 59 | "cd":{ 60 | "color":{ 61 | "g":1, 62 | "b":0.0, 63 | "r":0.0 64 | }, 65 | "type":"flat" 66 | }, 67 | "type":"diffuse" 68 | }, 69 | "geometry":{ 70 | "radius":0.2, 71 | "center":{ 72 | "z":0.4, 73 | "x":-0.4, 74 | "y":-0.8 75 | }, 76 | "type":"sphere" 77 | } 78 | }, 79 | { 80 | "material":{ 81 | "ior":1.5, 82 | "type":"transparent" 83 | }, 84 | "geometry":{ 85 | "radius":0.2, 86 | "center":{ 87 | "z":0.3, 88 | "x":0.1, 89 | "y":-0.3 90 | }, 91 | "type":"sphere" 92 | } 93 | }, 94 | { 95 | "material":{ 96 | "ce":{ 97 | "g":1, 98 | "b":1, 99 | "r":1 100 | }, 101 | "type":"emmit" 102 | }, 103 | "geometry":{ 104 | "radius":0.1, 105 | "center":{ 106 | "z":0.2, 107 | "x":0.6, 108 | "y":-0.4 109 | }, 110 | "type":"sphere" 111 | } 112 | }, 113 | { 114 | "material":{ 115 | "cd":{ 116 | "color":{ 117 | "g":2, 118 | "b":2, 119 | "r":2 120 | }, 121 | "type":"flat" 122 | }, 123 | "type":"diffuse" 124 | }, 125 | "geometry":{ 126 | "normal":{ 127 | "z":-1, 128 | "x":0.0, 129 | "y":0.0 130 | }, 131 | "point":{ 132 | "z":2, 133 | "x":0.0, 134 | "y":0.0 135 | }, 136 | "type":"plane", 137 | "tangent":{ 138 | "z":0.0, 139 | "x":1, 140 | "y":0.0 141 | } 142 | } 143 | }, 144 | { 145 | "material":{ 146 | "cd":{ 147 | "color":{ 148 | "g":1, 149 | "b":0.0, 150 | "r":0.0 151 | }, 152 | "type":"flat" 153 | }, 154 | "type":"diffuse" 155 | }, 156 | "geometry":{ 157 | "normal":{ 158 | "z":0.0, 159 | "x":-1, 160 | "y":0.0 161 | }, 162 | "point":{ 163 | "z":0.0, 164 | "x":1, 165 | "y":0.0 166 | }, 167 | "type":"plane", 168 | "tangent":{ 169 | "z":0.0, 170 | "x":0.0, 171 | "y":1 172 | } 173 | } 174 | }, 175 | { 176 | "material":{ 177 | "cd":{ 178 | "color":{ 179 | "g":0.0, 180 | "b":0.0, 181 | "r":1 182 | }, 183 | "type":"flat" 184 | }, 185 | "type":"diffuse" 186 | }, 187 | "geometry":{ 188 | "normal":{ 189 | "z":0.0, 190 | "x":1, 191 | "y":0.0 192 | }, 193 | "point":{ 194 | "z":0.0, 195 | "x":-1, 196 | "y":0.0 197 | }, 198 | "type":"plane", 199 | "tangent":{ 200 | "z":0.0, 201 | "x":0.0, 202 | "y":1 203 | } 204 | } 205 | }, 206 | { 207 | "material":{ 208 | "cd":{ 209 | "color":{ 210 | "g":2, 211 | "b":2, 212 | "r":2 213 | }, 214 | "type":"flat" 215 | }, 216 | "type":"diffuse" 217 | }, 218 | "geometry":{ 219 | "normal":{ 220 | "z":0.0, 221 | "x":0.0, 222 | "y":-1 223 | }, 224 | "point":{ 225 | "z":0.0, 226 | "x":0.0, 227 | "y":1 228 | }, 229 | "type":"plane", 230 | "tangent":{ 231 | "z":1, 232 | "x":0.0, 233 | "y":0.0 234 | } 235 | } 236 | }, 237 | { 238 | "material":{ 239 | "ior":2, 240 | "cd":{ 241 | "color2":{ 242 | "g":2, 243 | "b":2, 244 | "r":2 245 | }, 246 | "size":0.25, 247 | "color1":{ 248 | "g":0.0, 249 | "b":0.0, 250 | "r":0.0 251 | }, 252 | "type":"checker" 253 | }, 254 | "type":"plastic" 255 | }, 256 | "geometry":{ 257 | "normal":{ 258 | "z":0.0, 259 | "x":0.0, 260 | "y":1 261 | }, 262 | "point":{ 263 | "z":0.0, 264 | "x":0.0, 265 | "y":-1 266 | }, 267 | "type":"plane", 268 | "tangent":{ 269 | "z":1, 270 | "x":0.0, 271 | "y":0.0 272 | } 273 | } 274 | }, 275 | { 276 | "material":{ 277 | "ior":1.9, 278 | "cd":{ 279 | "color":{ 280 | "g":1.5, 281 | "b":1.5, 282 | "r":1.5 283 | }, 284 | "type":"flat" 285 | }, 286 | "type":"plastic" 287 | }, 288 | "geometry":{ 289 | "type":"mesh", 290 | "transform":{ 291 | "type":"translate", 292 | "vector":{ 293 | "z":1.5, 294 | "x":-0.4, 295 | "y":-0.6 296 | } 297 | }, 298 | "fileName":"data/cube.obj" 299 | } 300 | }, 301 | { 302 | "material":{ 303 | "ior":1.7, 304 | "cd":{ 305 | "color":{ 306 | "g":1, 307 | "b":0.6, 308 | "r":1 309 | }, 310 | "type":"flat" 311 | }, 312 | "type":"plastic" 313 | }, 314 | "geometry":{ 315 | "type":"mesh", 316 | "transform":{ 317 | "type":"translate", 318 | "vector":{ 319 | "z":1.5, 320 | "x":-0.4, 321 | "y":0.15000000000000002 322 | } 323 | }, 324 | "fileName":"data/torus.obj" 325 | } 326 | } 327 | ], 328 | "lights":[ 329 | { 330 | "color":{ 331 | "g":200, 332 | "b":200, 333 | "r":200 334 | }, 335 | "radius":0.1, 336 | "type":"point", 337 | "position":{ 338 | "z":0.75, 339 | "x":0.0, 340 | "y":0.9 341 | } 342 | }, 343 | { 344 | "color":{ 345 | "g":50, 346 | "b":50, 347 | "r":50 348 | }, 349 | "radius":0.1, 350 | "type":"point", 351 | "position":{ 352 | "z":0.2, 353 | "x":0.6, 354 | "y":-0.4 355 | } 356 | } 357 | ] 358 | } 359 | } 360 | -------------------------------------------------------------------------------- /data/cube.obj: -------------------------------------------------------------------------------- 1 | # Blender v2.73 (sub 0) OBJ File: '' 2 | # www.blender.org 3 | v -0.539977 0.400000 -0.168596 4 | v -0.539977 -0.400000 -0.168596 5 | v -0.168596 -0.400000 0.539977 6 | v -0.168596 0.400000 0.539977 7 | v 0.168596 0.400000 -0.539977 8 | v 0.168596 -0.400000 -0.539977 9 | v 0.539977 -0.400000 0.168596 10 | v 0.539977 0.400000 0.168596 11 | vn -0.885700 0.000000 0.464200 12 | vn 0.885700 -0.000000 -0.464200 13 | vn -0.464200 -0.000000 -0.885700 14 | vn 0.000000 -1.000000 0.000000 15 | vn 0.464200 0.000000 0.885700 16 | vn 0.000000 1.000000 -0.000000 17 | s off 18 | f 2//1 3//1 4//1 19 | f 8//2 7//2 6//2 20 | f 5//3 6//3 2//3 21 | f 6//4 7//4 3//4 22 | f 3//5 7//5 8//5 23 | f 1//6 4//6 8//6 24 | f 1//1 2//1 4//1 25 | f 5//2 8//2 6//2 26 | f 1//3 5//3 2//3 27 | f 2//4 6//4 3//4 28 | f 4//5 3//5 8//5 29 | f 5//6 1//6 8//6 30 | -------------------------------------------------------------------------------- /data/dragon.json: -------------------------------------------------------------------------------- 1 | { 2 | "width": 512, 3 | "height": 512, 4 | "maxDepth": 3, 5 | "camera":{ 6 | "position":{"x":0, "y":0, "z":-2}, 7 | "target":{"x":0, "y":0, "z":0}, 8 | "up":{"x":0, "y":1, "z":0}, 9 | "projection":{ 10 | "type":"perspective", 11 | "fovy":0.9272952180016123, 12 | "width":2, 13 | "height":2, 14 | "near": 2 15 | } 16 | }, 17 | "scene":{ 18 | "objects":[ 19 | { 20 | "material":{ 21 | "ior":1.9, 22 | "cd":{ 23 | "color":{ 24 | "g":0.0, 25 | "b":0.0, 26 | "r":1 27 | }, 28 | "type":"flat" 29 | }, 30 | "type":"plastic" 31 | }, 32 | "geometry":{ 33 | "type":"mesh", 34 | "transform":{ 35 | "type":"translate", 36 | "vector":{ 37 | "z":0.5, 38 | "x":0.0, 39 | "y":-1 40 | } 41 | }, 42 | "fileName":"data/dragon_superlow.obj" 43 | } 44 | }, 45 | { 46 | "material":{ 47 | "cd":{ 48 | "color":{ 49 | "g":2, 50 | "b":2, 51 | "r":2 52 | }, 53 | "type":"flat" 54 | }, 55 | "type":"diffuse" 56 | }, 57 | "geometry":{ 58 | "normal":{ 59 | "z":-1, 60 | "x":0.0, 61 | "y":0.0 62 | }, 63 | "point":{ 64 | "z":2, 65 | "x":0.0, 66 | "y":0.0 67 | }, 68 | "type":"plane", 69 | "tangent":{ 70 | "z":0.0, 71 | "x":1, 72 | "y":0.0 73 | } 74 | } 75 | }, 76 | { 77 | "material":{ 78 | "cd":{ 79 | "color":{ 80 | "g":1, 81 | "b":0.0, 82 | "r":0.0 83 | }, 84 | "type":"flat" 85 | }, 86 | "type":"diffuse" 87 | }, 88 | "geometry":{ 89 | "normal":{ 90 | "z":0.0, 91 | "x":-1, 92 | "y":0.0 93 | }, 94 | "point":{ 95 | "z":0.0, 96 | "x":1, 97 | "y":0.0 98 | }, 99 | "type":"plane", 100 | "tangent":{ 101 | "z":0.0, 102 | "x":0.0, 103 | "y":1 104 | } 105 | } 106 | }, 107 | { 108 | "material":{ 109 | "cd":{ 110 | "color":{ 111 | "g":0.0, 112 | "b":0.0, 113 | "r":1 114 | }, 115 | "type":"flat" 116 | }, 117 | "type":"diffuse" 118 | }, 119 | "geometry":{ 120 | "normal":{ 121 | "z":0.0, 122 | "x":1, 123 | "y":0.0 124 | }, 125 | "point":{ 126 | "z":0.0, 127 | "x":-1, 128 | "y":0.0 129 | }, 130 | "type":"plane", 131 | "tangent":{ 132 | "z":0.0, 133 | "x":0.0, 134 | "y":1 135 | } 136 | } 137 | }, 138 | { 139 | "material":{ 140 | "cd":{ 141 | "color":{ 142 | "g":1.5, 143 | "b":1.5, 144 | "r":1.5 145 | }, 146 | "type":"flat" 147 | }, 148 | "type":"diffuse" 149 | }, 150 | "geometry":{ 151 | "normal":{ 152 | "z":0.0, 153 | "x":0.0, 154 | "y":-1 155 | }, 156 | "point":{ 157 | "z":0.0, 158 | "x":0.0, 159 | "y":1 160 | }, 161 | "type":"plane", 162 | "tangent":{ 163 | "z":1, 164 | "x":0.0, 165 | "y":0.0 166 | } 167 | } 168 | }, 169 | { 170 | "material":{ 171 | "ce":{ 172 | "g":1, 173 | "b":1, 174 | "r":1 175 | }, 176 | "type":"emmit" 177 | }, 178 | "geometry":{ 179 | "radius":0.1, 180 | "center":{ 181 | "z":-0.1, 182 | "x":0.4, 183 | "y":-0.1 184 | }, 185 | "type":"sphere" 186 | } 187 | }, 188 | { 189 | "material":{ 190 | "ce":{ 191 | "g":1, 192 | "b":1, 193 | "r":1 194 | }, 195 | "type":"emmit" 196 | }, 197 | "geometry":{ 198 | "radius":7.0e-2, 199 | "center":{ 200 | "z":0.12, 201 | "x":-0.5, 202 | "y":-0.2 203 | }, 204 | "type":"sphere" 205 | } 206 | }, 207 | { 208 | "material":{ 209 | "ior":2, 210 | "cd":{ 211 | "color2":{ 212 | "g":2, 213 | "b":2, 214 | "r":2 215 | }, 216 | "size":0.5, 217 | "color1":{ 218 | "g":0.0, 219 | "b":0.0, 220 | "r":0.0 221 | }, 222 | "type":"checker" 223 | }, 224 | "type":"plastic" 225 | }, 226 | "geometry":{ 227 | "normal":{ 228 | "z":0.0, 229 | "x":0.0, 230 | "y":1 231 | }, 232 | "point":{ 233 | "z":0.0, 234 | "x":0.0, 235 | "y":-1 236 | }, 237 | "type":"plane", 238 | "tangent":{ 239 | "z":1, 240 | "x":0.0, 241 | "y":0.0 242 | } 243 | } 244 | } 245 | ], 246 | "lights":[ 247 | { 248 | "color":{ 249 | "g":150, 250 | "b":150, 251 | "r":150 252 | }, 253 | "radius":0.1, 254 | "type":"point", 255 | "position":{ 256 | "z":0.75, 257 | "x":0.0, 258 | "y":0.9 259 | } 260 | }, 261 | { 262 | "color":{ 263 | "g":50, 264 | "b":50, 265 | "r":50 266 | }, 267 | "radius":0.1, 268 | "type":"point", 269 | "position":{ 270 | "z":0.12, 271 | "x":-0.5, 272 | "y":-0.2 273 | } 274 | }, 275 | { 276 | "color":{ 277 | "g":50, 278 | "b":50, 279 | "r":50 280 | }, 281 | "radius":0.1, 282 | "type":"point", 283 | "position":{ 284 | "z":-0.1, 285 | "x":0.4, 286 | "y":-0.1 287 | } 288 | } 289 | ] 290 | } 291 | } 292 | -------------------------------------------------------------------------------- /data/example_dumps.json: -------------------------------------------------------------------------------- 1 | 2 | "scene" : { 3 | "objects": [{ 4 | "geometry": { 5 | "type": "mesh", 6 | "fileName": "test", 7 | "translation": {"x": 1, "y": 0, "z": 0} 8 | }, 9 | "material": { 10 | "type": "mirror", 11 | "ior": 1 12 | } 13 | }], 14 | "lights": [{ 15 | "type": "point", 16 | "position": {"x": 1, "y": 0, "z": 0}, 17 | "color": { "r":1,"g":2,"b":3 }, 18 | "radius": 1 19 | }] 20 | } 21 | 22 | // One liner tests 23 | 24 | // ColorMap 25 | { "type": "flat", "color": { "r":1,"g":2,"b":3 } } 26 | { "type": "checker", "color1": { "r":1,"g":2,"b":3 }, "color2": { "r":1,"g":2,"b":3 }, "size": 10 } 27 | 28 | // Projection 29 | { "type": "perspective", "fovy": 0, "width": 2, "height": 2, "near": 0.1 } 30 | 31 | // Material 32 | { "type": "diffuse", "cd": { "type": "flat", "color": { "r":1,"g":2,"b":3 } } } 33 | { "type": "mirror", "ior": 1 } 34 | { "type": "plastic", "cd": { "type": "flat", "color": { "r":1,"g":2,"b":3 } }, "ior": 1 } 35 | { "type": "transparent", "ior": 1 } 36 | { "type": "emmit", "ce": { "r":1,"g":2,"b":3 } } 37 | 38 | // GeometryDesc 39 | { "type": "plane", "normal": {"x": 1, "y": 0, "z": 0}, "point": {"x": 1, "y": 0, "z": 0}, "tangent": {"x": 1, "y": 0, "z": 0}} 40 | { "type": "sphere", "center": {"x": 1, "y": 0, "z": 0}, "radius": 10 } 41 | { "type": "mesh", "fileName": "test", "translation": {"x": 1, "y": 0, "z": 0}} 42 | 43 | // ObjectDesc 44 | { "geometry": { "type": "mesh", "fileName": "test", "translation": {"x": 1, "y": 0, "z": 0}}, "material": { "type": "mirror", "ior": 1 } } 45 | 46 | // Light 47 | { "type": "directional", "direction": {"x": 1, "y": 0, "z": 0}, "color": { "r":1,"g":2,"b":3 } } 48 | { "type": "point", "position": {"x": 1, "y": 0, "z": 0}, "color": { "r":1,"g":2,"b":3 }, "radius": 1 } 49 | 50 | // SceneDesc 51 | { "objects": [{ "geometry": { "type": "mesh", "fileName": "test", "translation": {"x": 1, "y": 0, "z": 0}}, "material": { "type": "mirror", "ior": 1 } }], "lights": [{ "type": "point", "position": {"x": 1, "y": 0, "z": 0}, "color": { "r":1,"g":2,"b":3 }, "radius": 1 }] } -------------------------------------------------------------------------------- /data/outScene.json: -------------------------------------------------------------------------------- 1 | { 2 | "width":1280, 3 | "height":720, 4 | "maxDepth":3, 5 | "camera":{ 6 | "position":{"x":0, "y":1, "z":-1}, 7 | "target":{"x":0, "y":0, "z":1}, 8 | "up":{"x":0, "y":1, "z":0}, 9 | "projection":{ 10 | "type":"perspective", 11 | "fovy":0.9272952180016123, 12 | "width":2, 13 | "height":2, 14 | "near": 0.1 15 | } 16 | }, 17 | "scene":{ 18 | "objects":[ 19 | { 20 | "material":{ 21 | "ior":1.9, 22 | "cd":{ 23 | "color2":{ 24 | "g":1, 25 | "b":0.6, 26 | "r":1 27 | }, 28 | "size":0.2, 29 | "color1":{ 30 | "g":0.0, 31 | "b":0.0, 32 | "r":1 33 | }, 34 | "type":"checker" 35 | }, 36 | "type":"plastic" 37 | }, 38 | "geometry":{ 39 | "radius":0.4, 40 | "center":{ 41 | "z":3.2, 42 | "x":0.5, 43 | "y":-0.6 44 | }, 45 | "type":"sphere" 46 | } 47 | }, 48 | { 49 | "material":{ 50 | "ior":0.1, 51 | "type":"mirror" 52 | }, 53 | "geometry":{ 54 | "radius":0.4, 55 | "center":{ 56 | "z":3.3, 57 | "x":-0.7, 58 | "y":-0.6 59 | }, 60 | "type":"sphere" 61 | } 62 | }, 63 | { 64 | "material":{ 65 | "cd":{ 66 | "color":{ 67 | "g":1, 68 | "b":0.0, 69 | "r":0.0 70 | }, 71 | "type":"flat" 72 | }, 73 | "type":"diffuse" 74 | }, 75 | "geometry":{ 76 | "radius":0.2, 77 | "center":{ 78 | "z":2, 79 | "x":-0.1, 80 | "y":-0.8 81 | }, 82 | "type":"sphere" 83 | } 84 | }, 85 | { 86 | "material":{ 87 | "ce":{ 88 | "g":0.8, 89 | "b":0.8, 90 | "r":0.8 91 | }, 92 | "type":"emmit" 93 | }, 94 | "geometry":{ 95 | "radius":0.1, 96 | "center":{ 97 | "z":3, 98 | "x":0.0, 99 | "y":2 100 | }, 101 | "type":"sphere" 102 | } 103 | }, 104 | { 105 | "material":{ 106 | "ior":1.7, 107 | "cd":{ 108 | "color2":{ 109 | "g":1, 110 | "b":1, 111 | "r":1 112 | }, 113 | "size":2, 114 | "color1":{ 115 | "g":0.0, 116 | "b":0.0, 117 | "r":0.0 118 | }, 119 | "type":"checker" 120 | }, 121 | "type":"plastic" 122 | }, 123 | "geometry":{ 124 | "normal":{ 125 | "z":0.0, 126 | "x":0.0, 127 | "y":1 128 | }, 129 | "point":{ 130 | "z":0.0, 131 | "x":0.0, 132 | "y":-1 133 | }, 134 | "type":"plane", 135 | "tangent":{ 136 | "z":0.0, 137 | "x":1, 138 | "y":0.0 139 | } 140 | } 141 | }, 142 | { 143 | "material":{ 144 | "ior":1.9, 145 | "cd":{ 146 | "color":{ 147 | "g":1.5, 148 | "b":1.5, 149 | "r":1.5 150 | }, 151 | "type":"flat" 152 | }, 153 | "type":"plastic" 154 | }, 155 | "geometry":{ 156 | "type":"mesh", 157 | "fileName":"data/cube.obj", 158 | "transform":{ 159 | "type": "translate", 160 | "vector": { 161 | "z":4, 162 | "x":-2, 163 | "y":-0.6 164 | } 165 | } 166 | } 167 | }, 168 | { 169 | "material":{ 170 | "ior":1.7, 171 | "cd":{ 172 | "color":{ 173 | "g":1, 174 | "b":0.6, 175 | "r":1 176 | }, 177 | "type":"flat" 178 | }, 179 | "type":"plastic" 180 | }, 181 | "geometry":{ 182 | "type":"mesh", 183 | "fileName":"data/torus.obj", 184 | "transform":{ 185 | "type": "translate", 186 | "vector": { 187 | "z":4, 188 | "x":-2, 189 | "y":0.15000000000000002 190 | } 191 | } 192 | } 193 | }, 194 | { 195 | "material":{ 196 | "cd":{ 197 | "color2":{ 198 | "g":1, 199 | "b":1, 200 | "r":1 201 | }, 202 | "size":2, 203 | "color1":{ 204 | "g":0.0, 205 | "b":1, 206 | "r":0.0 207 | }, 208 | "type":"checker" 209 | }, 210 | "type":"diffuse" 211 | }, 212 | "geometry":{ 213 | "type":"mesh", 214 | "fileName":"data/uvtorus2.obj", 215 | "transform":{ 216 | "type": "sequence", 217 | "transforms":[ 218 | { 219 | "type": "rotateX", 220 | "angle": 2.7 221 | }, 222 | { 223 | "type": "rotateY", 224 | "angle": 1.2 225 | }, 226 | { 227 | "type": "translate", 228 | "vector": { 229 | "z":2.7, 230 | "x":0.1, 231 | "y":0.3 232 | } 233 | } 234 | ] 235 | } 236 | } 237 | } 238 | ], 239 | "lights":[ 240 | { 241 | "color":{ 242 | "g":1, 243 | "b":1, 244 | "r":1 245 | }, 246 | "direction":{ 247 | "z":-0.6337242505244779, 248 | "x":0.6337242505244779, 249 | "y":0.4436069753671345 250 | }, 251 | "type":"directional" 252 | }, 253 | { 254 | "color":{ 255 | "g":1000, 256 | "b":1000, 257 | "r":1000 258 | }, 259 | "radius":0.1, 260 | "type":"point", 261 | "position":{ 262 | "z":3, 263 | "x":0.0, 264 | "y":1.5 265 | } 266 | } 267 | ] 268 | } 269 | } 270 | -------------------------------------------------------------------------------- /data/texture.json: -------------------------------------------------------------------------------- 1 | { 2 | "width":512, 3 | "height":512, 4 | "maxDepth":3, 5 | "camera":{ 6 | "position":{"x":0, "y":0, "z":-2}, 7 | "target":{"x":0, "y":0, "z":0}, 8 | "up":{"x":0, "y":1, "z":0}, 9 | "projection":{ 10 | "type":"perspective", 11 | "fovy":0.9272952180016123, 12 | "width":2, 13 | "height":2, 14 | "near": 0.1 15 | } 16 | }, 17 | "scene":{ 18 | "objects":[ 19 | { 20 | "material":{ 21 | "cd":{ 22 | "fileName":"data/earth.ppm", 23 | "type":"texture" 24 | }, 25 | "type":"diffuse" 26 | }, 27 | "geometry":{ 28 | "radius":0.8, 29 | "center":{ 30 | "z":2, 31 | "x":-0.1, 32 | "y":-0.2 33 | }, 34 | "type":"sphere" 35 | } 36 | }, 37 | { 38 | "material":{ 39 | "ce":{ 40 | "g":0.8, 41 | "b":0.8, 42 | "r":0.8 43 | }, 44 | "type":"emmit" 45 | }, 46 | "geometry":{ 47 | "radius":0.1, 48 | "center":{ 49 | "z":3, 50 | "x":0.0, 51 | "y":2 52 | }, 53 | "type":"sphere" 54 | } 55 | }, 56 | { 57 | "material":{ 58 | "cd":{ 59 | "fileName": "data/checkerboard.ppm", 60 | "type":"texture" 61 | }, 62 | "type":"diffuse" 63 | }, 64 | "geometry":{ 65 | "normal":{ 66 | "z":0.0, 67 | "x":0.0, 68 | "y":1.0 69 | }, 70 | "point":{ 71 | "z":0.0, 72 | "x":0.0, 73 | "y":-1.0 74 | }, 75 | "type":"plane", 76 | "tangent":{ 77 | "z":0.0, 78 | "x":1, 79 | "y":0.0 80 | } 81 | } 82 | }, 83 | { 84 | "material":{ 85 | "cd":{ 86 | "type":"texture", 87 | "fileName":"data/tile.ppm" 88 | }, 89 | "type":"diffuse" 90 | }, 91 | "geometry":{ 92 | "type":"mesh", 93 | "fileName":"data/uvtorus.obj", 94 | "transform":{ 95 | "type":"translate", 96 | "vector":{ 97 | "z":0.5, 98 | "x":-0.4, 99 | "y":-1 100 | } 101 | } 102 | } 103 | } 104 | ], 105 | "lights":[ 106 | { 107 | "color":{ 108 | "g":4, 109 | "b":4, 110 | "r":4 111 | }, 112 | "direction":{ 113 | "z":-0.6337242505244779, 114 | "x":0.6337242505244779, 115 | "y":0.4436069753671345 116 | }, 117 | "type":"directional" 118 | }, 119 | { 120 | "color":{ 121 | "g":1000, 122 | "b":1000, 123 | "r":1000 124 | }, 125 | "radius":0.1, 126 | "type":"point", 127 | "position":{ 128 | "z":3, 129 | "x":0.0, 130 | "y":1.5 131 | } 132 | } 133 | ] 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /data/torus.obj: -------------------------------------------------------------------------------- 1 | #### 2 | # 3 | # OBJ File Generated by Meshlab 4 | # 5 | #### 6 | # Object torus.obj 7 | # 8 | # Vertices: 288 9 | # Faces: 576 10 | # 11 | #### 12 | vn 0.731283 -0.146177 0.666226 13 | v -0.146256 0.029236 -0.133245 14 | vn -0.644198 -0.081132 -0.760544 15 | v -0.257679 -0.032452 -0.304218 16 | vn -0.879629 -0.310735 -0.360133 17 | v -0.280968 -0.055898 -0.264375 18 | vn -0.879061 -0.456752 0.136489 19 | v -0.280755 -0.070888 -0.214829 20 | vn -0.643291 -0.480421 0.596131 21 | v -0.257098 -0.073405 -0.168857 22 | vn -0.235455 -0.375694 0.896334 23 | v -0.216335 -0.062775 -0.138775 24 | vn 0.235816 -0.170255 0.956767 25 | v -0.169389 -0.041846 -0.132645 26 | vn 0.644198 0.081132 0.760544 27 | v -0.128840 -0.016226 -0.152109 28 | vn 0.879630 0.310736 0.360132 29 | v -0.105551 0.007220 -0.191951 30 | vn 0.879061 0.456752 -0.136489 31 | v -0.105764 0.022209 -0.241497 32 | vn 0.643291 0.480421 -0.596131 33 | v -0.129421 0.024726 -0.287469 34 | vn 0.235455 0.375694 -0.896334 35 | v -0.170184 0.014097 -0.317551 36 | vn -0.235816 0.170255 -0.956767 37 | v -0.217129 -0.006832 -0.323682 38 | vn -0.513212 -0.302910 -0.803031 39 | v -0.205285 -0.121164 -0.321212 40 | vn -0.767111 -0.503037 -0.398113 41 | v -0.230329 -0.141638 -0.280800 42 | vn -0.815174 -0.568051 0.113177 43 | v -0.234909 -0.148510 -0.229700 44 | vn -0.645082 -0.481016 0.593711 45 | v -0.217802 -0.139938 -0.181603 46 | vn -0.302434 -0.265419 0.915471 47 | v -0.183588 -0.118219 -0.149397 48 | vn 0.121527 0.021459 0.992356 49 | v -0.141437 -0.089173 -0.141712 50 | vn 0.513211 0.302910 0.803031 51 | v -0.102642 -0.060582 -0.160606 52 | vn 0.767111 0.503037 0.398112 53 | v -0.077599 -0.040107 -0.201018 54 | vn 0.815174 0.568051 -0.113177 55 | v -0.073018 -0.033235 -0.252119 56 | vn 0.645082 0.481016 -0.593710 57 | v -0.090126 -0.041807 -0.300216 58 | vn 0.302434 0.265419 -0.915471 59 | v -0.124339 -0.063526 -0.332422 60 | vn -0.121527 -0.021459 -0.992356 61 | v -0.166490 -0.092573 -0.340107 62 | vn -0.624087 -0.677790 -0.388737 63 | v -0.166168 -0.219398 -0.276070 64 | vn -0.733418 -0.669605 0.117161 65 | v -0.176823 -0.218908 -0.225417 66 | vn -0.646415 -0.482266 0.591244 67 | v -0.168013 -0.200279 -0.177932 68 | vn -0.386486 -0.166021 0.907229 69 | v -0.142099 -0.168503 -0.146337 70 | vn -0.022813 0.194977 0.980542 71 | v -0.106021 -0.132095 -0.139100 72 | vn 0.347252 0.504046 0.790794 73 | v -0.069450 -0.100809 -0.158159 74 | vn 0.624088 0.677790 0.388736 75 | v -0.042184 -0.083029 -0.198407 76 | vn 0.733418 0.669605 -0.117161 77 | v -0.031527 -0.083519 -0.249060 78 | vn 0.646415 0.482266 -0.591244 79 | v -0.040337 -0.102148 -0.296545 80 | vn 0.386486 0.166021 -0.907229 81 | v -0.066253 -0.133924 -0.328139 82 | vn 0.022813 -0.194977 -0.980542 83 | v -0.102329 -0.170333 -0.335376 84 | vn -0.347252 -0.504046 -0.790794 85 | v -0.138900 -0.201618 -0.316317 86 | vn -0.460302 -0.823085 -0.332643 87 | v -0.092858 -0.283878 -0.250504 88 | vn -0.639367 -0.754490 0.148172 89 | v -0.110455 -0.277283 -0.202272 90 | vn -0.647196 -0.484084 0.588898 91 | v -0.111126 -0.250315 -0.158093 92 | vn -0.481886 -0.084274 0.872172 93 | v -0.094692 -0.210200 -0.129805 94 | vn -0.187370 0.338476 0.922132 95 | v -0.065556 -0.167687 -0.124989 96 | vn 0.157626 0.670832 0.724665 97 | v -0.031525 -0.134166 -0.144932 98 | vn 0.460303 0.823085 0.332644 99 | v -0.001718 -0.118621 -0.184295 100 | vn 0.639367 0.754490 -0.148172 101 | v 0.015879 -0.125216 -0.232527 102 | vn 0.647196 0.484084 -0.588898 103 | v 0.016550 -0.152184 -0.276706 104 | vn 0.481886 0.084274 -0.872172 105 | v 0.000117 -0.192299 -0.304994 106 | vn 0.187370 -0.338476 -0.922132 107 | v -0.029019 -0.234813 -0.309811 108 | vn -0.157626 -0.670832 -0.724665 109 | v -0.063050 -0.268333 -0.289866 110 | vn 0.042741 -0.791902 -0.609151 111 | v 0.017097 -0.316760 -0.243661 112 | vn -0.286920 -0.929021 -0.233656 113 | v -0.015395 -0.330684 -0.205846 114 | vn -0.539429 -0.816922 0.204095 115 | v -0.040326 -0.319658 -0.161842 116 | vn -0.647373 -0.486348 0.586833 117 | v -0.051015 -0.286636 -0.123439 118 | vn -0.582131 -0.025748 0.812687 119 | v -0.044600 -0.240467 -0.100927 120 | vn -0.360928 0.442175 0.821104 121 | v -0.022798 -0.193523 -0.100338 122 | vn -0.042742 0.791902 0.609151 123 | v 0.008549 -0.158380 -0.121830 124 | vn 0.286921 0.929021 0.233656 125 | v 0.041040 -0.144457 -0.159645 126 | vn 0.539429 0.816921 -0.204095 127 | v 0.065971 -0.155483 -0.203649 128 | vn 0.647373 0.486348 -0.586833 129 | v 0.076661 -0.188505 -0.242052 130 | vn 0.582131 0.025748 -0.812687 131 | v 0.070245 -0.234674 -0.264564 132 | vn 0.360928 -0.442175 -0.821104 133 | v 0.048443 -0.281618 -0.265153 134 | vn -0.115755 -0.988379 -0.098520 135 | v 0.060941 -0.356626 -0.145139 136 | vn -0.440414 -0.852647 0.281119 137 | v 0.028783 -0.343144 -0.106883 138 | vn -0.646936 -0.488903 0.585190 139 | v 0.008221 -0.306767 -0.076331 140 | vn -0.680390 0.005569 0.732829 141 | v 0.004764 -0.257243 -0.061671 142 | vn -0.531660 0.499008 0.684345 143 | v 0.019338 -0.207842 -0.066829 144 | vn -0.240196 0.859005 0.452125 145 | v 0.048039 -0.171801 -0.090425 146 | vn 0.115755 0.988379 0.098520 147 | v 0.083176 -0.158777 -0.126136 148 | vn 0.440414 0.852647 -0.281119 149 | v 0.115334 -0.172259 -0.164392 150 | vn 0.646936 0.488903 -0.585190 151 | v 0.135896 -0.208636 -0.194944 152 | vn 0.680390 -0.005569 -0.732829 153 | v 0.139354 -0.258159 -0.209604 154 | vn 0.531660 -0.499008 -0.684345 155 | v 0.124780 -0.307560 -0.204446 156 | vn 0.240195 -0.859005 -0.452124 157 | v 0.096078 -0.343602 -0.180850 158 | vn 0.041528 -0.997114 0.063555 159 | v 0.130950 -0.359937 -0.072521 160 | vn -0.349072 -0.859230 0.373996 161 | v 0.092163 -0.346141 -0.041140 162 | vn -0.645912 -0.491576 0.584081 163 | v 0.062546 -0.309336 -0.019980 164 | vn -0.769967 0.007542 0.638040 165 | v 0.050035 -0.259384 -0.014710 166 | vn -0.687932 0.505101 0.521175 167 | v 0.057981 -0.209670 -0.026745 168 | vn -0.421282 0.867568 0.264287 169 | v 0.084256 -0.173514 -0.052857 170 | vn -0.041528 0.997114 -0.063555 171 | v 0.121820 -0.160604 -0.086052 172 | vn 0.349072 0.859230 -0.373996 173 | v 0.160606 -0.174400 -0.117433 174 | vn 0.645912 0.491576 -0.584081 175 | v 0.190222 -0.211205 -0.138593 176 | vn 0.769967 -0.007542 -0.638040 177 | v 0.202734 -0.261156 -0.143862 178 | vn 0.687932 -0.505101 -0.521174 179 | v 0.194787 -0.310872 -0.131828 180 | vn 0.421281 -0.867568 -0.264287 181 | v 0.168512 -0.347028 -0.105715 182 | vn 0.174210 -0.954629 0.241524 183 | v 0.189858 -0.340390 0.007061 184 | vn -0.271626 -0.836223 0.476394 185 | v 0.145495 -0.328445 0.030907 186 | vn -0.644372 -0.494184 0.583582 187 | v 0.108259 -0.294168 0.041775 188 | vn -0.844756 -0.019965 0.534779 189 | v 0.088129 -0.246744 0.036751 190 | vn -0.819092 0.460041 0.342711 191 | v 0.090498 -0.198880 0.017183 192 | vn -0.573658 0.817008 0.058438 193 | v 0.114732 -0.163401 -0.011687 194 | vn -0.174210 0.954629 -0.241524 195 | v 0.154337 -0.149814 -0.042124 196 | vn 0.271626 0.836223 -0.476395 197 | v 0.198700 -0.161760 -0.065970 198 | vn 0.644371 0.494184 -0.583582 199 | v 0.235936 -0.196037 -0.076838 200 | vn 0.844756 0.019965 -0.534779 201 | v 0.256066 -0.243461 -0.071814 202 | vn 0.819092 -0.460041 -0.342711 203 | v 0.253697 -0.291324 -0.052246 204 | vn 0.573657 -0.817008 -0.058439 205 | v 0.229463 -0.326804 -0.023376 206 | vn 0.273249 -0.863822 0.423258 207 | v 0.233653 -0.299318 0.088182 208 | vn -0.213353 -0.785193 0.581338 209 | v 0.185144 -0.291261 0.104348 210 | vn -0.642421 -0.496549 0.583725 211 | v 0.142243 -0.262297 0.104724 212 | vn -0.899662 -0.075074 0.430084 213 | v 0.116449 -0.220185 0.089209 214 | vn -0.916203 0.366895 0.161119 215 | v 0.114672 -0.176210 0.061960 216 | vn -0.686939 0.710770 -0.151393 217 | v 0.137388 -0.142154 0.030278 218 | vn -0.273249 0.863822 -0.423258 219 | v 0.178510 -0.127144 0.002653 220 | vn 0.213353 0.785193 -0.581338 221 | v 0.227021 -0.135200 -0.013512 222 | vn 0.642420 0.496549 -0.583725 223 | v 0.269920 -0.164166 -0.013889 224 | vn 0.899662 0.075075 -0.430084 225 | v 0.295714 -0.206278 0.001626 226 | vn 0.916203 -0.366895 -0.161118 227 | v 0.297492 -0.250253 0.028875 228 | vn 0.686939 -0.710770 0.151393 229 | v 0.274776 -0.284308 0.060557 230 | vn 0.753408 -0.556095 0.350907 231 | v 0.301363 -0.222438 0.140363 232 | vn 0.331897 -0.730878 0.596374 233 | v 0.259351 -0.239521 0.165315 234 | vn -0.178227 -0.709617 0.681674 235 | v 0.208407 -0.237125 0.174178 236 | vn -0.640191 -0.498510 0.584503 237 | v 0.162184 -0.215894 0.164578 238 | vn -0.930942 -0.154032 0.331089 239 | v 0.133066 -0.181515 0.139087 240 | vn -0.972647 0.232014 -0.011228 241 | v 0.128856 -0.143202 0.104536 242 | vn -0.753408 0.556095 -0.350907 243 | v 0.150681 -0.111219 0.070181 244 | vn -0.331897 0.730878 -0.596374 245 | v 0.192695 -0.094136 0.045229 246 | vn 0.178227 0.709617 -0.681674 247 | v 0.243637 -0.096531 0.036366 248 | vn 0.640191 0.498510 -0.584503 249 | v 0.289861 -0.117762 0.045965 250 | vn 0.930942 0.154032 -0.331089 251 | v 0.318978 -0.152141 0.071456 252 | vn 0.972647 -0.232014 0.011229 253 | v 0.323188 -0.190455 0.106008 254 | vn 0.768532 -0.363523 0.526507 255 | v 0.307412 -0.145409 0.210603 256 | vn 0.346155 -0.564859 0.749074 257 | v 0.265197 -0.165071 0.233202 258 | vn -0.168639 -0.614647 0.770565 259 | v 0.213701 -0.169725 0.235638 260 | vn -0.637834 -0.499933 0.585861 261 | v 0.166722 -0.158122 0.217259 262 | vn -0.936466 -0.251459 0.244542 263 | v 0.136848 -0.133372 0.182987 264 | vn -0.984578 0.064589 -0.162586 265 | v 0.132084 -0.102107 0.142008 266 | vn -0.768532 0.363523 -0.526507 267 | v 0.153706 -0.072704 0.105301 268 | vn -0.346155 0.564859 -0.749074 269 | v 0.195922 -0.053042 0.082702 270 | vn 0.168639 0.614647 -0.770565 271 | v 0.247419 -0.048388 0.080266 272 | vn 0.637834 0.499933 -0.585861 273 | v 0.294398 -0.059991 0.098645 274 | vn 0.936466 0.251459 -0.244542 275 | v 0.324272 -0.084740 0.132916 276 | vn 0.984578 -0.064589 0.162586 277 | v 0.329036 -0.116006 0.173895 278 | vn 0.315053 -0.377078 0.870950 279 | v 0.250797 -0.081045 0.287218 280 | vn -0.185243 -0.506755 0.841953 281 | v 0.200664 -0.093654 0.284540 282 | vn -0.635513 -0.500723 0.587707 283 | v 0.155546 -0.092919 0.259174 284 | vn -0.915856 -0.360712 0.176338 285 | v 0.127535 -0.079036 0.217917 286 | vn -0.951183 -0.123971 -0.282637 287 | v 0.124135 -0.055727 0.171825 288 | vn -0.731283 0.146177 -0.666226 289 | v 0.146256 -0.029236 0.133245 290 | vn -0.315052 0.377078 -0.870950 291 | v 0.187973 -0.006661 0.112518 292 | vn 0.185244 0.506755 -0.841953 293 | v 0.238107 0.005948 0.115196 294 | vn 0.635513 0.500723 -0.587707 295 | v 0.283223 0.005212 0.140561 296 | vn 0.915856 0.360712 -0.176338 297 | v 0.311234 -0.008670 0.181818 298 | vn 0.951182 0.123971 0.282637 299 | v 0.314635 -0.031979 0.227911 300 | vn 0.731283 -0.146177 0.666226 301 | v 0.292513 -0.058471 0.266490 302 | vn 0.240710 -0.180334 0.953697 303 | v 0.217129 0.006832 0.323682 304 | vn -0.226910 -0.393292 0.890973 305 | v 0.170184 -0.014097 0.317551 306 | vn -0.633384 -0.500823 0.589916 307 | v 0.129421 -0.024726 0.287469 308 | vn -0.870517 -0.474348 0.131128 309 | v 0.105764 -0.022209 0.241497 310 | vn -0.874735 -0.320815 -0.363203 311 | v 0.105551 -0.007220 0.191951 312 | vn -0.644197 -0.081132 -0.760544 313 | v 0.128840 0.016226 0.152109 314 | vn -0.240709 0.180334 -0.953697 315 | v 0.169389 0.041846 0.132645 316 | vn 0.226910 0.393292 -0.890973 317 | v 0.216335 0.062775 0.138775 318 | vn 0.633384 0.500823 -0.589916 319 | v 0.257098 0.073405 0.168857 320 | vn 0.870516 0.474348 -0.131128 321 | v 0.280755 0.070888 0.214829 322 | vn 0.874735 0.320815 0.363203 323 | v 0.280968 0.055898 0.264375 324 | vn 0.644197 0.081131 0.760544 325 | v 0.257679 0.032452 0.304218 326 | vn 0.513211 0.302910 0.803032 327 | v 0.205285 0.121164 0.321212 328 | vn 0.128192 0.011967 0.991677 329 | v 0.166490 0.092573 0.340107 330 | vn -0.290797 -0.281991 0.914285 331 | v 0.124339 0.063526 0.332422 332 | vn -0.631593 -0.500228 0.592336 333 | v 0.090126 0.041807 0.300216 334 | vn -0.803538 -0.584623 0.111991 335 | v 0.073018 0.033235 0.252119 336 | vn -0.760448 -0.512529 -0.398792 337 | v 0.077599 0.040107 0.201018 338 | vn -0.513211 -0.302910 -0.803031 339 | v 0.102642 0.060582 0.160606 340 | vn -0.128192 -0.011967 -0.991677 341 | v 0.141437 0.089173 0.141712 342 | vn 0.290797 0.281991 -0.914285 343 | v 0.183588 0.118219 0.149397 344 | vn 0.631593 0.500228 -0.592336 345 | v 0.217802 0.139938 0.181603 346 | vn 0.803538 0.584623 -0.111991 347 | v 0.234909 0.148510 0.229700 348 | vn 0.760447 0.512529 0.398791 349 | v 0.230327 0.141638 0.280801 350 | vn 0.347251 0.504045 0.790794 351 | v 0.138900 0.201618 0.316317 352 | vn -0.014833 0.186720 0.982301 353 | v 0.102329 0.170333 0.335376 354 | vn -0.372552 -0.180439 0.910300 355 | v 0.066253 0.133924 0.328139 356 | vn -0.630260 -0.498980 0.594804 357 | v 0.040337 0.102148 0.296545 358 | vn -0.719485 -0.684021 0.120232 359 | v 0.031527 0.083519 0.249060 360 | vn -0.616106 -0.686047 -0.386978 361 | v 0.042184 0.083029 0.198407 362 | vn -0.347251 -0.504045 -0.790794 363 | v 0.069450 0.100810 0.158158 364 | vn 0.014833 -0.186720 -0.982301 365 | v 0.106021 0.132095 0.139100 366 | vn 0.372552 0.180439 -0.910300 367 | v 0.142099 0.168503 0.146337 368 | vn 0.630260 0.498980 -0.594804 369 | v 0.168013 0.200279 0.177932 370 | vn 0.719485 0.684021 -0.120232 371 | v 0.176823 0.218908 0.225417 372 | vn 0.616106 0.686047 0.386978 373 | v 0.166168 0.219398 0.276070 374 | vn -0.178617 0.332016 0.926208 375 | v 0.029019 0.234813 0.309811 376 | vn -0.466604 -0.095554 0.879289 377 | v -0.000117 0.192299 0.304994 378 | vn -0.629479 -0.497161 0.597150 379 | v -0.016550 0.152184 0.276706 380 | vn -0.624085 -0.765769 0.155290 381 | v -0.015879 0.125216 0.232527 382 | vn -0.451550 -0.829546 -0.328567 383 | v 0.001718 0.118621 0.184295 384 | vn -0.157625 -0.670832 -0.724665 385 | v 0.031525 0.134166 0.144932 386 | vn 0.178617 -0.332016 -0.926208 387 | v 0.065556 0.167687 0.124989 388 | vn 0.466604 0.095554 -0.879289 389 | v 0.094692 0.210200 0.129805 390 | vn 0.629479 0.497161 -0.597150 391 | v 0.111126 0.250315 0.158093 392 | vn 0.624085 0.765769 -0.155290 393 | v 0.110455 0.277283 0.202272 394 | vn 0.451550 0.829546 0.328567 395 | v 0.092858 0.283878 0.250504 396 | vn 0.157625 0.670832 0.724665 397 | v 0.063050 0.268333 0.289866 398 | vn -0.352000 0.437952 0.827221 399 | v -0.048443 0.281618 0.265153 400 | vn -0.566543 -0.033121 0.823367 401 | v -0.070245 0.234674 0.264564 402 | vn -0.629301 -0.494896 0.599214 403 | v -0.076661 0.188505 0.242052 404 | vn -0.523840 -0.824296 0.214775 405 | v -0.065971 0.155483 0.203649 406 | vn -0.277992 -0.933245 -0.227539 407 | v -0.041040 0.144457 0.159645 408 | vn 0.042742 -0.791901 -0.609151 409 | v -0.008549 0.158380 0.121830 410 | vn 0.352000 -0.437952 -0.827221 411 | v 0.022798 0.193523 0.100338 412 | vn 0.566543 0.033121 -0.823367 413 | v 0.044600 0.240467 0.100927 414 | vn 0.629301 0.494896 -0.599214 415 | v 0.051015 0.286636 0.123439 416 | vn 0.523840 0.824296 -0.214775 417 | v 0.040326 0.319658 0.161842 418 | vn 0.277992 0.933245 0.227539 419 | v 0.015395 0.330684 0.205846 420 | vn -0.042742 0.791901 0.609152 421 | v -0.017097 0.316760 0.243661 422 | vn -0.240196 0.859005 0.452125 423 | v -0.096078 0.343602 0.180850 424 | vn -0.523165 0.497310 0.692085 425 | v -0.124780 0.307560 0.204446 426 | vn -0.665557 0.002604 0.746343 427 | v -0.139354 0.258159 0.209604 428 | vn -0.629739 -0.492341 0.600857 429 | v -0.135896 0.208636 0.194944 430 | vn -0.425581 -0.855612 0.294633 431 | v -0.115334 0.172259 0.164392 432 | vn -0.107259 -0.990078 -0.090780 433 | v -0.083176 0.158777 0.126136 434 | vn 0.240196 -0.859005 -0.452125 435 | v -0.048039 0.171801 0.090425 436 | vn 0.523165 -0.497309 -0.692085 437 | v -0.019338 0.207842 0.066829 438 | vn 0.665557 -0.002603 -0.746343 439 | v -0.004764 0.257243 0.061671 440 | vn 0.629739 0.492341 -0.600857 441 | v -0.008221 0.306767 0.076331 442 | vn 0.425581 0.855612 -0.294633 443 | v -0.028783 0.343144 0.106883 444 | vn 0.107259 0.990078 0.090780 445 | v -0.060941 0.356626 0.145139 446 | vn -0.421282 0.867568 0.264287 447 | v -0.168512 0.347028 0.105715 448 | vn -0.680447 0.506045 0.530010 449 | v -0.194787 0.310872 0.131828 450 | vn -0.756899 0.009187 0.653467 451 | v -0.202734 0.261156 0.143862 452 | vn -0.630763 -0.489668 0.601966 453 | v -0.190222 0.211205 0.138593 454 | vn -0.336005 -0.857584 0.389422 455 | v -0.160606 0.174400 0.117433 456 | vn 0.049012 -0.996171 0.072390 457 | v -0.121820 0.160604 0.086052 458 | vn 0.421282 -0.867568 -0.264287 459 | v -0.084256 0.173514 0.052857 460 | vn 0.680447 -0.506044 -0.530010 461 | v -0.057981 0.209670 0.026745 462 | vn 0.756899 -0.009187 -0.653467 463 | v -0.050035 0.259384 0.014710 464 | vn 0.630763 0.489668 -0.601966 465 | v -0.062546 0.309336 0.019980 466 | vn 0.336005 0.857584 -0.389422 467 | v -0.092163 0.346141 0.041140 468 | vn -0.049012 0.996171 -0.072390 469 | v -0.130950 0.359937 0.072521 470 | vn -0.813129 0.463559 0.352041 471 | v -0.253697 0.291324 0.052246 472 | vn -0.834346 -0.013820 0.551068 473 | v -0.256066 0.243461 0.071814 474 | vn -0.632303 -0.487061 0.602466 475 | v -0.235936 0.196037 0.076838 476 | vn -0.261215 -0.830079 0.492683 477 | v -0.198700 0.161760 0.065970 478 | vn 0.180173 -0.951110 0.250853 479 | v -0.154337 0.149814 0.042124 480 | vn 0.573658 -0.817007 -0.058439 481 | v -0.114732 0.163401 0.011687 482 | vn 0.813129 -0.463559 -0.352041 483 | v -0.090498 0.198880 -0.017183 484 | vn 0.834346 0.013820 -0.551068 485 | v -0.088129 0.246744 -0.036751 486 | vn 0.632303 0.487060 -0.602466 487 | v -0.108259 0.294168 -0.041775 488 | vn 0.261215 0.830079 -0.492683 489 | v -0.145495 0.328445 -0.030907 490 | vn -0.180173 0.951110 -0.250853 491 | v -0.189858 0.340390 -0.007061 492 | vn -0.573658 0.817007 0.058439 493 | v -0.229463 0.326804 0.023376 494 | vn -0.912169 0.372751 0.170306 495 | v -0.297492 0.250253 -0.028875 496 | vn -0.892619 -0.064851 0.446125 497 | v -0.295714 0.206277 -0.001627 498 | vn -0.634254 -0.484696 0.602321 499 | v -0.269920 0.164166 0.013889 500 | vn -0.206309 -0.774969 0.597377 501 | v -0.227021 0.135200 0.013512 502 | vn 0.277284 -0.857965 0.432446 503 | v -0.178510 0.127144 -0.002653 504 | vn 0.686939 -0.710771 0.151392 505 | v -0.137387 0.142154 -0.030279 506 | vn 0.912169 -0.372751 -0.170306 507 | v -0.114673 0.176210 -0.061960 508 | vn 0.892619 0.064851 -0.446125 509 | v -0.116449 0.220185 -0.089209 510 | vn 0.634254 0.484696 -0.602321 511 | v -0.142244 0.262297 -0.104724 512 | vn 0.206310 0.774969 -0.597377 513 | v -0.185144 0.291261 -0.104348 514 | vn -0.277284 0.857965 -0.432446 515 | v -0.233653 0.299318 -0.088182 516 | vn -0.686939 0.710771 -0.151392 517 | v -0.274776 0.284308 -0.060557 518 | vn -0.753408 0.556094 -0.350906 519 | v -0.301363 0.222438 -0.140363 520 | vn -0.970816 0.239808 -0.002810 521 | v -0.323188 0.190455 -0.106008 522 | vn -0.927745 -0.140426 0.345788 523 | v -0.318978 0.152141 -0.071456 524 | vn -0.636484 -0.482734 0.601544 525 | v -0.289861 0.117762 -0.045965 526 | vn -0.175029 -0.696010 0.696373 527 | v -0.243637 0.096531 -0.036366 528 | vn 0.333728 -0.723084 0.604793 529 | v -0.192695 0.094136 -0.045229 530 | vn 0.753408 -0.556095 0.350907 531 | v -0.150681 0.111219 -0.070181 532 | vn 0.970816 -0.239807 0.002810 533 | v -0.128856 0.143202 -0.104536 534 | vn 0.927745 0.140426 -0.345788 535 | v -0.133067 0.181515 -0.139088 536 | vn 0.636484 0.482734 -0.601544 537 | v -0.162184 0.215894 -0.164578 538 | vn 0.175030 0.696010 -0.696373 539 | v -0.208407 0.237125 -0.174178 540 | vn -0.333728 0.723084 -0.604793 541 | v -0.259351 0.239521 -0.165315 542 | vn -0.768532 0.363522 -0.526507 543 | v -0.307412 0.145409 -0.210603 544 | vn -0.985074 0.073789 -0.155510 545 | v -0.329036 0.116006 -0.173895 546 | vn -0.937333 -0.235396 0.256897 547 | v -0.324272 0.084740 -0.132916 548 | vn -0.638840 -0.481311 0.600186 549 | v -0.294398 0.059991 -0.098645 550 | vn -0.169505 -0.598585 0.782921 551 | v -0.247419 0.048388 -0.080266 552 | vn 0.345659 -0.555659 0.756151 553 | v -0.195922 0.053042 -0.082702 554 | vn 0.768532 -0.363522 0.526507 555 | v -0.153706 0.072704 -0.105301 556 | vn 0.985075 -0.073789 0.155508 557 | v -0.132084 0.102107 -0.142008 558 | vn 0.937333 0.235396 -0.256897 559 | v -0.136848 0.133372 -0.182987 560 | vn 0.638840 0.481311 -0.600186 561 | v -0.166722 0.158122 -0.217259 562 | vn 0.169505 0.598585 -0.782921 563 | v -0.213701 0.169725 -0.235638 564 | vn -0.345659 0.555659 -0.756151 565 | v -0.265197 0.165071 -0.233202 566 | vn -0.731283 0.146176 -0.666226 567 | v -0.292513 0.058471 -0.266490 568 | vn -0.953973 -0.113991 -0.277385 569 | v -0.314635 0.031979 -0.227911 570 | vn -0.920728 -0.343289 0.185509 571 | v -0.311234 0.008670 -0.181818 572 | vn -0.641162 -0.480523 0.598340 573 | v -0.283223 -0.005212 -0.140561 574 | vn -0.190116 -0.489331 0.851124 575 | v -0.238107 -0.005948 -0.115196 576 | vn 0.312262 -0.367099 0.876202 577 | v -0.187973 0.006661 -0.112518 578 | vn 0.953973 0.113991 0.277385 579 | v -0.124135 0.055727 -0.171825 580 | vn 0.920728 0.343289 -0.185509 581 | v -0.127535 0.079036 -0.217917 582 | vn 0.641162 0.480523 -0.598339 583 | v -0.155546 0.092919 -0.259174 584 | vn 0.190116 0.489331 -0.851124 585 | v -0.200664 0.093654 -0.284540 586 | vn -0.312262 0.367099 -0.876202 587 | v -0.250797 0.081045 -0.287218 588 | # 288 vertices, 0 vertices normals 589 | 590 | f 3//3 279//279 278//278 591 | f 278//278 2//2 3//3 592 | f 4//4 280//280 279//279 593 | f 279//279 3//3 4//4 594 | f 5//5 281//281 280//280 595 | f 280//280 4//4 5//5 596 | f 6//6 282//282 281//281 597 | f 281//281 5//5 6//6 598 | f 7//7 283//283 282//282 599 | f 282//282 6//6 7//7 600 | f 8//8 1//1 283//283 601 | f 283//283 7//7 8//8 602 | f 9//9 284//284 1//1 603 | f 1//1 8//8 9//9 604 | f 10//10 285//285 284//284 605 | f 284//284 9//9 10//10 606 | f 11//11 286//286 285//285 607 | f 285//285 10//10 11//11 608 | f 12//12 287//287 286//286 609 | f 286//286 11//11 12//12 610 | f 13//13 288//288 287//287 611 | f 287//287 12//12 13//13 612 | f 2//2 278//278 288//288 613 | f 288//288 13//13 2//2 614 | f 15//15 3//3 2//2 615 | f 2//2 14//14 15//15 616 | f 16//16 4//4 3//3 617 | f 3//3 15//15 16//16 618 | f 17//17 5//5 4//4 619 | f 4//4 16//16 17//17 620 | f 18//18 6//6 5//5 621 | f 5//5 17//17 18//18 622 | f 19//19 7//7 6//6 623 | f 6//6 18//18 19//19 624 | f 20//20 8//8 7//7 625 | f 7//7 19//19 20//20 626 | f 21//21 9//9 8//8 627 | f 8//8 20//20 21//21 628 | f 22//22 10//10 9//9 629 | f 9//9 21//21 22//22 630 | f 23//23 11//11 10//10 631 | f 10//10 22//22 23//23 632 | f 24//24 12//12 11//11 633 | f 11//11 23//23 24//24 634 | f 25//25 13//13 12//12 635 | f 12//12 24//24 25//25 636 | f 14//14 2//2 13//13 637 | f 13//13 25//25 14//14 638 | f 26//26 15//15 14//14 639 | f 14//14 37//37 26//26 640 | f 27//27 16//16 15//15 641 | f 15//15 26//26 27//27 642 | f 28//28 17//17 16//16 643 | f 16//16 27//27 28//28 644 | f 29//29 18//18 17//17 645 | f 17//17 28//28 29//29 646 | f 30//30 19//19 18//18 647 | f 18//18 29//29 30//30 648 | f 31//31 20//20 19//19 649 | f 19//19 30//30 31//31 650 | f 32//32 21//21 20//20 651 | f 20//20 31//31 32//32 652 | f 33//33 22//22 21//21 653 | f 21//21 32//32 33//33 654 | f 34//34 23//23 22//22 655 | f 22//22 33//33 34//34 656 | f 35//35 24//24 23//23 657 | f 23//23 34//34 35//35 658 | f 36//36 25//25 24//24 659 | f 24//24 35//35 36//36 660 | f 37//37 14//14 25//25 661 | f 25//25 36//36 37//37 662 | f 38//38 26//26 37//37 663 | f 37//37 49//49 38//38 664 | f 39//39 27//27 26//26 665 | f 26//26 38//38 39//39 666 | f 40//40 28//28 27//27 667 | f 27//27 39//39 40//40 668 | f 41//41 29//29 28//28 669 | f 28//28 40//40 41//41 670 | f 42//42 30//30 29//29 671 | f 29//29 41//41 42//42 672 | f 43//43 31//31 30//30 673 | f 30//30 42//42 43//43 674 | f 44//44 32//32 31//31 675 | f 31//31 43//43 44//44 676 | f 45//45 33//33 32//32 677 | f 32//32 44//44 45//45 678 | f 46//46 34//34 33//33 679 | f 33//33 45//45 46//46 680 | f 47//47 35//35 34//34 681 | f 34//34 46//46 47//47 682 | f 48//48 36//36 35//35 683 | f 35//35 47//47 48//48 684 | f 49//49 37//37 36//36 685 | f 36//36 48//48 49//49 686 | f 51//51 38//38 49//49 687 | f 49//49 50//50 51//51 688 | f 52//52 39//39 38//38 689 | f 38//38 51//51 52//52 690 | f 53//53 40//40 39//39 691 | f 39//39 52//52 53//53 692 | f 54//54 41//41 40//40 693 | f 40//40 53//53 54//54 694 | f 55//55 42//42 41//41 695 | f 41//41 54//54 55//55 696 | f 56//56 43//43 42//42 697 | f 42//42 55//55 56//56 698 | f 57//57 44//44 43//43 699 | f 43//43 56//56 57//57 700 | f 58//58 45//45 44//44 701 | f 44//44 57//57 58//58 702 | f 59//59 46//46 45//45 703 | f 45//45 58//58 59//59 704 | f 60//60 47//47 46//46 705 | f 46//46 59//59 60//60 706 | f 61//61 48//48 47//47 707 | f 47//47 60//60 61//61 708 | f 50//50 49//49 48//48 709 | f 48//48 61//61 50//50 710 | f 62//62 51//51 50//50 711 | f 50//50 73//73 62//62 712 | f 63//63 52//52 51//51 713 | f 51//51 62//62 63//63 714 | f 64//64 53//53 52//52 715 | f 52//52 63//63 64//64 716 | f 65//65 54//54 53//53 717 | f 53//53 64//64 65//65 718 | f 66//66 55//55 54//54 719 | f 54//54 65//65 66//66 720 | f 67//67 56//56 55//55 721 | f 55//55 66//66 67//67 722 | f 68//68 57//57 56//56 723 | f 56//56 67//67 68//68 724 | f 69//69 58//58 57//57 725 | f 57//57 68//68 69//69 726 | f 70//70 59//59 58//58 727 | f 58//58 69//69 70//70 728 | f 71//71 60//60 59//59 729 | f 59//59 70//70 71//71 730 | f 72//72 61//61 60//60 731 | f 60//60 71//71 72//72 732 | f 73//73 50//50 61//61 733 | f 61//61 72//72 73//73 734 | f 74//74 62//62 73//73 735 | f 73//73 85//85 74//74 736 | f 75//75 63//63 62//62 737 | f 62//62 74//74 75//75 738 | f 76//76 64//64 63//63 739 | f 63//63 75//75 76//76 740 | f 77//77 65//65 64//64 741 | f 64//64 76//76 77//77 742 | f 78//78 66//66 65//65 743 | f 65//65 77//77 78//78 744 | f 79//79 67//67 66//66 745 | f 66//66 78//78 79//79 746 | f 80//80 68//68 67//67 747 | f 67//67 79//79 80//80 748 | f 81//81 69//69 68//68 749 | f 68//68 80//80 81//81 750 | f 82//82 70//70 69//69 751 | f 69//69 81//81 82//82 752 | f 83//83 71//71 70//70 753 | f 70//70 82//82 83//83 754 | f 84//84 72//72 71//71 755 | f 71//71 83//83 84//84 756 | f 85//85 73//73 72//72 757 | f 72//72 84//84 85//85 758 | f 86//86 74//74 85//85 759 | f 85//85 97//97 86//86 760 | f 87//87 75//75 74//74 761 | f 74//74 86//86 87//87 762 | f 88//88 76//76 75//75 763 | f 75//75 87//87 88//88 764 | f 89//89 77//77 76//76 765 | f 76//76 88//88 89//89 766 | f 90//90 78//78 77//77 767 | f 77//77 89//89 90//90 768 | f 91//91 79//79 78//78 769 | f 78//78 90//90 91//91 770 | f 92//92 80//80 79//79 771 | f 79//79 91//91 92//92 772 | f 93//93 81//81 80//80 773 | f 80//80 92//92 93//93 774 | f 94//94 82//82 81//81 775 | f 81//81 93//93 94//94 776 | f 95//95 83//83 82//82 777 | f 82//82 94//94 95//95 778 | f 96//96 84//84 83//83 779 | f 83//83 95//95 96//96 780 | f 97//97 85//85 84//84 781 | f 84//84 96//96 97//97 782 | f 98//98 86//86 97//97 783 | f 97//97 109//109 98//98 784 | f 99//99 87//87 86//86 785 | f 86//86 98//98 99//99 786 | f 100//100 88//88 87//87 787 | f 87//87 99//99 100//100 788 | f 101//101 89//89 88//88 789 | f 88//88 100//100 101//101 790 | f 102//102 90//90 89//89 791 | f 89//89 101//101 102//102 792 | f 103//103 91//91 90//90 793 | f 90//90 102//102 103//103 794 | f 104//104 92//92 91//91 795 | f 91//91 103//103 104//104 796 | f 105//105 93//93 92//92 797 | f 92//92 104//104 105//105 798 | f 106//106 94//94 93//93 799 | f 93//93 105//105 106//106 800 | f 107//107 95//95 94//94 801 | f 94//94 106//106 107//107 802 | f 108//108 96//96 95//95 803 | f 95//95 107//107 108//108 804 | f 109//109 97//97 96//96 805 | f 96//96 108//108 109//109 806 | f 111//111 98//98 109//109 807 | f 109//109 110//110 111//111 808 | f 112//112 99//99 98//98 809 | f 98//98 111//111 112//112 810 | f 113//113 100//100 99//99 811 | f 99//99 112//112 113//113 812 | f 114//114 101//101 100//100 813 | f 100//100 113//113 114//114 814 | f 115//115 102//102 101//101 815 | f 101//101 114//114 115//115 816 | f 116//116 103//103 102//102 817 | f 102//102 115//115 116//116 818 | f 117//117 104//104 103//103 819 | f 103//103 116//116 117//117 820 | f 118//118 105//105 104//104 821 | f 104//104 117//117 118//118 822 | f 119//119 106//106 105//105 823 | f 105//105 118//118 119//119 824 | f 120//120 107//107 106//106 825 | f 106//106 119//119 120//120 826 | f 121//121 108//108 107//107 827 | f 107//107 120//120 121//121 828 | f 110//110 109//109 108//108 829 | f 108//108 121//121 110//110 830 | f 123//123 111//111 110//110 831 | f 110//110 122//122 123//123 832 | f 124//124 112//112 111//111 833 | f 111//111 123//123 124//124 834 | f 125//125 113//113 112//112 835 | f 112//112 124//124 125//125 836 | f 126//126 114//114 113//113 837 | f 113//113 125//125 126//126 838 | f 127//127 115//115 114//114 839 | f 114//114 126//126 127//127 840 | f 128//128 116//116 115//115 841 | f 115//115 127//127 128//128 842 | f 129//129 117//117 116//116 843 | f 116//116 128//128 129//129 844 | f 130//130 118//118 117//117 845 | f 117//117 129//129 130//130 846 | f 131//131 119//119 118//118 847 | f 118//118 130//130 131//131 848 | f 132//132 120//120 119//119 849 | f 119//119 131//131 132//132 850 | f 133//133 121//121 120//120 851 | f 120//120 132//132 133//133 852 | f 122//122 110//110 121//121 853 | f 121//121 133//133 122//122 854 | f 134//134 123//123 122//122 855 | f 122//122 145//145 134//134 856 | f 135//135 124//124 123//123 857 | f 123//123 134//134 135//135 858 | f 136//136 125//125 124//124 859 | f 124//124 135//135 136//136 860 | f 137//137 126//126 125//125 861 | f 125//125 136//136 137//137 862 | f 138//138 127//127 126//126 863 | f 126//126 137//137 138//138 864 | f 139//139 128//128 127//127 865 | f 127//127 138//138 139//139 866 | f 140//140 129//129 128//128 867 | f 128//128 139//139 140//140 868 | f 141//141 130//130 129//129 869 | f 129//129 140//140 141//141 870 | f 142//142 131//131 130//130 871 | f 130//130 141//141 142//142 872 | f 143//143 132//132 131//131 873 | f 131//131 142//142 143//143 874 | f 144//144 133//133 132//132 875 | f 132//132 143//143 144//144 876 | f 145//145 122//122 133//133 877 | f 133//133 144//144 145//145 878 | f 146//146 134//134 145//145 879 | f 145//145 157//157 146//146 880 | f 147//147 135//135 134//134 881 | f 134//134 146//146 147//147 882 | f 148//148 136//136 135//135 883 | f 135//135 147//147 148//148 884 | f 149//149 137//137 136//136 885 | f 136//136 148//148 149//149 886 | f 150//150 138//138 137//137 887 | f 137//137 149//149 150//150 888 | f 151//151 139//139 138//138 889 | f 138//138 150//150 151//151 890 | f 152//152 140//140 139//139 891 | f 139//139 151//151 152//152 892 | f 153//153 141//141 140//140 893 | f 140//140 152//152 153//153 894 | f 154//154 142//142 141//141 895 | f 141//141 153//153 154//154 896 | f 155//155 143//143 142//142 897 | f 142//142 154//154 155//155 898 | f 156//156 144//144 143//143 899 | f 143//143 155//155 156//156 900 | f 157//157 145//145 144//144 901 | f 144//144 156//156 157//157 902 | f 159//159 146//146 157//157 903 | f 157//157 158//158 159//159 904 | f 160//160 147//147 146//146 905 | f 146//146 159//159 160//160 906 | f 161//161 148//148 147//147 907 | f 147//147 160//160 161//161 908 | f 162//162 149//149 148//148 909 | f 148//148 161//161 162//162 910 | f 163//163 150//150 149//149 911 | f 149//149 162//162 163//163 912 | f 164//164 151//151 150//150 913 | f 150//150 163//163 164//164 914 | f 165//165 152//152 151//151 915 | f 151//151 164//164 165//165 916 | f 166//166 153//153 152//152 917 | f 152//152 165//165 166//166 918 | f 167//167 154//154 153//153 919 | f 153//153 166//166 167//167 920 | f 168//168 155//155 154//154 921 | f 154//154 167//167 168//168 922 | f 169//169 156//156 155//155 923 | f 155//155 168//168 169//169 924 | f 158//158 157//157 156//156 925 | f 156//156 169//169 158//158 926 | f 171//171 159//159 158//158 927 | f 158//158 170//170 171//171 928 | f 172//172 160//160 159//159 929 | f 159//159 171//171 172//172 930 | f 173//173 161//161 160//160 931 | f 160//160 172//172 173//173 932 | f 174//174 162//162 161//161 933 | f 161//161 173//173 174//174 934 | f 175//175 163//163 162//162 935 | f 162//162 174//174 175//175 936 | f 176//176 164//164 163//163 937 | f 163//163 175//175 176//176 938 | f 177//177 165//165 164//164 939 | f 164//164 176//176 177//177 940 | f 178//178 166//166 165//165 941 | f 165//165 177//177 178//178 942 | f 179//179 167//167 166//166 943 | f 166//166 178//178 179//179 944 | f 180//180 168//168 167//167 945 | f 167//167 179//179 180//180 946 | f 181//181 169//169 168//168 947 | f 168//168 180//180 181//181 948 | f 170//170 158//158 169//169 949 | f 169//169 181//181 170//170 950 | f 182//182 171//171 170//170 951 | f 170//170 193//193 182//182 952 | f 183//183 172//172 171//171 953 | f 171//171 182//182 183//183 954 | f 184//184 173//173 172//172 955 | f 172//172 183//183 184//184 956 | f 185//185 174//174 173//173 957 | f 173//173 184//184 185//185 958 | f 186//186 175//175 174//174 959 | f 174//174 185//185 186//186 960 | f 187//187 176//176 175//175 961 | f 175//175 186//186 187//187 962 | f 188//188 177//177 176//176 963 | f 176//176 187//187 188//188 964 | f 189//189 178//178 177//177 965 | f 177//177 188//188 189//189 966 | f 190//190 179//179 178//178 967 | f 178//178 189//189 190//190 968 | f 191//191 180//180 179//179 969 | f 179//179 190//190 191//191 970 | f 192//192 181//181 180//180 971 | f 180//180 191//191 192//192 972 | f 193//193 170//170 181//181 973 | f 181//181 192//192 193//193 974 | f 194//194 182//182 193//193 975 | f 193//193 205//205 194//194 976 | f 195//195 183//183 182//182 977 | f 182//182 194//194 195//195 978 | f 196//196 184//184 183//183 979 | f 183//183 195//195 196//196 980 | f 197//197 185//185 184//184 981 | f 184//184 196//196 197//197 982 | f 198//198 186//186 185//185 983 | f 185//185 197//197 198//198 984 | f 199//199 187//187 186//186 985 | f 186//186 198//198 199//199 986 | f 200//200 188//188 187//187 987 | f 187//187 199//199 200//200 988 | f 201//201 189//189 188//188 989 | f 188//188 200//200 201//201 990 | f 202//202 190//190 189//189 991 | f 189//189 201//201 202//202 992 | f 203//203 191//191 190//190 993 | f 190//190 202//202 203//203 994 | f 204//204 192//192 191//191 995 | f 191//191 203//203 204//204 996 | f 205//205 193//193 192//192 997 | f 192//192 204//204 205//205 998 | f 207//207 194//194 205//205 999 | f 205//205 206//206 207//207 1000 | f 208//208 195//195 194//194 1001 | f 194//194 207//207 208//208 1002 | f 209//209 196//196 195//195 1003 | f 195//195 208//208 209//209 1004 | f 210//210 197//197 196//196 1005 | f 196//196 209//209 210//210 1006 | f 211//211 198//198 197//197 1007 | f 197//197 210//210 211//211 1008 | f 212//212 199//199 198//198 1009 | f 198//198 211//211 212//212 1010 | f 213//213 200//200 199//199 1011 | f 199//199 212//212 213//213 1012 | f 214//214 201//201 200//200 1013 | f 200//200 213//213 214//214 1014 | f 215//215 202//202 201//201 1015 | f 201//201 214//214 215//215 1016 | f 216//216 203//203 202//202 1017 | f 202//202 215//215 216//216 1018 | f 217//217 204//204 203//203 1019 | f 203//203 216//216 217//217 1020 | f 206//206 205//205 204//204 1021 | f 204//204 217//217 206//206 1022 | f 219//219 207//207 206//206 1023 | f 206//206 218//218 219//219 1024 | f 220//220 208//208 207//207 1025 | f 207//207 219//219 220//220 1026 | f 221//221 209//209 208//208 1027 | f 208//208 220//220 221//221 1028 | f 222//222 210//210 209//209 1029 | f 209//209 221//221 222//222 1030 | f 223//223 211//211 210//210 1031 | f 210//210 222//222 223//223 1032 | f 224//224 212//212 211//211 1033 | f 211//211 223//223 224//224 1034 | f 225//225 213//213 212//212 1035 | f 212//212 224//224 225//225 1036 | f 226//226 214//214 213//213 1037 | f 213//213 225//225 226//226 1038 | f 227//227 215//215 214//214 1039 | f 214//214 226//226 227//227 1040 | f 228//228 216//216 215//215 1041 | f 215//215 227//227 228//228 1042 | f 229//229 217//217 216//216 1043 | f 216//216 228//228 229//229 1044 | f 218//218 206//206 217//217 1045 | f 217//217 229//229 218//218 1046 | f 230//230 219//219 218//218 1047 | f 218//218 241//241 230//230 1048 | f 231//231 220//220 219//219 1049 | f 219//219 230//230 231//231 1050 | f 232//232 221//221 220//220 1051 | f 220//220 231//231 232//232 1052 | f 233//233 222//222 221//221 1053 | f 221//221 232//232 233//233 1054 | f 234//234 223//223 222//222 1055 | f 222//222 233//233 234//234 1056 | f 235//235 224//224 223//223 1057 | f 223//223 234//234 235//235 1058 | f 236//236 225//225 224//224 1059 | f 224//224 235//235 236//236 1060 | f 237//237 226//226 225//225 1061 | f 225//225 236//236 237//237 1062 | f 238//238 227//227 226//226 1063 | f 226//226 237//237 238//238 1064 | f 239//239 228//228 227//227 1065 | f 227//227 238//238 239//239 1066 | f 240//240 229//229 228//228 1067 | f 228//228 239//239 240//240 1068 | f 241//241 218//218 229//229 1069 | f 229//229 240//240 241//241 1070 | f 242//242 230//230 241//241 1071 | f 241//241 253//253 242//242 1072 | f 243//243 231//231 230//230 1073 | f 230//230 242//242 243//243 1074 | f 244//244 232//232 231//231 1075 | f 231//231 243//243 244//244 1076 | f 245//245 233//233 232//232 1077 | f 232//232 244//244 245//245 1078 | f 246//246 234//234 233//233 1079 | f 233//233 245//245 246//246 1080 | f 247//247 235//235 234//234 1081 | f 234//234 246//246 247//247 1082 | f 248//248 236//236 235//235 1083 | f 235//235 247//247 248//248 1084 | f 249//249 237//237 236//236 1085 | f 236//236 248//248 249//249 1086 | f 250//250 238//238 237//237 1087 | f 237//237 249//249 250//250 1088 | f 251//251 239//239 238//238 1089 | f 238//238 250//250 251//251 1090 | f 252//252 240//240 239//239 1091 | f 239//239 251//251 252//252 1092 | f 253//253 241//241 240//240 1093 | f 240//240 252//252 253//253 1094 | f 255//255 242//242 253//253 1095 | f 253//253 254//254 255//255 1096 | f 256//256 243//243 242//242 1097 | f 242//242 255//255 256//256 1098 | f 257//257 244//244 243//243 1099 | f 243//243 256//256 257//257 1100 | f 258//258 245//245 244//244 1101 | f 244//244 257//257 258//258 1102 | f 259//259 246//246 245//245 1103 | f 245//245 258//258 259//259 1104 | f 260//260 247//247 246//246 1105 | f 246//246 259//259 260//260 1106 | f 261//261 248//248 247//247 1107 | f 247//247 260//260 261//261 1108 | f 262//262 249//249 248//248 1109 | f 248//248 261//261 262//262 1110 | f 263//263 250//250 249//249 1111 | f 249//249 262//262 263//263 1112 | f 264//264 251//251 250//250 1113 | f 250//250 263//263 264//264 1114 | f 265//265 252//252 251//251 1115 | f 251//251 264//264 265//265 1116 | f 254//254 253//253 252//252 1117 | f 252//252 265//265 254//254 1118 | f 267//267 255//255 254//254 1119 | f 254//254 266//266 267//267 1120 | f 268//268 256//256 255//255 1121 | f 255//255 267//267 268//268 1122 | f 269//269 257//257 256//256 1123 | f 256//256 268//268 269//269 1124 | f 270//270 258//258 257//257 1125 | f 257//257 269//269 270//270 1126 | f 271//271 259//259 258//258 1127 | f 258//258 270//270 271//271 1128 | f 272//272 260//260 259//259 1129 | f 259//259 271//271 272//272 1130 | f 273//273 261//261 260//260 1131 | f 260//260 272//272 273//273 1132 | f 274//274 262//262 261//261 1133 | f 261//261 273//273 274//274 1134 | f 275//275 263//263 262//262 1135 | f 262//262 274//274 275//275 1136 | f 276//276 264//264 263//263 1137 | f 263//263 275//275 276//276 1138 | f 277//277 265//265 264//264 1139 | f 264//264 276//276 277//277 1140 | f 266//266 254//254 265//265 1141 | f 265//265 277//277 266//266 1142 | f 279//279 267//267 266//266 1143 | f 266//266 278//278 279//279 1144 | f 280//280 268//268 267//267 1145 | f 267//267 279//279 280//280 1146 | f 281//281 269//269 268//268 1147 | f 268//268 280//280 281//281 1148 | f 282//282 270//270 269//269 1149 | f 269//269 281//281 282//282 1150 | f 283//283 271//271 270//270 1151 | f 270//270 282//282 283//283 1152 | f 1//1 272//272 271//271 1153 | f 271//271 283//283 1//1 1154 | f 284//284 273//273 272//272 1155 | f 272//272 1//1 284//284 1156 | f 285//285 274//274 273//273 1157 | f 273//273 284//284 285//285 1158 | f 286//286 275//275 274//274 1159 | f 274//274 285//285 286//286 1160 | f 287//287 276//276 275//275 1161 | f 275//275 286//286 287//287 1162 | f 288//288 277//277 276//276 1163 | f 276//276 287//287 288//288 1164 | f 278//278 266//266 277//277 1165 | f 277//277 288//288 278//278 1166 | # 576 faces, 0 coords texture 1167 | 1168 | # End of File 1169 | -------------------------------------------------------------------------------- /data/transform.json: -------------------------------------------------------------------------------- 1 | { 2 | "width":512, 3 | "height":512, 4 | "maxDepth":3, 5 | "camera":{ 6 | "position":{"x":0, "y":0, "z":-3}, 7 | "target":{"x":0, "y":0, "z":0}, 8 | "up":{"x":0, "y":1, "z":0}, 9 | "projection":{ 10 | "type":"perspective", 11 | "fovy":0.9272952180016123, 12 | "width":2, 13 | "height":2, 14 | "near": 0.1 15 | } 16 | }, 17 | "scene":{ 18 | "objects":[ 19 | { 20 | "material":{ 21 | "cd":{ 22 | "color":{ 23 | "g":1, 24 | "b":1, 25 | "r":1 26 | }, 27 | "type":"flat" 28 | }, 29 | "type":"diffuse" 30 | }, 31 | "geometry":{ 32 | "type":"mesh", 33 | "transform": { 34 | "type":"rotateY", 35 | "angle":1.0 36 | }, 37 | "fileName":"data/cone.obj" 38 | } 39 | } 40 | ], 41 | "lights":[ 42 | { 43 | "color":{ 44 | "g":1, 45 | "b":1, 46 | "r":1 47 | }, 48 | "type":"directional", 49 | "direction":{ 50 | "x":0.0, 51 | "y":-1.0, 52 | "z":1.0 53 | } 54 | }, 55 | { 56 | "color":{ 57 | "g":1, 58 | "b":1, 59 | "r":1 60 | }, 61 | "type":"directional", 62 | "direction":{ 63 | "x":0.0, 64 | "y":-1.0, 65 | "z":-1.0 66 | } 67 | } 68 | 69 | ] 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /data/uvcube.obj: -------------------------------------------------------------------------------- 1 | # Blender v2.73 (sub 0) OBJ File: '' 2 | # www.blender.org 3 | mtllib uvcube.mtl 4 | v 0.500000 -0.500000 -0.500000 5 | v 0.500000 -0.500000 0.500000 6 | v -0.500000 -0.500000 0.500000 7 | v -0.500000 -0.500000 -0.500000 8 | v 0.500000 0.500000 -0.500000 9 | v 0.500000 0.500000 0.500000 10 | v -0.500000 0.500000 0.500000 11 | v -0.500000 0.500000 -0.500000 12 | vt 0.000000 1.000000 13 | vt 1.000000 1.000000 14 | vt 1.000000 0.000000 15 | vt 1.000000 1.000000 16 | vt 0.000000 0.000000 17 | vt 0.000000 1.000000 18 | vt 1.000000 1.000000 19 | vt 1.000000 0.000000 20 | vn 0.000000 -1.000000 0.000000 21 | vn 0.000000 1.000000 0.000000 22 | vn 1.000000 0.000000 0.000000 23 | vn -0.000000 0.000000 1.000000 24 | vn -1.000000 -0.000000 -0.000000 25 | vn 0.000000 0.000000 -1.000000 26 | usemtl Material 27 | s off 28 | f 2/1/1 3/2/1 4/3/1 29 | f 8/4/2 7/3/2 6/5/2 30 | f 5/6/3 6/4/3 2/3/3 31 | f 6/6/4 7/4/4 3/3/4 32 | f 3/5/5 7/6/5 8/7/5 33 | f 1/1/6 4/2/6 8/3/6 34 | f 1/5/1 2/1/1 4/3/1 35 | f 5/6/2 8/4/2 6/5/2 36 | f 1/5/3 5/6/3 2/3/3 37 | f 2/5/4 6/6/4 3/3/4 38 | f 4/8/5 3/5/5 8/7/5 39 | f 5/5/6 1/1/6 8/3/6 40 | -------------------------------------------------------------------------------- /rayhs.cabal: -------------------------------------------------------------------------------- 1 | -- Initial rayhs.cabal generated by cabal init. For further 2 | -- documentation, see http://haskell.org/cabal/users-guide/ 3 | 4 | name: RayHs 5 | version: 0.1.0.0 6 | -- synopsis: 7 | -- description: 8 | license: MIT 9 | license-file: LICENSE 10 | author: olivier 11 | maintainer: o.rouiller@gmail.com 12 | -- copyright: 13 | category: Graphics 14 | build-type: Simple 15 | -- extra-source-files: 16 | cabal-version: >=1.10 17 | 18 | executable rayhs 19 | hs-source-dirs: src 20 | main-is: RayHs.hs 21 | -- other-modules: 22 | -- other-extensions: 23 | build-depends: 24 | base >=4.7, 25 | bytestring -any, 26 | parallel -any, 27 | vector -any, 28 | deepseq-generics -any, 29 | split -any, 30 | text -any, 31 | aeson -any, 32 | mtl -any, 33 | random -any 34 | -- hs-source-dirs: 35 | default-language: Haskell2010 -------------------------------------------------------------------------------- /src/Bitmap.hs: -------------------------------------------------------------------------------- 1 | module Bitmap (Bitmap(..) 2 | , (@@) 3 | , readPPM) where 4 | 5 | import Data.List 6 | import Data.Vector (Vector, cons, (!), (!?), (//)) 7 | import qualified Data.Vector as V 8 | 9 | import Math 10 | import Color 11 | 12 | {- Image -} 13 | data Bitmap = Bitmap { width :: !Int 14 | , height :: !Int 15 | , pixels :: Vector Color } deriving Show 16 | 17 | (@@) :: Bitmap -> (Int, Int) -> Color 18 | (Bitmap w _ pixels) @@ (i, j) = pixels ! (i + w * j) 19 | 20 | readWidthAndHeight :: String -> (Int, Int) 21 | readWidthAndHeight s = (head ints, ints !! 1) 22 | where ints = map read (words s) 23 | 24 | colors :: [Double] -> [Color] 25 | colors (r:g:b:rest) = (RGB r g b:colors rest) 26 | colors _ = [] 27 | 28 | readPixels :: [String] -> [Color] 29 | readPixels words = colors $ map (\s -> (read s) / 255) words 30 | 31 | readPPM :: String -> IO Bitmap 32 | readPPM path = do 33 | content <- readFile path 34 | let (header, pixels) = splitAt 3 (lines content) 35 | let (w, h) = readWidthAndHeight $ header !! 1 36 | let maxC = (read $ header !! 2) :: Int 37 | return $ Bitmap w h (V.fromList $ readPixels $ concat $ map words pixels) 38 | -------------------------------------------------------------------------------- /src/Color.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE DeriveGeneric #-} 2 | 3 | module Color (Color(RGB) 4 | , rgbi 5 | , black 6 | , white 7 | , red 8 | , green 9 | , blue 10 | , gray 11 | , pink 12 | , yellow) where 13 | 14 | import Math 15 | 16 | import GHC.Generics 17 | 18 | {- Color -} 19 | data Color = RGB !Double !Double !Double deriving (Show, Generic) 20 | 21 | instance Num Color where 22 | {-# INLINE (+) #-} 23 | (RGB x1 y1 z1) + (RGB x2 y2 z2) = RGB (x1+x2) (y1+y2) (z1+z2) 24 | {-# INLINE (*) #-} 25 | (RGB x1 y1 z1) * (RGB x2 y2 z2) = RGB (x1*x2) (y1*y2) (z1*z2) 26 | {-# INLINE (-) #-} 27 | (RGB x1 y1 z1) - (RGB x2 y2 z2) = RGB (x1-x2) (y1-y2) (z1-z2) 28 | {-# INLINE negate #-} 29 | negate (RGB x y z) = RGB (-x) (-y) (-z) 30 | 31 | rgbi :: Int -> Int -> Int -> Color 32 | {-# INLINE rgbi #-} 33 | rgbi r g b = RGB (fdiv r 255) (fdiv r 255) (fdiv r 255) 34 | 35 | black :: Color 36 | black = RGB 0 0 0 37 | 38 | white :: Color 39 | white = RGB 1 1 1 40 | 41 | red :: Color 42 | red = RGB 1 0 0 43 | 44 | green :: Color 45 | green = RGB 0 1 0 46 | 47 | blue :: Color 48 | blue = RGB 0 0 1 49 | 50 | gray :: Double -> Color 51 | gray g = RGB g g g 52 | 53 | pink :: Color 54 | pink = RGB 1 0.8 1 55 | 56 | yellow :: Color 57 | yellow = RGB 1 1 0.6 58 | 59 | mul :: Double -> Color -> Color 60 | {-# INLINE mul #-} 61 | mul v (RGB r g b) = RGB (v*r) (v*g) (v*b) 62 | -------------------------------------------------------------------------------- /src/ColorMap.hs: -------------------------------------------------------------------------------- 1 | module ColorMap (ColorMap(..) 2 | , colorAt) where 3 | 4 | import Data.Fixed 5 | 6 | import Color 7 | import Math 8 | import Vec 9 | import Bitmap 10 | 11 | data ColorMap = Flat { color :: !Color } 12 | | CheckerBoard { color1 :: !Color 13 | , color2 :: !Color 14 | , size :: !Double } 15 | | Texture { image :: !Bitmap } 16 | deriving Show 17 | 18 | colorAt :: ColorMap -> UV -> Color 19 | {-# INLINE colorAt #-} 20 | colorAt (Flat color) _ = color 21 | colorAt (CheckerBoard c0 c1 scale) (UV u v) = 22 | if (mod' u scale - (0.5*scale)) * (mod' v scale - (0.5*scale)) < 0 23 | then c0 24 | else c1 25 | 26 | colorAt (Texture bitmap@(Bitmap w h pixels)) uv = bilinearInterp c0 c1 c2 c3 lx ly 27 | where (u, v) = toPixel w h uv 28 | ui = round u 29 | vi = round v 30 | x0 = (ui-1) `mod` w 31 | x1 = ui `mod` w 32 | y0 = (vi-1) `mod` h 33 | y1 = vi `mod` h 34 | lx = u - (fromIntegral $ ui - 1) - 0.5 35 | ly = v - (fromIntegral $ vi - 1) - 0.5 36 | c0 = bitmap Bitmap.@@ (x0, y0) 37 | c1 = bitmap Bitmap.@@ (x1, y0) 38 | c2 = bitmap Bitmap.@@ (x0, y1) 39 | c3 = bitmap Bitmap.@@ (x1, y1) 40 | 41 | bilinearInterp :: Color -> Color -> Color -> Color -> Double -> Double -> Color 42 | {-# INLINE bilinearInterp #-} 43 | bilinearInterp c0 c1 c2 c3 u v = mul v cx1 + mul (1-v) cx0 44 | where cx0 = mul u c1 + mul (1-u) c0 45 | cx1 = mul u c3 + mul (1-u) c2 46 | 47 | toPixel :: Int -> Int -> UV -> (Double, Double) 48 | {-# INLINE toPixel #-} 49 | toPixel w h uv = (ui, vi) 50 | where (UV u v) = repeatUV uv 51 | ui = u * (fromIntegral w) 52 | vi = v * (fromIntegral h) 53 | 54 | repeatUV :: UV -> UV 55 | {-# INLINE repeatUV #-} 56 | repeatUV (UV u v) = UV ui vi 57 | where ui = mod' u 1 58 | vi = mod' v 1 59 | -------------------------------------------------------------------------------- /src/Descriptors.hs: -------------------------------------------------------------------------------- 1 | module Descriptors (GeometryDesc(..) 2 | , ObjectDesc(..) 3 | , SceneDesc(..) 4 | , RenderDesc(..) 5 | , buildScene) where 6 | 7 | import Vec 8 | import Light 9 | import MaterialDescriptors 10 | import Geometry 11 | import Projection 12 | import Mesh hiding (transform) 13 | import qualified Mesh 14 | import Scene 15 | import KDTree 16 | import Transform hiding (transform) 17 | 18 | {- Scene Descriptor -} 19 | data RenderDesc = RenderDesc { scene :: SceneDesc 20 | , camera :: Camera 21 | , width :: Int 22 | , height :: Int 23 | , maxDepth :: Int } 24 | 25 | data GeometryDesc = MeshDesc { fileName :: String 26 | , transform :: Transform } 27 | | SphereDesc { center :: Vec 28 | , radius :: Double } 29 | | PlaneDesc { normal :: Vec 30 | , point :: Vec 31 | , tangent :: Vec } deriving Show 32 | 33 | data ObjectDesc = ObjectDesc { geometry :: GeometryDesc 34 | , material :: MaterialDesc } deriving Show 35 | 36 | data SceneDesc = SceneDesc { objects :: [ObjectDesc] 37 | , lights :: [Light] } deriving Show 38 | 39 | buildScene :: SceneDesc -> IO Scene 40 | buildScene (SceneDesc objectDescs lights) = do 41 | objects <- mapM buildObject objectDescs 42 | return $ Scene objects lights 43 | 44 | buildObject :: ObjectDesc -> IO Object 45 | buildObject (ObjectDesc objDesc matDesc) = do 46 | geometry <- buildGeometry objDesc 47 | material <- buildMaterial matDesc 48 | return $ Object geometry material 49 | 50 | buildGeometry :: GeometryDesc -> IO Geometry 51 | buildGeometry (PlaneDesc p n t) = return (geom $ Plane p n t) 52 | buildGeometry (SphereDesc c r) = return (geom $ Sphere c r) 53 | buildGeometry (MeshDesc filename trans) = do 54 | mesh <- readOBJ filename 55 | return (geom $ buildKDTree (Mesh.transform mesh trans)) 56 | -------------------------------------------------------------------------------- /src/Geometry.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE ExistentialQuantification #-} 2 | 3 | module Geometry (Ray(..) 4 | , eps 5 | , rayAt 6 | , rayEps 7 | , Hit(..) 8 | , Inter 9 | , intersection 10 | , closestHit 11 | , Geometry(..) 12 | , geom 13 | , Shape(..) 14 | ) where 15 | 16 | import Math 17 | import Vec 18 | 19 | import Data.List 20 | import Data.Maybe 21 | import Data.Function 22 | 23 | {- Ray -} 24 | data Ray = Ray { origin :: !Vec 25 | , direction :: !Vec } deriving Show 26 | 27 | rayAt :: Ray -> Double -> Vec 28 | {-# INLINE rayAt #-} 29 | rayAt (Ray o d) t = o + Vec.mul t d 30 | 31 | eps :: Double 32 | eps = 0.000001 33 | 34 | rayEps :: Vec -> Vec -> Ray 35 | {-# INLINE rayEps #-} 36 | rayEps p n = Ray (p + Vec.mul eps n) n 37 | 38 | {- Intersection hit -} 39 | data Hit = Hit { p :: !Position, n :: !Normal, uv :: !UV, t :: !Double } 40 | deriving Show 41 | 42 | {- Geometry Class -} 43 | class Inter a where 44 | intersection :: Ray -> a -> Maybe Hit 45 | 46 | data Geometry = forall a. Inter a => Geometry a 47 | 48 | geom :: Inter a => a -> Geometry 49 | geom = Geometry 50 | 51 | instance Inter Geometry where 52 | intersection ray (Geometry a) = intersection ray a 53 | 54 | closestHit :: [Maybe Hit] -> Maybe Hit 55 | closestHit hits = case catMaybes hits of 56 | [] -> Nothing 57 | xs -> Just $ minimumBy (compare `on` t) xs 58 | 59 | {- Ray/Primitives intersection -} 60 | 61 | {- Basic shapes -} 62 | data Shape = Plane { point :: !Vec, normal :: !Vec, tangent :: !Vec} 63 | | Sphere { center :: !Vec, radius :: !Double } deriving Show 64 | 65 | instance Inter Shape where 66 | intersection = rayShapeIntersection 67 | 68 | rayShapeIntersection :: Ray -> Shape -> Maybe Hit 69 | {-# INLINE rayShapeIntersection #-} 70 | rayShapeIntersection ray@(Ray o d) (Plane p n t) 71 | | abs dDotn > 0 && time > 0 = Just (Hit pos n (UV u v) time) 72 | | otherwise = Nothing 73 | where dDotn = dot d n 74 | time = dot n (p - o) / dDotn 75 | pos = rayAt ray time --intersection 76 | b = cross t n 77 | rel = pos - p 78 | u = dot t rel 79 | v = dot b rel 80 | 81 | rayShapeIntersection ray@(Ray o d) (Sphere ct r) 82 | | delta < 0.0 = Nothing 83 | | t0 > 0 = Just (Hit p0 n0 (polar n0) t0) 84 | | t1 > 0 = Just (Hit p1 n1 (polar n1) t1) 85 | | otherwise = Nothing 86 | where delta = b ^ (2 :: Int) - 4.0*a*c 87 | a = dot d d 88 | b = 2.0 * dot d (o - ct) 89 | c = sqrLen (o - ct) - r ^ (2 :: Int) 90 | t0 = 0.5 * ((-b) - sqrt delta) / a 91 | p0 = rayAt ray t0 92 | n0 = normalize (p0 - ct) 93 | t1 = 0.5 * ((-b) + sqrt delta) / a 94 | p1 = rayAt ray t1 95 | n1 = normalize (p1 - ct) 96 | polar p = UV (piInv * atan (z p / x p)) (piInv * acos (y p)) 97 | -------------------------------------------------------------------------------- /src/Image.hs: -------------------------------------------------------------------------------- 1 | module Image (Image(Image) 2 | , generatePixels 3 | , generatePixelsRnd 4 | , mapPixels 5 | , gradient 6 | , solidImage 7 | , emptyImage 8 | , writePPM 9 | , readPPM) where 10 | 11 | import Data.List 12 | import Data.Vector (Vector, cons, (!), (!?), (//)) 13 | import qualified Data.Vector as V 14 | import Control.Parallel.Strategies 15 | 16 | import Math 17 | import Color 18 | import RandomSamples 19 | 20 | {- Image -} 21 | data Image = Image { width :: Int 22 | , height :: Int 23 | , pixels :: [Color] } deriving Show 24 | 25 | mapPixels :: (Color -> (Int, Int) -> Color) -> Image -> Image 26 | mapPixels f (Image w h px) = Image w h (zipWith f px indices) 27 | where indices = [(x,y) | y <- [0..h-1], x <- [0..w-1]] 28 | 29 | instance NFData Color 30 | 31 | pixelCoord :: Int -> Int -> Int -> (Double, Double) 32 | pixelCoord w h i = (fromIntegral (i `mod` w), fromIntegral (i `div` w)) 33 | 34 | generatePixels :: Int -> Int -> ((Double, Double) -> Color) -> Image 35 | generatePixels w h f = Image w h (map (f . pixelCoord w h) [0..(w*h)] 36 | `using` parListChunk 10 rdeepseq ) 37 | 38 | generatePixelsRnd :: Int -> Int -> ((Double, Double) -> Rnd Color) -> Rnd Image 39 | generatePixelsRnd w h f = do 40 | pixels <- mapM (f . pixelCoord w h) [0..(w*h)] 41 | return $ Image w h pixels 42 | 43 | gradient :: Int -> Int -> Image 44 | gradient w h = Image w h (map 45 | (\i -> gray (fdiv i (w * h - 1))) 46 | [0..(w*h)]) 47 | 48 | solidImage :: Int -> Int -> Color -> Image 49 | solidImage w h c = Image w h (replicate (w*h) c) 50 | 51 | emptyImage :: Int -> Int -> Image 52 | emptyImage w h = solidImage w h black 53 | 54 | toIntC :: Double -> Int 55 | toIntC c = truncate $ 255 * min c 1 56 | 57 | toFloatC :: Int -> Double 58 | toFloatC c = (fromIntegral c) / 255 59 | 60 | formatPixelsPPM :: Image -> String 61 | formatPixelsPPM (Image w h pix) = concat $ intercalate ["\n"] 62 | [[formatPixel 63 | (V.fromList pix ! (x+w*y)) ++ " " 64 | | x <- [0..(w-1)]] 65 | | y <- [0..(h-1)]] 66 | where formatPixel (RGB r g b) = show (toIntC r) 67 | ++ " " ++ show (toIntC g) 68 | ++ " " ++ show (toIntC b) 69 | 70 | writePPM :: String -> Image -> IO() 71 | writePPM path image = do 72 | let content = "P3\n" ++ show (width image) 73 | ++ " " ++ show (height image) ++ "\n255\n" 74 | ++ formatPixelsPPM image 75 | writeFile path content 76 | 77 | readWidthAndHeight :: String -> (Int, Int) 78 | readWidthAndHeight s = (head ints, ints !! 1) 79 | where ints = map read (words s) 80 | 81 | colors :: [Double] -> [Color] 82 | colors (r:g:b:rest) = (RGB r g b:colors rest) 83 | colors _ = [] 84 | 85 | readPixels :: Int -> Int -> [String] -> Image 86 | readPixels w h lines = Image w h pixels 87 | where pixels = colors $ map (\s -> (read s) / 255) lines 88 | 89 | readPPM :: String -> IO Image 90 | readPPM path = do 91 | content <- readFile path 92 | let (header, pixels) = splitAt 3 (lines content) 93 | let (w, h) = readWidthAndHeight $ header !! 1 94 | let maxC = (read $ header !! 2) :: Int 95 | return $ readPixels w h (concat $ map words pixels) 96 | -------------------------------------------------------------------------------- /src/JSON.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE OverloadedStrings #-} 2 | module JSON ( encode 3 | , decode 4 | , FromJSON(..) 5 | ) where 6 | 7 | import Data.String 8 | import Data.Text 9 | import Data.Aeson 10 | import Data.Aeson.Types 11 | import Data.Monoid 12 | import Control.Applicative 13 | 14 | import Descriptors 15 | import MaterialDescriptors 16 | import Vec 17 | import Color 18 | import Light 19 | import Projection 20 | import Transform 21 | 22 | instance FromJSON Vec where 23 | parseJSON (Object v) = Vec <$> 24 | v .: "x" <*> 25 | v .: "y" <*> 26 | v .: "z" 27 | parseJSON _ = fail "Error reaging Vec" 28 | 29 | instance FromJSON Color where 30 | parseJSON (Object v) = RGB <$> 31 | v .: "r" <*> 32 | v .: "g" <*> 33 | v .: "b" 34 | parseJSON _ = mempty 35 | 36 | 37 | typeName :: Text 38 | typeName = "type" 39 | 40 | instance FromJSON ColorMapDesc where 41 | parseJSON = withObject "colorMap" $ \o -> do 42 | kind <- o .: typeName 43 | case kind of 44 | "flat" -> FlatDesc <$> o .: "color" 45 | "checker" -> CheckerBoardDesc <$> 46 | o .: "color1" <*> 47 | o .: "color2" <*> 48 | o .: "size" 49 | "texture" -> TextureDesc <$> o .: "fileName" 50 | _ -> fail ("Unknown type for color map " ++ kind) 51 | 52 | instance FromJSON MaterialDesc where 53 | parseJSON = withObject "material" $ \obj -> do 54 | kind <- obj .: typeName 55 | case kind of 56 | "mirror" -> MirrorDesc <$> obj .: "ior" 57 | "diffuse" -> DiffuseDesc <$> obj .: "cd" 58 | "plastic" -> PlasticDesc <$> obj .: "cd" <*> obj .: "ior" 59 | "emmit" -> EmmitDesc <$> obj .: "ce" 60 | "transparent" -> TransparentDesc <$> obj .: "ior" 61 | _ -> fail ("Unknown type for material " ++ kind) 62 | 63 | instance FromJSON Light where 64 | parseJSON = withObject "light" $ \obj -> do 65 | kind <- obj .: typeName 66 | case kind of 67 | "directional" -> Directional <$> obj .: "direction" <*> obj .: "color" 68 | "point" -> Point <$> 69 | obj .: "position" <*> 70 | obj .: "color" <*> 71 | obj .: "radius" 72 | _ -> fail ("Unknown type for light " ++ kind) 73 | 74 | instance FromJSON Projection where 75 | parseJSON = withObject "projection" $ \obj -> do 76 | kind <- obj .: typeName 77 | case kind of 78 | "orthographic" -> Orthographic <$> obj .: "width" <*> obj .: "height" 79 | "perspective" -> Perspective <$> 80 | obj .: "fovy" <*> 81 | obj .: "width" <*> 82 | obj .: "height" <*> 83 | obj .: "near" 84 | _ -> fail ("Unknown type for projection " ++ kind) 85 | 86 | instance FromJSON Transform where 87 | parseJSON = withObject "transform" $ \obj -> do 88 | kind <- obj .: typeName 89 | case kind of 90 | "scale" -> Scale <$> obj .: "vector" 91 | "translate" -> Translate <$> obj .: "vector" 92 | "rotateX" -> RotateX <$> obj .: "angle" 93 | "rotateY" -> RotateY <$> obj .: "angle" 94 | "rotateZ" -> RotateZ <$> obj .: "angle" 95 | "rotate" -> Rotate <$> obj .: "axis" <*> obj .: "angle" 96 | "sequence" -> Sequence <$> obj .: "transforms" 97 | _ -> fail ("Unknown type for transform " ++ kind) 98 | 99 | instance FromJSON Camera where 100 | parseJSON (Object v) = LookAt <$> 101 | v .: "position" <*> 102 | v .: "target" <*> 103 | v .: "up" <*> 104 | v .: "projection" 105 | parseJSON _ = mempty 106 | 107 | 108 | instance FromJSON GeometryDesc where 109 | parseJSON = withObject "geometry" $ \obj -> do 110 | kind <- ((obj .: typeName) :: Parser String) 111 | case kind of 112 | "sphere" -> SphereDesc <$> 113 | obj .: "center" <*> 114 | obj .: "radius" 115 | "plane" -> PlaneDesc <$> 116 | obj .: "point" <*> 117 | obj .: "normal" <*> 118 | obj .: "tangent" 119 | "mesh" -> MeshDesc <$> 120 | obj .: "fileName" <*> 121 | obj .: "transform" 122 | 123 | instance FromJSON ObjectDesc where 124 | parseJSON (Object v) = ObjectDesc <$> 125 | v .: "geometry" <*> 126 | v .: "material" 127 | parseJSON _ = mempty 128 | 129 | instance FromJSON SceneDesc where 130 | parseJSON (Object v) = SceneDesc <$> 131 | v .: "objects" <*> 132 | v .: "lights" 133 | parseJSON _ = mempty 134 | 135 | instance FromJSON RenderDesc where 136 | parseJSON (Object v) = RenderDesc <$> 137 | v .: "scene" <*> 138 | v .: "camera" <*> 139 | v .: "width" <*> 140 | v .: "height" <*> 141 | v .: "maxDepth" 142 | 143 | {- encoding 144 | 145 | instance ToJSON Vec where 146 | toJSON (Vec x y z) = object ["x" .= x, "y" .= y, "z" .= z] 147 | 148 | instance ToJSON Color where 149 | toJSON (RGB x y z) = object ["r" .= x, "g" .= y, "b" .= z] 150 | 151 | instance ToJSON ColorMapDesc where 152 | toJSON (FlatDesc c) = object ["type" .= ("flat" :: Text), "color" .= c] 153 | toJSON (CheckerBoardDesc c1 c2 s) = object ["type" .= ("checker" :: Text), 154 | "color2" .= c2, 155 | "color1" .= c1, 156 | "size" .= s] 157 | 158 | instance ToJSON MaterialDesc where 159 | toJSON (DiffuseDesc cd) = object ["type" .= ("diffuse" :: Text), "cd" .= cd] 160 | toJSON (EmmitDesc cd) = object ["type" .= ("emmit" :: Text), "ce" .= cd] 161 | toJSON (PlasticDesc cd ior) = object ["type" .= ("plastic" :: Text), 162 | "cd" .= cd, 163 | "ior" .= ior] 164 | toJSON (MirrorDesc ior) = object ["type" .= ("mirror" :: Text), 165 | "ior" .= ior] 166 | toJSON (TransparentDesc ior) = object ["type" .= ("transparent" :: Text), 167 | "ior" .= ior] 168 | 169 | instance ToJSON Light where 170 | toJSON (Directional d c) = object ["type" .= ("directional" :: Text), 171 | "direction" .= d, 172 | "color" .= c] 173 | toJSON (Point pos color rad) = object ["type" .= ("point" :: Text), 174 | "position" .= pos, 175 | "color" .= color, 176 | "radius" .= rad] 177 | 178 | instance ToJSON GeometryDesc where 179 | toJSON (SphereDesc c r) = object ["type" .= ("sphere" :: Text), 180 | "center" .= c, 181 | "radius" .= r] 182 | toJSON (PlaneDesc n p t) = object ["type" .= ("plane" :: Text), 183 | "normal" .= n, 184 | "point" .= p, 185 | "tangent" .= t] 186 | toJSON (MeshDesc fn t) = object ["type" .= ("mesh" :: Text), 187 | "fileName" .= fn, 188 | "translation" .= t] 189 | 190 | instance ToJSON ObjectDesc where 191 | toJSON (ObjectDesc g m) = object ["material" .= m, 192 | "geometry" .= g] 193 | 194 | instance ToJSON SceneDesc where 195 | toJSON (SceneDesc objs lights) = object ["objects" .= objs, 196 | "lights" .= lights] 197 | -} 198 | -------------------------------------------------------------------------------- /src/KDTree.hs: -------------------------------------------------------------------------------- 1 | module KDTree (KDTree(..) 2 | , buildKDTree) where 3 | 4 | import Math 5 | import Vec 6 | import Geometry 7 | import Mesh 8 | 9 | import Data.Vector (Vector, cons, (!), (!?), (//)) 10 | import qualified Data.Vector as V 11 | 12 | {- Bounding Box -} 13 | data Box = Box { lower :: !Vec 14 | , upper :: !Vec } deriving Show 15 | 16 | empty :: Box 17 | empty = Box (Vec inf inf inf) (Vec (-inf) (-inf) (-inf)) 18 | 19 | include :: Box -> Vec -> Box 20 | include (Box min max) p = Box (minV min p) (maxV max p) 21 | 22 | includeTriangle :: Box -> Triangle -> Box 23 | includeTriangle box (Triangle 24 | (Vertex a _ _) 25 | (Vertex b _ _) 26 | (Vertex c _ _)) = include (include (include box a) b) c 27 | 28 | buildBoundingBox :: [Triangle] -> Box 29 | buildBoundingBox triangles = foldl includeTriangle empty triangles 30 | 31 | max3 :: Double -> Double -> Double -> Double 32 | {-# INLINE max3 #-} 33 | max3 a b = max (max a b) 34 | 35 | min3 :: Double -> Double -> Double -> Double 36 | {-# INLINE min3 #-} 37 | min3 a b = min (min a b) 38 | 39 | rayInterBox :: Ray -> Box -> Maybe Double 40 | {-# INLINE rayInterBox #-} 41 | rayInterBox (Ray (Vec ox oy oz) (Vec dx dy dz)) 42 | (Box (Vec mx my mz) (Vec mX mY mZ)) = 43 | if tmax < 0 || tmin > tmax 44 | then Nothing 45 | else Just tmin 46 | where idx = 1 / dx 47 | idy = 1 / dy 48 | idz = 1 / dz 49 | t1 = idx * (mx - ox) 50 | t2 = idx * (mX - ox) 51 | t3 = idy * (my - oy) 52 | t4 = idy * (mY - oy) 53 | t5 = idz * (mz - oz) 54 | t6 = idz * (mZ - oz) 55 | tmin = max3 (min t1 t2) (min t3 t4) (min t5 t6) 56 | tmax = min3 (max t1 t2) (max t3 t4) (max t5 t6) 57 | 58 | {- KDTree -} 59 | data KDTree = Leaf Box [Triangle] 60 | | Node Box KDTree KDTree 61 | | Empty 62 | 63 | instance Show KDTree where 64 | show (Leaf b tris) = "Leaf [" ++ (show $ length tris) ++ "]" 65 | show (Node b l r) = "Node (" ++ show l ++ ", " ++ show r ++ ")" 66 | show Empty = "Empty" 67 | 68 | buildKDTree :: Mesh -> KDTree 69 | buildKDTree mesh = buildNode (triangles mesh) 0 0 70 | 71 | baryCenter :: Triangle -> Vec 72 | baryCenter (Triangle (Vertex a _ _) 73 | (Vertex b _ _) 74 | (Vertex c _ _)) = mul (1 / 3) (a + b + c) 75 | 76 | maxDepth :: Int 77 | maxDepth = 100 78 | 79 | buildNode :: [Triangle] -> Int -> Int -> KDTree 80 | buildNode tris depth axis 81 | | null tris = Empty 82 | | length tris < 20 || depth >= maxDepth = Leaf box tris 83 | | otherwise = Node box left right 84 | where box = buildBoundingBox tris 85 | left = buildNode [t | t <- tris, (baryCenter t) @@ axis < split] 86 | (depth + 1) nextAxis 87 | right = buildNode [t | t <- tris, split <= (baryCenter t) @@ axis] 88 | (depth + 1) nextAxis 89 | split = 0.5 * ((upper box) @@ axis + (lower box) @@ axis) 90 | nextAxis = (axis + 1) `mod` 3 91 | 92 | {- Intersection -} 93 | instance Inter KDTree where 94 | intersection = rayInter 95 | 96 | rayInter :: Ray -> KDTree -> Maybe Hit 97 | {-# INLINE rayInter #-} 98 | rayInter ray (Leaf bbox triangles) = case rayInterBox ray bbox of 99 | Nothing -> Nothing 100 | Just _ -> closestHit $ map (triangleIntersection ray) triangles 101 | 102 | rayInter ray (Node bbox left right) = case rayInterBox ray bbox of 103 | Nothing -> Nothing 104 | Just _ -> let lHit = rayInter ray left 105 | rHit = rayInter ray right 106 | in minMaybeHit lHit rHit 107 | rayInter _ Empty = Nothing 108 | 109 | minMaybeHit :: Maybe Hit -> Maybe Hit -> Maybe Hit 110 | minMaybeHit Nothing Nothing = Nothing 111 | minMaybeHit (Just hit) Nothing = Just hit 112 | minMaybeHit Nothing (Just hit) = Just hit 113 | minMaybeHit (Just h1) (Just h2) = if t h1 < t h2 114 | then Just h1 115 | else Just h2 116 | -------------------------------------------------------------------------------- /src/Light.hs: -------------------------------------------------------------------------------- 1 | module Light (Light(..) 2 | , lightAt) where 3 | 4 | import Color 5 | import Vec 6 | 7 | {- Light -} 8 | data Light = Directional { direction :: !Vec, color :: !Color } 9 | | Point { position :: !Vec, color :: !Color, radius :: !Double } 10 | deriving Show 11 | 12 | lightAt :: Light -> Vec -> (Vec, Color) 13 | {-# INLINE lightAt #-} 14 | lightAt (Directional d c) _ = (d, c) 15 | lightAt (Point p0 c r) p = (Vec.mul (1/d) (p0 - p), mul falloff c) 16 | where falloff = 1.0 / (1.0 + d/r)^(2::Int) 17 | d = dist p0 p 18 | -------------------------------------------------------------------------------- /src/Mat.hs: -------------------------------------------------------------------------------- 1 | module Mat (Mat3(..) 2 | , identity 3 | , scale 4 | , rotateX 5 | , rotateY 6 | , rotateZ 7 | , rotate 8 | , fromColumns 9 | , transpose 10 | , lookAt 11 | , apply) where 12 | 13 | import Vec 14 | 15 | data Mat3 = Mat3 16 | !Double !Double !Double 17 | !Double !Double !Double 18 | !Double !Double !Double 19 | 20 | instance Num Mat3 where 21 | {-# INLINE (+) #-} 22 | (Mat3 a1 b1 c1 d1 e1 f1 g1 h1 i1) 23 | + (Mat3 a2 b2 c2 d2 e2 f2 g2 h2 i2) = 24 | Mat3 (a1+a2) (b1+b2) (c1+c2) (d1+d2) (e1+e2) (f1+f2) (g1+g2) (h1+h2) (i1+i2) 25 | {-# INLINE (*) #-} 26 | (Mat3 a1 b1 c1 d1 e1 f1 g1 h1 i1) 27 | * (Mat3 a2 b2 c2 d2 e2 f2 g2 h2 i2) = 28 | Mat3 29 | (a1*a2 + b1*d2 + c1*g2) (a1*b2 + b1*e2 + c1*h2) (a1*c2 + b1*f2 + c1*i2) 30 | (d1*a2 + e1*d2 + f1*g2) (d1*b2 + e1*e2 + f1*h2) (d1*c2 + e1*f2 + f1*i2) 31 | (g1*a2 + h1*d2 + i1*g2) (g1*b2 + h1*e2 + i1*h2) (g1*c2 + h1*f2 + i1*i2) 32 | {-# INLINE (-) #-} 33 | (Mat3 a1 b1 c1 d1 e1 f1 g1 h1 i1) 34 | - (Mat3 a2 b2 c2 d2 e2 f2 g2 h2 i2) = 35 | Mat3 (a1-a2) (b1-b2) (c1-c2) (d1-d2) (e1-e2) (f1-f2) (g1-g2) (h1-h2) (i1-i2) 36 | {-# INLINE negate #-} 37 | negate (Mat3 a1 b1 c1 d1 e1 f1 g1 h1 i1) = 38 | Mat3 (-a1) (-b1) (-c1) (-d1) (-e1) (-f1) (-g1) (-h1) (-i1) 39 | 40 | apply :: Mat3 -> Vec -> Vec 41 | apply (Mat3 a b c d e f g h i) (Vec x y z) = Vec v1 v2 v3 42 | where v1 = a*x + b*y + c*z 43 | v2 = d*x + e*y + f*z 44 | v3 = g*x + h*y + i*z 45 | 46 | {- transpose -} 47 | transpose :: Mat3 -> Mat3 48 | transpose (Mat3 a b c d r f g h i) = 49 | Mat3 a d g b r h c f i 50 | 51 | {- constructors -} 52 | identity :: Mat3 53 | identity = Mat3 1 0 0 0 1 0 0 0 1 54 | 55 | scale :: Vec -> Mat3 56 | scale (Vec sx sy sz) = Mat3 sx 0 0 0 sy 0 0 0 sz 57 | 58 | rotateZ :: Double -> Mat3 59 | rotateZ angle = Mat3 60 | (cos angle) (-(sin angle)) 0 61 | (sin angle) (cos angle) 0 62 | 0 0 1 63 | 64 | rotateY :: Double -> Mat3 65 | rotateY angle = Mat3 66 | (cos angle) 0 (sin angle) 67 | 0 1 0 68 | (-(sin angle)) 0 (cos angle) 69 | 70 | rotateX :: Double -> Mat3 71 | rotateX angle = Mat3 72 | 1 0 0 73 | 0 (cos angle) (-(sin angle)) 74 | 0 (sin angle) (cos angle) 75 | 76 | rotate :: Vec -> Double -> Mat3 77 | rotate axis angle = mt * rot * m 78 | where (r, s, t) = orthonormal axis 79 | m = fromColumns r s t 80 | mt = transpose m 81 | rot = rotateX angle 82 | 83 | fromColumns :: Vec -> Vec -> Vec -> Mat3 84 | fromColumns v1 v2 v3 = Mat3 85 | (x v1) (x v2) (x v3) 86 | (y v1) (y v2) (y v3) 87 | (z v1) (z v2) (z v3) 88 | 89 | lookAt :: Vec -> Vec -> Vec -> Mat3 90 | lookAt pos target tup = fromColumns right up forward 91 | where forward = normalize $ target - pos 92 | right = normalize $ cross tup forward 93 | up = cross forward right 94 | -------------------------------------------------------------------------------- /src/Material.hs: -------------------------------------------------------------------------------- 1 | module Material (Material(..) 2 | , r0 3 | , fresnel 4 | , diffuse) where 5 | 6 | import Data.Fixed 7 | 8 | import Color 9 | import ColorMap 10 | import Math 11 | import Vec 12 | 13 | data Material = Mirror { ior :: !Double } 14 | | Diffuse { cd :: !ColorMap } 15 | | Plastic { cd :: !ColorMap, ior :: !Double} 16 | | Emmit { ce :: !Color } 17 | | Transparent { ior :: !Double } 18 | | ShowNormal 19 | | ShowUV 20 | deriving Show 21 | 22 | r0 :: Double -> Double -> Double 23 | {-# INLINE r0 #-} 24 | r0 n1 n2 = ((n1 - n2) / (n1 + n2)) ^ (2 :: Int) 25 | 26 | fresnel :: Double -> Double -> Double 27 | {-# INLINE fresnel #-} 28 | fresnel ior cos0 = r + (1 - r) * (1 - cos0) ^ (5 :: Int) 29 | where r = r0 1.0 ior 30 | 31 | diffuse :: Color -> Color -> Vec -> Vec -> Color 32 | {-# INLINE diffuse #-} 33 | diffuse cd lc l n = mul (max (dot l n) 0 * piInv) (cd * lc) 34 | -------------------------------------------------------------------------------- /src/MaterialDescriptors.hs: -------------------------------------------------------------------------------- 1 | module MaterialDescriptors (MaterialDesc(..) 2 | , ColorMapDesc(..) 3 | , buildColorMap 4 | , buildMaterial) where 5 | 6 | import Material 7 | import Color 8 | import ColorMap 9 | import Bitmap 10 | 11 | data MaterialDesc = MirrorDesc { ior :: Double } 12 | | DiffuseDesc { cd :: ColorMapDesc } 13 | | PlasticDesc { cd :: ColorMapDesc, ior :: Double} 14 | | EmmitDesc { ce :: Color } 15 | | TransparentDesc { ior :: Double } 16 | | ShowNormalDesc 17 | | ShowUVDesc 18 | deriving Show 19 | 20 | data ColorMapDesc = FlatDesc { color :: Color } 21 | | CheckerBoardDesc { color1 :: Color 22 | , color2 :: Color 23 | , size :: Double } 24 | | TextureDesc { fileName :: String } 25 | deriving Show 26 | 27 | buildColorMap :: ColorMapDesc -> IO ColorMap 28 | buildColorMap (FlatDesc c) = return $ Flat c 29 | buildColorMap (CheckerBoardDesc c1 c2 s) = return $ CheckerBoard c1 c2 s 30 | buildColorMap (TextureDesc fileName) = do 31 | image <- readPPM fileName 32 | return $ Texture image 33 | 34 | buildMaterial :: MaterialDesc -> IO Material 35 | buildMaterial (MirrorDesc ior) = return $ Mirror ior 36 | buildMaterial (DiffuseDesc cdd) = do 37 | cd <- buildColorMap cdd 38 | return $ Diffuse cd 39 | buildMaterial (PlasticDesc cdd ior) = do 40 | cd <- buildColorMap cdd 41 | return $ Plastic cd ior 42 | buildMaterial (EmmitDesc ce) = return $ Emmit ce 43 | buildMaterial (TransparentDesc ior) = return $ Transparent ior 44 | buildMaterial ShowNormalDesc = return ShowNormal 45 | buildMaterial ShowUVDesc = return ShowUV 46 | -------------------------------------------------------------------------------- /src/Math.hs: -------------------------------------------------------------------------------- 1 | module Math (fdiv 2 | , piInv 3 | , twoPiInv 4 | , inf) where 5 | 6 | import Data.Function 7 | 8 | fdiv :: Int -> Int -> Double 9 | fdiv = (/) `on` fromIntegral 10 | 11 | piInv :: Double 12 | piInv = 1 / pi 13 | 14 | twoPiInv :: Double 15 | twoPiInv = 0.5 / pi 16 | 17 | inf :: Double 18 | inf = read "Infinity" 19 | -------------------------------------------------------------------------------- /src/Mesh.hs: -------------------------------------------------------------------------------- 1 | module Mesh (Mesh(..) 2 | , Vertex(..) 3 | , Triangle(..) 4 | , triangleIntersection 5 | , triangles 6 | , readOBJ 7 | , translate 8 | , Mesh.transform) where 9 | 10 | import Vec 11 | import Geometry 12 | import Transform as T 13 | 14 | import Data.List 15 | import Data.List.Split 16 | import Data.Maybe 17 | import Data.Function 18 | import Data.Vector (Vector, cons, (!), (!?), (//)) 19 | import Text.Read 20 | 21 | import qualified Data.Vector as V 22 | 23 | {- Triangle Mesh -} 24 | 25 | {- As simple as possible indexed face set. 26 | Represented by a list of positions, list of normals and list of indices. 27 | It should be guaranted that there is as many normals as vertices. 28 | Also, each index in the indices should be a valid index in the list of normals 29 | and positions. 30 | -} 31 | 32 | data Vertex = Vertex !Position !Normal !UV deriving Show 33 | 34 | data Mesh = Mesh { vertices :: Vector Vertex 35 | , indices :: [Int] } deriving Show 36 | 37 | empty :: Mesh 38 | empty = Mesh V.empty [] 39 | 40 | instance Inter Mesh where 41 | intersection = rayInterMesh 42 | 43 | {- Ray Intersection -} 44 | rayInterMesh :: Ray -> Mesh -> Maybe Hit 45 | rayInterMesh ray mesh = closestHit $ mapTriangles (triangleIntersection ray) mesh 46 | 47 | -- Convenience type to store 3 vertices 48 | data Triangle = Triangle !Vertex !Vertex !Vertex deriving Show 49 | 50 | triLookup :: Vector Vertex -> (Int, Int, Int) -> Triangle 51 | triLookup verts (i, j, k) = Triangle (verts ! i) (verts ! j) (verts ! k) 52 | 53 | barycentricInterp :: (Num a, Ext a) => 54 | Double -> a -> Double -> a -> Double -> a 55 | -> a 56 | {-# INLINE barycentricInterp #-} 57 | barycentricInterp a p b q c r = mul a p + mul b q + mul c r 58 | 59 | triangleIntersection :: Ray -> Triangle -> Maybe Hit 60 | {-# INLINE triangleIntersection #-} 61 | triangleIntersection ray@(Ray o d) (Triangle 62 | (Vertex p0 n0 uv0) 63 | (Vertex p1 n1 uv1) 64 | (Vertex p2 n2 uv2)) = 65 | if abs det < eps || 66 | u < 0 || u > 1 || 67 | v < 0 || (u + v) > 1 || 68 | t < eps 69 | then Nothing 70 | else Just $ Hit (rayAt ray t) n uv t 71 | where e1 = p1 - p0 72 | e2 = p2 - p0 73 | p = cross d e2 74 | det = dot e1 p 75 | idet = 1 / det 76 | t0 = o - p0 77 | u = idet * dot t0 p 78 | q = cross t0 e1 79 | v = idet * dot d q 80 | t = idet * dot e2 q 81 | n = barycentricInterp u n1 v n2 (1-u-v) n0 82 | uv = barycentricInterp u uv1 v uv2 (1-u-v) uv0 83 | 84 | translate :: Mesh -> Vec -> Mesh 85 | translate mesh t = transformVertices 86 | (\(Vertex p n uv) -> Vertex (p+t) n uv) 87 | mesh 88 | 89 | transform :: Mesh -> T.Transform -> Mesh 90 | transform mesh trans@(Translate _) = transformVertices 91 | (\(Vertex p n uv) -> 92 | Vertex (T.transform trans p) 93 | n 94 | uv) 95 | mesh 96 | transform mesh trans = transformVertices 97 | (\(Vertex p n uv) -> 98 | Vertex (T.transform trans p) 99 | (T.transform trans n) 100 | uv) 101 | mesh 102 | 103 | 104 | {- Mapping functions -} 105 | triangles :: Mesh -> [Triangle] 106 | triangles (Mesh vertices indices) = 107 | map (triLookup vertices) (faces indices) 108 | where faces [] = [] 109 | faces (i:j:k:is) = (i, j, k):faces is 110 | 111 | mapTriangles :: (Triangle -> b) -> Mesh -> [b] 112 | mapTriangles f mesh = map f (triangles mesh) 113 | 114 | transformVertices :: (Vertex -> Vertex) -> Mesh -> Mesh 115 | transformVertices f mesh = Mesh (V.map f (vertices mesh)) (indices mesh) 116 | 117 | 118 | {- Obj Loading -} 119 | 120 | {- Obj vertices can be Position, Normal or Texture Coord (not supported yet) 121 | Faces must have a position index and have optionaly a normal index and 122 | tc index 123 | -} 124 | 125 | type OBJIndex = (Int, Maybe Int, Maybe Int) 126 | data OBJToken = Vert Vec 127 | | Norm Vec 128 | | UVS UV 129 | | Face [OBJIndex] 130 | deriving Show 131 | 132 | readDoubles :: [String] -> [Double] 133 | readDoubles = map read 134 | 135 | readVertex :: String -> Maybe OBJToken 136 | readVertex s = let floats = readDoubles (words s) in 137 | case length floats of 138 | 3 -> Just (Vert $ fromList floats) 139 | _ -> Nothing 140 | 141 | readNormal :: String -> Maybe OBJToken 142 | readNormal s = let floats = readDoubles (words s) in 143 | case length floats of 144 | 3 -> Just (Norm $ fromList floats) 145 | _ -> Nothing 146 | 147 | readUV :: String -> Maybe OBJToken 148 | readUV s = let floats = readDoubles (words s) in 149 | case length floats of 150 | 2 -> Just (UVS $ UV (head floats) (floats !! 1)) 151 | _ -> Nothing 152 | 153 | readOBJIndex :: String -> Maybe OBJIndex 154 | readOBJIndex s = parseIndex $ readMaybeInts s 155 | 156 | readMaybeInts :: String -> [Maybe Int] 157 | readMaybeInts s = map readMaybe (splitOn "/" s) 158 | 159 | parseIndex :: [Maybe Int] -> Maybe OBJIndex 160 | parseIndex (Just pi:ti:ni:_) = Just (pi, ti, ni) 161 | parseIndex (Just pi:ti:_) = Just (pi, ti, Nothing) 162 | parseIndex (Just pi:_) = Just (pi, Nothing, Nothing) 163 | parseIndex _ = Nothing 164 | 165 | readFace :: String -> Maybe OBJToken 166 | readFace s = let indices = mapMaybe readOBJIndex (words s) in 167 | if length indices > 2 168 | then Just $ Face indices 169 | else Nothing 170 | 171 | readLine :: String -> Maybe OBJToken 172 | readLine ('v':' ':rest) = readVertex rest 173 | readLine ('v':'n':' ':rest) = readNormal rest 174 | readLine ('v':'t':' ':rest) = readUV rest 175 | readLine ('f':' ':rest) = readFace rest 176 | readLine _ = Nothing 177 | 178 | buildMeshData :: [OBJToken] -> ([Vec], [Vec], [UV], [OBJIndex]) 179 | buildMeshData = foldl dispatch ([], [], [], []) 180 | where dispatch (vs, ns, uvs, is) (Vert v) = (vs ++ [v], ns, uvs, is) 181 | dispatch (vs, ns, uvs, is) (Norm n) = (vs, ns ++ [n], uvs, is) 182 | dispatch (vs, ns, uvs, is) (UVS u) = (vs, ns, uvs ++ [u], is) 183 | dispatch (vs, ns, uvs, is) (Face f) = (vs, ns, uvs, is ++ f) 184 | 185 | -- Functional style lookup table 186 | type IndexMap = OBJIndex -> Maybe Int 187 | emptyMap :: IndexMap 188 | emptyMap _ = Nothing 189 | 190 | insertIndex :: IndexMap -> OBJIndex -> Int -> IndexMap 191 | insertIndex imap oi i query = if query == oi 192 | then Just i 193 | else imap query 194 | 195 | flattenVertices :: ([Position], [Normal], [UV], [OBJIndex]) -> ([Vertex], [Int]) 196 | flattenVertices (pos, norms, uvs, inds) = (verts, ids) 197 | where (verts, ids, _) = foldl addVertex ([], [], emptyMap) inds 198 | addVertex (vs, is, imap) id = 199 | case imap id of 200 | Nothing -> let next = length vs in 201 | (vs ++ [mkV id], 202 | is ++ [next], 203 | insertIndex imap id next) 204 | Just x -> (vs, is ++ [x], imap) 205 | mkV (pi, Nothing, Nothing) = 206 | Vertex (pos !! (pi-1)) (Vec 0 0 0) (UV 0 0) 207 | mkV (pi, Just ui, Nothing) = 208 | Vertex (pos !! (pi-1)) (Vec 0 0 0) (uvs !! (ui-1)) 209 | mkV (pi, Just ui, Just ni) = 210 | Vertex (pos !! (pi-1)) (norms !! (ni-1)) (uvs !! (ui -1)) 211 | mkV (pi, Nothing, Just ni) = 212 | Vertex (pos !! (pi-1)) (norms !! (ni-1)) (UV 0 0) 213 | 214 | buildMesh :: [OBJToken] -> Mesh 215 | buildMesh tokens = Mesh (V.fromList verts) ids 216 | where (verts, ids) = flattenVertices . buildMeshData $ tokens 217 | 218 | readOBJ :: String -> IO Mesh 219 | readOBJ path = do 220 | content <- readFile path 221 | return . buildMesh . catMaybes $ map readLine (lines content) 222 | -------------------------------------------------------------------------------- /src/Projection.hs: -------------------------------------------------------------------------------- 1 | module Projection (Projection(..) 2 | , Camera(..) 3 | , rayFromPixel ) where 4 | 5 | import Vec 6 | import Mat 7 | import Geometry (Ray(..)) 8 | 9 | {- Projection -} 10 | data Projection = Orthographic { width :: Double, height :: Double} 11 | | Perspective { fovy :: Double 12 | , width :: Double 13 | , height :: Double 14 | , near :: Double } 15 | deriving Show 16 | 17 | data Camera = LookAt { position :: Vec 18 | , target :: Vec 19 | , up :: Vec 20 | , projection :: Projection } deriving Show 21 | 22 | rayFromPixel :: Double -> Double -> Camera -> Double -> Double -> Ray 23 | rayFromPixel w h (LookAt p t up proj) px py = Ray (o+p) (apply mat d) 24 | where (Ray o d) = unproject w h proj px py 25 | mat = lookAt p t up 26 | 27 | {- Create ray from camera givent the projection -} 28 | unproject :: Double -> Double -> Projection 29 | -> Double -> Double -> Ray 30 | unproject w h (Orthographic pw ph) px py = Ray o (Vec 0 0 1) 31 | where (apw, aph) = aspectSize w h 32 | o = Vec (apw * (px - (w/2)) / w) (aph * ((-py) + (h/2)) / h) 0 33 | 34 | unproject w h (Perspective fovy pw ph n) px py = Ray o d 35 | where f = 0.5 * h / (tan 0.5 * fovy) 36 | (apw, aph) = aspectSize w h 37 | viewPlanePos = Vec (apw * (px - (w/2)) / w) (aph * ((-py) + (h/2)) / h) f 38 | d = normalize viewPlanePos 39 | o = Vec.o --Vec ((x viewPlanePos) * n / f) ((y viewPlanePos) * n / f) n 40 | 41 | aspectSize :: Double -> Double -> (Double, Double) 42 | aspectSize w h = (apw, aph) 43 | where aspect = w / h 44 | (apw, aph) = if aspect > 1 45 | then (w, w/aspect) 46 | else (aspect*h, h) 47 | -------------------------------------------------------------------------------- /src/RandomSamples.hs: -------------------------------------------------------------------------------- 1 | module RandomSamples (Rnd 2 | , runRandom 3 | , sampleUniform01 4 | , sampleUniformSq) where 5 | 6 | import Control.Monad 7 | import Control.Monad.State (State, evalState, get, put) 8 | import System.Random (StdGen, mkStdGen, random) 9 | import Control.Applicative ((<$>)) 10 | 11 | {- Type encapsulating the state of a random generator -} 12 | type Rnd a = State StdGen a 13 | 14 | {- Run a computation that takes random samples -} 15 | runRandom :: Rnd a -> Int -> a 16 | runRandom action seed = evalState action $ mkStdGen seed 17 | 18 | {- get a random sample an pass the state along -} 19 | rand :: Rnd Double 20 | rand = do 21 | gen <- get 22 | let (r, gen') = random gen 23 | put gen' 24 | return r 25 | 26 | randPair :: Rnd (Double, Double) 27 | randPair = do 28 | x <- rand 29 | y <- rand 30 | return (x, y) 31 | 32 | {- Uniform distributions -} 33 | uniform01 :: Rnd [Double] 34 | uniform01 = mapM (\_ -> rand) $ repeat () 35 | 36 | uniform :: Double -> Double -> Rnd [Double] 37 | uniform a b = mapM (\_ -> (\s -> s * (b - a) + a) <$> rand) $ repeat () 38 | 39 | uniform2 :: Double -> Rnd [(Double, Double)] 40 | uniform2 s = mapM (\_ -> (\(x, y) -> (2 * s * (x-0.5), 2 * s * (y-0.5))) 41 | <$> randPair) $ repeat () 42 | 43 | {- Get n samples uniformly distributed between 0 and 1 -} 44 | sampleUniform01 :: Int -> Rnd [Double] 45 | sampleUniform01 n = sequence $ replicate n rand 46 | 47 | {- Get n samples uniformly distributed in a square centerd at the origin 48 | of size s -} 49 | sampleUniformSq :: Double -> Int -> Rnd [(Double, Double)] 50 | sampleUniformSq halfSize n = liftM (take n) (uniform2 halfSize) 51 | -------------------------------------------------------------------------------- /src/RayHs.hs: -------------------------------------------------------------------------------- 1 | {-# OPTIONS_GHC -Wall #-} 2 | {-# LANGUAGE OverloadedStrings #-} 3 | module Main where 4 | 5 | import Control.Monad 6 | 7 | import Data.Maybe 8 | import Data.List 9 | import Data.Function 10 | import Data.Vector (Vector, cons, (!), (!?), (//)) 11 | import qualified Data.Vector as V 12 | import qualified Data.ByteString as B 13 | import qualified Data.ByteString.Lazy as BS 14 | 15 | import Text.Printf 16 | import System.Environment (getArgs) 17 | import System.Console.GetOpt 18 | import System.CPUTime 19 | import System.Random 20 | 21 | import Math 22 | import Color 23 | import ColorMap 24 | import Image 25 | import Vec hiding (o) 26 | import Material 27 | import Light 28 | import Scene 29 | import Geometry hiding (intersection) 30 | import Mesh 31 | import Projection 32 | import KDTree 33 | import RandomSamples 34 | import Descriptors 35 | import JSON 36 | 37 | import qualified Vec (o) 38 | import qualified Geometry as Geom (intersection) 39 | 40 | {- Raytracing -} 41 | data Rendering = Rendering { scene :: Scene 42 | , camera :: Camera 43 | , width :: Int 44 | , height :: Int 45 | , maxDepth :: Int } 46 | 47 | buildRendering :: RenderDesc -> IO Rendering 48 | buildRendering (RenderDesc sceneDesc proj w h d) = do 49 | scene <- buildScene sceneDesc 50 | return $ Rendering scene proj w h d 51 | 52 | data MatHit = MatHit { position :: !Vec 53 | , normal :: !Vec 54 | , uv :: !UV 55 | , time :: !Double 56 | , material :: !Material } deriving Show 57 | 58 | intersection :: Ray -> Object -> Maybe MatHit 59 | intersection ray (Object shape material) = do 60 | hit <- Geom.intersection ray shape 61 | case hit of 62 | (Hit p n uv t) -> return (MatHit p n uv t material) 63 | 64 | intersections :: [Object] -> Ray -> [MatHit] 65 | intersections scene ray = mapMaybe (intersection ray) scene 66 | 67 | closestIntersection :: [Object] -> Ray -> Maybe MatHit 68 | closestIntersection scene r = case hits of 69 | [] -> Nothing 70 | _ -> Just $ minimumBy (compare `on` time) hits 71 | where hits = intersections scene r 72 | 73 | {- trace ray towards light to see if occluded -} 74 | shadowIntersection :: [Object] -> Light -> Ray -> Maybe MatHit 75 | shadowIntersection scene light ray = case hits of 76 | [] -> Nothing 77 | _ -> Just $ minimumBy (compare `on` time) hits 78 | where hits = filter isOccluder (filter 79 | (inFrontOfLight light ray) 80 | (intersections scene ray)) 81 | isOccluder (MatHit _ _ _ _ (Emmit _)) = False 82 | isOccluder _ = True 83 | 84 | inFrontOfLight :: Light -> Ray -> MatHit -> Bool 85 | inFrontOfLight light (Ray origin _) (MatHit pos _ _ _ _) = case light of 86 | (Directional _ _) -> True 87 | (Point p _ _) -> sqrDist origin p > sqrDist origin pos 88 | 89 | accumDiffuse :: [Object] -> [Light] -> Vec -> Vec -> Color -> Color 90 | accumDiffuse sc lts p n color = 91 | foldl (\c l -> c + diffFromLight l) black lts 92 | where diffFromLight light = 93 | let inter = shadowIntersection sc light (rayEps p ld) 94 | in case inter of 95 | Just _ -> black 96 | Nothing -> diffuse color lc ld n 97 | where (ld, lc) = lightAt light p 98 | 99 | specular :: Scene -> Int -> Int -> Vec -> Vec -> Vec -> Color 100 | specular scene depth maxDepth v p n 101 | | depth < maxDepth = mul (dot (reflect v n) n) 102 | (traceRay scene (depth+1) maxDepth 103 | (rayEps p (reflect v n))) 104 | | otherwise = black 105 | 106 | {- Irradiance comutation at a point with view direction, normal and material -} 107 | irradiance :: Int -> Int -> Scene -> Material -> 108 | Direction -> Position -> Normal -> UV -> Color 109 | 110 | {- Diffuse + Ambient -} 111 | irradiance _ _ (Scene shapes lights) (Diffuse cdMap) _ p n uv = 112 | mul 0.2 cd + 113 | accumDiffuse shapes lights p n cd 114 | where cd = colorAt cdMap uv 115 | 116 | {- Plastic -} 117 | irradiance d maxDepth scene@(Scene shapes lights) (Plastic cdMap ior) v p n uv = 118 | accumDiffuse shapes lights p n cd 119 | + mul (fresnel ior (dot n (-v))) (specular scene d maxDepth v p n) 120 | where cd = colorAt cdMap uv 121 | 122 | {- Mirror -} 123 | irradiance d maxDepth scene (Mirror ior) v p n _ = 124 | mul (fresnel ior (dot n (-v))) (specular scene d maxDepth v p n) 125 | 126 | {- Emmitter -} 127 | irradiance _ _ _ (Emmit ce) _ _ _ _ = ce 128 | 129 | {- Transparent -} 130 | irradiance d maxDepth scene (Transparent ior) v p n _ = 131 | case transmitedRadiance of 132 | Nothing -> mul (fresnel ior (dot n (-v))) (specular scene d maxDepth v p n) 133 | Just radiance -> mul (1 - r0 ior 1.0) radiance 134 | + mul (fresnel ior (dot n (-v))) 135 | (specular scene d maxDepth v p n) 136 | where transmitedRadiance 137 | | d == maxDepth = Nothing 138 | | otherwise = do 139 | refr@(Ray _ refDir) <- (liftM $ rayEps p) (refract v n 1.0 ior) 140 | (MatHit outp outn _ _ _) <- closestIntersection (shapes scene) refr 141 | outRay <- liftM (rayEps outp) 142 | (refract refDir (-outn) ior 1.0) 143 | return $ traceRay scene (d+1) maxDepth outRay 144 | 145 | {- Debug material -} 146 | irradiance _ _ _ ShowNormal _ _ n _ = toRGB n 147 | irradiance _ _ _ ShowUV _ _ _ (UV u v) = RGB u v 0 148 | 149 | traceRay :: Scene -> Int -> Int -> Ray -> Color 150 | traceRay scene depth maxDepth ray@(Ray _ v) = 151 | let inter = closestIntersection (shapes scene) ray 152 | in case inter of 153 | Just (MatHit p n uv _ mat) -> irradiance depth maxDepth scene mat v p n uv 154 | Nothing -> black 155 | 156 | tracePixel :: Scene -> Int -> Double -> Double -> Camera 157 | -> (Double, Double) -> Color 158 | tracePixel scene d w h cam (i, j) = traceRay scene 0 d ray 159 | where ray = rayFromPixel w h cam i j 160 | 161 | rayTrace :: Rendering -> Image 162 | rayTrace (Rendering scene camera w h d) = generatePixels w h 163 | (tracePixel scene d 164 | (fromIntegral w) 165 | (fromIntegral h) 166 | camera) 167 | 168 | {- Distributed ray tracer -} 169 | average :: [Color] -> Color 170 | average colors = mul (1.0 / (fromIntegral . length $ colors)) sumc 171 | where sumc = foldl (+) black colors 172 | 173 | distributedTracePixel :: Scene -> Int -> Double -> Double -> Camera 174 | -> (Double, Double) -> Rnd Color 175 | distributedTracePixel scene d w h proj (i, j) = do 176 | samples <- sampleUniform01 128 177 | let pixelSamples = makePixelSamples samples 178 | let rays = map 179 | (\(oi, oj) -> 180 | rayFromPixel w h proj (i+oi) (j+oj)) 181 | pixelSamples 182 | let colors = map (traceRay scene 0 d) rays 183 | return $ average colors 184 | 185 | makePixelSamples :: [Double] -> [(Double, Double)] 186 | makePixelSamples [] = [] 187 | makePixelSamples (x:y:xs) = ((x-0.5, y-0.5):makePixelSamples xs) 188 | makePixelSamples _ = [] 189 | 190 | distributedRayTrace :: Rendering -> Rnd Image 191 | distributedRayTrace (Rendering scene camera w h d) = 192 | generatePixelsRnd w h (distributedTracePixel scene d 193 | (fromIntegral w) 194 | (fromIntegral h) 195 | camera) 196 | 197 | parseFile :: FromJSON a => FilePath -> IO (Maybe a) 198 | parseFile path = do 199 | content <- BS.readFile path 200 | return $ decode content 201 | 202 | 203 | {- Command line options -} 204 | data Flag = Output String deriving Show 205 | 206 | options :: [OptDescr Flag] 207 | options = [Option ['o'] ["output"] (OptArg makeOutput "FILE") 208 | "Specify the ouput filename." ] 209 | 210 | header = "Usage: main [OPTION...]" 211 | 212 | makeOutput :: Maybe String -> Flag 213 | makeOutput = Output . fromMaybe "out.ppm" 214 | 215 | main :: IO () 216 | main = do 217 | args <- getArgs 218 | case getOpt RequireOrder options args of 219 | (flags, (fn:_), []) -> do 220 | let outFile = case flags of 221 | [] -> "out.ppm" 222 | (Output fn:_) -> fn 223 | putStrLn $ "Loading scene from " ++ fn ++ "..." 224 | jobDesc <- parseFile $ fn 225 | case jobDesc of 226 | Nothing -> error "Failed to read scene" 227 | Just jd -> do 228 | putStrLn $ "Rendering..." 229 | job <- buildRendering jd 230 | let simpleRay = rayTrace job 231 | writePPM outFile simpleRay 232 | putStrLn $ "Done! Output written to " ++ outFile 233 | (_, [], []) -> error $ "No input." 234 | (_, _, msgs) -> error $ concat msgs ++ usageInfo header options 235 | 236 | 237 | 238 | 239 | --let multipleRay = runRandom (distributedRayTrace job) 24 240 | --writePPM "dist.ppm" multipleRay 241 | -------------------------------------------------------------------------------- /src/Scene.hs: -------------------------------------------------------------------------------- 1 | module Scene (Object(..) 2 | , Scene(..)) where 3 | 4 | import Geometry 5 | import Material 6 | import Light 7 | 8 | data Object = Object Geometry Material 9 | 10 | data Scene = Scene { shapes :: [Object], lights :: [Light] } 11 | -------------------------------------------------------------------------------- /src/Setup.hs: -------------------------------------------------------------------------------- 1 | import Distribution.Simple 2 | main = defaultMain 3 | -------------------------------------------------------------------------------- /src/Transform.hs: -------------------------------------------------------------------------------- 1 | module Transform (Transform(..) 2 | , transform) where 3 | 4 | import Vec 5 | import Mat 6 | 7 | data Transform = Translate Vec 8 | | Scale Vec 9 | | Rotate Vec Double 10 | | RotateX Double 11 | | RotateY Double 12 | | RotateZ Double 13 | | Sequence [Transform] deriving Show 14 | 15 | 16 | transform :: Transform -> Vec -> Vec 17 | transform (Translate t) p = p + t 18 | transform (Scale (Vec sx sy sz)) (Vec x y z) = Vec (sx*x) (sy*y) (sz*z) 19 | transform (Rotate axis angle) v = apply rMat v 20 | where rMat = rotate axis angle 21 | transform (RotateX angle) p = apply (rotateX angle) p 22 | transform (RotateY angle) p = apply (rotateY angle) p 23 | transform (RotateZ angle) p = apply (rotateZ angle) p 24 | transform (Sequence transforms) p = foldl (flip transform) p transforms 25 | -------------------------------------------------------------------------------- /src/Vec.hs: -------------------------------------------------------------------------------- 1 | module Vec (Vec (..) 2 | , Ext (..) 3 | , Position 4 | , Normal 5 | , Direction 6 | , UV (..) 7 | , (@@) 8 | , o 9 | , xAxis 10 | , yAxis 11 | , zAxis 12 | , dot 13 | , cross 14 | , sqrLen 15 | , sqrDist 16 | , dist 17 | , normalize 18 | , reflect 19 | , refract 20 | , minV 21 | , maxV 22 | , toRGB 23 | , fromRGB 24 | , fromList 25 | , orthonormal) where 26 | 27 | import Color 28 | 29 | data Vec = Vec { x :: !Double, 30 | y :: !Double, 31 | z :: !Double} deriving (Eq, Show) 32 | 33 | data UV = UV { u :: !Double, 34 | v :: !Double } deriving (Eq, Show) 35 | 36 | instance Num Vec where 37 | {-# INLINE (+) #-} 38 | (Vec x1 y1 z1) + (Vec x2 y2 z2) = Vec (x1+x2) (y1+y2) (z1+z2) 39 | {-# INLINE (*) #-} 40 | (Vec x1 y1 z1) * (Vec x2 y2 z2) = Vec (x1*x2) (y1*y2) (z1*z2) 41 | {-# INLINE (-) #-} 42 | (Vec x1 y1 z1) - (Vec x2 y2 z2) = Vec (x1-x2) (y1-y2) (z1-z2) 43 | {-# INLINE negate #-} 44 | negate (Vec x y z) = Vec (-x) (-y) (-z) 45 | 46 | instance Num UV where 47 | {-# INLINE (+) #-} 48 | (UV x1 y1) + (UV x2 y2) = UV (x1+x2) (y1+y2) 49 | {-# INLINE (*) #-} 50 | (UV x1 y1) * (UV x2 y2) = UV (x1*x2) (y1*y2) 51 | {-# INLINE (-) #-} 52 | (UV x1 y1) - (UV x2 y2) = UV (x1-x2) (y1-y2) 53 | {-# INLINE negate #-} 54 | negate (UV x y) = UV (-x) (-y) 55 | 56 | {- Index lookup -} 57 | (@@) :: Vec -> Int -> Double 58 | v @@ 0 = x v 59 | v @@ 1 = y v 60 | v @@ 2 = z v 61 | v @@ _ = 0 62 | 63 | {- Exterior product -} 64 | class Ext a where 65 | mul :: Double -> a -> a 66 | mult :: a -> Double -> a 67 | 68 | instance Ext Vec where 69 | {-# INLINE mul #-} 70 | mul l (Vec x y z) = Vec (l*x) (l*y) (l*z) 71 | {-# INLINE mult #-} 72 | mult v l = mul l v 73 | 74 | instance Ext UV where 75 | {-# INLINE mul #-} 76 | mul l (UV x y) = UV (l*x) (l*y) 77 | {-# INLINE mult #-} 78 | mult v l = mul l v 79 | 80 | instance Ext Color where 81 | {-# INLINE mul #-} 82 | mul l (RGB x y z) = RGB (l*x) (l*y) (l*z) 83 | {-# INLINE mult #-} 84 | mult v l = mul l v 85 | 86 | type Position = Vec 87 | type Normal = Vec 88 | type Direction = Vec 89 | 90 | o :: Vec 91 | o = Vec 0 0 0 92 | 93 | xAxis :: Vec 94 | xAxis = Vec 1 0 0 95 | 96 | yAxis :: Vec 97 | yAxis = Vec 0 1 0 98 | 99 | zAxis :: Vec 100 | zAxis = Vec 0 0 1 101 | 102 | {- Functions -} 103 | dot :: Vec -> Vec -> Double 104 | {-# INLINE dot #-} 105 | dot (Vec x1 y1 z1) (Vec x2 y2 z2) = x1*x2 + y1*y2 + z1*z2 106 | 107 | cross :: Vec -> Vec -> Vec 108 | {-# INLINE cross #-} 109 | cross (Vec x1 y1 z1) (Vec x2 y2 z2) = 110 | Vec (y1*z2 - z1*y2) (z1*x2 - x1*z2) (x1*y2 - y1*x2) 111 | 112 | sqrLen :: Vec -> Double 113 | {-# INLINE sqrLen #-} 114 | sqrLen v = dot v v 115 | 116 | sqrDist :: Vec -> Vec -> Double 117 | {-# INLINE sqrDist #-} 118 | sqrDist v w = sqrLen (v - w) 119 | 120 | dist :: Vec -> Vec -> Double 121 | {-# INLINE dist #-} 122 | dist v w = sqrt (sqrDist v w) 123 | 124 | normalize :: Vec -> Vec 125 | {-# INLINE normalize #-} 126 | normalize v = mul (1 / (sqrt . sqrLen $ v)) v 127 | 128 | reflect :: Vec -> Vec -> Vec 129 | {-# INLINE reflect #-} 130 | reflect v n = v - mul (2 * dot v n) n 131 | 132 | refract :: Vec -> Vec -> Double -> Double -> Maybe Vec 133 | {-# INLINE refract #-} 134 | refract i n n1 n2 135 | | sin20 > 1 = Nothing 136 | | otherwise = Just $ mul n1n2 i + mul coeff n 137 | where n1n2 = n1 / n2 138 | cos0 = -(dot i n) 139 | sin20 = n1n2 * n1n2 * (1 - cos0*cos0) 140 | coeff = n1n2 * cos0 - sqrt (1.0-sin20) 141 | 142 | minV :: Vec -> Vec -> Vec 143 | {-# INLINE minV #-} 144 | minV (Vec a b c) (Vec x y z) = Vec (min a x) (min b y) (min c z) 145 | 146 | maxV :: Vec -> Vec -> Vec 147 | {-# INLINE maxV #-} 148 | maxV (Vec a b c) (Vec x y z) = Vec (max a x) (max b y) (max c z) 149 | 150 | {- Make a orthonormal bais -} 151 | orthonormal :: Vec -> (Vec, Vec, Vec) 152 | orthonormal r = (r, s, t) 153 | where s = if abs (x r) < abs (y r) && abs (x r) < abs (z r) 154 | then normalize $ Vec 0 (-(z r)) (y r) 155 | else if abs (y r) < abs (x r) && abs (y r) < abs (z r) 156 | then normalize $ Vec (-(z r)) 0 (x r) 157 | else normalize $ Vec (-(y r)) (x r) 0 158 | t = cross r s 159 | 160 | {- Type conversions -} 161 | fromList :: [Double] -> Vec 162 | fromList d = Vec (head d) (d !! 1) (d !! 2) 163 | 164 | toRGB :: Vec -> Color 165 | toRGB (Vec x y z) = RGB x y z 166 | 167 | fromRGB :: Color -> Vec 168 | fromRGB (RGB x y z) = Vec x y z 169 | -------------------------------------------------------------------------------- /src/test.hs: -------------------------------------------------------------------------------- 1 | module Main (main 2 | , computeArray) where 3 | 4 | import Control.Monad 5 | import Control.Monad.State (State, evalState, get, put) 6 | import System.Random (StdGen, mkStdGen, random) 7 | import Control.Applicative ((<$>)) 8 | 9 | type Rnd a = State StdGen a 10 | 11 | runRandom :: Rnd a -> Int -> a 12 | runRandom action seed = evalState action $ mkStdGen seed 13 | 14 | rand :: Rnd Double 15 | rand = do 16 | gen <- get 17 | let (r, gen') = random gen 18 | put gen' 19 | return r 20 | 21 | {- Uniform distributions -} 22 | uniform01 :: Rnd [Double] 23 | uniform01 = mapM (\_ -> rand) $ repeat () 24 | 25 | {- Get n samples uniformly distributed between 0 and 1 -} 26 | sampleUniform :: Int -> Rnd [Double] 27 | sampleUniform n = sequence $ replicate n rand 28 | 29 | computeArray :: Int -> Rnd [Bool] 30 | computeArray n = do 31 | let samples1 = runRandom (sampleUniform 10) 24 32 | let samples2 = runRandom (sampleUniform 10) 56 33 | let dat = zip samples1 samples2 34 | return $ uncurry (<) <$> dat 35 | 36 | main :: IO () 37 | main = do 38 | let seed = 48 39 | let res = runRandom computeArray seed 40 | putStrLn $ show res 41 | -------------------------------------------------------------------------------- /test.sh: -------------------------------------------------------------------------------- 1 | ./build.sh 2 | if [ $? -eq 0 ]; then 3 | echo "Compilation succeded, rendering..." 4 | time ./rayhs data/outScene.json 5 | open out.ppm 6 | else 7 | echo "Compilation failed!" 8 | fi 9 | -------------------------------------------------------------------------------- /testAll.sh: -------------------------------------------------------------------------------- 1 | ./build.sh 2 | if [ $? -eq 0 ]; then 3 | echo "Compilation succeded, rendering..." 4 | time ./rayhs -otexture.ppm data/texture.json 5 | open texture.ppm 6 | time ./rayhs -ooutScene.ppm data/outScene.json 7 | open outScene.ppm 8 | time ./rayhs -ocornell.ppm data/cornellBox.json 9 | open cornell.ppm 10 | time ./rayhs -odragon.ppm data/dragon.json 11 | open dragon.ppm 12 | else 13 | echo "Compilation failed!" 14 | fi 15 | --------------------------------------------------------------------------------