├── .gitignore ├── CMakeLists.txt ├── README.md ├── build ├── obj │ ├── forme.obj │ ├── light.obj │ ├── plane.obj │ ├── plane1.obj │ ├── plane2.obj │ ├── plane3.obj │ ├── shape1.obj │ └── triangle.obj ├── run.sh └── scenes │ ├── cbox1.sc │ ├── cbox2.sc │ ├── cbox3.sc │ ├── forme_cbox-v2.sc │ ├── forme_cbox.sc │ ├── random1.sc │ └── random2.sc └── src ├── main.cpp ├── math ├── coremaths.h ├── mathshelpers.h ├── matrix3.cpp ├── matrix3.h ├── matrix4.cpp ├── matrix4.h ├── vec2.cpp ├── vec2.h ├── vec3.cpp ├── vec3.h └── vec4.h ├── netpbm ├── image.h ├── netpbmloader.cpp ├── netpbmloader.h ├── pgmimage.cpp ├── pgmimage.h ├── ppmimage.cpp └── ppmimage.h └── pathtracer ├── bbox.cpp ├── bbox.h ├── camera.cpp ├── camera.h ├── color.h ├── config.h ├── helpers.h ├── intersection.h ├── material.h ├── object.h ├── objparser.cpp ├── objparser.h ├── pathtracer.h ├── plane.cpp ├── plane.h ├── ray.h ├── renderer.cpp ├── renderer.h ├── renderingtask.cpp ├── renderingtask.h ├── scene.cpp ├── scene.h ├── sceneparser.cpp ├── sceneparser.h ├── shading.cpp ├── shading.h ├── sphere.cpp ├── sphere.h ├── triangle.cpp └── triangle.h /.gitignore: -------------------------------------------------------------------------------- 1 | #cmake 2 | CmakeCache.txt 3 | Makefile 4 | CMakeFiles 5 | cmake_install.cmake 6 | 7 | #compiled source 8 | *.o 9 | *.out 10 | *.a 11 | 12 | #latex 13 | *.aux 14 | *.synctex.gz 15 | 16 | #other files 17 | *.swp 18 | *.swo 19 | *.log 20 | 21 | build/images/* 22 | build/linux/ 23 | build/osx/ 24 | 25 | #os file 26 | .DS_Store 27 | .DS_Store? 28 | ._* 29 | .Spotlight-V100 30 | .Trashes 31 | ehthumbs.db 32 | Thumbs.db 33 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8) 2 | project(pathtracer) 3 | 4 | if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") 5 | set(CMAKE_CXX_FLAGS "-g -std=c++11 -stdlib=libc++ -Wall -g -O0 -fms-extensions") 6 | endif(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") 7 | 8 | if (${CMAKE_SYSTEM_NAME} MATCHES "Linux") 9 | set(CMAKE_CXX_FLAGS "-g -std=c++0x -pthread -Wall -g -O0 -fms-extensions") 10 | endif(${CMAKE_SYSTEM_NAME} MATCHES "Linux") 11 | 12 | file(GLOB_RECURSE SOURCES "src/*.cpp") 13 | file(GLOB_RECURSE HEADERS "src/*.h") 14 | 15 | set(INCLUDE_DIRS "") 16 | foreach(_headerFile ${HEADERS}) 17 | get_filename_component(_dir ${_headerFile} PATH) 18 | list(APPEND INCLUDE_DIRS ${_dir}) 19 | endforeach() 20 | list(REMOVE_DUPLICATES INCLUDE_DIRS) 21 | 22 | include_directories(${INCLUDE_DIRS}) 23 | 24 | add_executable(pathtracer.out ${SOURCES}) 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | pathtracer 2 | ========== 3 | 4 | version 0.9.2 5 | 6 | dependencies 7 | ------------ 8 | 9 | This project uses cmake. 10 | 11 | #### mac osx 12 | 13 | Download and install [CMake](http://www.cmake.org/cmake/resources/software.html) 14 | if you don't already have it. 15 | To simplify installation you may use [Homebrew](http://brew.sh): 16 | 17 | ```bash 18 | brew install cmake 19 | ``` 20 | 21 | #### linux (ubuntu) 22 | 23 | ```bash 24 | sudo apt-get install cmake 25 | ``` 26 | 27 | build and run 28 | ------------- 29 | 30 | To build and run it you can either do: 31 | 32 | ```bash 33 | $ cd build 34 | $ ./run.sh scene_file_name samples_per_pixel 35 | ``` 36 | 37 | which will give you more information about the time it took to render the image, and save a png image into a images/ subfolder with the standard name scene-hour-sppx.png, or: 38 | 39 | ```bash 40 | $ cd build 41 | $ cmake .. && make 42 | $ ./pathtracer.out scenes/scene_file_name samples_per_pixel 43 | ``` 44 | which will only output an image.ppm file. 45 | 46 | usage 47 | ----- 48 | 49 | #### scenes 50 | 51 | To define a camera, you can provide a lens size (for depth of field) and the focus plane distance, if you don't, the rendering will be without depth of field (pinhole camera). For the other parameters, **p** is the position, **la** is the _look at_ position, and **res** defines the resolution of the film of the camera: 52 | 53 | ``` 54 | camera lens(0.08) focus(1.0) p(0.0, 2.5, -4.0) la(0.0, 2.5, 0.0) res(640, 480) 55 | ``` 56 | 57 | To define basic objects (planes & spheres), the object can be either a sphere with **s** or a plane with **p**, next **p** is the position of this object, **e** is its emission, **c** is its color, the material can be **s**, **d** or **r** for respectively _specular_, _diffuse_ or _refractive_ material. 58 | 59 | ``` 60 | object:s|p p(2.0, 1.0, 0.0) e(0.0, 0.0, 0.0) c(1.0, 1.0, 1.0) material:s|d|r 61 | ``` 62 | 63 | For meshes, you first have to define its _.obj_ file location, and the last parameters are the same as basic objects. 64 | 65 | ``` 66 | mesh:obj/plane1.obj p(0.0, 0.0, 0.0) e(0.0, 0.0, 0.0) c(1.0, 1.0, 1.0) material:s|d|r 67 | ``` 68 | 69 | #### example 70 | 71 | ```bash 72 | # cornell box scene 73 | camera lens(0.08) focus(1.0) p(0.0, 2.5, -4.0) la(0.0, 2.5, 0.0) res(640, 480) 74 | 75 | # light sphere 76 | object:s p(1.0, 3.5, 3.5) e(2.5, 2.5, 2.5) c(1.0, 1.0, 1.0) material:d 77 | 78 | # spheres 79 | object:s p(2.0, 1.0, 0.0) e(0.0, 0.0, 0.0) c(1.0, 1.0, 1.0) material:s 80 | object:s p(-2.9, 1.0, 2.0) e(0.0, 0.0, 0.0) c(1.0, 1.0, 1.0) material:r 81 | 82 | # floor plane 83 | object:p p(0.0, 0.0, 0.0) e(0.0, 0.0, 0.0) c(0.88, 0.85, 0.78) material:d 84 | 85 | # meshes / walls 86 | mesh:obj/plane1.obj p(0.0, 0.0, 0.0) e(0.0, 0.0, 0.0) c(1.0, 1.0, 1.0) material:d 87 | mesh:obj/plane2.obj p(0.0, 0.0, 0.0) e(0.0, 0.0, 0.0) c(0.41, 0.21, 0.35) material:d 88 | mesh:obj/plane3.obj p(0.0, 0.0, 0.0) e(0.0, 0.0, 0.0) c(0.81, 0.29, 0.0) material:d 89 | ``` 90 | 91 | #### results 92 | 93 | ![example](http://karim.naaji.fr/images/path_tracing3.png) 94 | 95 | First attempts on depth of field (there's still some artifacts): 96 | 97 | ![example](http://karim.naaji.fr/images/path_tracing4.png) 98 | 99 | licence 100 | ======= 101 | 102 | Copyright (C) 2014 Naaji Karim (karim.naaji@gmail.com) 103 | 104 | This program is free software: you can redistribute it and/or modify 105 | it under the terms of the GNU General Public License as published by 106 | the Free Software Foundation, either version 3 of the License, or 107 | (at your option) any later version. 108 | 109 | This program is distributed in the hope that it will be useful, 110 | but WITHOUT ANY WARRANTY; without even the implied warranty of 111 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 112 | GNU General Public License for more details. 113 | 114 | You should have received a copy of the GNU General Public License 115 | along with this program. If not, see . 116 | -------------------------------------------------------------------------------- /build/obj/forme.obj: -------------------------------------------------------------------------------- 1 | # Blender v2.62 (sub 0) OBJ File: '' 2 | # www.blender.org 3 | o Cube 4 | v 1.621475 0.751957 -2.058985 5 | v 0.058860 2.465518 1.654575 6 | v -3.594482 1.096932 3.170309 7 | v -1.941140 2.465518 -0.345425 8 | v 0.058860 4.465518 -0.345424 9 | v 0.794039 5.200698 2.389756 10 | v -1.941141 4.465518 1.654575 11 | v -1.941140 4.465518 -0.345425 12 | vn -0.032991 -0.998911 0.032991 13 | vn -0.132030 0.982413 -0.132030 14 | vn 0.991462 0.092203 0.092203 15 | vn 0.091146 0.091146 0.991657 16 | vn -0.946877 0.227402 -0.227403 17 | vn -0.223436 0.223437 -0.948764 18 | s off 19 | f 1//1 2//1 3//1 20 | f 1//1 3//1 4//1 21 | f 5//2 8//2 7//2 22 | f 5//2 7//2 6//2 23 | f 1//3 5//3 6//3 24 | f 1//3 6//3 2//3 25 | f 2//4 6//4 7//4 26 | f 2//4 7//4 3//4 27 | f 3//5 7//5 8//5 28 | f 3//5 8//5 4//5 29 | f 5//6 1//6 4//6 30 | f 5//6 4//6 8//6 31 | -------------------------------------------------------------------------------- /build/obj/light.obj: -------------------------------------------------------------------------------- 1 | v 4.1 4.8 4.5 2 | v 4.5 4.8 4.1 3 | v 4.6 4.0 4.2 4 | v 4.2 4.0 4.6 5 | 6 | f 1//2 2//3 3//1 7 | f 3//1 1//4 4//3 8 | -------------------------------------------------------------------------------- /build/obj/plane.obj: -------------------------------------------------------------------------------- 1 | v -50.0 50.0 3.0 2 | v 50.0 50.0 3.0 3 | v 50.0 0.0 3.0 4 | v -50.0 0.0 3.0 5 | 6 | f 1//2 2//3 3//1 7 | f 1//3 3//4 4//1 8 | -------------------------------------------------------------------------------- /build/obj/plane1.obj: -------------------------------------------------------------------------------- 1 | v -5.0 5.0 5.0 2 | v 5.0 5.0 5.0 3 | v 5.0 0.0 5.0 4 | v -5.0 0.0 5.0 5 | v -5.0 5.0 -5.0 6 | v 5.0 5.0 -5.0 7 | v 5.0 0.0 -5.0 8 | v -5.0 0.0 -5.0 9 | 10 | f 1//2 2//3 3//4 11 | f 1//3 3//4 4//1 12 | f 1//2 2//6 6//1 13 | f 1//5 5//6 6//1 14 | f 5//6 6//7 7//5 15 | f 5//7 7//8 8//5 16 | -------------------------------------------------------------------------------- /build/obj/plane2.obj: -------------------------------------------------------------------------------- 1 | v -5.0 5.0 -5.0 2 | v -5.0 5.0 5.0 3 | v -5.0 0.0 -5.0 4 | v -5.0 0.0 5.0 5 | f 1//2 2//3 3//1 6 | f 3//2 2//4 4//3 7 | -------------------------------------------------------------------------------- /build/obj/plane3.obj: -------------------------------------------------------------------------------- 1 | v 5.0 5.0 -5.0 2 | v 5.0 5.0 5.0 3 | v 5.0 0.0 -5.0 4 | v 5.0 0.0 5.0 5 | f 1//2 2//3 3//1 6 | f 3//2 2//4 4//3 7 | -------------------------------------------------------------------------------- /build/obj/shape1.obj: -------------------------------------------------------------------------------- 1 | # Blender v2.66 (sub 1) OBJ File: '' 2 | # www.blender.org 3 | v -5.000000 4.999999 5.000000 4 | v 5.000000 4.999999 5.000000 5 | v 5.000000 -0.000001 5.000000 6 | v -5.000000 -0.000001 5.000000 7 | v 5.000000 5.000001 -4.999999 8 | v -5.000000 5.000001 -4.999999 9 | v 5.000000 0.000001 -4.999999 10 | v -5.000000 0.000001 -4.999999 11 | v 0.696011 -0.186876 0.503495 12 | v 0.696011 -0.186876 2.503495 13 | v -1.303990 -0.186876 2.503494 14 | v -1.303989 -0.186876 0.503494 15 | v 0.696011 1.813124 0.503495 16 | v 0.696010 1.813124 2.503495 17 | v -1.303990 1.813124 2.503494 18 | v -1.303989 1.813124 0.503495 19 | v -0.212886 2.999198 2.566036 20 | v -0.212886 2.999198 1.145405 21 | v 1.207746 2.999198 1.145405 22 | v 1.207746 2.999198 2.566036 23 | v -0.212886 1.578567 2.566036 24 | v -0.212885 1.578567 1.145404 25 | v 1.207746 1.578567 1.145405 26 | v 1.207746 1.578567 2.566036 27 | v 1.948406 0.043726 0.762700 28 | v 1.948406 0.043726 2.136357 29 | v 0.574748 0.043726 2.136357 30 | v 0.574749 0.043726 0.762699 31 | v 1.948406 1.417384 0.762700 32 | v 1.948405 1.417384 2.136357 33 | v 0.574748 1.417383 2.136357 34 | v 0.574748 1.417383 0.762700 35 | v -0.670174 1.529619 0.062029 36 | v -0.670174 1.529619 1.374141 37 | v -1.982286 1.529618 1.374140 38 | v -1.982286 1.529618 0.062028 39 | v -0.670174 2.841731 0.062029 40 | v -0.670175 2.841731 1.374141 41 | v -1.982286 2.841730 1.374140 42 | v -1.982286 2.841730 0.062028 43 | v -1.266461 3.619861 1.415171 44 | v -1.266461 3.619861 0.483157 45 | v -0.334447 3.619861 0.483158 46 | v -0.334447 3.619861 1.415172 47 | v -1.266461 2.687848 1.415171 48 | v -1.266460 2.687848 0.483157 49 | v -0.334447 2.687848 0.483158 50 | v -0.334447 2.687848 1.415171 51 | v 0.151467 1.680907 0.232082 52 | v 0.151467 1.680907 1.133278 53 | v -0.749729 1.680906 1.133278 54 | v -0.749729 1.680906 0.232082 55 | v 0.151467 2.582103 0.232083 56 | v 0.151467 2.582103 1.133278 57 | v -0.749729 2.582102 1.133278 58 | v -0.749729 2.582102 0.232082 59 | f 1//1 2//1 3//1 60 | f 1//1 3//1 4//1 61 | f 1//2 2//2 5//2 62 | f 1//3 6//3 5//3 63 | f 6//1 5//1 7//1 64 | f 6//1 7//1 8//1 65 | f 17//3 18//3 19//3 66 | f 21//2 24//2 23//2 67 | f 17//4 21//4 22//4 68 | f 18//5 22//5 19//5 69 | f 19//6 23//6 20//6 70 | f 21//1 17//1 20//1 71 | f 20//3 17//3 19//3 72 | f 22//2 21//2 23//2 73 | f 18//7 17//7 22//7 74 | f 22//8 23//8 19//8 75 | f 23//6 24//6 20//6 76 | f 24//1 21//1 20//1 77 | f 9//3 10//3 11//3 78 | f 13//2 16//2 14//2 79 | f 9//4 13//4 14//4 80 | f 10//5 14//5 11//5 81 | f 11//6 15//6 12//6 82 | f 13//1 9//1 12//1 83 | f 12//3 9//3 11//3 84 | f 16//2 15//2 14//2 85 | f 10//7 9//7 14//7 86 | f 14//5 15//5 11//5 87 | f 15//6 16//6 12//6 88 | f 16//1 13//1 12//1 89 | f 25//3 26//3 27//3 90 | f 29//2 32//2 30//2 91 | f 25//4 29//4 30//4 92 | f 26//5 30//5 27//5 93 | f 27//6 31//6 28//6 94 | f 29//1 25//1 28//1 95 | f 28//3 25//3 27//3 96 | f 32//2 31//2 30//2 97 | f 26//7 25//7 30//7 98 | f 30//5 31//5 27//5 99 | f 31//6 32//6 28//6 100 | f 32//1 29//1 28//1 101 | f 41//3 42//3 43//3 102 | f 45//2 48//2 46//2 103 | f 41//4 45//4 46//4 104 | f 42//8 46//8 43//8 105 | f 43//6 47//6 44//6 106 | f 45//9 41//9 44//9 107 | f 44//3 41//3 43//3 108 | f 48//2 47//2 46//2 109 | f 42//7 41//7 46//7 110 | f 46//8 47//8 43//8 111 | f 47//6 48//6 44//6 112 | f 48//9 45//9 44//9 113 | f 33//3 34//3 35//3 114 | f 37//10 40//10 38//10 115 | f 33//4 37//4 38//4 116 | f 34//8 38//8 35//8 117 | f 35//6 39//6 36//6 118 | f 37//9 33//9 40//9 119 | f 36//3 33//3 35//3 120 | f 40//10 39//10 38//10 121 | f 34//7 33//7 38//7 122 | f 38//8 39//8 35//8 123 | f 39//6 40//6 36//6 124 | f 33//9 36//9 40//9 125 | f 49//11 50//11 51//11 126 | f 53//10 56//10 54//10 127 | f 49//4 53//4 54//4 128 | f 50//8 54//8 51//8 129 | f 51//6 55//6 52//6 130 | f 53//9 49//9 56//9 131 | f 52//11 49//11 51//11 132 | f 56//10 55//10 54//10 133 | f 50//7 49//7 54//7 134 | f 54//8 55//8 51//8 135 | f 55//6 56//6 52//6 136 | f 49//9 52//9 56//9 137 | -------------------------------------------------------------------------------- /build/obj/triangle.obj: -------------------------------------------------------------------------------- 1 | v -1.0 0.0 0.3 2 | v 0.0 1.0 0.4 3 | v 1.0 0.0 -0.4 4 | f 1//2 2//3 3//1 5 | -------------------------------------------------------------------------------- /build/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # ./run.sh scene_name samples_per_pixel 3 | # compile, build and run the path tracer 4 | # stores the output inside images/ 5 | 6 | cmake .. && make 7 | 8 | if [[ $? == 0 ]] 9 | then 10 | d1=$(date +"%s") 11 | 12 | ./pathtracer.out scenes/$1 $2 13 | 14 | if [[ $? != 0 ]] 15 | then 16 | echo -e "$(tput setaf 1)Bash: An error occured while running ./pathtracer" 17 | exit $? 18 | fi 19 | 20 | d2=$(date +"%s") 21 | d=$(($d2-$d1)) 22 | 23 | echo -e "$(tput bold)Bash: $(($d/60)) minutes and $(($d%60)) seconds elapsed." 24 | 25 | now=`date +"%d%b%Y-%s"` 26 | scene=`echo $1 | cut -d'.' -f1` 27 | filename="images/$scene-$now-$2sppx.png" 28 | 29 | mkdir -p images 30 | convert image.ppm $filename 31 | 32 | echo -e "$(tput bold)Bash: Image saved as $filename" 33 | if [[ "$OSTYPE" == "linux-gnu" ]]; then 34 | xdg-open $filename 35 | elif [[ "$OSTYPE" == "darwin12" ]]; then 36 | open $filename 37 | fi 38 | 39 | echo -e "$(tput bold)Bash: Remove of output file image.ppm" 40 | rm image.ppm 41 | fi 42 | -------------------------------------------------------------------------------- /build/scenes/cbox1.sc: -------------------------------------------------------------------------------- 1 | version 0.9.2 2 | # test scene 3 | camera lens(0.08) focus(1.5) p(0.0, 2.5, -4.0) la(0.0, 2.5, 0.0) res(640, 480) 4 | 5 | # spheres 6 | object:s p(2.5, 1.0, 2.5) e(0.0, 0.0, 0.0) c(0.85, 1.0, 0.9) material:d 7 | object:s p(-2.0, 1.0, 0.5) e(0.0, 0.0, 0.0) c(0.5, 0.5, 0.5) material:s 8 | object:s p(0.0, 4.5, 0.0) e(5.0, 5.0, 5.0) c(1.0, 1.0, 1.0) material:s 9 | 10 | # floor plane 11 | object:p p(0.0, 0.0, 0.0) e(0.0, 0.0, 0.0) c(0.88, 0.85, 0.78) material:d 12 | 13 | # meshes 14 | mesh:obj/plane1.obj p(0.0, 0.0, 0.0) e(0.0, 0.0, 0.0) c(1.0, 1.0, 1.0) material:d 15 | mesh:obj/plane2.obj p(0.0, 0.0, 0.0) e(0.0, 0.0, 0.0) c(0.41, 0.21, 0.35) material:d 16 | mesh:obj/plane3.obj p(0.0, 0.0, 0.0) e(0.0, 0.0, 0.0) c(0.81, 0.29, 0.0) material:d 17 | -------------------------------------------------------------------------------- /build/scenes/cbox2.sc: -------------------------------------------------------------------------------- 1 | version 0.9.2 2 | # test scene 3 | camera lens(0.1) focus(2.0) p(-1.0, 1.5, -4.0) la(0.0, 1.0, 0.0) res(640, 480) 4 | 5 | # spheres 6 | object:s p(0.0, 2.5, 3.5) e(3.5, 3.5, 3.5) c(1.0, 1.0, 1.0) material:d 7 | object:s p(0.0, 1.0, -1.0) e(0.0, 0.0, 0.0) c(1.0, 1.0, 1.0) material:r 8 | 9 | # floor plane 10 | object:p p(0.0, 0.0, 0.0) e(0.0, 0.0, 0.0) c(0.88, 0.88, 0.88) material:d 11 | 12 | # meshes 13 | mesh:obj/plane1.obj p(0.0, 0.0, 0.0) e(0.0, 0.0, 0.0) c(1.0, 1.0, 1.0) material:d 14 | mesh:obj/plane2.obj p(0.0, 0.0, 0.0) e(0.0, 0.0, 0.0) c(0.15, 0.28, 0.41) material:d 15 | mesh:obj/plane3.obj p(0.0, 0.0, 0.0) e(0.0, 0.0, 0.0) c(0.96, 0.72, 0.01) material:d 16 | -------------------------------------------------------------------------------- /build/scenes/cbox3.sc: -------------------------------------------------------------------------------- 1 | version 0.9.2 2 | # test scene 3 | camera lens(0.1) focus(2.3) p(1.0, 2.5, -1.8) la(0.5, 1.5, 0.0) res(640, 480) 4 | 5 | # spheres 6 | object:s p(3.0, 2.5, 4.0) e(3.5, 3.5, 3.5) c(1.0, 1.0, 1.0) material:d 7 | #object:s p(1.0, 1.0, -2.0) e(0.0, 0.0, 0.0) c(0.3, 0.3, 0.3) material:s 8 | #object:s p(-1.7, 1.0, -2.0) e(0.0, 0.0, 0.0) c(1.0, 1.0, 1.0) material:s 9 | 10 | # floor plane 11 | object:p p(0.0, 0.0, 0.0) e(0.0, 0.0, 0.0) c(0.88, 0.85, 0.78) material:d 12 | 13 | # meshes 14 | mesh:obj/shape1.obj p(0.0, 0.0, 0.0) e(0.0, 0.0, 0.0) c(1.0, 1.0, 1.0) material:d 15 | mesh:obj/plane2.obj p(0.0, 0.0, 0.0) e(0.0, 0.0, 0.0) c(0.15, 0.28, 0.41) material:d 16 | mesh:obj/plane3.obj p(0.0, 0.0, 0.0) e(0.0, 0.0, 0.0) c(0.96, 0.72, 0.01) material:d 17 | -------------------------------------------------------------------------------- /build/scenes/forme_cbox-v2.sc: -------------------------------------------------------------------------------- 1 | version 0.9.2 2 | # test scene 3 | camera lens(0.001) focus(2.0) p(0.0, 4.5, -4.0) la(0.0, 0.2, 0.0) res(640, 480) 4 | 5 | # spheres 6 | object:s p(1.0, 1.5, 3.5) e(2.6, 2.6, 2.6) c(1.0, 1.0, 1.0) material:d 7 | object:s p(2.0, 1.0, 0.0) e(0.0, 0.0, 0.0) c(1.0, 1.0, 1.0) material:s 8 | object:s p(0.0, 2.5, 0.0) e(0.0, 0.0, 0.0) c(1.0, 1.0, 1.0) material:r 9 | object:s p(-2.0, 1.5, 3.5) e(0.0, 0.0, 0.0) c(1.0, 1.0, 1.0) material:r 10 | object:s p(-1.0, 0.0, 0.0) e(0.0, 0.0, 0.0) c(1.0, 1.0, 1.0) material:d 11 | 12 | # floor plane 13 | object:p p(0.0, 0.0, 0.0) e(0.0, 0.0, 0.0) c(0.88, 0.85, 0.78) material:d 14 | 15 | # meshes 16 | #mesh:obj/plane1.obj p(0.0, 0.0, 0.0) e(0.0, 0.0, 0.0) c(1.0, 1.0, 1.0) material:d 17 | mesh:obj/plane2.obj p(0.0, 0.0, 0.0) e(0.0, 0.0, 0.0) c(0.15, 0.28, 0.41) material:d 18 | mesh:obj/plane3.obj p(0.0, 0.0, 0.0) e(0.0, 0.0, 0.0) c(0.96, 0.72, 0.01) material:d -------------------------------------------------------------------------------- /build/scenes/forme_cbox.sc: -------------------------------------------------------------------------------- 1 | versio 0.9.2 2 | # test scene 3 | camera lens(0.0) focus(0.0) p(0.0, 2.5, -4.0) la(0.0, 2.5, 0.0) res(640, 480) 4 | 5 | # spheres 6 | #object:s p(2.5, 1.0, 2.5) e(0.0, 0.0, 0.0) c(0.85, 1.0, 0.9) material:d 7 | #object:s p(-2.0, 1.0, 0.5) e(0.0, 0.0, 0.0) c(0.5, 0.5, 0.5) material:s 8 | 9 | # old light hidden by forme.obj: 10 | # object:s p(1.0, 2.5, 3.5) e(6.0, 6.0, 6.0) c(1.0, 1.0, 1.0) material:d 11 | 12 | object:s p(1.0, 3.5, 3.5) e(2.5, 2.5, 2.5) c(1.0, 1.0, 1.0) material:d 13 | object:s p(-1.0, 1.5, 0.0) e(0.0, 0.0, 0.0) c(0.25, 0.25, 0.25) material:s 14 | object:s p(2.0, 1.0, 0.0) e(0.0, 0.0, 0.0) c(1.0, 1.0, 1.0) material:s 15 | object:s p(0.0, 3.5, 0.0) e(0.0, 0.0, 0.0) c(0.95, 0.67, 0.68) material:r 16 | object:s p(-2.9, 1.0, 2.0) e(0.0, 0.0, 0.0) c(1.0, 1.0, 1.0) material:r 17 | #mesh:obj/forme.obj p(0.0, 0.0, 0.0) e(0.0, 0.0, 0.0) c(1.0, 1.0, 1.0) material:d 18 | 19 | # floor plane 20 | object:p p(0.0, 0.0, 0.0) e(0.0, 0.0, 0.0) c(0.88, 0.85, 0.78) material:d 21 | 22 | # meshes 23 | mesh:obj/plane1.obj p(0.0, 0.0, 0.0) e(0.0, 0.0, 0.0) c(1.0, 1.0, 1.0) material:d 24 | mesh:obj/plane2.obj p(0.0, 0.0, 0.0) e(0.0, 0.0, 0.0) c(0.41, 0.21, 0.35) material:d 25 | mesh:obj/plane3.obj p(0.0, 0.0, 0.0) e(0.0, 0.0, 0.0) c(0.81, 0.29, 0.0) material:d 26 | -------------------------------------------------------------------------------- /build/scenes/random1.sc: -------------------------------------------------------------------------------- 1 | version 0.9.2 2 | # test scene 3 | camera lens(0.0) focus(0.0) p(0.0, 2.5, -5.0) la(0.0, 0.0, -1.0) res(640, 480) 4 | # spheres 5 | object:s p(0.0, 3.0, 4.0) e(1.0, 1.0, 1.0) c(1.0, 1.0, 1.0) material:d 6 | object:s p(0.0, 5.0, -10.0) e(100.0, 100.0, 100.0) c(1.0, 1.0, 1.0) material:d 7 | object:s p(0.0, -0.5, -2.0) e(1.0, 1.0, 0.5) c(1.0, 1.0, 1.0) material:d 8 | object:s p(2.0, 2.0, -1.0) e(0.0, 0.0, 0.0) c(1.0, 1.0, 1.0) material:d 9 | #object:s p(0.0, 1.5, 0.5) e( 0.0, 0.0, 0.0) c(0.5, 0.5, 0.5) material:s 10 | object:s p(-2.5, 1.0, 0.0) e( 0.0, 0.0, 0.0) c(0.8, 0.6, 0.5) material:s 11 | # plane 12 | object:p p(0.0, 0.0, 0.0) e(0.0, 0.0, 0.0) c(0.9, 0.85, 0.8) material:d 13 | 14 | -------------------------------------------------------------------------------- /build/scenes/random2.sc: -------------------------------------------------------------------------------- 1 | version 0.9.2 2 | # test scene 3 | camera lens(0.05) focus(1.0) p(0.0, 2.5, -2.5) la(0.0, 0.0, 0.0) res(640, 480) 4 | 5 | # spheres 6 | object:s p(0.0, 1.0, 0.0) e(4.0, 4.0, 4.0) c(1.0, 1.0, 1.0) material:d 7 | 8 | # floor plane 9 | object:p p(0.0, 0.0, 0.0) e(0.0, 0.0, 0.0) c(0.88, 0.85, 0.78) material:d 10 | 11 | # meshes 12 | #mesh:obj/plane1.obj p(0.0, 0.0, 0.0) e(0.0, 0.0, 0.0) c(1.0, 1.0, 1.0) material:d 13 | #mesh:obj/plane2.obj p(0.0, 0.0, 0.0) e(0.0, 0.0, 0.0) c(1.0, 0.71, 0.21) material:d 14 | #mesh:obj/plane3.obj p(0.0, 0.0, 0.0) e(0.0, 0.0, 0.0) c(0.0, 0.29, 0.61) material:d 15 | -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "config.h" 4 | #include "renderer.h" 5 | #include "sceneparser.h" 6 | #include "scene.h" 7 | #include "pathtracer.h" 8 | 9 | int main(int argc, char** argv) { 10 | if(argc < 3) { 11 | cerr << "Abort: Must specify scene file and sppxl" << endl; 12 | return -1; 13 | } 14 | 15 | string scenefile(argv[1]); 16 | 17 | PrintVersion(); 18 | 19 | SceneParser parser(scenefile); 20 | Scene *scene = parser.BuildScene(); 21 | 22 | PPMImage *film = scene->GetCamera()->Film(); 23 | 24 | Renderer renderer(atoi(argv[2])); 25 | renderer.Init(*film); 26 | 27 | renderer.Render(scene); 28 | 29 | NetPBMLoader loader; 30 | loader.SavePPM(*film, "image"); 31 | 32 | delete scene; 33 | 34 | return 0; 35 | } 36 | -------------------------------------------------------------------------------- /src/math/coremaths.h: -------------------------------------------------------------------------------- 1 | #ifndef __CORE_MATHS_H__ 2 | #define __CORE_MATHS_H__ 3 | 4 | #include 5 | 6 | #include "matrix4.h" 7 | #include "matrix3.h" 8 | 9 | #include "vec2.h" 10 | #include "vec3.h" 11 | #include "vec4.h" 12 | 13 | #include "mathshelpers.h" 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /src/math/mathshelpers.h: -------------------------------------------------------------------------------- 1 | #ifndef __MATHS_HELPERS_H__ 2 | #define __MATHS_HELPERS_H__ 3 | 4 | #ifdef M_PI 5 | #undef M_PI 6 | #endif 7 | #define M_PI 3.14159265358979323846f 8 | #define INV_PI 0.31830988618379067154f 9 | #define INV_TWOPI 0.15915494309189533577f 10 | #define INV_FOURPI 0.07957747154594766788f 11 | 12 | #define PI_360 (M_PI * 2.0) 13 | 14 | #ifndef INFINITY 15 | #define INFINITY FLT_MAX 16 | #endif 17 | 18 | #define EPSILON 1e-5f 19 | 20 | inline float Radians(float deg) { 21 | return ((float)M_PI/180.f) * deg; 22 | } 23 | 24 | inline float Degrees(float rad) { 25 | return (180.f/(float)M_PI) * rad; 26 | } 27 | 28 | inline float Lerp(float t, float v1, float v2) { 29 | return (1.f - t) * v1 + t * v2; 30 | } 31 | 32 | inline float Clamp(float val, float low, float high) { 33 | if(val > high) return high; 34 | else if(val < low) return low; 35 | else return val; 36 | } 37 | 38 | inline float Max(float a, float b) { 39 | return a > b ? a : b; 40 | } 41 | 42 | inline float Min(float a, float b) { 43 | return a > b ? b : a; 44 | } 45 | 46 | inline void Swap(float& a, float& b) { 47 | float tmp = a; 48 | a = b; 49 | b = tmp; 50 | } 51 | 52 | #endif 53 | -------------------------------------------------------------------------------- /src/math/matrix3.cpp: -------------------------------------------------------------------------------- 1 | #include "matrix3.h" 2 | 3 | Matrix3::Matrix3() 4 | { 5 | ToIdentity(); 6 | } 7 | 8 | Matrix3::Matrix3(float elements[9]) { 9 | memcpy(this->array, elements, 9 * sizeof(float)); 10 | } 11 | 12 | Matrix3 Matrix3::GetInverse(const Matrix4& m1) 13 | { 14 | float a11 = m1.array[10] * m1.array[5] - m1.array[6] * m1.array[9]; 15 | float a21 = - m1.array[10] * m1.array[1] + m1.array[2] * m1.array[9]; 16 | float a31 = m1.array[6] * m1.array[1] - m1.array[2] * m1.array[5]; 17 | float a12 = - m1.array[10] * m1.array[4] + m1.array[6] * m1.array[8]; 18 | float a22 = m1.array[10] * m1.array[0] - m1.array[2] * m1.array[8]; 19 | float a32 = - m1.array[6] * m1.array[0] + m1.array[2] * m1.array[4]; 20 | float a13 = m1.array[9] * m1.array[4] - m1.array[5] * m1.array[8]; 21 | float a23 = - m1.array[9] * m1.array[0] + m1.array[1] * m1.array[8]; 22 | float a33 = m1.array[5] * m1.array[0] - m1.array[1] * m1.array[4]; 23 | 24 | float det = m1.array[0] * a11 + m1.array[1] * a12 + m1.array[2] * a13; 25 | 26 | if (det == 0.0) 27 | { 28 | return Matrix3::Identity(); 29 | } 30 | 31 | Matrix3 m2; 32 | 33 | float idet = 1.0 / det; 34 | 35 | m2.array[0] = idet * a11; m2.array[1] = idet * a21; m2.array[2] = idet * a31; 36 | m2.array[3] = idet * a12; m2.array[4] = idet * a22; m2.array[5] = idet * a32; 37 | m2.array[6] = idet * a13; m2.array[7] = idet * a23; m2.array[8] = idet * a33; 38 | 39 | return m2; 40 | } 41 | 42 | void Matrix3::Transpose() 43 | { 44 | float tmp; 45 | 46 | tmp = array[1]; array[1] = array[3]; array[3] = tmp; 47 | tmp = array[2]; array[2] = array[6]; array[6] = tmp; 48 | tmp = array[5]; array[5] = array[7]; array[7] = tmp; 49 | } 50 | 51 | Matrix3 Matrix3::Identity() 52 | { 53 | Matrix3 m; 54 | m.ToIdentity(); 55 | return m; 56 | } 57 | 58 | void Matrix3::ToZero() { 59 | for(int i = 0; i < 9; i++) { 60 | array[i] = 0.0f; 61 | } 62 | } 63 | 64 | void Matrix3::ToIdentity() 65 | { 66 | ToZero(); 67 | array[0] = array[4] = array[8] = 1; 68 | } -------------------------------------------------------------------------------- /src/math/matrix3.h: -------------------------------------------------------------------------------- 1 | #ifndef __MATRIX3_H__ 2 | #define __MATRIX3_H__ 3 | 4 | #include "matrix4.h" 5 | 6 | class Matrix3 { 7 | public: 8 | union 9 | { 10 | float data[3][3]; 11 | float array[9]; 12 | }; 13 | 14 | Matrix3(); 15 | Matrix3(float elements[9]); 16 | 17 | void Transpose(); 18 | void ToIdentity(); 19 | void ToZero(); 20 | 21 | static Matrix3 Identity(); 22 | static Matrix3 GetInverse(const Matrix4& m); 23 | }; 24 | 25 | #endif -------------------------------------------------------------------------------- /src/math/matrix4.cpp: -------------------------------------------------------------------------------- 1 | #include "matrix4.h" 2 | 3 | Matrix4::Matrix4(void) { 4 | ToIdentity(); 5 | } 6 | 7 | Matrix4::Matrix4(float elements[16]) { 8 | memcpy(this->array, elements, 16 * sizeof(float)); 9 | } 10 | 11 | Matrix4::~Matrix4(void) { 12 | ToIdentity(); 13 | } 14 | 15 | void Matrix4::ToIdentity() { 16 | ToZero(); 17 | 18 | array[0] = 1.0f; 19 | array[5] = 1.0f; 20 | array[10] = 1.0f; 21 | array[15] = 1.0f; 22 | } 23 | 24 | Matrix4& Matrix4::operator=(const Matrix4 &a) { 25 | if(this != &a) { 26 | for(int i = 0; i < 16; i++) { 27 | array[i] = a.array[i]; 28 | } 29 | } 30 | 31 | return *this; 32 | } 33 | 34 | 35 | void Matrix4::ToZero() { 36 | for(int i = 0; i < 16; i++) { 37 | array[i] = 0.0f; 38 | } 39 | } 40 | 41 | Vec3 Matrix4::GetPositionVector() const { 42 | return Vec3(array[12], array[13], array[14]); 43 | } 44 | 45 | void Matrix4::SetPositionVector(const Vec3 in) { 46 | array[12] = in.x; 47 | array[13] = in.y; 48 | array[14] = in.z; 49 | } 50 | 51 | Vec3 Matrix4::GetScalingVector() const{ 52 | return Vec3(array[0], array[5], array[10]); 53 | } 54 | 55 | void Matrix4::SetScalingVector(const Vec3 &in) { 56 | array[0] = in.x; 57 | array[5] = in.y; 58 | array[10] = in.z; 59 | } 60 | 61 | Matrix4 Matrix4::Identity() { 62 | Matrix4 m; 63 | 64 | m.ToIdentity(); 65 | return m; 66 | } 67 | 68 | Matrix4 Matrix4::CreatePerspective(float znear, float zfar, float aspect, float fov) { 69 | Matrix4 m; 70 | 71 | const float h = 1.0f / tan(fov * PI_360); 72 | float neg_depth = znear-zfar; 73 | 74 | m.array[0] = h / aspect; 75 | m.array[5] = h; 76 | m.array[10] = (zfar+znear) / neg_depth; 77 | m.array[11] = -1.0f; 78 | m.array[14] = 2.0f * (znear*zfar) / neg_depth; 79 | m.array[15] = 0.0f; 80 | 81 | return m; 82 | } 83 | 84 | Matrix4 Matrix4::CreateOrthographic(float znear, float zfar,float right, float left, float top, float bottom) { 85 | Matrix4 m; 86 | 87 | m.array[0] = 2.0f / (right-left); 88 | m.array[5] = 2.0f / (top-bottom); 89 | m.array[10] = -2.0f / (zfar-znear); 90 | 91 | m.array[12] = -(right+left) / (right-left); 92 | m.array[13] = -(top+bottom) / (top-bottom); 93 | m.array[14] = -(zfar+znear) / (zfar-znear); 94 | m.array[15] = 1.0f; 95 | 96 | return m; 97 | } 98 | 99 | Matrix4 Matrix4::CreateLookAt(const Vec3 &from, const Vec3 &lookingAt) { 100 | Matrix4 r; 101 | Matrix4 m; 102 | Vec3 f = (lookingAt - from); 103 | Vec3 up = Vec3::Up(); 104 | 105 | r.SetPositionVector(Vec3(-from.x, -from.y, -from.z)); 106 | f.Normalize(); 107 | 108 | Vec3 s = f.Cross(up); 109 | Vec3 u = s.Cross(f); 110 | 111 | m.array[0] = s.x; 112 | m.array[4] = s.y; 113 | m.array[8] = s.z; 114 | 115 | m.array[1] = u.x; 116 | m.array[5] = u.y; 117 | m.array[9] = u.z; 118 | 119 | m.array[2] = -f.x; 120 | m.array[6] = -f.y; 121 | m.array[10] = -f.z; 122 | 123 | return m*r; 124 | } 125 | 126 | Matrix4 Matrix4::CreateRotation(float degrees, const Vec3 &inaxis) { 127 | Matrix4 m; 128 | 129 | Vec3 axis = inaxis; 130 | 131 | axis.Normalize(); 132 | 133 | float c = cos((float)Radians(degrees)); 134 | float s = sin((float)Radians(degrees)); 135 | 136 | m.array[0] = (axis.x * axis.x) * (1.0f - c) + c; 137 | m.array[1] = (axis.y * axis.x) * (1.0f - c) + (axis.z * s); 138 | m.array[2] = (axis.z * axis.x) * (1.0f - c) - (axis.y * s); 139 | 140 | m.array[4] = (axis.x * axis.y) * (1.0f - c) - (axis.z * s); 141 | m.array[5] = (axis.y * axis.y) * (1.0f - c) + c; 142 | m.array[6] = (axis.z * axis.y) * (1.0f - c) + (axis.x * s); 143 | 144 | m.array[8] = (axis.x * axis.z) * (1.0f - c) + (axis.y * s); 145 | m.array[9] = (axis.y * axis.z) * (1.0f - c) - (axis.x * s); 146 | m.array[10] = (axis.z * axis.z) * (1.0f - c) + c; 147 | 148 | return m; 149 | } 150 | 151 | Matrix4 Matrix4::CreateScale(const Vec3 &scale) { 152 | Matrix4 m; 153 | 154 | m.array[0] = scale.x; 155 | m.array[5] = scale.y; 156 | m.array[10] = scale.z; 157 | 158 | return m; 159 | } 160 | 161 | Matrix4 Matrix4::CreateTranslation(const Vec3 &translation) { 162 | Matrix4 m; 163 | 164 | m.array[12] = translation.x; 165 | m.array[13] = translation.y; 166 | m.array[14] = translation.z; 167 | 168 | return m; 169 | } -------------------------------------------------------------------------------- /src/math/matrix4.h: -------------------------------------------------------------------------------- 1 | #ifndef __MATRIX4_H__ 2 | #define __MATRIX4_H__ 3 | 4 | #include 5 | #include 6 | #include "vec3.h" 7 | #include "vec4.h" 8 | #include "mathshelpers.h" 9 | 10 | class Matrix4 { 11 | public: 12 | union 13 | { 14 | float data[4][4]; 15 | float array[16]; 16 | }; 17 | 18 | Matrix4(void); 19 | Matrix4(float elements[16]); 20 | ~Matrix4(void); 21 | Matrix4& operator=(const Matrix4 &a); 22 | 23 | void ToZero(); 24 | void ToIdentity(); 25 | Vec3 GetPositionVector() const; 26 | void SetPositionVector(const Vec3 in); 27 | Vec3 GetScalingVector() const; 28 | void SetScalingVector(const Vec3 &in); 29 | 30 | static Matrix4 CreateRotation(float degrees, const Vec3 &axis); 31 | static Matrix4 CreateScale(const Vec3 &scale); 32 | static Matrix4 CreateTranslation(const Vec3 &translation); 33 | static Matrix4 CreatePerspective(float znear, float zfar, float aspect, float fov); 34 | static Matrix4 CreateOrthographic(float znear, float zfar,float right, float left, float top, float bottom); 35 | static Matrix4 CreateLookAt(const Vec3 &from, const Vec3 &lookingAt); 36 | 37 | static Matrix4 Identity(); 38 | 39 | inline Matrix4 operator*(const Matrix4 &a) const { 40 | Matrix4 out; 41 | 42 | for(unsigned int r = 0; r < 4; ++r) { 43 | for(unsigned int c = 0; c < 4; ++c) { 44 | out.array[c + (r*4)] = 0.0f; 45 | for(unsigned int i = 0; i < 4; ++i) { 46 | out.array[c + (r*4)] += this->array[c+(i*4)] * a.array[(r*4)+i]; 47 | } 48 | } 49 | } 50 | 51 | return out; 52 | } 53 | 54 | inline Vec3 operator*(const Vec3 &v) const { 55 | Vec3 vec; 56 | 57 | float temp; 58 | 59 | vec.x = v.x * array[0] + v.y * array[4] + v.z * array[8] + array[12]; 60 | vec.y = v.x * array[1] + v.y * array[5] + v.z * array[9] + array[13]; 61 | vec.z = v.x * array[2] + v.y * array[6] + v.z * array[10] + array[14]; 62 | 63 | temp = v.x * array[3] + v.y * array[7] + v.z * array[11] + array[15]; 64 | 65 | vec.x = vec.x / temp; 66 | vec.y = vec.y / temp; 67 | vec.z = vec.z / temp; 68 | 69 | return vec; 70 | }; 71 | 72 | inline Vec4 operator*(const Vec4 &v) const { 73 | return Vec4( 74 | v.x*array[0] + v.y * array[4] + v.z * array[8] + v.w * array[12], 75 | v.x*array[1] + v.y * array[5] + v.z * array[9] + v.w * array[13], 76 | v.x*array[2] + v.y * array[6] + v.z * array[10] + v.w * array[14], 77 | v.x*array[3] + v.y * array[7] + v.z * array[11] + v.w * array[15] 78 | ); 79 | }; 80 | 81 | inline friend std::ostream& operator<<(std::ostream& o, const Matrix4& m) { 82 | o << "\t" << m.array[0] << " " << m.array[1] << " " << m.array[2] << " " << m.array [3] << std::endl; 83 | o << "\t" << m.array[4] << " " << m.array[5] << " " << m.array[6] << " " << m.array [7] << std::endl; 84 | o << "\t" << m.array[8] << " " << m.array[9] << " " << m.array[10] << " " << m.array [11] << std::endl; 85 | o << "\t" << m.array[12] << " " << m.array[13] << " " << m.array[14] << " " << m.array [15] << std::endl; 86 | return o; 87 | } 88 | }; 89 | 90 | #endif 91 | -------------------------------------------------------------------------------- /src/math/vec2.cpp: -------------------------------------------------------------------------------- 1 | #include "vec2.h" 2 | 3 | Vec2::Vec2() { 4 | x = 0; 5 | y = 0; 6 | } 7 | 8 | Vec2::Vec2(float x_, float y_) { 9 | x = x_; 10 | y = y_; 11 | } 12 | 13 | Vec2::Vec2(const Vec2& v) { 14 | x = v.x; 15 | y = v.y; 16 | } 17 | 18 | Vec2::Vec2(const Vec2& from,const Vec2& to) { 19 | x = to.x - from.x; 20 | y = to.y - from.y; 21 | } 22 | 23 | Vec2& Vec2::operator= (const Vec2& v) { 24 | x = v.x; 25 | y = v.y; 26 | return *this; 27 | } 28 | 29 | Vec2& Vec2::operator+= (const Vec2& v) { 30 | x += v.x; 31 | y += v.y; 32 | return *this; 33 | } 34 | 35 | Vec2 Vec2::operator+ (const Vec2& v) const { 36 | Vec2 t = *this; 37 | t += v; 38 | return t; 39 | } 40 | 41 | Vec2 Vec2::operator+(const float a) const { 42 | Vec2 t = *this; 43 | t.x += a; 44 | t.y += a; 45 | return t; 46 | } 47 | 48 | Vec2 Vec2::operator-(const float a) const { 49 | Vec2 t = *this; 50 | t.x -= a; 51 | t.y -= a; 52 | return t; 53 | } 54 | 55 | Vec2 & Vec2::operator-= (const Vec2& v) { 56 | x -= v.x; 57 | y -= v.y; 58 | return *this; 59 | } 60 | 61 | Vec2 Vec2::operator-(const Vec2& v) const { 62 | Vec2 t = *this; 63 | t -= v; 64 | return t; 65 | } 66 | 67 | Vec2 & Vec2::operator*=(const float a) { 68 | x *= a; 69 | y *= a; 70 | return *this; 71 | } 72 | 73 | Vec2 Vec2::operator*(const float a)const { 74 | Vec2 t = *this; 75 | t *= a; 76 | return t; 77 | } 78 | 79 | Vec2 operator*(const float a, const Vec2 & v) { 80 | return Vec2(v.x*a, v.y*a); 81 | } 82 | 83 | Vec2& Vec2::operator/=(const float a) { 84 | x /= a; 85 | y /= a; 86 | return *this; 87 | } 88 | 89 | Vec2 Vec2::operator/(const float a)const { 90 | Vec2 t = *this; 91 | t /= a; 92 | return t; 93 | } 94 | 95 | float Vec2::length() const { 96 | return sqrt(x*x+y*y); 97 | } 98 | 99 | Vec2& Vec2::normalize() { 100 | (*this) /= length(); 101 | return (*this); 102 | } 103 | 104 | float Vec2::operator[](const int dim) const { 105 | if(dim == 0) return x; 106 | else return y; 107 | } 108 | -------------------------------------------------------------------------------- /src/math/vec2.h: -------------------------------------------------------------------------------- 1 | #ifndef __VEC2_H__ 2 | #define __VEC2_H__ 3 | 4 | #include 5 | #include 6 | 7 | using std::ostream; 8 | 9 | class Vec2 { 10 | public: 11 | union { 12 | struct { float x, y; }; 13 | float v[2]; 14 | }; 15 | 16 | Vec2(); 17 | Vec2(float x, float y); 18 | Vec2(const Vec2& v); 19 | Vec2(const Vec2& from,const Vec2 & to); 20 | 21 | Vec2& operator=(const Vec2 & v); 22 | Vec2& operator+=(const Vec2 & v); 23 | Vec2 operator+(const float a) const; 24 | Vec2 operator-(const float a) const; 25 | Vec2 operator+(const Vec2 & v) const; 26 | Vec2& operator-=(const Vec2 & v); 27 | Vec2 operator-(const Vec2 & v) const; 28 | Vec2& operator*=(const float a); 29 | Vec2 operator*(const float a)const; 30 | Vec2& operator/=(const float a); 31 | Vec2 operator/(const float a)const; 32 | float operator[](const int dim) const; 33 | friend Vec2 operator*(const float a,const Vec2 & v); 34 | 35 | float length()const; 36 | Vec2& normalize(); 37 | 38 | 39 | inline friend ostream& operator<<(ostream& o, const Vec2& vec) { 40 | o << "(" << vec.x << ", " << vec.y << ")"; 41 | return o; 42 | } 43 | }; 44 | #endif 45 | -------------------------------------------------------------------------------- /src/math/vec3.cpp: -------------------------------------------------------------------------------- 1 | #include "vec3.h" 2 | 3 | Vec3::Vec3() { 4 | x = 0; 5 | y = 0; 6 | z = 0; 7 | } 8 | 9 | Vec3::Vec3(float x_,float y_,float z_) { 10 | x = x_; 11 | y = y_; 12 | z = z_; 13 | } 14 | 15 | Vec3::Vec3(float val) { 16 | x = val; 17 | y = val; 18 | z = val; 19 | } 20 | 21 | Vec3::Vec3(const Vec3& v) { 22 | x = v.x; 23 | y = v.y; 24 | z = v.z; 25 | } 26 | 27 | Vec3::Vec3(const Vec3& from,const Vec3& to) { 28 | x = to.x - from.x; 29 | y = to.y - from.y; 30 | z = to.z - from.z; 31 | } 32 | 33 | Vec3& Vec3::operator=(const Vec3& v) { 34 | x = v.x; 35 | y = v.y; 36 | z = v.z; 37 | return *this; 38 | } 39 | 40 | Vec3& Vec3::operator+=(const Vec3& v) { 41 | x += v.x; 42 | y += v.y; 43 | z += v.z; 44 | return *this; 45 | } 46 | 47 | Vec3 Vec3::operator+(const Vec3& v) const { 48 | Vec3 t = *this; 49 | t += v; 50 | return t; 51 | } 52 | 53 | Vec3& Vec3::operator-=(const Vec3& v) { 54 | x -= v.x; 55 | y -= v.y; 56 | z -= v.z; 57 | return *this; 58 | } 59 | 60 | Vec3 Vec3::operator-(const Vec3& v) const { 61 | Vec3 t = *this; 62 | t -= v; 63 | return t; 64 | } 65 | 66 | Vec3 Vec3::operator-() const { 67 | Vec3 t = *this * -1.0f; 68 | return t; 69 | } 70 | 71 | Vec3& Vec3::operator*=(const float a) { 72 | x *= a; 73 | y *= a; 74 | z *= a; 75 | return *this; 76 | } 77 | 78 | Vec3 Vec3::operator*(const float a) const { 79 | Vec3 t = *this; 80 | t *= a; 81 | return t; 82 | } 83 | 84 | Vec3 operator*(const float a ,const Vec3& v) { 85 | return Vec3(v.x*a,v.y*a,v.z*a); 86 | } 87 | 88 | Vec3 Vec3::operator*(const Vec3& v) const { 89 | return Vec3(x*v.x, y*v.y, z*v.z); 90 | } 91 | 92 | Vec3& Vec3::operator/=(const float a) { 93 | x /= a; 94 | y /= a; 95 | z /= a; 96 | return *this; 97 | } 98 | 99 | Vec3 Vec3::operator/(const float a) const { 100 | Vec3 t = *this; 101 | t /= a; 102 | return t; 103 | } 104 | 105 | float Vec3::operator[](const int dim) const { 106 | if(dim == 0) return x; 107 | else if(dim == 1) return y; 108 | else return z; 109 | } 110 | 111 | Vec3 Vec3::Cross(const Vec3& v) const { 112 | Vec3 t; 113 | t.x = y*v.z - z*v.y; 114 | t.y = z*v.x - x*v.z; 115 | t.z = x*v.y - y*v.x; 116 | return t; 117 | } 118 | 119 | Vec3 Vec3::Abs(Vec3 v) { 120 | v.x = fabs(v.x); 121 | v.y = fabs(v.y); 122 | v.z = fabs(v.z); 123 | return v; 124 | } 125 | 126 | Vec3 Vec3::VClamp(Vec3 v, float low, float high) { 127 | v.x = Clamp(v.x, low, high); 128 | v.y = Clamp(v.y, low, high); 129 | v.z = Clamp(v.z, low, high); 130 | return v; 131 | } 132 | 133 | float Vec3::Dot(const Vec3& v) const { 134 | return x*v.x + y*v.y + z*v.z; 135 | } 136 | 137 | Vec3 Vec3::Up() { 138 | return Vec3(0.0, 1.0, 0.0); 139 | } 140 | 141 | float Vec3::Length() const { 142 | return sqrt(x*x + y*y + z*z); 143 | } 144 | 145 | Vec3& Vec3::Normalize() { 146 | (*this) /= Length(); 147 | return (*this); 148 | } 149 | 150 | Vec3 Vec3::Zero() { 151 | return Vec3(0, 0, 0); 152 | } 153 | -------------------------------------------------------------------------------- /src/math/vec3.h: -------------------------------------------------------------------------------- 1 | #ifndef __VEC3_H__ 2 | #define __VEC3_H__ 3 | 4 | #include 5 | #include 6 | #include "mathshelpers.h" 7 | 8 | using std::ostream; 9 | 10 | class Vec3 { 11 | public: 12 | union { 13 | struct { float x, y, z; }; 14 | struct { float r, g, b; }; 15 | float v[3]; 16 | }; 17 | 18 | Vec3(); 19 | Vec3(float x,float y,float z); 20 | Vec3(float val); 21 | Vec3(const Vec3& v); 22 | Vec3(const Vec3& from,const Vec3& to); 23 | 24 | Vec3& operator=(const Vec3& v); 25 | Vec3& operator+=(const Vec3& v); 26 | Vec3 operator+(const Vec3& v) const; 27 | Vec3& operator-=(const Vec3& v); 28 | Vec3 operator-(const Vec3& v) const; 29 | Vec3 operator-() const; 30 | Vec3& operator*=(const float a); 31 | Vec3 operator*(const float a)const; 32 | Vec3 operator*(const Vec3& v) const; 33 | Vec3& operator/=(const float a); 34 | Vec3 operator/(const float a)const; 35 | float operator[](const int dim) const; 36 | friend Vec3 operator*(const float a, const Vec3& v); 37 | 38 | static Vec3 Zero(); 39 | static Vec3 VClamp(Vec3 v, float low, float high); 40 | static Vec3 Abs(Vec3 v); 41 | static Vec3 Up(); 42 | Vec3 Cross(const Vec3& v) const; 43 | float Length() const; 44 | float Dot(const Vec3& v) const; 45 | Vec3& Normalize(); 46 | 47 | inline friend ostream& operator<<(ostream& o, const Vec3& vec) { 48 | o << "(" << vec.x << ", " << vec.y << ", " << vec.z << ")"; 49 | return o; 50 | } 51 | }; 52 | 53 | #endif 54 | -------------------------------------------------------------------------------- /src/math/vec4.h: -------------------------------------------------------------------------------- 1 | #ifndef __VECTOR4_H__ 2 | #define __VECTOR4_H__ 3 | 4 | class Vec4 { 5 | public: 6 | union { 7 | struct { float x, y, z, w; }; 8 | struct { float r, g, b, a; }; 9 | float v[4]; 10 | }; 11 | 12 | Vec4(void) { 13 | x = y = z = w = 1.0f; 14 | } 15 | 16 | Vec4(float x, float y, float z, float w) { 17 | this->x = x; 18 | this->y = y; 19 | this->z = z; 20 | this->w = w; 21 | } 22 | 23 | 24 | float operator[](const int dim) const { 25 | if(dim == 0) return x; 26 | else if(dim == 1) return y; 27 | else if(dim == 2) return z; 28 | else return w; 29 | } 30 | }; 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /src/netpbm/image.h: -------------------------------------------------------------------------------- 1 | #ifndef __IMAGE_H__ 2 | #define __IMAGE_H__ 3 | 4 | template class Image { 5 | public: 6 | Image() {} 7 | Image(int width, int height) { 8 | this->width = width; 9 | this->height = height; 10 | } 11 | 12 | virtual ~Image() {} 13 | 14 | int GetWidth() const { return width; } 15 | int GetHeight() const { return height; } 16 | int GetSize() const { return width * height; } 17 | 18 | virtual T operator()(int i, int j) const = 0; 19 | virtual T& operator()(int i, int j) = 0; 20 | 21 | protected: 22 | int width; 23 | int height; 24 | }; 25 | 26 | #endif 27 | -------------------------------------------------------------------------------- /src/netpbm/netpbmloader.cpp: -------------------------------------------------------------------------------- 1 | #include "netpbmloader.h" 2 | 3 | void NetPBMLoader::Read(std::string filename, std::string ext, s_NetPBMFileDesc* fileDesc) { 4 | std::string path = filename + ext; 5 | std::string line1; 6 | std::string line2; 7 | std::ifstream file(path.c_str(), std::ios::in | std::ios::binary); 8 | std::ifstream::pos_type start, end, size; 9 | std::ifstream::off_type newStart; 10 | 11 | if(!file) { 12 | std::cerr << "Error while opening " << path << std::endl; 13 | throw std::runtime_error("Can't open file" + path); 14 | } 15 | 16 | std::cout << "Reading " << path << std::endl; 17 | 18 | getline(file, line1); 19 | start = file.tellg(); 20 | getline(file, line2); 21 | 22 | std::cout << "Header: " << std::endl; 23 | std::cout << line1 << std::endl; 24 | 25 | if(line2[0] != '#') { 26 | file.seekg(start, std::ios::beg); 27 | } else { 28 | std::cout << line2 << std::endl; 29 | } 30 | 31 | file >> fileDesc->length; 32 | file >> fileDesc->width; 33 | file >> fileDesc->colors; 34 | 35 | std::cout << " - Width: " << fileDesc->width << ", Length: " << fileDesc->length << std::endl; 36 | std::cout << " - Colors: " << fileDesc->colors << std::endl; 37 | 38 | start = file.tellg(); 39 | file.seekg (0, std::ios::end); 40 | end = file.tellg(); 41 | size = end - start; 42 | 43 | char* memblock = new char[size]; 44 | newStart = static_cast(start); 45 | file.seekg(newStart+1, std::ios::beg); 46 | file.read(memblock, size); 47 | file.close(); 48 | 49 | fileDesc->memblock = (unsigned char*)memblock; 50 | } 51 | 52 | PGMImage NetPBMLoader::LoadPGM(std::string filename) { 53 | s_NetPBMFileDesc* fileDesc = new s_NetPBMFileDesc(); 54 | Read(filename, ".pgm", fileDesc); 55 | PGMImage image(fileDesc->length, fileDesc->width); 56 | 57 | for(int i = 0; i < image.GetWidth(); ++i) { 58 | for(int j = 0; j < image.GetHeight(); ++j) { 59 | image(i, j) = (float)(fileDesc->memblock[i*image.GetWidth()+j]); 60 | } 61 | } 62 | 63 | delete[] fileDesc->memblock; 64 | delete fileDesc; 65 | 66 | return image; 67 | } 68 | 69 | PPMImage NetPBMLoader::LoadPPM(std::string filename) { 70 | s_NetPBMFileDesc* fileDesc = new s_NetPBMFileDesc(); 71 | Read(filename, ".ppm", fileDesc); 72 | PPMImage image(fileDesc->length, fileDesc->width); 73 | const int nbChannels = 3; 74 | 75 | for(int i = 0; i < image.GetWidth(); ++i) { 76 | for(int j = 0; j < image.GetHeight()*nbChannels; j+=3) { 77 | Vec3 color; 78 | color.r = (float)(fileDesc->memblock[i*image.GetWidth()*nbChannels+j]); 79 | color.g = (float)(fileDesc->memblock[i*image.GetWidth()*nbChannels+j+1]); 80 | color.b = (float)(fileDesc->memblock[i*image.GetWidth()*nbChannels+j+2]); 81 | image(i, j/nbChannels) = color; 82 | } 83 | } 84 | 85 | delete[] fileDesc->memblock; 86 | delete fileDesc; 87 | 88 | return image; 89 | } 90 | 91 | 92 | void NetPBMLoader::SavePGM(PGMImage& pgmimage, std::string filename) { 93 | std::string path = filename + ".pgm"; 94 | std::ofstream file(path.c_str(), std::ios::out | std::ios::binary); 95 | 96 | if(file.is_open()) { 97 | time_t now = time(0); 98 | char* dt = ctime(&now); 99 | 100 | file << "P5\n"; 101 | file << "# " << dt; 102 | file << pgmimage.GetWidth() << " " << pgmimage.GetHeight() << "\n"; 103 | file << COLOR_LEVELS << "\n"; 104 | 105 | for(int j = 0; j < pgmimage.GetHeight(); ++j) { 106 | for(int i = 0; i < pgmimage.GetWidth(); ++i) { 107 | file << (char)(pgmimage(i, j)); 108 | } 109 | } 110 | 111 | file.close(); 112 | std::cout << "Saved file " << path << std::endl; 113 | } 114 | } 115 | 116 | void NetPBMLoader::SavePPM(PPMImage& pgmimage, std::string filename) { 117 | std::string path = filename + ".ppm"; 118 | std::ofstream file(path.c_str(), std::ios::out | std::ios::binary); 119 | 120 | if(file.is_open()) { 121 | time_t now = time(0); 122 | char* dt = ctime(&now); 123 | 124 | file << "P6\n"; 125 | file << "# " << dt; 126 | file << pgmimage.GetWidth() << " " << pgmimage.GetHeight() << "\n"; 127 | file << COLOR_LEVELS << "\n"; 128 | 129 | for(int j = 0; j < pgmimage.GetHeight(); ++j) { 130 | for(int i = 0; i < pgmimage.GetWidth(); ++i) { 131 | file << (char)(pgmimage(i, j).r); 132 | file << (char)(pgmimage(i, j).g); 133 | file << (char)(pgmimage(i, j).b); 134 | } 135 | } 136 | 137 | file.close(); 138 | std::cout << "Saved file " << path << std::endl; 139 | } 140 | } 141 | 142 | -------------------------------------------------------------------------------- /src/netpbm/netpbmloader.h: -------------------------------------------------------------------------------- 1 | #ifndef __NET_PBM_LOADER_H__ 2 | #define __NET_PBM_LOADER_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "vec3.h" 12 | #include "pgmimage.h" 13 | #include "ppmimage.h" 14 | 15 | #define COLOR_LEVELS 255 16 | 17 | struct s_NetPBMFileDesc { 18 | unsigned int length; 19 | unsigned int width; 20 | unsigned int colors; 21 | unsigned char* memblock; 22 | }; 23 | 24 | class NetPBMLoader { 25 | public: 26 | NetPBMLoader() {}; 27 | ~NetPBMLoader() {}; 28 | PGMImage LoadPGM(std::string filename); 29 | PPMImage LoadPPM(std::string filename); 30 | void SavePGM(PGMImage& pgmimage, std::string filename); 31 | void SavePPM(PPMImage& ppmimage, std::string filename); 32 | 33 | private: 34 | void Read(std::string filename, std::string ext, s_NetPBMFileDesc* fileDesc); 35 | }; 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /src/netpbm/pgmimage.cpp: -------------------------------------------------------------------------------- 1 | #include "pgmimage.h" 2 | 3 | PGMImage::PGMImage() : Image(0, 0) { 4 | data = NULL; 5 | } 6 | 7 | PGMImage::PGMImage(int width_, int height_) : Image(width_, height_) { 8 | data = new float[height*width]; 9 | 10 | for(int i = 0; i < width; ++i) { 11 | for(int j = 0; j < height; ++j) { 12 | (*this)(i,j) = 0.0; 13 | } 14 | } 15 | } 16 | 17 | PGMImage::PGMImage(const PGMImage& image) { 18 | height = image.height; 19 | width = image.width; 20 | data = new float[height*width]; 21 | 22 | for(int i = 0; i < width; ++i) { 23 | for(int j = 0; j < height; ++j) { 24 | (*this)(i,j) = image(i,j); 25 | } 26 | } 27 | } 28 | 29 | PGMImage& PGMImage::operator=(const PGMImage& image) { 30 | if(this != &image) { 31 | if(data != NULL) { 32 | delete[] data; 33 | } 34 | height = image.height; 35 | width = image.width; 36 | 37 | data = new float[height*width]; 38 | for(int i = 0; i < width; ++i) { 39 | for(int j = 0; j < height; ++j) { 40 | (*this)(i,j) = image(i,j); 41 | } 42 | } 43 | } 44 | return *this; 45 | } 46 | 47 | PGMImage::~PGMImage() { 48 | if(data != NULL) { 49 | delete[] data; 50 | } 51 | } 52 | 53 | float PGMImage::operator()(int i, int j) const { 54 | return data[j*height+i]; 55 | } 56 | 57 | float& PGMImage::operator()(int i, int j) { 58 | return data[j*height+i]; 59 | } 60 | 61 | void PGMImage::Threshold(float threshold, float newValue) { 62 | for(int i = 0; i < width; ++i) { 63 | for(int j = 0; j < height; ++j) { 64 | if((*this)(i,j) > threshold) { 65 | (*this)(i,j) = newValue; 66 | } 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/netpbm/pgmimage.h: -------------------------------------------------------------------------------- 1 | #ifndef __PGM_IMAGE_H__ 2 | #define __PGM_IMAGE_H__ 3 | 4 | #include 5 | #include "image.h" 6 | 7 | class PGMImage : public Image { 8 | public: 9 | PGMImage(); 10 | PGMImage(int width, int height); 11 | PGMImage(const PGMImage& image); 12 | PGMImage& operator=(const PGMImage& image); 13 | ~PGMImage(); 14 | 15 | float operator()(int i, int j) const; 16 | float& operator()(int i, int j); 17 | 18 | void Threshold(float threshold, float newValue); 19 | private: 20 | float* data; 21 | }; 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /src/netpbm/ppmimage.cpp: -------------------------------------------------------------------------------- 1 | #include "ppmimage.h" 2 | 3 | PPMImage::PPMImage() : Image(0, 0) { 4 | data = NULL; 5 | } 6 | 7 | PPMImage::PPMImage(int width_, int height_) : Image(width_, height_) { 8 | data = new Vec3*[height]; 9 | for(int j = 0; j < height; ++j) { 10 | data[j] = new Vec3[width]; 11 | } 12 | 13 | for(int i = 0; i < width; ++i) { 14 | for(int j = 0; j < height; ++j) { 15 | (*this)(i,j) = Vec3::Zero(); 16 | } 17 | } 18 | } 19 | 20 | PPMImage::PPMImage(const PPMImage& image) { 21 | height = image.height; 22 | width = image.width; 23 | data = new Vec3*[height]; 24 | for(int j = 0; j < height; ++j) { 25 | data[j] = new Vec3[width]; 26 | } 27 | 28 | for(int i = 0; i < width; ++i) { 29 | for(int j = 0; j < height; ++j) { 30 | (*this)(i,j) = image(i,j); 31 | } 32 | } 33 | } 34 | 35 | PPMImage& PPMImage::operator=(const PPMImage& image) { 36 | if(this != &image) { 37 | if(data != NULL) { 38 | for(int j = 0; j < height; ++j) 39 | delete[] data[j]; 40 | delete[] data; 41 | } 42 | height = image.height; 43 | width = image.width; 44 | 45 | data = new Vec3*[height]; 46 | for(int i = 0; i < width; ++i) { 47 | data[i] = new Vec3[width]; 48 | } 49 | for(int i = 0; i < width; ++i) { 50 | for(int j = 0; j < height; ++j) { 51 | (*this)(i,j) = image(i,j); 52 | } 53 | } 54 | } 55 | return *this; 56 | } 57 | 58 | PPMImage::~PPMImage() { 59 | if(data != NULL) { 60 | for(int j = 0; j < height; ++j) 61 | delete[] data[j]; 62 | delete[] data; 63 | } 64 | } 65 | 66 | Vec3 PPMImage::operator()(int i, int j) const { 67 | return data[j][i]; 68 | } 69 | 70 | Vec3& PPMImage::operator()(int i, int j) { 71 | return data[j][i]; 72 | } 73 | 74 | float* PPMImage::Data() const { 75 | return reinterpret_cast(data); 76 | } 77 | -------------------------------------------------------------------------------- /src/netpbm/ppmimage.h: -------------------------------------------------------------------------------- 1 | #ifndef __PPM_IMAGE_H__ 2 | #define __PPM_IMAGE_H__ 3 | 4 | #include 5 | #include 6 | 7 | #include "vec3.h" 8 | #include "image.h" 9 | 10 | class PPMImage : public Image { 11 | public: 12 | PPMImage(); 13 | PPMImage(int width, int height); 14 | PPMImage(const PPMImage& image); 15 | PPMImage& operator=(const PPMImage& image); 16 | ~PPMImage(); 17 | 18 | Vec3 operator()(int i, int j) const; 19 | Vec3& operator()(int i, int j); 20 | int GetGrayscale() const; 21 | float* Data() const; 22 | private: 23 | int grayscale; 24 | Vec3** data; 25 | }; 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /src/pathtracer/bbox.cpp: -------------------------------------------------------------------------------- 1 | #include "bbox.h" 2 | 3 | BBox::BBox(const Vec3 &min, const Vec3 &max) { 4 | this->min = Vec3(Min(min.x, max.x), Min(min.y, max.y), Min(min.z, max.z)); 5 | this->max = Vec3(Max(min.x, max.x), Max(min.y, max.y), Max(min.z, max.z)); 6 | } 7 | 8 | bool BBox::Intersect(const Ray &ray, float *mint, float *maxt) { 9 | float t0 = ray.mint; 10 | float t1 = ray.maxt; 11 | for(int i = 0; i < 3; ++i) { 12 | float invRayDir = 1.0f / ray.d[i]; 13 | float tNear = (min[i] - ray.o[i]) * invRayDir; 14 | float tFar = (max[i] - ray.o[i]) * invRayDir; 15 | if(tNear > tFar) { 16 | float tmp = tNear; 17 | tNear = tFar; 18 | tFar = tmp; 19 | } 20 | t0 = tNear > t0 ? tNear : t0; 21 | t1 = tFar < t1 ? tFar : t1; 22 | if(t0 > t1) return false; 23 | } 24 | if(mint) *mint = t0; 25 | if(maxt) *maxt = t1; 26 | return true; 27 | } 28 | 29 | Dimension BBox::Extent() { 30 | Vec3 diagonal = min - max; 31 | if(diagonal.x > diagonal.y && diagonal.x > diagonal.z) 32 | return DIM_X; 33 | else if(diagonal.y > diagonal.z) 34 | return DIM_Y; 35 | else 36 | return DIM_Z; 37 | } 38 | 39 | BBox Union(const BBox &box1, const BBox &box2) { 40 | BBox box; 41 | box.min.x = Min(box1.min.x, box2.min.x); 42 | box.min.y = Min(box1.min.y, box2.min.y); 43 | box.min.z = Min(box1.min.z, box2.min.z); 44 | box.max.x = Max(box1.max.x, box2.max.x); 45 | box.max.y = Max(box1.max.y, box2.max.y); 46 | box.max.z = Max(box1.max.z, box2.max.z); 47 | return box; 48 | } 49 | 50 | BBox Union(const BBox &b, const Vec3 &p) { 51 | BBox box; 52 | box.min.x = Min(b.min.x, p.x); 53 | box.min.y = Min(b.min.y, p.y); 54 | box.min.z = Min(b.min.z, p.z); 55 | box.max.x = Max(b.max.x, p.x); 56 | box.max.y = Max(b.max.y, p.y); 57 | box.max.z = Max(b.max.z, p.z); 58 | return box; 59 | } 60 | 61 | -------------------------------------------------------------------------------- /src/pathtracer/bbox.h: -------------------------------------------------------------------------------- 1 | #ifndef __BBOX_H__ 2 | #define __BBOX_H__ 3 | 4 | #include "config.h" 5 | #include "ray.h" 6 | 7 | enum Dimension { DIM_X, DIM_Y, DIM_Z }; 8 | 9 | class BBox { 10 | public: 11 | Vec3 min, max; 12 | BBox() {}; 13 | BBox(const Vec3 &min, const Vec3 &max); 14 | bool Intersect(const Ray &ray, float *mint, float *maxt); 15 | Dimension Extent(); 16 | 17 | friend BBox Union(const BBox &box1, const BBox &box2); 18 | friend BBox Union(const BBox &b, const Vec3 &p); 19 | }; 20 | 21 | BBox Union(const BBox &box1, const BBox &box2); 22 | BBox Union(const BBox &b, const Vec3 &p); 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /src/pathtracer/camera.cpp: -------------------------------------------------------------------------------- 1 | #include "camera.h" 2 | 3 | Camera::Camera() { 4 | lensRadius = 0.0f; 5 | focalDistance = 0.0f; 6 | } 7 | 8 | Camera::Camera(Vec3 &pos, Vec2 &resolution, float lensRad, float focal) 9 | : cp(pos), lensRadius(lensRad), focalDistance(focal) { 10 | film = new PPMImage(resolution.x, resolution.y); 11 | } 12 | 13 | Camera::~Camera() { 14 | if(film != NULL) 15 | delete film; 16 | } 17 | 18 | void Camera::LookAt(const Vec3 &p) { 19 | Vec3 up = Vec3::Up(); 20 | cd = (p - cp).Normalize(); 21 | cr = cd.Cross(up).Normalize(); 22 | cu = cr.Cross(cd).Normalize(); 23 | } 24 | 25 | float Camera::getLensRadius() const { 26 | return lensRadius; 27 | } 28 | 29 | float Camera::getFocalDistance() const { 30 | return focalDistance; 31 | } 32 | 33 | Vec2 Camera::SampleLens() const { 34 | Vec2 uv; 35 | uv.x = (2.0 * rand_0_1() - 1.0) * lensRadius; 36 | uv.y = (2.0 * rand_0_1() - 1.0) * lensRadius; 37 | return uv; 38 | } 39 | 40 | Ray Camera::PrimaryRay(const Vec2& sp) const { 41 | Vec2 p = -2.0f * sp + 1.0f; 42 | Vec3 rd = (cr * p.x + cu * p.y + cd).Normalize(); 43 | Ray r = Ray(cp, rd); 44 | return r; 45 | } 46 | -------------------------------------------------------------------------------- /src/pathtracer/camera.h: -------------------------------------------------------------------------------- 1 | #ifndef __CAMERA_H__ 2 | #define __CAMERA_H__ 3 | 4 | #include "ray.h" 5 | #include "config.h" 6 | #include "helpers.h" 7 | 8 | class Camera { 9 | public: 10 | Camera(); 11 | Camera(Vec3 &pos, Vec2 &resolution, float lensRadius, float focalDistance); 12 | ~Camera(); 13 | void LookAt(const Vec3 &p); 14 | 15 | Vec3 GetRight() const { return cr; } 16 | Vec3 GetUp() const { return cu; } 17 | Vec3 GetDir() const { return cd; } 18 | Vec3 GetPos() const { return cp; } 19 | 20 | Ray PrimaryRay(const Vec2& sp) const; 21 | PPMImage* Film() const { return film; } 22 | Vec2 SampleLens() const; 23 | float getLensRadius() const; 24 | float getFocalDistance() const; 25 | 26 | private: 27 | Vec3 cp; 28 | Vec3 cd; 29 | Vec3 cr; 30 | Vec3 cu; 31 | PPMImage *film; 32 | float lensRadius; 33 | float focalDistance; 34 | }; 35 | 36 | #endif 37 | -------------------------------------------------------------------------------- /src/pathtracer/color.h: -------------------------------------------------------------------------------- 1 | #ifndef __COLOR_H__ 2 | #define __COLOR_H__ 3 | 4 | #include "config.h" 5 | typedef Vec3 Color; 6 | 7 | #endif 8 | -------------------------------------------------------------------------------- /src/pathtracer/config.h: -------------------------------------------------------------------------------- 1 | #ifndef __CONFIG_H__ 2 | #define __CONFIG_H__ 3 | 4 | #include 5 | #include 6 | 7 | #include "coremaths.h" 8 | #include "netpbmloader.h" 9 | #include "ppmimage.h" 10 | #include "pathtracer.h" 11 | 12 | using namespace std; 13 | 14 | #define AA_MAX_DEPTH 1 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /src/pathtracer/helpers.h: -------------------------------------------------------------------------------- 1 | #ifndef __HELPERS_H__ 2 | #define __HELPERS_H__ 3 | 4 | inline float rand_0_1() { 5 | return (float) rand() / RAND_MAX; 6 | } 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /src/pathtracer/intersection.h: -------------------------------------------------------------------------------- 1 | #ifndef __INTERSECTION_H__ 2 | #define __INTERSECTION_H__ 3 | 4 | #include "config.h" 5 | 6 | class Object; 7 | 8 | class Intersection { 9 | public: 10 | Intersection() : t(0.0), obj(NULL) {} 11 | 12 | inline friend ostream& operator<<(ostream& o, const Intersection& isect) { 13 | o << "Intersection at " << isect.spos << ", t: " << isect.t << endl; 14 | o << " n: " << isect.n << endl; 15 | o << " p: " << isect.p; 16 | return o; 17 | } 18 | 19 | float t; 20 | Object *obj; 21 | Vec2 spos; 22 | Vec3 n; 23 | Vec3 p; 24 | }; 25 | 26 | #endif 27 | -------------------------------------------------------------------------------- /src/pathtracer/material.h: -------------------------------------------------------------------------------- 1 | #ifndef __MATERIAL_H__ 2 | #define __MATERIAL_H__ 3 | 4 | enum MaterialType { 5 | E_DIFFUSE, 6 | E_SPECULAR, 7 | E_REFRACT 8 | }; 9 | 10 | inline MaterialType MaterialByChar(char material) { 11 | switch(material) { 12 | case 'd': return E_DIFFUSE; 13 | case 's': return E_SPECULAR; 14 | case 'r': return E_REFRACT; 15 | default: return (MaterialType) -1; 16 | } 17 | } 18 | 19 | #endif 20 | -------------------------------------------------------------------------------- /src/pathtracer/object.h: -------------------------------------------------------------------------------- 1 | #ifndef __PRIMITIVE_H__ 2 | #define __PRIMITIVE_H__ 3 | 4 | #include "ray.h" 5 | #include "intersection.h" 6 | #include "material.h" 7 | #include "color.h" 8 | #include "config.h" 9 | #include "bbox.h" 10 | 11 | class Object { 12 | public: 13 | Object(Vec3 pos, Color col, Color emis) : 14 | position(pos), color(col), emission(emis) {} 15 | virtual bool Intersect(const Ray &ray, Intersection *isect) = 0; 16 | virtual ~Object() {} 17 | virtual string Description() const = 0; 18 | Vec3 virtual Normal(Vec3 p, Vec3 dir) const = 0; 19 | BBox virtual Bounds() const = 0; 20 | 21 | bool Emit() const { 22 | return emission.r > 0 || emission.g > 0 || emission.b > 0; 23 | } 24 | 25 | void FillIntersection(Intersection* isect, float t, const Ray& ray) { 26 | isect->t = t; 27 | isect->obj = this; 28 | isect->p = ray(t); 29 | isect->n = Normal(isect->p, ray.d); 30 | } 31 | 32 | Vec3 position; 33 | Color color; 34 | Color emission; 35 | MaterialType material; 36 | 37 | inline friend ostream& operator<<(ostream& o, const Object& obj) { 38 | o << obj.Description() << endl; 39 | o << "Position: " << obj.position << endl; 40 | o << "Color: " << obj.color << endl; 41 | o << "Material: "; 42 | switch(obj.material) { 43 | case E_DIFFUSE: o << "E_DIFFUSE" << endl; break; 44 | case E_REFRACT: o << "E_REFRACT" << endl; break; 45 | case E_SPECULAR: o << "E_SPECULAR" << endl; break; 46 | } 47 | return o; 48 | } 49 | 50 | private: 51 | Matrix4 transform; 52 | }; 53 | 54 | #endif 55 | -------------------------------------------------------------------------------- /src/pathtracer/objparser.cpp: -------------------------------------------------------------------------------- 1 | #include "objparser.h" 2 | 3 | void ObjParser::Parse(string objfile, Scene* scene, Vec3 pos, Vec3 col, Vec3 emis, MaterialType material) const { 4 | ifstream file(objfile.c_str(), ios::in); 5 | if(!file) { 6 | cerr << "Can't open file " << objfile << endl; 7 | return; 8 | } 9 | 10 | int lines = 0; 11 | while(file.ignore(std::numeric_limits::max(), '\n')) { 12 | ++lines; 13 | } 14 | file.close(); 15 | 16 | ifstream f(objfile.c_str(), ios::in); 17 | 18 | cout << "Loading " << objfile << ".. " << endl; 19 | 20 | string token; 21 | vector vertices; 22 | int currentLine = 0; 23 | 24 | while(!f.eof()) { 25 | f >> token; 26 | 27 | if(token == "#") { 28 | f.ignore(std::numeric_limits::max(), '\n'); 29 | continue; 30 | } else if(token == "v") { // vertex 31 | Vec3 vertex; 32 | f >> vertex.x >> vertex.y >> vertex.z; 33 | vertices.push_back(vertex); 34 | } else if(token == "vt") { // tex coord 35 | } else if(token == "vn") { // vertex normal 36 | } else if(token == "f") { // face 37 | string faceLine; 38 | getline(f, faceLine); 39 | 40 | for(unsigned int i = 0; i < faceLine.length(); ++i) { 41 | if(faceLine[i] == '/') { 42 | faceLine[i] = ' '; 43 | } 44 | } 45 | 46 | stringstream ss(faceLine); 47 | string faceToken; 48 | 49 | Vec3 faceVertex[3]; 50 | for(int i = 0; i < 6; ++i) { 51 | ss >> faceToken; 52 | if(faceToken.find_first_not_of("\t\n ") != string::npos) { 53 | if(i % 2 == 0) { 54 | faceVertex[i/2] = vertices[atoi(faceToken.c_str()) - 1]; 55 | } else { 56 | // normals 57 | } 58 | } 59 | } 60 | Triangle* triangle = new Triangle(faceVertex[0], faceVertex[1], faceVertex[2], pos, col, emis); 61 | triangle->material = material; 62 | scene->AddObject(triangle); 63 | } 64 | currentLine++; 65 | } 66 | f.close(); 67 | } 68 | -------------------------------------------------------------------------------- /src/pathtracer/objparser.h: -------------------------------------------------------------------------------- 1 | #ifndef __OBJ_PARSER_H__ 2 | #define __OBJ_PARSER_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "scene.h" 12 | #include "config.h" 13 | #include "triangle.h" 14 | 15 | class ObjParser { 16 | public: 17 | ObjParser() {} 18 | void Parse(string objfile, Scene* scene, Vec3 pos, Vec3 col, Vec3 emis, MaterialType material) const; 19 | }; 20 | 21 | #endif 22 | -------------------------------------------------------------------------------- /src/pathtracer/pathtracer.h: -------------------------------------------------------------------------------- 1 | #ifndef __PATH_TRACER_H__ 2 | #define __PATH_TRACER_H__ 3 | 4 | #include 5 | 6 | #define VERSION_MAJOR 0 7 | #define VERSION_MINOR 9 8 | #define VERSION_MAINT 2 9 | 10 | inline void PrintVersion() { 11 | std::cout << "VERSION -- " << 12 | VERSION_MAJOR << "." << 13 | VERSION_MINOR << "." << 14 | VERSION_MAINT << std::endl; 15 | } 16 | 17 | inline bool CompareVersion(int vmaj, int vmin, int vmaint) { 18 | return VERSION_MAJOR == vmaj && 19 | VERSION_MINOR == vmin && 20 | VERSION_MAINT == vmaint; 21 | } 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /src/pathtracer/plane.cpp: -------------------------------------------------------------------------------- 1 | #include "plane.h" 2 | 3 | bool Plane::Intersect(const Ray &ray, Intersection *isect) { 4 | float t = -ray.o.y / ray.d.y; 5 | 6 | if((!isect->obj || (t > 0.0 && t < isect->t)) && t > 0.0) { 7 | FillIntersection(isect, t, ray); 8 | return true; 9 | } 10 | 11 | return false; 12 | } 13 | 14 | Vec3 Plane::Normal(Vec3 p, Vec3 dir) const { 15 | Vec3 n = Vec3(0.0, 1.0, 0.0); 16 | if(n.Dot(dir) > 0.0) { 17 | n = -n; 18 | } 19 | return n; 20 | } 21 | 22 | string Plane::Description() const { 23 | string s = "Plane"; 24 | return s; 25 | } 26 | 27 | BBox Plane::Bounds() const { 28 | return BBox(); 29 | } 30 | -------------------------------------------------------------------------------- /src/pathtracer/plane.h: -------------------------------------------------------------------------------- 1 | #ifndef __PLANE_H__ 2 | #define __PLANE_H__ 3 | 4 | #include "object.h" 5 | 6 | class Plane : public Object { 7 | public: 8 | Plane(Vec3 p, Vec3 col, Vec3 emis) : Object(p, col, emis) {} 9 | ~Plane() {} 10 | bool Intersect(const Ray &ray, Intersection *isect); 11 | string Description() const; 12 | Vec3 Normal(Vec3 p, Vec3 dir) const; 13 | BBox Bounds() const; 14 | }; 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /src/pathtracer/ray.h: -------------------------------------------------------------------------------- 1 | #ifndef __RAY_H__ 2 | #define __RAY_H__ 3 | 4 | #include "config.h" 5 | 6 | class Ray { 7 | public: 8 | Ray() : mint(0.f), maxt(INFINITY), depth(0) { } 9 | Ray(const Vec3 &origin, const Vec3 &direction, 10 | float start = 0.0f, float end = INFINITY, int d = 0) 11 | : o(origin), d(direction), mint(start), maxt(end), depth(d) { } 12 | 13 | Vec3 operator()(float t) const { return o + d * t; } 14 | 15 | Vec3 o; 16 | Vec3 d; 17 | mutable float mint; 18 | mutable float maxt; 19 | int depth; 20 | 21 | inline friend ostream& operator<<(ostream& o, const Ray& r) { 22 | o << "ray d: " << r.d << " o: " << r.o; 23 | return o; 24 | } 25 | }; 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /src/pathtracer/renderer.cpp: -------------------------------------------------------------------------------- 1 | #include "renderer.h" 2 | 3 | Renderer::Renderer(int samples) : sppxl(samples) { 4 | mtx = new mutex(); 5 | tasks = new vector(); 6 | } 7 | 8 | void Renderer::Init(const PPMImage &film) { 9 | int width = film.GetWidth(); 10 | int height = film.GetHeight(); 11 | int bwidth = film.GetWidth() / 4; 12 | int bheight = film.GetHeight() / 4; 13 | int id = 0; 14 | 15 | for(int x = 0; x < width; x += bwidth) { 16 | int minx = x; 17 | int maxx = x + bwidth > width ? width : x + bwidth; 18 | for(int y = 0; y < height; y += bheight) { 19 | int miny = y; 20 | int maxy = y + bheight > height ? height : y + bheight; 21 | 22 | // create the new rendering task 23 | Bucket *bucket = new Bucket(minx, miny, maxx, maxy); 24 | RenderingTask *rt = new RenderingTask(bucket, sppxl, Vec2(width, height), ++id, mtx); 25 | tasks->push_back(rt); 26 | } 27 | } 28 | 29 | cout << "Initialized " << tasks->size() << " rendering tasks" << endl; 30 | } 31 | 32 | Renderer::~Renderer() { 33 | vector::iterator it; 34 | for(it = tasks->begin(); it != tasks->end(); it++) 35 | delete *it; 36 | delete tasks; 37 | delete mtx; 38 | } 39 | 40 | void Renderer::Render(Scene *scene) { 41 | thread *threads = new thread[tasks->size()]; 42 | int *progress = new int(); 43 | 44 | *progress = 0; 45 | 46 | for(unsigned int i = 0; i < tasks->size(); ++i) { 47 | RenderingTask *task = (*tasks)[i]; 48 | threads[i] = thread(&RenderingTask::Start, task, scene, progress); 49 | } 50 | 51 | // start threads 52 | for(unsigned int i = 0; i < tasks->size(); ++i) { 53 | threads[i].join(); 54 | } 55 | 56 | cout << endl; 57 | 58 | delete[] threads; 59 | delete progress; 60 | } 61 | -------------------------------------------------------------------------------- /src/pathtracer/renderer.h: -------------------------------------------------------------------------------- 1 | #ifndef __RENDERER_H__ 2 | #define __RENDERER_H__ 3 | 4 | #include 5 | #include 6 | 7 | #include "renderingtask.h" 8 | #include "scene.h" 9 | 10 | class Renderer { 11 | public: 12 | Renderer(int samples = 1); 13 | ~Renderer(); 14 | void Init(const PPMImage &film); 15 | void Render(Scene *scene); 16 | 17 | private: 18 | vector *tasks; 19 | int sppxl; 20 | mutex *mtx; 21 | }; 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /src/pathtracer/renderingtask.cpp: -------------------------------------------------------------------------------- 1 | #include "renderingtask.h" 2 | 3 | RenderingTask::~RenderingTask() { 4 | delete bucket; 5 | } 6 | 7 | void RenderingTask::Start(Scene* scene, int *progress) { 8 | PPMImage *film = scene->GetCamera()->Film(); 9 | 10 | int width = film->GetWidth(); 11 | int height = film->GetHeight(); 12 | float n = (float) width * height; 13 | 14 | float pxw = 1.0 / (float) width; 15 | float pxh = 1.0 / (float) height; 16 | float gamma = 2.2; 17 | 18 | for(int x = bucket->minx; x < bucket->maxx; ++x) { 19 | float xval = x / (float) width; 20 | for(int y = bucket->miny; y < bucket->maxy; ++y) { 21 | float yval = y / (float) height; 22 | Color c; 23 | 24 | for(int s = 0; s < sppxl; ++s) 25 | c += AverageColor(scene, xval, yval, pxw, pxh, 0, sppxl); 26 | c = (c / (float) sppxl); 27 | // gamma correction 28 | c = Vec3(pow(c.r, 1.0 / gamma), pow(c.g, 1.0 / gamma), pow(c.b, 1.0 / gamma)); 29 | 30 | (*film)(x, y) = Color::VClamp(c, 0.0, 1.0) * 255.0; 31 | *progress = *progress + 1; 32 | } 33 | mtx->lock(); 34 | fprintf(stdout, "\rProgress %5.2f%%", 100.0 * (float)*progress / n); 35 | mtx->unlock(); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/pathtracer/renderingtask.h: -------------------------------------------------------------------------------- 1 | #ifndef __RENDERING_TASK_H__ 2 | #define __RENDERING_TASK_H__ 3 | 4 | #include 5 | 6 | #include "config.h" 7 | #include "shading.h" 8 | #include "helpers.h" 9 | #include "scene.h" 10 | 11 | struct Bucket { 12 | Bucket(int mix, int miy, int max, int may) : 13 | minx(mix), miny(miy), maxx(max), maxy(may) {} 14 | int minx, miny; 15 | int maxx, maxy; 16 | }; 17 | 18 | class RenderingTask { 19 | public: 20 | RenderingTask(Bucket* bckt, int samplesppx, Vec2 imgSize, int identitifier, mutex* mutx) 21 | : bucket(bckt), sppxl(samplesppx), size(imgSize), id(identitifier), mtx(mutx) {} 22 | ~RenderingTask(); 23 | void Start(Scene* scene, int *progress); 24 | 25 | private: 26 | Bucket *bucket; 27 | int sppxl; 28 | Vec2 size; 29 | int id; 30 | mutex *mtx; 31 | }; 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /src/pathtracer/scene.cpp: -------------------------------------------------------------------------------- 1 | #include "scene.h" 2 | 3 | Scene::Scene(Camera *cam) 4 | : camera(cam) { 5 | objects = new vector(); 6 | lights = new vector(); 7 | } 8 | 9 | Scene::Scene() { 10 | objects = new vector(); 11 | lights = new vector(); 12 | } 13 | 14 | Scene::~Scene() { 15 | vector::iterator it; 16 | for(it = objects->begin(); it != objects->end(); ++it) 17 | delete *it; 18 | delete objects; 19 | delete lights; 20 | delete camera; 21 | } 22 | 23 | void Scene::AddObject(Object* object) { 24 | if(object->Emit()) { 25 | lights->push_back(object); 26 | } 27 | objects->push_back(object); 28 | } 29 | 30 | bool Scene::Intersect(const Ray& ray, Intersection *isect, Object *caller) const { 31 | bool hit = false; 32 | 33 | for(vector::iterator it = objects->begin(); it != objects->end(); ++it) { 34 | if(*it == caller) continue; 35 | hit |= (*it)->Intersect(ray, isect); 36 | if(!hit) isect->obj = NULL; 37 | } 38 | 39 | return hit; 40 | } 41 | 42 | unsigned int Scene::ObjectsCount() const { 43 | return objects->size(); 44 | } 45 | 46 | vector Scene::Lights() const { 47 | vector lghts(lights->cbegin(), lights->cend()); 48 | return lghts; 49 | } 50 | -------------------------------------------------------------------------------- /src/pathtracer/scene.h: -------------------------------------------------------------------------------- 1 | #ifndef __SCENE_H__ 2 | #define __SCENE_H__ 3 | 4 | #include "camera.h" 5 | #include "object.h" 6 | #include "config.h" 7 | 8 | class Scene { 9 | public : 10 | Scene(); 11 | Scene(Camera *cam); 12 | ~Scene(); 13 | 14 | bool Intersect(const Ray &ray, Intersection *isect, Object *caller) const; 15 | void AddObject(Object* object); 16 | void SetCamera(Camera *cam) { camera = cam; } 17 | Camera* GetCamera() const { return camera; } 18 | vector Lights() const; 19 | unsigned int ObjectsCount() const; 20 | 21 | private: 22 | Camera *camera; 23 | vector *objects; 24 | vector *lights; 25 | }; 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /src/pathtracer/sceneparser.cpp: -------------------------------------------------------------------------------- 1 | #include "sceneparser.h" 2 | 3 | Scene* SceneParser::BuildScene() const { 4 | ifstream file(filename.c_str(), ios::in); 5 | 6 | if(!file) { 7 | cerr << "Failed to open scene file " << filename << endl; 8 | return NULL; 9 | } 10 | 11 | Scene *scene = new Scene(); 12 | string line; 13 | 14 | cout << "Parsing scene " << filename << endl; 15 | 16 | if(file.is_open()) { 17 | // parse version 18 | int major; 19 | int minor; 20 | int maintenance; 21 | getline(file, line); 22 | sscanf(line.c_str(), "version %d.%d.%d", &major, &minor, &maintenance); 23 | 24 | if(!CompareVersion(major, minor, maintenance)) { 25 | cerr << "Scene version does not match with current path tracer version" << endl; 26 | return NULL; 27 | } 28 | 29 | while (file.good()) { 30 | getline(file, line); 31 | char token = line[0]; 32 | if(token == '#') { 33 | continue; 34 | } else if(token == 'c') { 35 | LoadCamera(scene, line.c_str()); 36 | } else if(token == 'o') { 37 | LoadObject(scene, line.c_str()); 38 | } else if(token == 'm') { 39 | LoadMesh(scene, line.c_str()); 40 | } 41 | } 42 | } 43 | 44 | cout << "Loaded scene with " << scene->ObjectsCount() << " objects "; 45 | cout << "and " << scene->Lights().size() << " lights" << endl; 46 | 47 | file.close(); 48 | 49 | return scene; 50 | } 51 | 52 | void SceneParser::LoadCamera(Scene* scene, const char* line) const { 53 | Vec3 la; 54 | Vec3 p; 55 | Vec2 res; 56 | float lens; 57 | float focal; 58 | 59 | int r = sscanf(line, "camera lens(%f) focus(%f) p(%f, %f, %f) la(%f, %f, %f) res(%f, %f)\n", 60 | &lens, &focal, &p.x, &p.y, &p.z, &la.x, &la.y, &la.z, &res.x, &res.y); 61 | if(r < 10) { 62 | cerr << "Error while parsing camera" << endl; 63 | return; 64 | } 65 | 66 | res.x = (int) res.x; 67 | res.y = (int) res.y; 68 | 69 | Camera *cam = new Camera(p, res, lens, focal); 70 | cam->LookAt(la); 71 | scene->SetCamera(cam); 72 | } 73 | 74 | void SceneParser::LoadMesh(Scene* scene, const char* line) const { 75 | Color c; 76 | Color e; 77 | Vec3 p; 78 | char m; 79 | char objfile[255]; 80 | 81 | int r = sscanf(line, "mesh:%s p(%f, %f, %f) e(%f, %f, %f) c(%f, %f, %f) material:%c\n", 82 | objfile, &p.x, &p.y, &p.z, &e.r, &e.g, &e.b, &c.r, &c.g, &c.b, &m); 83 | 84 | if(r < 11) { 85 | cerr << "Error while parsing object at line:" << endl; 86 | cerr << line << endl; 87 | return; 88 | } 89 | 90 | MaterialType material = MaterialByChar(m); 91 | 92 | if(material == -1) { 93 | cerr << "Unrecognized material at line:" << endl; 94 | cerr << line << endl; 95 | return; 96 | } 97 | 98 | objparser.Parse(string(objfile), scene, p, c, e, material); 99 | } 100 | 101 | void SceneParser::LoadObject(Scene* scene, const char* line) const { 102 | Color c; 103 | Color e; 104 | Vec3 p; 105 | char m; 106 | char o; 107 | 108 | int r = sscanf(line, "object:%c p(%f, %f, %f) e(%f, %f, %f) c(%f, %f, %f) material:%c\n", 109 | &o, &p.x, &p.y, &p.z, &e.r, &e.g, &e.b, &c.r, &c.g, &c.b, &m); 110 | 111 | if(r < 11) { 112 | cerr << "Error while parsing object at line:" << endl; 113 | cerr << line << endl; 114 | return; 115 | } 116 | 117 | Object *obj; 118 | 119 | switch(o) { 120 | case 's': obj = new Sphere(p, c, e); break; 121 | case 'p': obj = new Plane(p, c, e); break; 122 | default: 123 | cerr << "Unrecognized object at line:" << endl; 124 | cerr << line << endl; 125 | return; 126 | } 127 | 128 | MaterialType material = MaterialByChar(m); 129 | 130 | if(material == -1) { 131 | cerr << "Unrecognized material at line:" << endl; 132 | cerr << line << endl; 133 | return; 134 | } 135 | 136 | obj->material = material; 137 | scene->AddObject(obj); 138 | } 139 | -------------------------------------------------------------------------------- /src/pathtracer/sceneparser.h: -------------------------------------------------------------------------------- 1 | #ifndef __SCENE_PARSER_H__ 2 | #define __SCENE_PARSER_H__ 3 | 4 | #include 5 | #include 6 | 7 | #include "objparser.h" 8 | #include "scene.h" 9 | #include "object.h" 10 | #include "sphere.h" 11 | #include "triangle.h" 12 | #include "plane.h" 13 | #include "config.h" 14 | #include "pathtracer.h" 15 | 16 | class SceneParser { 17 | public: 18 | SceneParser(string scenefile) : filename(scenefile) {} 19 | 20 | Scene* BuildScene() const; 21 | 22 | private: 23 | void LoadCamera(Scene* scene, const char* line) const; 24 | void LoadObject(Scene* scene, const char* line) const; 25 | void LoadMesh(Scene* scene, const char* line) const; 26 | string filename; 27 | 28 | ObjParser objparser; 29 | }; 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /src/pathtracer/shading.cpp: -------------------------------------------------------------------------------- 1 | #include "shading.h" 2 | 3 | Color AverageColor(Scene *scene, float x, float y, float pxw, float pxh, int aadepth, int sppxl) { 4 | Camera *cam = scene->GetCamera(); 5 | 6 | if(aadepth == AA_MAX_DEPTH) { 7 | if(sppxl > 1) { 8 | x += rand_0_1() * pxw - pxw / 2.0; 9 | y += rand_0_1() * pxh - pxh / 2.0; 10 | } 11 | 12 | Ray ray = cam->PrimaryRay(Vec2(x,y)); 13 | 14 | if(cam->getLensRadius() > 0.) { 15 | Intersection isect; 16 | Vec2 uv = cam->SampleLens(); 17 | scene->Intersect(ray, &isect, NULL); 18 | float ft = abs(cam->getFocalDistance() / isect.p.z); 19 | Vec3 focus = ray(ft); 20 | ray.o = Vec3(ray.o.x + uv.x, ray.o.y + uv.y, ray.o.z); 21 | ray.d = (ray.d + focus - ray.o).Normalize(); 22 | } 23 | 24 | return Shade(scene, ray, 0, Vec2(x, y)); 25 | } 26 | 27 | Color c; 28 | 29 | c += AverageColor(scene, x - pxw / 2.0, y - pxh / 2.0, pxw / 2.0, pxh / 2.0, aadepth + 1, sppxl); 30 | c += AverageColor(scene, x + pxw / 2.0, y - pxh / 2.0, pxw / 2.0, pxh / 2.0, aadepth + 1, sppxl); 31 | c += AverageColor(scene, x - pxw / 2.0, y + pxh / 2.0, pxw / 2.0, pxh / 2.0, aadepth + 1, sppxl); 32 | c += AverageColor(scene, x + pxw / 2.0, y + pxh / 2.0, pxw / 2.0, pxh / 2.0, aadepth + 1, sppxl); 33 | 34 | return c / 4.0; 35 | } 36 | 37 | Color Shade(Scene *scene, const Ray& ray, int depth, const Vec2 &pixelPos, Object *caller) { 38 | Intersection isect; 39 | isect.spos = pixelPos; 40 | 41 | if(!scene->Intersect(ray, &isect, caller)) { 42 | // background color 43 | return Vec3::Zero(); 44 | } 45 | 46 | Object *obj = isect.obj; 47 | Color c = obj->color; 48 | 49 | if(depth > 8) { 50 | return obj->emission; 51 | } 52 | 53 | switch(obj->material) { 54 | case E_DIFFUSE: 55 | { 56 | float rdx, rdy, rdz; 57 | float magnitude; 58 | 59 | do { 60 | rdx = 2.0 * rand_0_1() - 1.0; 61 | rdy = 2.0 * rand_0_1() - 1.0; 62 | rdz = 2.0 * rand_0_1() - 1.0; 63 | magnitude = sqrt(rdx*rdx + rdy*rdy + rdz*rdz); 64 | } while(magnitude > 1.0); 65 | 66 | Vec3 d = Vec3(rdx / magnitude, rdy / magnitude, rdz / magnitude); 67 | if(d.Dot(isect.n) < 0.0) { 68 | d = -d; 69 | } 70 | Ray r(isect.p, d); 71 | return obj->emission + c * Shade(scene, r, depth + 1, pixelPos, obj); 72 | } 73 | break; 74 | case E_SPECULAR: 75 | { 76 | Vec3 d = ray.d - 2.0 * isect.n * isect.n.Dot(ray.d); 77 | d.Normalize(); 78 | Ray r = Ray(isect.p, d); 79 | return obj->emission + c * Shade(scene, r, depth + 1, pixelPos, obj); 80 | } 81 | break; 82 | case E_REFRACT: 83 | { 84 | bool into = ray.d.Dot(isect.n); 85 | Vec3 n = isect.n; 86 | Vec3 nl = n.Dot(ray.d) < 0 ? n : n * -1; 87 | 88 | Ray newRay(isect.p, ray.d - n * 2 * n.Dot(ray.d)); 89 | 90 | float nc = 1; 91 | float nt = 1.5; 92 | float nnt = into ? nc / nt : nt / nc; 93 | float ddn = ray.d.Dot(nl); 94 | float cos2t = 1 - nnt * nnt * (1 - ddn * ddn); 95 | 96 | if (cos2t < 0) { 97 | return obj->emission + c * Shade(scene, newRay, depth + 1, pixelPos, obj); 98 | } 99 | 100 | Vec3 tdir = (ray.d * nnt - n * ((into ? 1 : - 1) * (ddn * nnt + sqrt(cos2t)))); 101 | tdir.Normalize(); 102 | 103 | float a = nt - nc; 104 | float b = nt + nc; 105 | float R0 = a * a / (b * b); 106 | float d = 1 - (into ? -ddn : tdir.Dot(n)); 107 | float Re = R0 + (1 - R0) * d * d * d * d * d; 108 | float Tr = 1 - Re; 109 | 110 | if(depth > 2) { 111 | float P = .25 + .5 * Re; 112 | float r = rand_0_1(); 113 | 114 | if (r < P) { 115 | float RP = Re / P; 116 | return obj->emission + c * Shade(scene, newRay, depth + 1, pixelPos, obj) * RP; 117 | } else { 118 | float TP = Tr / (1 - P); 119 | return obj->emission + c * Shade(scene, Ray(isect.p, tdir), depth + 1, pixelPos, obj) * TP; 120 | } 121 | } else { 122 | return obj->emission + c * 123 | (Shade(scene, newRay, depth + 1, pixelPos, obj) * Re 124 | + Shade(scene, Ray(isect.p, tdir), depth + 1, pixelPos, obj) * Tr); 125 | } 126 | } 127 | break; 128 | } 129 | 130 | return obj->emission + c; 131 | } 132 | -------------------------------------------------------------------------------- /src/pathtracer/shading.h: -------------------------------------------------------------------------------- 1 | #ifndef __SHADING_H__ 2 | #define __SHADING_H__ 3 | 4 | #include "scene.h" 5 | #include "helpers.h" 6 | 7 | Color AverageColor(Scene *scene, float x, float y, float pxw, float pxh, int aadepth, int sppxl); 8 | Color Shade(Scene *scene, const Ray& ray, int depth, const Vec2 &pixelPos, Object *caller = NULL); 9 | 10 | #endif 11 | -------------------------------------------------------------------------------- /src/pathtracer/sphere.cpp: -------------------------------------------------------------------------------- 1 | #include "sphere.h" 2 | 3 | bool Sphere::Intersect(const Ray &ray, Intersection *isect) { 4 | Vec3 oc = ray.o - position; 5 | float b = 2.0 * oc.Dot(ray.d); 6 | float c = oc.Dot(oc) - 1.0; 7 | float delta = b*b - 4.0*c; 8 | 9 | if(delta < 0.0) 10 | return false; 11 | 12 | float t = (-b - sqrt(delta)) * 0.5; 13 | 14 | if((!isect->obj || t < isect->t) && t > 0.0) { 15 | FillIntersection(isect, t, ray); 16 | return true; 17 | } 18 | 19 | return false; 20 | } 21 | 22 | Vec3 Sphere::Normal(Vec3 p, Vec3 dir) const { 23 | return (p - position).Normalize(); 24 | } 25 | 26 | string Sphere::Description() const { 27 | string s = "Sphere"; 28 | return s; 29 | } 30 | 31 | BBox Sphere::Bounds() const { 32 | return BBox(); 33 | } 34 | -------------------------------------------------------------------------------- /src/pathtracer/sphere.h: -------------------------------------------------------------------------------- 1 | #ifndef __SPHERE_H__ 2 | #define __SPHERE_H__ 3 | 4 | #include "object.h" 5 | 6 | class Sphere : public Object { 7 | public: 8 | Sphere(Vec3 p, Vec3 col, Vec3 emis) : Object(p, col, emis) {} 9 | ~Sphere() {} 10 | bool Intersect(const Ray &ray, Intersection *isect); 11 | string Description() const; 12 | Vec3 Normal(Vec3 p, Vec3 dir) const; 13 | BBox Bounds() const; 14 | }; 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /src/pathtracer/triangle.cpp: -------------------------------------------------------------------------------- 1 | #include "triangle.h" 2 | 3 | bool Triangle::Intersect(const Ray &ray, Intersection *isect) { 4 | Vec3 e1 = (p2 - p1); 5 | Vec3 e2 = (p3 - p1); 6 | 7 | Vec3 s1 = ray.d.Cross(e2); 8 | float divisor = s1.Dot(e1); 9 | if(divisor == 0.0) 10 | return false; 11 | 12 | float invDivisor = 1.0f / divisor; 13 | Vec3 d = ray.o - p1; 14 | float b1 = d.Dot(s1) * invDivisor; 15 | if(b1 < 0.0 || b1 > 1.0) 16 | return false; 17 | 18 | Vec3 s2 = d.Cross(e1); 19 | float b2 = ray.d.Dot(s2) * invDivisor; 20 | if(b2 < 0.0 || b1 + b2 > 1.0) 21 | return false; 22 | 23 | float t = e2.Dot(s2) * invDivisor; 24 | if(t < ray.mint || t > ray.maxt) 25 | return false; 26 | 27 | if((!isect->obj || t < isect->t) && t > 0.0) { 28 | FillIntersection(isect, t, ray); 29 | return true; 30 | } 31 | 32 | return false; 33 | } 34 | 35 | Vec3 Triangle::Normal(Vec3 p, Vec3 dir) const { 36 | Vec3 n = (p1 - p2).Cross(p1 - p3); 37 | if(n.Dot(dir) > 0.0) { 38 | n = -n; 39 | } 40 | return n; 41 | } 42 | 43 | string Triangle::Description() const { 44 | string s = "Triangle"; 45 | return s; 46 | } 47 | 48 | BBox Triangle::Bounds() const { 49 | return BBox(); 50 | } 51 | -------------------------------------------------------------------------------- /src/pathtracer/triangle.h: -------------------------------------------------------------------------------- 1 | #ifndef __TRIANGLE_H__ 2 | #define __TRIANGLE_H__ 3 | 4 | #include "object.h" 5 | 6 | class Triangle : public Object { 7 | public: 8 | Triangle(Vec3 pt1, Vec3 pt2, Vec3 pt3, Vec3 pos, Vec3 col, Vec3 emis) 9 | : Object(pos, col, emis), p1(pt1), p2(pt2), p3(pt3) {} 10 | ~Triangle() {} 11 | bool Intersect(const Ray &ray, Intersection *isect); 12 | string Description() const; 13 | Vec3 Normal(Vec3 p, Vec3 dir) const; 14 | BBox Bounds() const; 15 | 16 | private: 17 | Vec3 p1, p2, p3; 18 | Vec3 n; 19 | }; 20 | 21 | #endif 22 | --------------------------------------------------------------------------------