├── include ├── core │ ├── EmbreeWrapper.h │ ├── BatchItem.h │ ├── Constants.h │ ├── OpenImageWrapper.h │ ├── RayCompressed.h │ ├── Buffer.h │ ├── SamplerInterface.h │ ├── RayIntersect.h │ ├── Convolve.h │ ├── RayDecompress.h │ ├── RandomGenerator.h │ ├── CameraInterface.h │ ├── GridSampler.h │ ├── Scene.h │ ├── RaySort.h │ ├── StratifiedSampler.h │ ├── IndependentSampler.h │ ├── Singleton.h │ ├── ObjectInterface.h │ ├── TextureInterface.h │ ├── Settings.h │ ├── RayBoundingbox.h │ ├── FilterInterface.h │ ├── Image.h │ ├── BoxFilter.h │ ├── Camera.h │ ├── TentFilter.h │ ├── LightInterface.h │ ├── ConstantTexture.h │ ├── StandardTexture.h │ ├── DirectionalBins.h │ ├── RayUncompressed.h │ ├── NullShader.h │ ├── Common.h │ ├── PinHoleCamera.h │ ├── ShaderInterface.h │ ├── Pathtracer.h │ ├── ThinLensCamera.h │ ├── QuadLight.h │ ├── PolygonObject.h │ ├── Integrator.h │ ├── LambertShader.h │ └── LayeredTexture.h └── framebuffer │ ├── PlatformSpecification.h │ └── Framebuffer.h ├── src ├── core │ ├── RandomGenerator.cpp │ ├── RayIntersect.cpp │ ├── Convolve.cpp │ ├── IndependentSampler.cpp │ ├── ConstantTexture.cpp │ ├── GridSampler.cpp │ ├── StratifiedSampler.cpp │ ├── LayeredTexture.cpp │ ├── BoxFilter.cpp │ ├── NullShader.cpp │ ├── RayDecompress.cpp │ ├── PinHoleCamera.cpp │ ├── StandardTexture.cpp │ ├── RayBoundingbox.cpp │ ├── ThinLensCamera.cpp │ ├── LambertShader.cpp │ ├── TentFilter.cpp │ ├── Camera.cpp │ ├── QuadLight.cpp │ ├── PolygonObject.cpp │ ├── DirectionalBins.cpp │ ├── RaySort.cpp │ └── Integrator.cpp ├── main.cpp └── framebuffer │ └── Framebuffer.cpp ├── .gitignore ├── README.md ├── LICENSE.md ├── cmake ├── FindOpenColorIO.cmake ├── FindEmbree.cmake ├── FindYamlCpp.cmake ├── FindOpenImageIO.cmake ├── FindOpenEXR.cmake ├── FindEigen3.cmake ├── FindGLEW.cmake ├── FindPTex.cmake ├── FindGLFW.cmake └── FindTBB.cmake ├── thirdparty └── tinyobjloader │ └── tiny_obj_loader.h └── CMakeLists.txt /include/core/EmbreeWrapper.h: -------------------------------------------------------------------------------- 1 | #ifndef _EMBREEWRAPPER_H_ 2 | #define _EMBREEWRAPPER_H_ 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | #endif -------------------------------------------------------------------------------- /src/core/RandomGenerator.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | MSC_NAMESPACE_BEGIN 4 | 5 | //Generate uniform sample (mutates class) 6 | float RandomGenerator::sample() 7 | { 8 | return m_uniform_dist(m_generator); 9 | } 10 | 11 | MSC_NAMESPACE_END -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .AppleDouble 3 | .LSOverride 4 | 5 | docs/ 6 | build/ 7 | 8 | # Icon must end with two \r 9 | Icon 10 | 11 | # Thumbnails 12 | ._* 13 | 14 | # Files that might appear on external disk 15 | .Spotlight-V100 16 | .Trashes 17 | 18 | # Directories potentially created on remote AFP share 19 | .AppleDB 20 | .AppleDesktop 21 | Network Trash Folder 22 | Temporary Items 23 | .apdisk -------------------------------------------------------------------------------- /src/core/RayIntersect.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | MSC_NAMESPACE_BEGIN 6 | 7 | void RayIntersect::operator()(const tbb::blocked_range< size_t >& r) const 8 | { 9 | // Test packing data for sse vectorization 10 | for(size_t index = r.begin(); index < r.end(); ++index) 11 | rtcIntersect(m_scene->rtc_scene, m_data[index].rtc_ray); 12 | } 13 | 14 | MSC_NAMESPACE_END -------------------------------------------------------------------------------- /include/core/BatchItem.h: -------------------------------------------------------------------------------- 1 | #ifndef _BATCHITEM_H_ 2 | #define _BATCHITEM_H_ 3 | 4 | #include 5 | 6 | #include 7 | 8 | MSC_NAMESPACE_BEGIN 9 | 10 | /** 11 | * @brief Used to represent an unprocessed batch 12 | * 13 | * Batch item cotains both a file path to the batch stored on disk as well as it's size in rays. 14 | */ 15 | struct BatchItem 16 | { 17 | std::string filename; 18 | size_t size; 19 | }; 20 | 21 | MSC_NAMESPACE_END 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /src/core/Convolve.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | MSC_NAMESPACE_BEGIN 4 | 5 | void Convolve::operator()(const tbb::blocked_range2d< size_t > &r) const 6 | { 7 | m_filter->convolve( 8 | m_image->width, 9 | m_image->height, 10 | m_image->base * m_image->base, 11 | r.rows().begin(), 12 | r.rows().end(), 13 | r.cols().begin(), 14 | r.cols().end(), 15 | &(m_image->samples[0]), 16 | &(m_image->pixels[0]) 17 | ); 18 | } 19 | 20 | MSC_NAMESPACE_END -------------------------------------------------------------------------------- /include/framebuffer/PlatformSpecification.h: -------------------------------------------------------------------------------- 1 | #ifndef _PLATFORM_SPECIFICATION_H_ 2 | #define _PLATFORM_SPECIFICATION_H_ 3 | 4 | #ifdef __APPLE__ 5 | #define GLFW_INCLUDE_GLCOREARB 6 | #include 7 | #elif __linux__ 8 | #define USING_GLEW 9 | #define GLEW_STATIC 10 | #include 11 | #include 12 | #elif _WIN32 13 | #define USING_GLEW 14 | #define GLEW_STATIC 15 | #include 16 | #include 17 | #endif 18 | 19 | #endif -------------------------------------------------------------------------------- /src/core/IndependentSampler.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | MSC_NAMESPACE_BEGIN 4 | 5 | void IndependentSampler::sample(const int _base, RandomGenerator* _random, float* _output) const 6 | { 7 | for(size_t index_x = 0; index_x < _base; ++index_x) 8 | { 9 | for(size_t index_y = 0; index_y < _base; ++index_y) 10 | { 11 | _output[2 * (index_y + index_x * _base) + 0] = _random->sample(); 12 | _output[2 * (index_y + index_x * _base) + 1] = _random->sample(); 13 | } 14 | } 15 | } 16 | 17 | MSC_NAMESPACE_END -------------------------------------------------------------------------------- /src/core/ConstantTexture.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | MSC_NAMESPACE_BEGIN 6 | 7 | TextureInterface* ConstantTexture::clone() 8 | { 9 | return new ConstantTexture(*this); 10 | } 11 | 12 | void ConstantTexture::initialize( 13 | const size_t _size, 14 | std::vector< float >& _u, 15 | std::vector< float >& _v, 16 | TextureSystem _texture_system 17 | ) 18 | { 19 | // Nothing to initialize 20 | } 21 | 22 | Colour3f ConstantTexture::colour(const size_t _index) const 23 | { 24 | return m_constant; 25 | } 26 | 27 | MSC_NAMESPACE_END -------------------------------------------------------------------------------- /include/core/Constants.h: -------------------------------------------------------------------------------- 1 | #ifndef _CONSTANTS_H_ 2 | #define _CONSTANTS_H_ 3 | 4 | #include 5 | 6 | #ifdef M_PI 7 | #undef M_PI 8 | #endif 9 | 10 | #define M_PI 3.14159265358979323846f 11 | #define M_INV_PI 0.31830988618379067154f 12 | #define M_PI_180 0.01745329251994329577f 13 | #define M_180_PI 57.2957795130823208768f 14 | 15 | #define M_EPSILON FLT_EPSILON 16 | #define M_INFINITY FLT_MAX 17 | 18 | #define MSC_NAMESPACE_BEGIN namespace msc { 19 | #define MSC_NAMESPACE_END } 20 | 21 | #define YAML_NAMESPACE_BEGIN namespace YAML { 22 | #define YAML_NAMESPACE_END } 23 | 24 | #endif -------------------------------------------------------------------------------- /include/core/OpenImageWrapper.h: -------------------------------------------------------------------------------- 1 | #ifndef _OPENIMAGEWRAPPER_H_ 2 | #define _OPENIMAGEWRAPPER_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | MSC_NAMESPACE_BEGIN 11 | 12 | typedef OpenImageIO::ImageCache* ImageCache; 13 | typedef OpenImageIO::TextureSystem* TextureSystem; 14 | typedef tbb::enumerable_thread_specific< TextureSystem > LocalTextureSystem; 15 | 16 | inline TextureSystem nullTextureSystem() 17 | { 18 | return NULL; 19 | } 20 | 21 | MSC_NAMESPACE_END 22 | 23 | #endif -------------------------------------------------------------------------------- /src/core/GridSampler.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | MSC_NAMESPACE_BEGIN 4 | 5 | void GridSampler::sample(const int _base, RandomGenerator* _random, float* _output) const 6 | { 7 | float cell_size = 1.f / _base; 8 | 9 | for(size_t index_x = 0; index_x < _base; ++index_x) 10 | { 11 | for(size_t index_y = 0; index_y < _base; ++index_y) 12 | { 13 | _output[2 * (index_y + index_x * _base) + 0] = index_x * cell_size + 0.5f * cell_size; 14 | _output[2 * (index_y + index_x * _base) + 1] = index_y * cell_size + 0.5f * cell_size; 15 | } 16 | } 17 | } 18 | 19 | MSC_NAMESPACE_END -------------------------------------------------------------------------------- /src/core/StratifiedSampler.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | MSC_NAMESPACE_BEGIN 4 | 5 | void StratifiedSampler::sample(const int _base, RandomGenerator* _random, float* _output) const 6 | { 7 | float cell_size = 1.f / _base; 8 | 9 | for(size_t index_x = 0; index_x < _base; ++index_x) 10 | { 11 | for(size_t index_y = 0; index_y < _base; ++index_y) 12 | { 13 | _output[2 * (index_y + index_x * _base) + 0] = index_x * cell_size + _random->sample() * cell_size; 14 | _output[2 * (index_y + index_x * _base) + 1] = index_y * cell_size + _random->sample() * cell_size; 15 | } 16 | } 17 | } 18 | 19 | MSC_NAMESPACE_END -------------------------------------------------------------------------------- /include/core/RayCompressed.h: -------------------------------------------------------------------------------- 1 | #ifndef _RAYCOMPRESSED_H_ 2 | #define _RAYCOMPRESSED_H_ 3 | 4 | #include 5 | 6 | MSC_NAMESPACE_BEGIN 7 | 8 | /** 9 | * @brief Structure to contain a compressed ray 10 | * 11 | * Minimal data required to store a ray that also represents the last segment of a light path within 12 | * a scene. This has a direct impact on the size of each batch and as result read/write performance. 13 | */ 14 | struct RayCompressed 15 | { 16 | float org[3]; 17 | float dir[3]; 18 | 19 | float weight[3]; 20 | float lastPdf; 21 | int rayDepth; 22 | int sampleID; 23 | }; 24 | 25 | MSC_NAMESPACE_END 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /include/core/Buffer.h: -------------------------------------------------------------------------------- 1 | #ifndef _BIN_H_ 2 | #define _BIN_H_ 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | MSC_NAMESPACE_BEGIN 10 | 11 | /** 12 | * @brief Holds local rays as they are produced to minimise thread contention 13 | * 14 | * Local thread buffer that will collect rays into six directional std::vectors during camera 15 | * sampling or surface shading. When a camera bucket or shading surface is finished, these will 16 | * then be loaded into the shared and memory mapped files. 17 | */ 18 | struct Buffer 19 | { 20 | std::vector< RayCompressed > direction[6]; 21 | }; 22 | 23 | MSC_NAMESPACE_END 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Sorted Shading for Uni-Directional Pathtracing: 2 | =============================================== 3 | 4 | This repository is the the implementation of a uni-directional pathtracer based upon the design described by Eisenacher et al. (2013), as well as other well established optimisations for production rendering. Compilation should have optimisations enabled and the Embree library will need to be compiled with RTCORE_ENABLE_RAY_MASK turned on. 5 | 6 | Required dependencies are: 7 | 8 | * CMake 2.8 9 | * Boost 1.55 10 | * TBB 4.2 11 | * Embree 2.6.1 12 | * OpenEXR 2.2 13 | * OpenColorIO 1.0.9 14 | * OpenImageIO 1.5.13 15 | * yaml-cpp 0.5.1 16 | * Eigen 3.2.4 17 | * Python 2.7 18 | * GLFW 3.0 19 | * OpenGL 3.3 20 | * GLEW 1.11 -------------------------------------------------------------------------------- /include/core/SamplerInterface.h: -------------------------------------------------------------------------------- 1 | #ifndef _SAMPLERINTERFACE_H_ 2 | #define _SAMPLERINTERFACE_H_ 3 | 4 | #include 5 | #include 6 | 7 | MSC_NAMESPACE_BEGIN 8 | 9 | /** 10 | * @brief Abstract interface class for image samplers 11 | * 12 | * This is a interface for using a sampler in a polymorphic sense. The purpose of the sampler is 13 | * to create a range of samples across a pixels surface when creating primary rays. 14 | */ 15 | class SamplerInterface 16 | { 17 | public: 18 | /** 19 | * @brief Virtual destructor required for interface 20 | */ 21 | virtual ~SamplerInterface() {} 22 | 23 | /** 24 | * @brief Create samples across pixel area 25 | * 26 | * @param[in] _base base of sample count 27 | * @param _random thread local random generator to prevent mutation 28 | * @param _output output array of samples 29 | */ 30 | virtual void sample(const int _base, RandomGenerator* _random, float* _output) const =0; 31 | }; 32 | 33 | MSC_NAMESPACE_END 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /include/core/RayIntersect.h: -------------------------------------------------------------------------------- 1 | #ifndef _RAYINTERSECT_H_ 2 | #define _RAYINTERSECT_H_ 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | MSC_NAMESPACE_BEGIN 11 | 12 | /** 13 | * @brief Functor class to intersect rays with scene geometry 14 | * 15 | * A simple functor class to allow parallelism while traversing rays across scene geometry using tbb. 16 | */ 17 | class RayIntersect 18 | { 19 | public: 20 | /** 21 | * @brief Initialiser list for class 22 | */ 23 | RayIntersect(Scene* _scene, RayUncompressed* _data) 24 | : m_scene(_scene) 25 | , m_data(_data) 26 | {;} 27 | 28 | /** 29 | * @brief Operator overloader to allow the class to act as a functor with tbb 30 | * 31 | * @param[in] r a one dimensional range over an array of rays 32 | */ 33 | void operator()(const tbb::blocked_range< size_t >& r) const; 34 | 35 | private: 36 | Scene* m_scene; 37 | RayUncompressed* m_data; 38 | }; 39 | 40 | MSC_NAMESPACE_END 41 | 42 | #endif -------------------------------------------------------------------------------- /include/core/Convolve.h: -------------------------------------------------------------------------------- 1 | #ifndef _CONVOLVE_H_ 2 | #define _CONVOLVE_H_ 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | MSC_NAMESPACE_BEGIN 11 | 12 | /** 13 | * @brief Used to filter the final image from sample data 14 | * 15 | * This is a tbb functor class that uses the filter and image data to convolve the final image in 16 | * a parrallel manner. 17 | */ 18 | class Convolve 19 | { 20 | public: 21 | /** 22 | * @brief Initialiser list for class 23 | */ 24 | Convolve(FilterInterface* _filter, Image* _image) 25 | : m_filter(_filter) 26 | , m_image(_image) 27 | {;} 28 | 29 | /** 30 | * @brief Operator overloader to allow the class to act as a functor with tbb 31 | * 32 | * @param[in] r a two dimentional blocked range over image resolution 33 | */ 34 | void operator()(const tbb::blocked_range2d< size_t > &r) const; 35 | 36 | private: 37 | FilterInterface* m_filter; 38 | Image* m_image; 39 | }; 40 | 41 | MSC_NAMESPACE_END 42 | 43 | #endif -------------------------------------------------------------------------------- /include/core/RayDecompress.h: -------------------------------------------------------------------------------- 1 | #ifndef _RAYDECOMPRESS_H_ 2 | #define _RAYDECOMPRESS_H_ 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | MSC_NAMESPACE_BEGIN 11 | 12 | /** 13 | * @brief Functor class to decompress an array of rays 14 | * 15 | * This class acts as a functor to decompress ray batches so that they can be sorted and traced 16 | * in a parallel manner using tbb. 17 | */ 18 | class RayDecompress 19 | { 20 | public: 21 | /** 22 | * @brief Initialiser list for class 23 | */ 24 | RayDecompress(RayCompressed* _input, RayUncompressed* _output) 25 | : m_input(_input) 26 | , m_output(_output) 27 | {;} 28 | 29 | /** 30 | * @brief Operator overloader to allow the class to act as a functor with tbb 31 | * 32 | * @param[in] r a one dimensional range over an array of rays 33 | */ 34 | void operator()(const tbb::blocked_range< size_t >& r) const; 35 | 36 | private: 37 | RayCompressed* m_input; 38 | RayUncompressed* m_output; 39 | }; 40 | 41 | MSC_NAMESPACE_END 42 | 43 | #endif -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Joshua Bainbridge 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /src/core/LayeredTexture.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | MSC_NAMESPACE_BEGIN 4 | 5 | TextureInterface* LayeredTexture::clone() 6 | { 7 | LayeredTexture* texture = new LayeredTexture(*this); 8 | texture->upper(m_upper->clone()); 9 | texture->lower(m_lower->clone()); 10 | texture->mask(m_mask->clone()); 11 | return texture; 12 | } 13 | 14 | void LayeredTexture::initialize( 15 | const size_t _size, 16 | std::vector< float >& _u, 17 | std::vector< float >& _v, 18 | TextureSystem _texture_system 19 | ) 20 | { 21 | m_upper->initialize(_size, _u, _v, _texture_system); 22 | m_lower->initialize(_size, _u, _v, _texture_system); 23 | m_mask->initialize(_size, _u, _v, _texture_system); 24 | 25 | m_colour.resize(_size); 26 | for(size_t index = 0; index < _size; ++index) 27 | { 28 | Colour3f mask = m_mask->colour(index); 29 | Colour3f inverse = Colour3f(1.f, 1.f, 1.f) - mask; 30 | m_colour[index] = (m_upper->colour(index) * mask) + (m_lower->colour(index) * inverse); 31 | } 32 | } 33 | 34 | Colour3f LayeredTexture::colour(const size_t _index) const 35 | { 36 | return m_colour[_index]; 37 | } 38 | 39 | MSC_NAMESPACE_END -------------------------------------------------------------------------------- /include/core/RandomGenerator.h: -------------------------------------------------------------------------------- 1 | #ifndef _RANDOMGENERATOR_H_ 2 | #define _RANDOMGENERATOR_H_ 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | MSC_NAMESPACE_BEGIN 10 | 11 | /** 12 | * @brief A uniform random generator 13 | * 14 | * This random generator uses boost's mersenne twister algorithm and a uniform distribution to 15 | * produce float values between zero and one. Local copies are created for each thread and passed 16 | * to scene objects to prevent mutation of shared data. 17 | */ 18 | class RandomGenerator 19 | { 20 | public: 21 | /** 22 | * @brief Creates a uniform random number between 0 and 1 23 | * 24 | * @return random number 25 | */ 26 | float sample(); 27 | 28 | /** 29 | * @brief Overload so that class can be used with std::generate 30 | */ 31 | inline float operator()(){return this->sample();} 32 | 33 | private: 34 | boost::mt19937 m_generator; 35 | boost::uniform_real m_uniform_dist; 36 | }; 37 | 38 | typedef tbb::enumerable_thread_specific< RandomGenerator > LocalRandomGenerator; 39 | 40 | MSC_NAMESPACE_END 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /include/core/CameraInterface.h: -------------------------------------------------------------------------------- 1 | #ifndef _CAMERAINTERFACE_H_ 2 | #define _CAMERAINTERFACE_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | MSC_NAMESPACE_BEGIN 9 | 10 | /** 11 | * @brief Abstract interface class for render camera 12 | * 13 | * This is a simple interface for using a camera in a polymorphic sense. As this operation is 14 | * unlikely to be used on single pixels it takes a range of data to compute the final result. 15 | */ 16 | class CameraInterface 17 | { 18 | public: 19 | /** 20 | * @brief Virtual destructor required for interface 21 | */ 22 | virtual ~CameraInterface() {} 23 | 24 | /** 25 | * @brief Creates primary rays from camera 26 | * 27 | * @param[in] _count sample count to process 28 | * @param _positions positions on film plane of samples 29 | * @param _random thread local random generator to prevent mutation 30 | * @param _ouput output of compressed rays 31 | */ 32 | virtual void sample(const int _count, float* _positions, RandomGenerator* _random, RayCompressed* _ouput) const =0; 33 | }; 34 | 35 | MSC_NAMESPACE_END 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /src/core/BoxFilter.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | MSC_NAMESPACE_BEGIN 4 | 5 | void BoxFilter::convolve( 6 | const size_t _width, 7 | const size_t _height, 8 | const size_t _samples, 9 | const size_t _rows_begin, 10 | const size_t _rows_end, 11 | const size_t _cols_begin, 12 | const size_t _cols_end, 13 | Sample* _input, 14 | Pixel* _output 15 | ) const 16 | { 17 | for(size_t index_x = _rows_begin; index_x < _rows_end; ++index_x) 18 | { 19 | for(size_t index_y = _cols_begin; index_y < _cols_end; ++index_y) 20 | { 21 | Colour3f summation(0.f, 0.f, 0.f); 22 | 23 | for(size_t index = 0; index < _samples; ++index) 24 | { 25 | size_t sample_index = (index_x * _height * _samples) + (index_y * _samples) + (index); 26 | summation[0] += _input[sample_index].r; 27 | summation[1] += _input[sample_index].g; 28 | summation[2] += _input[sample_index].b; 29 | } 30 | 31 | size_t pixel_index = index_y * _width + index_x; 32 | _output[pixel_index].r += (summation[0] / _samples); 33 | _output[pixel_index].g += (summation[1] / _samples); 34 | _output[pixel_index].b += (summation[2] / _samples); 35 | } 36 | } 37 | } 38 | 39 | MSC_NAMESPACE_END -------------------------------------------------------------------------------- /include/core/GridSampler.h: -------------------------------------------------------------------------------- 1 | #ifndef _GRIDSAMPLER_H_ 2 | #define _GRIDSAMPLER_H_ 3 | 4 | #include 5 | #include 6 | 7 | MSC_NAMESPACE_BEGIN 8 | 9 | /** 10 | * @brief Inherits from the sampler interface and represents a grid sampler function 11 | * 12 | * This will create an evenly ditributed range of samples across a single pixel without stocastic 13 | * variance unlike the stratified sampler. 14 | */ 15 | class GridSampler : public SamplerInterface 16 | { 17 | public: 18 | /** 19 | * @brief Create a grid of samples across pixel area 20 | * 21 | * @param[in] _base base of sample count 22 | * @param _random thread local random generator to prevent mutation 23 | * @param _output output array of samples 24 | */ 25 | void sample(const int _base, RandomGenerator* _random, float* _output) const; 26 | }; 27 | 28 | MSC_NAMESPACE_END 29 | 30 | YAML_NAMESPACE_BEGIN 31 | 32 | template<> struct convert 33 | { 34 | static bool decode(const Node& node, msc::GridSampler& rhs) 35 | { 36 | if(!node.IsMap() || node.size() != 1) 37 | return false; 38 | 39 | return true; 40 | } 41 | }; 42 | 43 | YAML_NAMESPACE_END 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /include/core/Scene.h: -------------------------------------------------------------------------------- 1 | #ifndef _SCENE_H_ 2 | #define _SCENE_H_ 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | MSC_NAMESPACE_BEGIN 16 | 17 | /** 18 | * @brief Data structure for scene information such as objects, lights and shaders 19 | * 20 | * The scene structure contains std::vectors of polymorphic pointers to implemented objects on 21 | * the heap. Smart pointers are used to manage memory and there is also a map that represents the 22 | * relationship between shaders and lights. The RTCScene is the acceleration structure used by 23 | * Embree to traverse rays across geometry stored in the objects vector. The scene should not mutate 24 | * after initial construction. 25 | */ 26 | struct Scene 27 | { 28 | RTCScene rtc_scene; 29 | 30 | std::vector< boost::shared_ptr< ObjectInterface > > objects; 31 | std::vector< boost::shared_ptr< ShaderInterface > > shaders; 32 | std::vector< boost::shared_ptr< LightInterface > > lights; 33 | std::map< int, int > shaders_to_lights; 34 | }; 35 | 36 | MSC_NAMESPACE_END 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /include/core/RaySort.h: -------------------------------------------------------------------------------- 1 | #ifndef _RAYSORT_H_ 2 | #define _RAYSORT_H_ 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | MSC_NAMESPACE_BEGIN 10 | 11 | /** 12 | * @brief Sorts rays according to a ray position and direction recursively and in parallel 13 | * 14 | * This will recursively sort rays according to the median split along the longest axis of a bounding 15 | * box. When the size reaches a minimum size it stops sorting rays according to position and starts 16 | * sorting according to direction to achieve maximum coherency. 17 | */ 18 | class RaySort 19 | { 20 | public: 21 | /** 22 | * @brief Initialiser list for class 23 | */ 24 | RaySort( 25 | size_t _begin, 26 | size_t _end, 27 | BoundingBox3f _limits, 28 | RayUncompressed* _output 29 | ) 30 | : m_begin(_begin) 31 | , m_end(_end) 32 | , m_limits(_limits) 33 | , m_output(_output) 34 | {;} 35 | 36 | /** 37 | * @brief Operator overloader to allow the class to act as a functor with tbb 38 | */ 39 | void operator()() const; 40 | 41 | private: 42 | size_t m_begin; 43 | size_t m_end; 44 | BoundingBox3f m_limits; 45 | RayUncompressed* m_output; 46 | }; 47 | 48 | MSC_NAMESPACE_END 49 | 50 | #endif -------------------------------------------------------------------------------- /include/core/StratifiedSampler.h: -------------------------------------------------------------------------------- 1 | #ifndef _STRATIFIEDSAMPLER_H_ 2 | #define _STRATIFIEDSAMPLER_H_ 3 | 4 | #include 5 | #include 6 | 7 | MSC_NAMESPACE_BEGIN 8 | 9 | /** 10 | * @brief Inherits from the sampler interface and represents a stratified sampler function 11 | * 12 | * This will create an ditributed range of samples across a single pixel with stocastic variance 13 | * unlike the grid sampler. 14 | */ 15 | class StratifiedSampler : public SamplerInterface 16 | { 17 | public: 18 | /** 19 | * @brief Create a stratified grid of samples across pixel area 20 | * 21 | * @param[in] _base base of sample count 22 | * @param _random thread local random generator to prevent mutation 23 | * @param _output output array of samples 24 | */ 25 | void sample(const int _base, RandomGenerator* _random, float* _output) const; 26 | }; 27 | 28 | MSC_NAMESPACE_END 29 | 30 | YAML_NAMESPACE_BEGIN 31 | 32 | template<> struct convert 33 | { 34 | static bool decode(const Node& node, msc::StratifiedSampler& rhs) 35 | { 36 | if(!node.IsMap() || node.size() != 1) 37 | return false; 38 | 39 | return true; 40 | } 41 | }; 42 | 43 | YAML_NAMESPACE_END 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /src/core/NullShader.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | MSC_NAMESPACE_BEGIN 4 | 5 | ShaderInterface* NullShader::clone() 6 | { 7 | return new NullShader(*this); 8 | } 9 | 10 | void NullShader::initialize( 11 | const size_t _size, 12 | std::vector< float >& _u, 13 | std::vector< float >& _v, 14 | TextureSystem _texture_system 15 | ) 16 | { 17 | // Nothing to initialize 18 | } 19 | 20 | float NullShader::continuation() const 21 | { 22 | return 1.f; 23 | } 24 | 25 | void NullShader::evaluate( 26 | const size_t _colour_index, 27 | const Vector3f& _input, 28 | const Vector3f& _output, 29 | const Vector3f& _normal, 30 | Colour3f* _weight, 31 | float* _cos_theta, 32 | float* _direct_pdfw 33 | ) const 34 | { 35 | *_weight = Colour3f(0.f, 0.f, 0.f); 36 | *_cos_theta = 1.f; 37 | *_direct_pdfw = 1.f * M_INV_PI * 0.5f; 38 | } 39 | 40 | void NullShader::sample( 41 | RandomGenerator* _random, 42 | const size_t _colour_index, 43 | const Vector3f& _output, 44 | const Vector3f& _normal, 45 | Vector3f* _input, 46 | Colour3f* _weight, 47 | float* _cos_theta, 48 | float* _direct_pdfw 49 | ) const 50 | { 51 | *_weight = Colour3f(0.f, 0.f, 0.f); 52 | *_cos_theta = 1.f; 53 | *_direct_pdfw = 1.f * M_INV_PI * 0.5f; 54 | } 55 | 56 | MSC_NAMESPACE_END -------------------------------------------------------------------------------- /include/core/IndependentSampler.h: -------------------------------------------------------------------------------- 1 | #ifndef _INDEPENDENTSAMPLER_H_ 2 | #define _INDEPENDENTSAMPLER_H_ 3 | 4 | #include 5 | #include 6 | 7 | MSC_NAMESPACE_BEGIN 8 | 9 | /** 10 | * @brief Inherits from the sampler interface and represents an independent sampler function 11 | * 12 | * This will produce samples across the pixel area in a stochastic fasion with no dependence on 13 | * other sample poitions. 14 | */ 15 | class IndependentSampler : public SamplerInterface 16 | { 17 | public: 18 | /** 19 | * @brief Create random and independent samples across pixel area 20 | * 21 | * @param[in] _base base of sample count 22 | * @param _random thread local random generator to prevent mutation 23 | * @param _output output array of samples 24 | */ 25 | void sample(const int _base, RandomGenerator* _random, float* _output) const; 26 | }; 27 | 28 | MSC_NAMESPACE_END 29 | 30 | YAML_NAMESPACE_BEGIN 31 | 32 | template<> struct convert 33 | { 34 | static bool decode(const Node& node, msc::IndependentSampler& rhs) 35 | { 36 | if(!node.IsMap() || node.size() != 1) 37 | return false; 38 | 39 | return true; 40 | } 41 | }; 42 | 43 | YAML_NAMESPACE_END 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /include/core/Singleton.h: -------------------------------------------------------------------------------- 1 | #ifndef _SINGLETON_H_ 2 | #define _SINGLETON_H_ 3 | 4 | #include 5 | 6 | #include 7 | 8 | MSC_NAMESPACE_BEGIN 9 | 10 | /** 11 | * @brief A templated class that is used to store one variable as singleton 12 | * 13 | * @tparam type data type to store 14 | * 15 | * This is primarly used for storing the path to the current scene file to allow for relative 16 | * directories to be created when constructing the scene. 17 | */ 18 | template < typename type > class Singleton 19 | { 20 | public: 21 | /** 22 | * @brief Retrieve reference to static data 23 | * 24 | * @return singleton reference 25 | */ 26 | static Singleton& instance() 27 | { 28 | static Singleton instance; 29 | return instance; 30 | } 31 | 32 | /** 33 | * @brief Get singleton data 34 | * 35 | * @return data 36 | */ 37 | inline type getData() const {return m_data;} 38 | 39 | /** 40 | * @brief Set singleton data 41 | * 42 | * @param[in] _data data 43 | */ 44 | inline void setData(type _data) {m_data = _data;} 45 | 46 | private: 47 | type m_data; 48 | 49 | private: 50 | Singleton() {;} 51 | }; 52 | 53 | typedef Singleton< std::string > SingletonString; 54 | 55 | MSC_NAMESPACE_END 56 | 57 | #endif 58 | -------------------------------------------------------------------------------- /src/core/RayDecompress.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | MSC_NAMESPACE_BEGIN 4 | 5 | void RayDecompress::operator()(const tbb::blocked_range< size_t >& r) const 6 | { 7 | for(size_t index = r.begin(); index < r.end(); ++index) 8 | { 9 | m_output[index].org[0] = m_input[index].org[0]; 10 | m_output[index].org[1] = m_input[index].org[1]; 11 | m_output[index].org[2] = m_input[index].org[2]; 12 | m_output[index].dir[0] = m_input[index].dir[0]; 13 | m_output[index].dir[1] = m_input[index].dir[1]; 14 | m_output[index].dir[2] = m_input[index].dir[2]; 15 | m_output[index].tnear = 0.001f; 16 | m_output[index].tfar = 100000.f; 17 | m_output[index].geomID = RTC_INVALID_GEOMETRY_ID; 18 | m_output[index].primID = RTC_INVALID_GEOMETRY_ID; 19 | m_output[index].instID = RTC_INVALID_GEOMETRY_ID; 20 | m_output[index].mask = 0xFFFFFFFF; 21 | m_output[index].time = 0.f; 22 | m_output[index].weight[0] = m_input[index].weight[0]; 23 | m_output[index].weight[1] = m_input[index].weight[1]; 24 | m_output[index].weight[2] = m_input[index].weight[2]; 25 | m_output[index].lastPdf = m_input[index].lastPdf; 26 | m_output[index].rayDepth = m_input[index].rayDepth; 27 | m_output[index].sampleID = m_input[index].sampleID; 28 | } 29 | } 30 | 31 | MSC_NAMESPACE_END -------------------------------------------------------------------------------- /include/core/ObjectInterface.h: -------------------------------------------------------------------------------- 1 | #ifndef _OBJECTINTERFACE_H_ 2 | #define _OBJECTINTERFACE_H_ 3 | 4 | #include 5 | 6 | MSC_NAMESPACE_BEGIN 7 | 8 | /** 9 | * @brief Abstract interface class for image samplers 10 | * 11 | * This is a simple interface for using a object in a polymorphic sense. It only requires that 12 | * each inherited class be able to retrieve texture coordinates using a primitive identification 13 | * number and some barycentric coordinates. 14 | */ 15 | class ObjectInterface 16 | { 17 | public: 18 | /** 19 | * @brief Virtual destructor required for interface 20 | */ 21 | virtual ~ObjectInterface() {} 22 | 23 | /** 24 | * @brief Getter method for shader id 25 | * 26 | * @return shader id 27 | */ 28 | virtual int shader() const =0; 29 | 30 | /** 31 | * @brief Gets u and v texture coordinates 32 | * 33 | * @param[in] _primitive primitive index value 34 | * @param[in] _s s coordinate 35 | * @param[in] _t t coordinate 36 | * @param _output output uv coordinates 37 | */ 38 | virtual void texture( 39 | const size_t _primitive, 40 | const float _s, 41 | const float _t, 42 | Vector2f* _output 43 | ) const =0; 44 | }; 45 | 46 | MSC_NAMESPACE_END 47 | 48 | #endif 49 | -------------------------------------------------------------------------------- /src/core/PinHoleCamera.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | MSC_NAMESPACE_BEGIN 4 | 5 | void PinHoleCamera::construct() 6 | { 7 | m_transform = Affine3f::Identity() 8 | * Eigen::Translation3f(m_translation) 9 | * Eigen::AngleAxisf(m_rotation.y() * M_PI_180, Vector3f::UnitY()) 10 | * Eigen::AngleAxisf(m_rotation.x() * M_PI_180, Vector3f::UnitX()) 11 | * Eigen::AngleAxisf(m_rotation.z() * M_PI_180, Vector3f::UnitZ()); 12 | 13 | m_normal = (m_transform.linear().inverse().transpose() * Vector3f::UnitX()).normalized(); 14 | } 15 | 16 | void PinHoleCamera::sample(const int _count, float* _positions, RandomGenerator* _random, RayCompressed* _ouput) const 17 | { 18 | Vector3f nodal_point = m_translation + (m_normal * m_focal_length); 19 | 20 | msc::Vector3fMap mapped_position(NULL); 21 | msc::Vector3fMap mapped_direction(NULL); 22 | for(size_t index = 0; index < _count; ++index) 23 | { 24 | new (&mapped_position) msc::Vector3fMap((float*) &(_ouput[index].org)); 25 | new (&mapped_direction) msc::Vector3fMap((float*) &(_ouput[index].dir)); 26 | 27 | Vector3f film_position = m_transform * Vector3f(0.f, _positions[2 * index + 1], _positions[2 * index + 0]); 28 | 29 | mapped_position = nodal_point; 30 | mapped_direction = (nodal_point - film_position).normalized(); 31 | } 32 | } 33 | 34 | MSC_NAMESPACE_END -------------------------------------------------------------------------------- /cmake/FindOpenColorIO.cmake: -------------------------------------------------------------------------------- 1 | # Module to find OpenColorIO 2 | # 3 | # This module will first look into the directories defined by the variables: 4 | # - OCIO_PATH, OCIO_INCLUDE_PATH, OCIO_LIBRARY_PATH 5 | # 6 | # This module defines the following variables: 7 | # 8 | # OCIO_FOUND - True if OpenColorIO was found. 9 | # OCIO_INCLUDES - where to find OpenColorIO.h 10 | # OCIO_LIBRARIES - list of libraries to link against when using OpenColorIO 11 | 12 | FIND_PATH( OCIO_INCLUDES OpenColorIO/OpenColorIO.h 13 | $ENV{OCIO_INCLUDE_PATH} 14 | $ENV{OCIO_PATH}/include/ 15 | /usr/include 16 | /usr/local/include 17 | /sw/include 18 | /opt/local/include 19 | DOC "The directory where OpenColorIO/OpenColorIO.h resides") 20 | FIND_LIBRARY(OCIO_LIBRARIES 21 | NAMES OpenColorIO 22 | PATHS 23 | $ENV{OCIO_LIBRARY_PATH} 24 | $ENV{OCIO_PATH}/lib/ 25 | /usr/lib64 26 | /usr/lib 27 | /usr/local/lib64 28 | /usr/local/lib 29 | /sw/lib 30 | /opt/local/lib 31 | DOC "The OCIO library") 32 | 33 | if(OCIO_INCLUDES AND OCIO_LIBRARIES) 34 | set(OCIO_FOUND TRUE) 35 | if (VERBOSE) 36 | message(STATUS "Found OCIO library ${OCIO_LIBRARIES}") 37 | message(STATUS "Found OCIO includes ${OCIO_INCLUDES}") 38 | endif () 39 | else() 40 | set(OCIO_FOUND FALSE) 41 | message(STATUS "OCIO not found. Specify OCIO_PATH to locate it") 42 | endif() 43 | 44 | -------------------------------------------------------------------------------- /include/core/TextureInterface.h: -------------------------------------------------------------------------------- 1 | #ifndef _TEXTUREINTERFACE_H_ 2 | #define _TEXTUREINTERFACE_H_ 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | MSC_NAMESPACE_BEGIN 10 | 11 | /** 12 | * @brief Abstract interface class for surface shaders 13 | * 14 | * This is an interface for using a texture in a polymorphic sense. It describes three main methods 15 | * that are responsible for cloning the class to allow for mutation on each thread locally, 16 | * initializing the texture to cache the texture colour and finally retrieving the value according 17 | * to an index. 18 | */ 19 | class TextureInterface 20 | { 21 | public: 22 | /** 23 | * @brief Virtual destructor required for interface 24 | */ 25 | virtual ~TextureInterface() {} 26 | 27 | /** 28 | * @brief Create polymorphic copy of derived class 29 | * 30 | * @return Is safe to have a covariant return type here 31 | */ 32 | virtual TextureInterface* clone() = 0; 33 | 34 | /** 35 | * @brief Initialize colour values potentially as vectorized texture lookup 36 | */ 37 | virtual void initialize( 38 | const size_t _size, 39 | std::vector< float >& _u, 40 | std::vector< float >& _v, 41 | TextureSystem _texture_system 42 | ) =0; 43 | 44 | virtual Colour3f colour(const size_t _index) const =0; 45 | }; 46 | 47 | MSC_NAMESPACE_END 48 | 49 | #endif -------------------------------------------------------------------------------- /cmake/FindEmbree.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # Find Embree 3 | # 4 | # Try to find Embree. 5 | # This module defines the following variables: 6 | # - EMBREE_INCLUDE_DIRS 7 | # - EMBREE_LIBRARIES 8 | # - EMBREE_FOUND 9 | # 10 | # The following variables can be set as arguments for the module. 11 | # - EMBREE_ROOT_DIR : Root library directory of Embree 12 | # 13 | 14 | # Additional modules 15 | include(FindPackageHandleStandardArgs) 16 | 17 | # Find include files 18 | find_path( 19 | EMBREE_INCLUDE_DIR 20 | NAMES embree2/rtcore.h 21 | PATHS 22 | /usr/include 23 | /usr/local/include 24 | /sw/include 25 | /opt/local/include 26 | DOC "The directory where embree2/rtcore.h resides") 27 | 28 | # Find library files 29 | # Try to use static libraries 30 | find_library( 31 | EMBREE_LIBRARY 32 | NAMES embree.2 33 | PATHS 34 | /usr/lib64 35 | /usr/lib 36 | /usr/local/lib64 37 | /usr/local/lib 38 | /sw/lib 39 | /opt/local/lib 40 | ${EMBREE_ROOT_DIR}/lib 41 | DOC "The Embree library") 42 | 43 | # Handle REQUIRD argument, define *_FOUND variable 44 | find_package_handle_standard_args(EMBREE DEFAULT_MSG EMBREE_INCLUDE_DIR EMBREE_LIBRARY) 45 | 46 | # Define EMBREE_LIBRARIES and EMBREE_INCLUDE_DIRS 47 | if (EMBREE_FOUND) 48 | set(EMBREE_LIBRARIES ${EMBREE_LIBRARY}) 49 | set(EMBREE_INCLUDE_DIRS ${EMBREE_INCLUDE_DIR}) 50 | endif() 51 | 52 | # Hide some variables 53 | mark_as_advanced(EMBREE_INCLUDE_DIR EMBREE_LIBRARY) -------------------------------------------------------------------------------- /include/core/Settings.h: -------------------------------------------------------------------------------- 1 | #ifndef _SETTINGS_H_ 2 | #define _SETTINGS_H_ 3 | 4 | #include 5 | 6 | MSC_NAMESPACE_BEGIN 7 | 8 | /** 9 | * @brief Structure of settings information 10 | * 11 | * The settings that are read from the scene file are stored here and mostly address limits on ray 12 | * depth when rendering and path termination when using russian roulette. It also contains information 13 | * on the amount of memory to be allocated when processing different operations. Most notable of these 14 | * is the bin exponent that controls the size of the batches. 15 | */ 16 | struct Settings 17 | { 18 | size_t min_depth; 19 | size_t max_depth; 20 | float threshold; 21 | size_t bucket_size; 22 | size_t shading_size; 23 | size_t bin_exponent; 24 | }; 25 | 26 | MSC_NAMESPACE_END 27 | 28 | YAML_NAMESPACE_BEGIN 29 | 30 | template<> struct convert 31 | { 32 | static bool decode(const Node& node, msc::Settings& rhs) 33 | { 34 | if(!node.IsMap() || node.size() != 6) 35 | return false; 36 | 37 | rhs.min_depth = node["min depth"].as(); 38 | rhs.max_depth = node["max depth"].as(); 39 | rhs.threshold = node["threshold"].as(); 40 | rhs.bucket_size = node["bucket size"].as(); 41 | rhs.shading_size = node["shading size"].as(); 42 | rhs.bin_exponent = node["bin exponent"].as(); 43 | return true; 44 | } 45 | }; 46 | 47 | YAML_NAMESPACE_END 48 | 49 | #endif 50 | -------------------------------------------------------------------------------- /src/core/StandardTexture.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | MSC_NAMESPACE_BEGIN 5 | 6 | TextureInterface* StandardTexture::clone() 7 | { 8 | return new StandardTexture(*this); 9 | } 10 | 11 | void StandardTexture::initialize( 12 | const size_t _size, 13 | std::vector< float >& _u, 14 | std::vector< float >& _v, 15 | TextureSystem _texture_system 16 | ) 17 | { 18 | OpenImageIO::TextureOptions options; 19 | options.swrap = OpenImageIO::TextureOptions::WrapPeriodic; 20 | options.twrap = OpenImageIO::TextureOptions::WrapPeriodic; 21 | std::vector< OpenImageIO::Runflag > runflags(_size, 1); 22 | std::vector< float > temp_colour(_size * 3); 23 | 24 | float nullvalue = 0; 25 | _texture_system->texture( 26 | m_string, 27 | options, 28 | &(runflags[0]), 29 | 0, _size, 30 | OpenImageIO::Varying(&(_u[0])), OpenImageIO::Varying(&(_v[0])), 31 | OpenImageIO::Uniform(nullvalue), OpenImageIO::Uniform(nullvalue), 32 | OpenImageIO::Uniform(nullvalue), OpenImageIO::Uniform(nullvalue), 33 | 3, &(temp_colour[0]) 34 | ); 35 | 36 | m_colour.resize(_size); 37 | Colour3fMap mapped_data(NULL); 38 | for(size_t index = 0; index < _size; ++index) 39 | { 40 | new (&mapped_data) Colour3fMap((float*) &(temp_colour[3 * index + 0])); 41 | m_colour[index] = mapped_data; 42 | } 43 | } 44 | 45 | Colour3f StandardTexture::colour(const size_t _index) const 46 | { 47 | return m_colour[_index]; 48 | } 49 | 50 | MSC_NAMESPACE_END -------------------------------------------------------------------------------- /include/core/RayBoundingbox.h: -------------------------------------------------------------------------------- 1 | #ifndef _RAYBOUNDINGBOX_H_ 2 | #define _RAYBOUNDINGBOX_H_ 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | MSC_NAMESPACE_BEGIN 10 | 11 | /** 12 | * @brief Functor class to find bounding box from an array of rays 13 | * 14 | * This class was created to find the bounding box of a group of rays using tbb in parrallel manner. 15 | */ 16 | class RayBoundingbox 17 | { 18 | public: 19 | /** 20 | * @brief Initialiser list for class 21 | */ 22 | RayBoundingbox(RayUncompressed* _data) 23 | : m_data(_data) 24 | {;} 25 | 26 | /** 27 | * @brief Initialiser list used when splitting class 28 | */ 29 | RayBoundingbox(RayBoundingbox& s, tbb::split ) 30 | : m_data(s.m_data) 31 | {;} 32 | 33 | /** 34 | * @brief Operator overloader to allow the class to act as a functor with tbb 35 | * 36 | * @param[in] r a one dimensional range over an array of rays 37 | */ 38 | void operator()(const tbb::blocked_range< size_t >& r); 39 | 40 | /** 41 | * @brief Join method to allow for a parallel reduction algorithm and avoid thread contention 42 | * 43 | * @param rhs { parameter_description } 44 | */ 45 | void join( RayBoundingbox& rhs ); 46 | 47 | /** 48 | * @brief Getter method for bounding box 49 | * 50 | * @return bounding box 51 | */ 52 | inline BoundingBox3f value() const {return m_value;} 53 | 54 | private: 55 | RayUncompressed* m_data; 56 | BoundingBox3f m_value; 57 | }; 58 | 59 | MSC_NAMESPACE_END 60 | 61 | #endif -------------------------------------------------------------------------------- /include/core/FilterInterface.h: -------------------------------------------------------------------------------- 1 | #ifndef _FILTERINTERFACE_H_ 2 | #define _FILTERINTERFACE_H_ 3 | 4 | #include 5 | #include 6 | 7 | MSC_NAMESPACE_BEGIN 8 | 9 | /** 10 | * @brief Abstract interface class for image filtering 11 | * 12 | * This is a simple interface for using a filter in a polymophic sense. As this operation is 13 | * unlikely to be used on single pixels it takes a range of data to compute the final result. 14 | */ 15 | class FilterInterface 16 | { 17 | public: 18 | /** 19 | * @brief Virtual destructor required for interface 20 | */ 21 | virtual ~FilterInterface() {} 22 | 23 | /** 24 | * @brief Convolution function for producing final image 25 | * 26 | * @param[in] _width width of image in pixels 27 | * @param[in] _height height of image in pixels 28 | * @param[in] _samples maximum samples 29 | * @param[in] _rows_begin begining of range to be calcualted in the vertical direction 30 | * @param[in] _rows_end end of range to be calcualted in the vertical direction 31 | * @param[in] _cols_begin begining of range to be calcualted in the horizontal direction 32 | * @param[in] _cols_end end of range to be calcualted in the horizontal direction 33 | * @param _input input sample data 34 | * @param _output output image 35 | */ 36 | virtual void convolve( 37 | const size_t _width, 38 | const size_t _height, 39 | const size_t _samples, 40 | const size_t _rows_begin, 41 | const size_t _rows_end, 42 | const size_t _cols_begin, 43 | const size_t _cols_end, 44 | Sample* _input, 45 | Pixel* _output 46 | ) const =0; 47 | }; 48 | 49 | MSC_NAMESPACE_END 50 | 51 | #endif 52 | -------------------------------------------------------------------------------- /src/core/RayBoundingbox.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | MSC_NAMESPACE_BEGIN 4 | 5 | void RayBoundingbox::operator()(const tbb::blocked_range< size_t >& r) 6 | { 7 | size_t begin = r.begin(); 8 | size_t end = r.end(); 9 | 10 | m_value.min[0] = m_data[begin].org[0]; 11 | m_value.min[1] = m_data[begin].org[1]; 12 | m_value.min[2] = m_data[begin].org[2]; 13 | m_value.max[0] = m_data[begin].org[0]; 14 | m_value.max[1] = m_data[begin].org[1]; 15 | m_value.max[2] = m_data[begin].org[2]; 16 | 17 | for(size_t index = begin; index < end; ++index) 18 | { 19 | if(m_data[index].org[0] < m_value.min[0]) 20 | m_value.min[0] = m_data[index].org[0]; 21 | if(m_data[index].org[1] < m_value.min[1]) 22 | m_value.min[1] = m_data[index].org[1]; 23 | if(m_data[index].org[2] < m_value.min[2]) 24 | m_value.min[2] = m_data[index].org[2]; 25 | 26 | if(m_data[index].org[0] > m_value.max[0]) 27 | m_value.max[0] = m_data[index].org[0]; 28 | if(m_data[index].org[1] > m_value.max[1]) 29 | m_value.max[1] = m_data[index].org[1]; 30 | if(m_data[index].org[2] > m_value.max[2]) 31 | m_value.max[2] = m_data[index].org[2]; 32 | } 33 | } 34 | 35 | void RayBoundingbox::join( RayBoundingbox& rhs ) 36 | { 37 | if(rhs.m_value.min[0] < m_value.min[0]) 38 | m_value.min[0] = rhs.m_value.min[0]; 39 | if(rhs.m_value.min[1] < m_value.min[1]) 40 | m_value.min[1] = rhs.m_value.min[1]; 41 | if(rhs.m_value.min[2] < m_value.min[2]) 42 | m_value.min[2] = rhs.m_value.min[2]; 43 | 44 | if(rhs.m_value.max[0] > m_value.max[0]) 45 | m_value.max[0] = rhs.m_value.max[0]; 46 | if(rhs.m_value.max[1] > m_value.max[1]) 47 | m_value.max[1] = rhs.m_value.max[1]; 48 | if(rhs.m_value.max[2] > m_value.max[2]) 49 | m_value.max[2] = rhs.m_value.max[2]; 50 | } 51 | 52 | MSC_NAMESPACE_END -------------------------------------------------------------------------------- /include/core/Image.h: -------------------------------------------------------------------------------- 1 | #ifndef _IMAGE_H_ 2 | #define _IMAGE_H_ 3 | 4 | #include 5 | 6 | #include 7 | 8 | MSC_NAMESPACE_BEGIN 9 | 10 | /** 11 | * @brief Sample structure representing colour and position on image 12 | * 13 | * A single sample with minimum data as to conserve system memory when using large sample counts. 14 | */ 15 | struct Sample 16 | { 17 | float x, y; 18 | float r, g, b; 19 | }; 20 | 21 | /** 22 | * @brief Union data type of a rgb spectral representation 23 | * 24 | * A single pixel that uses a tri-band representation in red, green and blue of the spectral energy 25 | * being integrated across the surface area. 26 | */ 27 | union Pixel 28 | { 29 | struct {float r, g, b;}; 30 | float v[3]; 31 | }; 32 | 33 | /** 34 | * @brief Image structure that contains sample and pixel data 35 | * 36 | * Basic image structure that contains width and height information as well as the base value for 37 | * the sample count. The iteration count represents how many times each pixel has received an 38 | * approximation of the lighting integral. The data itself is stored in std::vectors to allow 39 | * for automatic clean up. 40 | */ 41 | struct Image 42 | { 43 | size_t width; 44 | size_t height; 45 | size_t base; 46 | size_t iteration; 47 | 48 | std::vector< Sample > samples; 49 | std::vector< Pixel > pixels; 50 | }; 51 | 52 | MSC_NAMESPACE_END 53 | 54 | YAML_NAMESPACE_BEGIN 55 | 56 | template<> struct convert 57 | { 58 | static bool decode(const Node& node, msc::Image& rhs) 59 | { 60 | if(!node.IsMap() || node.size() != 3) 61 | return false; 62 | 63 | rhs.width = node["width"].as(); 64 | rhs.height = node["height"].as(); 65 | rhs.base = node["sample base"].as(); 66 | rhs.iteration = 0; 67 | return true; 68 | } 69 | }; 70 | 71 | YAML_NAMESPACE_END 72 | 73 | #endif 74 | -------------------------------------------------------------------------------- /include/core/BoxFilter.h: -------------------------------------------------------------------------------- 1 | #ifndef _BOXFILTER_H_ 2 | #define _BOXFILTER_H_ 3 | 4 | #include 5 | #include 6 | 7 | MSC_NAMESPACE_BEGIN 8 | 9 | /** 10 | * @brief Inherits from the filter interface and represents a box filter function 11 | * 12 | * Basic box filter to convolve samples into final image. As this operation is unlikely to be used 13 | * on single pixels it takes a range of data to compute the final result. 14 | */ 15 | class BoxFilter : public FilterInterface 16 | { 17 | public: 18 | /** 19 | * @brief Convolution function for producing final image 20 | * 21 | * @param[in] _width width of image in pixels 22 | * @param[in] _height height of image in pixels 23 | * @param[in] _samples maximum samples 24 | * @param[in] _rows_begin beginning of range to be calculated in the vertical direction 25 | * @param[in] _rows_end end of range to be calculated in the vertical direction 26 | * @param[in] _cols_begin beginning of range to be calculated in the horizontal direction 27 | * @param[in] _cols_end end of range to be calculated in the horizontal direction 28 | * @param _input input sample data 29 | * @param _output output image 30 | */ 31 | void convolve( 32 | const size_t _width, 33 | const size_t _height, 34 | const size_t _samples, 35 | const size_t _rows_begin, 36 | const size_t _rows_end, 37 | const size_t _cols_begin, 38 | const size_t _cols_end, 39 | Sample* _input, 40 | Pixel* _output 41 | ) const; 42 | }; 43 | 44 | MSC_NAMESPACE_END 45 | 46 | YAML_NAMESPACE_BEGIN 47 | 48 | template<> struct convert 49 | { 50 | static bool decode(const Node& node, msc::BoxFilter& rhs) 51 | { 52 | if(!node.IsMap() || node.size() != 1) 53 | return false; 54 | 55 | return true; 56 | } 57 | }; 58 | 59 | YAML_NAMESPACE_END 60 | 61 | #endif 62 | -------------------------------------------------------------------------------- /include/core/Camera.h: -------------------------------------------------------------------------------- 1 | #ifndef _CAMERA_H_ 2 | #define _CAMERA_H_ 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | MSC_NAMESPACE_BEGIN 17 | 18 | /** 19 | * @brief Used to create primary rays from scene camera 20 | * 21 | * This is a tbb functor class that uses the scene camera to produce primary rays and adds the 22 | * result into a local buffer. This is then added to the global bins that will in tern update 23 | * the batch queue. 24 | */ 25 | class Camera 26 | { 27 | public: 28 | /** 29 | * @brief Initialiser list for class 30 | */ 31 | Camera( 32 | CameraInterface* _camera, 33 | SamplerInterface* _sampler, 34 | Image* _image, 35 | DirectionalBins* _bins, 36 | tbb::concurrent_queue< BatchItem >* _batch_queue, 37 | LocalRandomGenerator* _local_thread_storage 38 | ) 39 | : m_camera(_camera) 40 | , m_sampler(_sampler) 41 | , m_image(_image) 42 | , m_bins(_bins) 43 | , m_batch_queue(_batch_queue) 44 | , m_local_thread_storage(_local_thread_storage) 45 | {;} 46 | 47 | /** 48 | * @brief Operator overloader to allow the class to act as a functor with tbb 49 | * 50 | * @param[in] r a two dimentional blocked range over image resolution 51 | */ 52 | void operator()(const tbb::blocked_range2d< size_t > &r) const; 53 | 54 | private: 55 | CameraInterface* m_camera; 56 | SamplerInterface* m_sampler; 57 | Image* m_image; 58 | DirectionalBins* m_bins; 59 | tbb::concurrent_queue< BatchItem >* m_batch_queue; 60 | LocalRandomGenerator* m_local_thread_storage; 61 | 62 | mutable Buffer m_buffer; 63 | }; 64 | 65 | MSC_NAMESPACE_END 66 | 67 | #endif -------------------------------------------------------------------------------- /include/core/TentFilter.h: -------------------------------------------------------------------------------- 1 | #ifndef _TENTFILTER_H_ 2 | #define _TENTFILTER_H_ 3 | 4 | #include 5 | #include 6 | 7 | MSC_NAMESPACE_BEGIN 8 | 9 | /** 10 | * @brief Inherits from the filter interface and represents a tent filter function 11 | * 12 | * Basic tent filter to convolve samples into final image. As this operation is unlikely to be used 13 | * on single pixels it takes a range of data to compute the final result. 14 | */ 15 | class TentFilter : public FilterInterface 16 | { 17 | public: 18 | /** 19 | * @brief Convolution function for producing final image 20 | * 21 | * @param[in] _width width of image in pixels 22 | * @param[in] _height height of image in pixels 23 | * @param[in] _samples maximum samples 24 | * @param[in] _rows_begin begining of range to be calcualted in the vertical direction 25 | * @param[in] _rows_end end of range to be calcualted in the vertical direction 26 | * @param[in] _cols_begin begining of range to be calcualted in the horizontal direction 27 | * @param[in] _cols_end end of range to be calcualted in the horizontal direction 28 | * @param _input input sample data 29 | * @param _output output image 30 | */ 31 | void convolve( 32 | const size_t _width, 33 | const size_t _height, 34 | const size_t _samples, 35 | const size_t _rows_begin, 36 | const size_t _rows_end, 37 | const size_t _cols_begin, 38 | const size_t _cols_end, 39 | Sample* _input, 40 | Pixel* _output 41 | ) const; 42 | }; 43 | 44 | MSC_NAMESPACE_END 45 | 46 | YAML_NAMESPACE_BEGIN 47 | 48 | template<> struct convert 49 | { 50 | static bool decode(const Node& node, msc::TentFilter& rhs) 51 | { 52 | if(!node.IsMap() || node.size() != 1) 53 | return false; 54 | 55 | return true; 56 | } 57 | }; 58 | 59 | YAML_NAMESPACE_END 60 | 61 | #endif 62 | -------------------------------------------------------------------------------- /cmake/FindYamlCpp.cmake: -------------------------------------------------------------------------------- 1 | # Locate yaml-cpp 2 | # 3 | # This module defines 4 | # YAMLCPP_FOUND, if false, do not try to link to yaml-cpp 5 | # YAMLCPP_LIBRARY, where to find yaml-cpp 6 | # YAMLCPP_INCLUDE_DIR, where to find yaml.h 7 | # 8 | # By default, the dynamic libraries of yaml-cpp will be found. To find the static ones instead, 9 | # you must set the YAMLCPP_STATIC_LIBRARY variable to TRUE before calling find_package(YamlCpp ...). 10 | # 11 | # If yaml-cpp is not installed in a standard path, you can use the YAMLCPP_DIR CMake variable 12 | # to tell CMake where yaml-cpp is. 13 | 14 | # attempt to find static library first if this is set 15 | if(YAMLCPP_STATIC_LIBRARY) 16 | set(YAMLCPP_STATIC libyaml-cpp.a) 17 | endif() 18 | 19 | # find the yaml-cpp include directory 20 | find_path(YAMLCPP_INCLUDE_DIR yaml-cpp/yaml.h 21 | PATH_SUFFIXES include 22 | PATHS 23 | ~/Library/Frameworks/yaml-cpp/include/ 24 | /Library/Frameworks/yaml-cpp/include/ 25 | /usr/local/include/ 26 | /usr/include/ 27 | /sw/yaml-cpp/ # Fink 28 | /opt/local/yaml-cpp/ # DarwinPorts 29 | /opt/csw/yaml-cpp/ # Blastwave 30 | /opt/yaml-cpp/ 31 | ${YAMLCPP_DIR}/include/) 32 | 33 | # find the yaml-cpp library 34 | find_library(YAMLCPP_LIBRARY 35 | NAMES ${YAMLCPP_STATIC} yaml-cpp 36 | PATH_SUFFIXES lib64 lib 37 | PATHS ~/Library/Frameworks 38 | /Library/Frameworks 39 | /usr/local 40 | /usr 41 | /sw 42 | /opt/local 43 | /opt/csw 44 | /opt 45 | ${YAMLCPP_DIR}/lib) 46 | 47 | # handle the QUIETLY and REQUIRED arguments and set YAMLCPP_FOUND to TRUE if all listed variables are TRUE 48 | include(FindPackageHandleStandardArgs) 49 | FIND_PACKAGE_HANDLE_STANDARD_ARGS(YAMLCPP DEFAULT_MSG YAMLCPP_INCLUDE_DIR YAMLCPP_LIBRARY) 50 | mark_as_advanced(YAMLCPP_INCLUDE_DIR YAMLCPP_LIBRARY) 51 | -------------------------------------------------------------------------------- /include/core/LightInterface.h: -------------------------------------------------------------------------------- 1 | #ifndef _LIGHTINTERFACE_H_ 2 | #define _LIGHTINTERFACE_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | MSC_NAMESPACE_BEGIN 9 | 10 | /** 11 | * @brief Abstract interface class for light sources 12 | * 13 | * This is a simple interface for using a light in a polymorphic sense. As lights are sampled 14 | * randomly within the integrator to limit ray branching, the methods compute individual positions 15 | * to be shaded. 16 | */ 17 | class LightInterface 18 | { 19 | public: 20 | /** 21 | * @brief Virtual destructor required for interface 22 | */ 23 | virtual ~LightInterface() {} 24 | 25 | /** 26 | * @brief Illumination of single position on a geometric surface 27 | * 28 | * @param _random thread local random generator to prevent mutation 29 | * @param _position position data 30 | * @param _direction input directions generated by light for surface evaluation 31 | * @param _distance distance between light sample and surface position 32 | * @param _radiance radiance value 33 | * @param _direct_pdfw probability in respect to solid angle 34 | */ 35 | virtual void illuminate( 36 | RandomGenerator* _random, 37 | const Vector3f& _position, 38 | Vector3f* _direction, 39 | float* _distance, 40 | Colour3f* _radiance, 41 | float* _direct_pdfw = NULL 42 | ) const =0; 43 | 44 | /** 45 | * @brief Radiance on light in direction towards surface 46 | * 47 | * @param[in] _direction input direction to be evaluated 48 | * @param _radiance radiance value 49 | * @param _cos_theta cosine theta between direction and light normal 50 | * @param _direct_pdfa probability in respect to surface area 51 | */ 52 | virtual void radiance( 53 | const Vector3f& _direction, 54 | Colour3f* _radiance, 55 | float* _cos_theta, 56 | float* _direct_pdfa = NULL 57 | ) const =0; 58 | }; 59 | 60 | MSC_NAMESPACE_END 61 | 62 | #endif 63 | -------------------------------------------------------------------------------- /src/core/ThinLensCamera.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | MSC_NAMESPACE_BEGIN 4 | 5 | void ThinLensCamera::construct() 6 | { 7 | m_transform = Affine3f::Identity() 8 | * Eigen::Translation3f(m_translation) 9 | * Eigen::AngleAxisf(m_rotation.y() * M_PI_180, Vector3f::UnitY()) 10 | * Eigen::AngleAxisf(m_rotation.x() * M_PI_180, Vector3f::UnitX()) 11 | * Eigen::AngleAxisf(m_rotation.z() * M_PI_180, Vector3f::UnitZ()); 12 | 13 | m_normal = (m_transform.linear().inverse().transpose() * Vector3f::UnitX()).normalized(); 14 | } 15 | 16 | void ThinLensCamera::sample(const int _count, float* _positions, RandomGenerator* _random, RayCompressed* _ouput) const 17 | { 18 | Vector3f nodal_point = m_translation + (m_normal * m_focal_length); 19 | float nodal_focal_ratio = m_focal_distance / m_focal_length; 20 | 21 | msc::Vector3fMap mapped_position(NULL); 22 | msc::Vector3fMap mapped_direction(NULL); 23 | for(size_t index = 0; index < _count; ++index) 24 | { 25 | new (&mapped_position) msc::Vector3fMap((float*) &(_ouput[index].org)); 26 | new (&mapped_direction) msc::Vector3fMap((float*) &(_ouput[index].dir)); 27 | 28 | Vector3f film_position = m_transform * Vector3f(0.f, _positions[2 * index + 1], _positions[2 * index + 0]); 29 | Vector3f focal_point = film_position + (nodal_point - film_position) * nodal_focal_ratio; 30 | 31 | Vector2f aperture_sample = rejectionSampling(_random) * (m_focal_length / m_aperture); 32 | Vector3f aperture_position = m_transform * Vector3f(0.f, aperture_sample.x(), aperture_sample.y()); 33 | 34 | mapped_position = aperture_position + (m_normal * m_focal_length); 35 | mapped_direction = (focal_point - mapped_position).normalized(); 36 | } 37 | } 38 | 39 | Vector2f ThinLensCamera::rejectionSampling(RandomGenerator* _random) const 40 | { 41 | float x; 42 | float y; 43 | Vector2f output; 44 | 45 | while(true) 46 | { 47 | x = _random->sample() - 0.5f; 48 | y = _random->sample() - 0.5f; 49 | output = Vector2f(x, y); 50 | 51 | if(output.norm() < 0.5f) 52 | break; 53 | } 54 | 55 | return output; 56 | } 57 | 58 | MSC_NAMESPACE_END -------------------------------------------------------------------------------- /src/core/LambertShader.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | MSC_NAMESPACE_BEGIN 4 | 5 | ShaderInterface* LambertShader::clone() 6 | { 7 | LambertShader* shader = new LambertShader(*this); 8 | shader->texture(m_texture->clone()); 9 | return shader; 10 | } 11 | 12 | void LambertShader::initialize( 13 | const size_t _size, 14 | std::vector< float >& _u, 15 | std::vector< float >& _v, 16 | TextureSystem _texture_system 17 | ) 18 | { 19 | m_texture->initialize(_size, _u, _v, _texture_system); 20 | } 21 | 22 | float LambertShader::continuation() const 23 | { 24 | return m_reflectance; 25 | } 26 | 27 | void LambertShader::evaluate( 28 | const size_t _colour_index, 29 | const Vector3f& _input, 30 | const Vector3f& _output, 31 | const Vector3f& _normal, 32 | Colour3f* _weight, 33 | float* _cos_theta, 34 | float* _direct_pdfw 35 | ) const 36 | { 37 | float cos_theta_input = _normal.dot(_input); 38 | float cos_theta_output = _normal.dot(_output); 39 | 40 | if(cos_theta_input < 0.f || cos_theta_output < 0.f) 41 | *_weight = Colour3f(0.f, 0.f, 0.f); 42 | else 43 | *_weight = m_texture->colour(_colour_index) * m_reflectance * M_INV_PI; 44 | 45 | *_cos_theta = (cos_theta_input < 0.f) ? 0.f : cos_theta_input; 46 | *_direct_pdfw = *_cos_theta * M_INV_PI; 47 | } 48 | 49 | void LambertShader::sample( 50 | RandomGenerator* _random, 51 | const size_t _colour_index, 52 | const Vector3f& _output, 53 | const Vector3f& _normal, 54 | Vector3f* _input, 55 | Colour3f* _weight, 56 | float* _cos_theta, 57 | float* _direct_pdfw 58 | ) const 59 | { 60 | float x, y, z; 61 | float azimuth = 2 * M_PI * _random->sample(); 62 | float zenith = acos(sqrt(_random->sample())); 63 | sphericalToCartesianCoord(azimuth, zenith, &x, &y, &z); 64 | 65 | Vector3f temp = (_normal.x() > 0.99f) ? Vector3f(0.f, 1.f, 0.f) : Vector3f(1.f, 0.f, 0.f); 66 | Vector3f s = temp.cross(_normal).normalized(); 67 | Vector3f t = _normal.cross(s).normalized(); 68 | 69 | *_input = x * t + y * s + z * _normal; 70 | *_weight = m_texture->colour(_colour_index) * m_reflectance * M_INV_PI; 71 | *_cos_theta = _normal.dot(*_input); 72 | *_direct_pdfw = *_cos_theta * M_INV_PI; 73 | } 74 | 75 | MSC_NAMESPACE_END -------------------------------------------------------------------------------- /cmake/FindOpenImageIO.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # (c) 2010-Present Peregrine Labs a division of Peregrine Visual Storytelling Ltd. 3 | # All rights reserved. 4 | # 5 | # The coded instructions, statements, computer programs, and/or related 6 | # material (collectively the "Data") in these files contain unpublished 7 | # information proprietary to Peregrine Visual Storytelling Ltd. ("Peregrine") 8 | # and/or its licensors, which is protected by U.S. and Canadian federal 9 | # copyright law and by international treaties. 10 | # 11 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND. PEREGRINE 12 | # DOES NOT MAKE AND HEREBY DISCLAIMS ANY EXPRESS OR IMPLIED WARRANTIES 13 | # INCLUDING, BUT NOT LIMITED TO, THE WARRANTIES OF NON-INFRINGEMENT, 14 | # MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR ARISING FROM A COURSE 15 | # OF DEALING, USAGE, OR TRADE PRACTICE. IN NO EVENT WILL PEREGRINE AND/OR ITS 16 | # LICENSORS BE LIABLE FOR ANY LOST REVENUES, DATA, OR PROFITS, OR SPECIAL, 17 | # DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES, EVEN IF PEREGRINE AND/OR ITS 18 | # LICENSORS HAS BEEN ADVISED OF THE POSSIBILITY OR PROBABILITY OF SUCH DAMAGES. 19 | # 20 | # 21 | 22 | # This module will define the following variables: 23 | # OIIO_INCLUDES - Location of the OIIO includes 24 | # OIIO_LIBRARIES - [TODO] Required libraries for all requested bindings 25 | # OIIO_FOUND - true if OIIO was found on the system 26 | 27 | FIND_PATH ( OIIO_INCLUDES OpenImageIO/imageio.h 28 | $ENV{OIIO_PATH}/include/ 29 | /usr/include 30 | /usr/local/include 31 | /sw/include 32 | /opt/local/include 33 | DOC "The directory where OpenImageIo/imageio.h resides") 34 | 35 | FIND_LIBRARY(OIIO_LIBRARIES 36 | NAMES OpenImageIO 37 | PATHS 38 | $ENV{OIIO_PATH}/lib/ 39 | /usr/lib64 40 | /usr/lib 41 | /usr/local/lib64 42 | /usr/local/lib 43 | /sw/lib 44 | /opt/local/lib 45 | DOC "The OIIO library") 46 | 47 | if(OIIO_INCLUDES AND OIIO_LIBRARIES) 48 | set(OIIO_FOUND TRUE) 49 | if (VERBOSE) 50 | message(STATUS "Found OIIO library ${OIIO_LIBRARIES}") 51 | message(STATUS "Found OIIO includes ${OIIO_INCLUDES}") 52 | endif () 53 | else() 54 | set(OIIO_FOUND FALSE) 55 | message(STATUS "OIIO not found. Specify OIIO_PATH to locate it") 56 | endif() 57 | 58 | -------------------------------------------------------------------------------- /include/core/ConstantTexture.h: -------------------------------------------------------------------------------- 1 | #ifndef _ConstantTexture_H_ 2 | #define _ConstantTexture_H_ 3 | 4 | #include 5 | #include 6 | 7 | MSC_NAMESPACE_BEGIN 8 | 9 | /** 10 | * @brief Inherits from the shader interface and represents a constant texture 11 | * 12 | * When initialized this will avoid creating a std::vector of data as it would be inefficient to 13 | * do so with non varying variables. As a result the colour method just returns the same colour 14 | * value without using the index. 15 | */ 16 | class ConstantTexture : public TextureInterface 17 | { 18 | public: 19 | /** 20 | * @brief Initialiser list for class 21 | */ 22 | ConstantTexture() 23 | : m_constant(Colour3f(0.f, 0.f, 0.f)) 24 | {;} 25 | 26 | /** 27 | * @brief Getter method for colour coefficient 28 | * 29 | * @return colour coefficient 30 | */ 31 | inline Colour3f constant() const {return m_constant;} 32 | 33 | /** 34 | * @brief Setter method for colour coefficient 35 | * 36 | * @param[in] _colour colour coefficient 37 | */ 38 | inline void constant(const Colour3f _constant){m_constant = _constant;} 39 | 40 | /** 41 | * @brief Create polymorphic copy of derived class 42 | * 43 | * @return Is safe to have a covariant return type here 44 | */ 45 | TextureInterface* clone(); 46 | 47 | /** 48 | * @brief Initialize colour values potentially as vectorized texture lookup 49 | */ 50 | void initialize( 51 | const size_t _size, 52 | std::vector< float >& _u, 53 | std::vector< float >& _v, 54 | TextureSystem _texture_system 55 | ); 56 | 57 | /** 58 | * @brief Gets colour value according to index 59 | * 60 | * @param[in] _index colour index to find value for specific position 61 | * 62 | * @return colour according to index 63 | */ 64 | Colour3f colour(const size_t _index) const; 65 | 66 | private: 67 | Colour3f m_constant; 68 | }; 69 | 70 | MSC_NAMESPACE_END 71 | 72 | YAML_NAMESPACE_BEGIN 73 | 74 | template<> struct convert 75 | { 76 | static bool decode(const Node& node, msc::ConstantTexture& rhs) 77 | { 78 | if(node.size() != 2) 79 | return false; 80 | 81 | rhs.constant(node["colour"].as()); 82 | 83 | return true; 84 | } 85 | }; 86 | 87 | YAML_NAMESPACE_END 88 | 89 | #endif -------------------------------------------------------------------------------- /src/core/TentFilter.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | MSC_NAMESPACE_BEGIN 4 | 5 | void TentFilter::convolve( 6 | const size_t _width, 7 | const size_t _height, 8 | const size_t _samples, 9 | const size_t _rows_begin, 10 | const size_t _rows_end, 11 | const size_t _cols_begin, 12 | const size_t _cols_end, 13 | Sample* _input, 14 | Pixel* _output 15 | ) const 16 | { 17 | for(int index_pixel_x = _rows_begin; index_pixel_x < _rows_end; ++index_pixel_x) 18 | { 19 | for(int index_pixel_y = _cols_begin; index_pixel_y < _cols_end; ++index_pixel_y) 20 | { 21 | Colour3f summation(0.f, 0.f, 0.f); 22 | float center_pos_x = index_pixel_x + 0.5f; 23 | float center_pos_y = index_pixel_y + 0.5f; 24 | 25 | float denominator = 0; 26 | 27 | for(int index_mask_x = -1; index_mask_x < 2; ++index_mask_x) 28 | { 29 | for(int index_mask_y = -1; index_mask_y < 2; ++index_mask_y) 30 | { 31 | int pixel_x = index_pixel_x + index_mask_x; 32 | int pixel_y = index_pixel_y + index_mask_y; 33 | 34 | if(!(pixel_x < 0) && (pixel_x < _width) && !(pixel_y < 0) && (pixel_y < _height)) 35 | { 36 | for(size_t index_sample = 0; index_sample < _samples; ++index_sample) 37 | { 38 | size_t sample_index = (pixel_x * _height * _samples) + (pixel_y * _samples) + (index_sample); 39 | 40 | float sample_pos_x = _input[sample_index].x; 41 | float sample_pos_y = _input[sample_index].y; 42 | float distance_x = fmax(0.f, 1.f - fabsf(sample_pos_x - center_pos_x)); 43 | float distance_y = fmax(0.f, 1.f - fabsf(sample_pos_y - center_pos_y)); 44 | 45 | float multiplier = distance_x * distance_y; 46 | 47 | denominator = denominator + multiplier; 48 | 49 | summation[0] += _input[sample_index].r * multiplier; 50 | summation[1] += _input[sample_index].g * multiplier; 51 | summation[2] += _input[sample_index].b * multiplier; 52 | } 53 | } 54 | } 55 | } 56 | 57 | size_t pixel_index = index_pixel_y * _width + index_pixel_x; 58 | _output[pixel_index].r += (summation[0] / denominator); 59 | _output[pixel_index].g += (summation[1] / denominator); 60 | _output[pixel_index].b += (summation[2] / denominator); 61 | } 62 | } 63 | } 64 | 65 | MSC_NAMESPACE_END -------------------------------------------------------------------------------- /src/core/Camera.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | MSC_NAMESPACE_BEGIN 5 | 6 | void Camera::operator()(const tbb::blocked_range2d< size_t > &r) const 7 | { 8 | LocalRandomGenerator::reference random = m_local_thread_storage->local(); 9 | 10 | size_t count = m_image->base * m_image->base; 11 | 12 | float* samples = new float[count * 2]; 13 | RayCompressed* rays = new RayCompressed[count]; 14 | 15 | for(size_t index_x = r.rows().begin(); index_x < r.rows().end(); ++index_x) 16 | { 17 | for(size_t index_y = r.cols().begin(); index_y < r.cols().end(); ++index_y) 18 | { 19 | m_sampler->sample(m_image->base, &random, samples); 20 | 21 | for(size_t index = 0; index < count; ++index) 22 | { 23 | rays[index].weight[0] = 1.f; 24 | rays[index].weight[1] = 1.f; 25 | rays[index].weight[2] = 1.f; 26 | rays[index].lastPdf = 1.f; 27 | rays[index].rayDepth = 0; 28 | rays[index].sampleID = (index_x * m_image->height * count) + (index_y * count) + index; 29 | m_image->samples[rays[index].sampleID].r = 0.f; 30 | m_image->samples[rays[index].sampleID].g = 0.f; 31 | m_image->samples[rays[index].sampleID].b = 0.f; 32 | m_image->samples[rays[index].sampleID].x = index_x + samples[2 * index + 0]; 33 | m_image->samples[rays[index].sampleID].y = index_y + samples[2 * index + 1]; 34 | samples[2 * index + 0] = (((index_x + samples[2 * index + 0]) * 2.f - m_image->width) / m_image->width) * 36.f; 35 | samples[2 * index + 1] = (((index_y + samples[2 * index + 1]) * 2.f - m_image->height) / m_image->width) * 36.f; 36 | } 37 | 38 | m_camera->sample(count, samples, &random, rays); 39 | 40 | for(size_t index = 0; index < count; ++index) 41 | { 42 | int max = (fabs(rays[index].dir[0]) < fabs(rays[index].dir[1])) ? 1 : 0; 43 | int axis = (fabs(rays[index].dir[max]) < fabs(rays[index].dir[2])) ? 2 : max; 44 | int cardinal = (rays[index].dir[axis] < 0.f) ? axis : axis + 3; 45 | 46 | m_buffer.direction[cardinal].push_back(rays[index]); 47 | } 48 | } 49 | } 50 | 51 | for(size_t index = 0; index < 6; ++index) 52 | { 53 | if(m_buffer.direction[index].size() > 0) 54 | m_bins->add(m_buffer.direction[index].size(), index, &(m_buffer.direction[index][0]), m_batch_queue); 55 | } 56 | 57 | delete[] samples; 58 | delete[] rays; 59 | } 60 | 61 | MSC_NAMESPACE_END -------------------------------------------------------------------------------- /include/core/StandardTexture.h: -------------------------------------------------------------------------------- 1 | #ifndef _STANDARDTEXTURE_H_ 2 | #define _STANDARDTEXTURE_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | MSC_NAMESPACE_BEGIN 9 | 10 | /** 11 | * @brief Inherits from the shader interface and represents a non-cntributing surface 12 | * 13 | * When initialized this will create a std::vector containing texture data for each position in a 14 | * range. Texture lookup is vectorized and sorted according to object and geometric primative. This 15 | * allows for optimal usage of memory when reading in large textures sets. 16 | */ 17 | class StandardTexture : public TextureInterface 18 | { 19 | public: 20 | /** 21 | * @brief Getter method for texture path 22 | * 23 | * @return texture path as string 24 | */ 25 | inline std::string string() const {return m_string.string();} 26 | 27 | /** 28 | * @brief Setter method for texture path 29 | * 30 | * @param[in] _colour texture path as string 31 | */ 32 | inline void string(const std::string _string){m_string = OpenImageIO::ustring(_string);} 33 | 34 | /** 35 | * @brief Create polymorphic copy of derived class 36 | * 37 | * @return Is safe to have a covariant return type here 38 | */ 39 | TextureInterface* clone(); 40 | 41 | /** 42 | * @brief Initialize colour values potentially as vectorized texture lookup 43 | */ 44 | void initialize( 45 | const size_t _size, 46 | std::vector< float >& _u, 47 | std::vector< float >& _v, 48 | TextureSystem _texture_system 49 | ); 50 | 51 | /** 52 | * @brief Gets colour value according to index 53 | * 54 | * @param[in] _index colour index to find value for specific position 55 | * 56 | * @return colour according to index 57 | */ 58 | Colour3f colour(const size_t _index) const; 59 | 60 | private: 61 | OpenImageIO::ustring m_string; 62 | std::vector< Colour3f > m_colour; 63 | }; 64 | 65 | MSC_NAMESPACE_END 66 | 67 | YAML_NAMESPACE_BEGIN 68 | 69 | template<> struct convert 70 | { 71 | static bool decode(const Node& node, msc::StandardTexture& rhs) 72 | { 73 | if(node.size() != 2) 74 | return false; 75 | 76 | msc::SingletonString& scene_root = msc::SingletonString::instance(); 77 | rhs.string(scene_root.getData().append("/").append(node["string"].as())); 78 | 79 | return true; 80 | } 81 | }; 82 | 83 | YAML_NAMESPACE_END 84 | 85 | #endif -------------------------------------------------------------------------------- /include/core/DirectionalBins.h: -------------------------------------------------------------------------------- 1 | #ifndef _BATCH_H_ 2 | #define _BATCH_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include 15 | #include 16 | #include 17 | 18 | MSC_NAMESPACE_BEGIN 19 | 20 | /** 21 | * @brief Single bin to store compressed ray data 22 | * 23 | * This stores the current memory mapped file as well as its path, size, writable position 24 | * and individual mutex. 25 | */ 26 | struct Bin 27 | { 28 | boost::iostreams::mapped_file_sink outfile; 29 | std::string path; 30 | 31 | RayCompressed* pointer; 32 | RayCompressed* end; 33 | size_t size; 34 | 35 | boost::mutex mutex; 36 | }; 37 | 38 | /** 39 | * @brief A shared container for six cardinal bins of compressed rays 40 | * 41 | * The DirectionalBins class combines six standard bins with one for each cardinal direction. It 42 | * also manages adding data from local buffers efficiently flushing this data to the batch queue 43 | * when required. If flushing the data is done without care to the order of which bins are cleared 44 | * first then performance will be dramatically reduced. 45 | */ 46 | class DirectionalBins 47 | { 48 | public: 49 | /** 50 | * @brief This constructor will initialize each cardinal bin and open the mapped files 51 | * 52 | * @param[in] _exponent the bin size exponent 53 | */ 54 | DirectionalBins(size_t _exponent); 55 | 56 | /** 57 | * @brief This destructor will close any remaining mapped files and remove them from disk 58 | */ 59 | ~DirectionalBins(); 60 | 61 | /** 62 | * @brief Add buffer of compressed rays to an indexed bin 63 | * 64 | * @param[in] _size size of array to be added 65 | * @param[in] _cardinal index of which directional bin 66 | * @param _data input ray data 67 | * @param _batch_queue output queue to store batch representation 68 | */ 69 | void add(const int _size, const int _cardinal, RayCompressed* _data, tbb::concurrent_queue< BatchItem >* _batch_queue); 70 | 71 | /** 72 | * @brief Flush data into batch queue for processing 73 | * 74 | * @param _batch_queue output queue to store batch representaton 75 | */ 76 | void flush(tbb::concurrent_queue< BatchItem >* _batch_queue); 77 | 78 | private: 79 | size_t m_exponent; 80 | Bin m_bin[6]; 81 | }; 82 | 83 | MSC_NAMESPACE_END 84 | 85 | #endif 86 | -------------------------------------------------------------------------------- /cmake/FindOpenEXR.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # Try to find OpenEXR's libraries, and include path. 3 | # Once done this will define: 4 | # 5 | # OPENEXR_FOUND = OpenEXR found. 6 | # OPENEXR_INCLUDE_PATHS = OpenEXR include directories. 7 | # OPENEXR_LIBRARIES = libraries that are needed to use OpenEXR. 8 | # 9 | 10 | INCLUDE(FindZLIB) 11 | 12 | 13 | IF(ZLIB_FOUND) 14 | 15 | SET(LIBRARY_PATHS 16 | /usr/lib 17 | /usr/local/lib 18 | /sw/lib 19 | /opt/local/lib 20 | $ENV{PROGRAM_FILES}/OpenEXR/lib/static) 21 | 22 | FIND_PATH(OPENEXR_INCLUDE_PATH ImfRgbaFile.h 23 | PATH_SUFFIXES OpenEXR 24 | /usr/include 25 | /usr/local/include 26 | /sw/include 27 | /opt/local/include) 28 | 29 | FIND_LIBRARY(OPENEXR_HALF_LIBRARY 30 | NAMES Half 31 | PATHS ${LIBRARY_PATHS}) 32 | 33 | FIND_LIBRARY(OPENEXR_IEX_LIBRARY 34 | NAMES Iex 35 | PATHS ${LIBRARY_PATHS}) 36 | 37 | FIND_LIBRARY(OPENEXR_IMATH_LIBRARY 38 | NAMES Imath 39 | PATHS ${LIBRARY_PATHS}) 40 | 41 | FIND_LIBRARY(OPENEXR_ILMIMF_LIBRARY 42 | NAMES IlmImf 43 | PATHS ${LIBRARY_PATHS}) 44 | 45 | FIND_LIBRARY(OPENEXR_ILMTHREAD_LIBRARY 46 | NAMES IlmThread 47 | PATHS ${LIBRARY_PATHS}) 48 | 49 | ENDIF(ZLIB_FOUND) 50 | 51 | #MESSAGE(STATUS ${OPENEXR_IMATH_LIBRARY} ${OPENEXR_ILMIMF_LIBRARY} ${OPENEXR_IEX_LIBRARY} ${OPENEXR_HALF_LIBRARY} ${OPENEXR_ILMTHREAD_LIBRARY} ${ZLIB_LIBRARY}) 52 | 53 | IF (OPENEXR_INCLUDE_PATH AND OPENEXR_IMATH_LIBRARY AND OPENEXR_ILMIMF_LIBRARY AND OPENEXR_IEX_LIBRARY AND OPENEXR_HALF_LIBRARY) 54 | SET(OPENEXR_FOUND TRUE) 55 | SET(OPENEXR_INCLUDE_PATHS ${OPENEXR_INCLUDE_PATH} CACHE STRING "The include paths needed to use OpenEXR") 56 | SET(OPENEXR_LIBRARIES ${OPENEXR_IMATH_LIBRARY} ${OPENEXR_ILMIMF_LIBRARY} ${OPENEXR_IEX_LIBRARY} ${OPENEXR_HALF_LIBRARY} ${OPENEXR_ILMTHREAD_LIBRARY} ${ZLIB_LIBRARY} CACHE STRING "The libraries needed to use OpenEXR") 57 | ENDIF (OPENEXR_INCLUDE_PATH AND OPENEXR_IMATH_LIBRARY AND OPENEXR_ILMIMF_LIBRARY AND OPENEXR_IEX_LIBRARY AND OPENEXR_HALF_LIBRARY) 58 | 59 | IF(OPENEXR_FOUND) 60 | IF(NOT OPENEXR_FIND_QUIETLY) 61 | MESSAGE(STATUS "Found OpenEXR: ${OPENEXR_ILMIMF_LIBRARY}") 62 | ENDIF(NOT OPENEXR_FIND_QUIETLY) 63 | ELSE(OPENEXR_FOUND) 64 | IF(OPENEXR_FIND_REQUIRED) 65 | MESSAGE(FATAL_ERROR "Could not find OpenEXR library") 66 | ENDIF(OPENEXR_FIND_REQUIRED) 67 | ENDIF(OPENEXR_FOUND) 68 | 69 | MARK_AS_ADVANCED( 70 | OPENEXR_INCLUDE_PATHS 71 | OPENEXR_LIBRARIES 72 | OPENEXR_ILMIMF_LIBRARY 73 | OPENEXR_IMATH_LIBRARY 74 | OPENEXR_IEX_LIBRARY 75 | OPENEXR_HALF_LIBRARY) -------------------------------------------------------------------------------- /include/core/RayUncompressed.h: -------------------------------------------------------------------------------- 1 | #ifndef _RAYUNCOMPRESSED_H_ 2 | #define _RAYUNCOMPRESSED_H_ 3 | 4 | #include 5 | #include 6 | 7 | MSC_NAMESPACE_BEGIN 8 | 9 | /** 10 | * @brief Structure to contain a uncompressed ray 11 | * 12 | * Uncompressed rays are an extension of Embree's ray type to support path tracing and are also used 13 | * for hit point sorting to minimise usage on memory. 14 | */ 15 | struct RayUncompressed 16 | { 17 | union 18 | { 19 | RTCRay rtc_ray; 20 | struct RTCORE_ALIGN(16) 21 | { 22 | //Ray data 23 | float org[3]; 24 | float align0; 25 | 26 | float dir[3]; 27 | float align1; 28 | 29 | float tnear; 30 | float tfar; 31 | 32 | float time; 33 | int mask; 34 | 35 | // Hit data 36 | float Ng[3]; 37 | float align2; 38 | 39 | float u; 40 | float v; 41 | 42 | int geomID; 43 | int primID; 44 | int instID; 45 | }; 46 | }; 47 | 48 | //Added data 49 | float weight[3]; 50 | float lastPdf; 51 | int rayDepth; 52 | int sampleID; 53 | }; 54 | 55 | inline bool operator==(const RayUncompressed &lhs, const RayUncompressed &rhs) 56 | {return (lhs.geomID == rhs.geomID);} 57 | inline bool operator!=(const RayUncompressed &lhs, const RayUncompressed &rhs) 58 | {return (lhs.geomID != rhs.geomID);} 59 | 60 | /** 61 | * @brief Comparison functor for uncompressed rays based on hit geometry and primative id 62 | */ 63 | struct CompareHit 64 | { 65 | bool operator()(const RayUncompressed &lhs, const RayUncompressed &rhs) const 66 | { 67 | return (lhs.geomID < rhs.geomID) || (lhs.geomID == rhs.geomID && lhs.primID < rhs.primID); 68 | } 69 | }; 70 | 71 | /** 72 | * @brief Comparison functor for uncompressed rays based on position 73 | */ 74 | class CompareOrg 75 | { 76 | public: 77 | CompareOrg(int _axis = 0) : m_axis(_axis) {;} 78 | 79 | bool operator()(const RayUncompressed &lhs, const RayUncompressed &rhs) const 80 | { 81 | return lhs.org[m_axis] < rhs.org[m_axis]; 82 | } 83 | 84 | private: 85 | size_t m_axis; 86 | }; 87 | 88 | /** 89 | * @brief Comparison functor for uncompressed rays based on direction 90 | */ 91 | class CompareDir 92 | { 93 | public: 94 | CompareDir(int _axis = 0) : m_axis(_axis) {;} 95 | 96 | bool operator()(const RayUncompressed &lhs, const RayUncompressed &rhs) const 97 | { 98 | return lhs.dir[m_axis] < rhs.dir[m_axis]; 99 | } 100 | 101 | private: 102 | size_t m_axis; 103 | }; 104 | 105 | MSC_NAMESPACE_END 106 | 107 | #endif 108 | -------------------------------------------------------------------------------- /src/core/QuadLight.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | MSC_NAMESPACE_BEGIN 4 | 5 | void QuadLight::construct() 6 | { 7 | const float tmp_positions[] = { 8 | 0.f, -0.5f, -0.5f, 0.f, 9 | 0.f, 0.5f, -0.5f, 0.f, 10 | 0.f, 0.5f, 0.5f, 0.f, 11 | 0.f, 0.5f, 0.5f, 0.f, 12 | 0.f, -0.5f, 0.5f, 0.f, 13 | 0.f, -0.5f, -0.5f, 0.f 14 | }; 15 | 16 | const unsigned int tmp_indices[] = { 17 | 0, 1, 2, 18 | 3, 4, 5, 19 | }; 20 | 21 | m_positions = std::vector(tmp_positions, tmp_positions + 24); 22 | m_indices = std::vector(tmp_indices, tmp_indices + 6); 23 | 24 | m_transform = Affine3f::Identity() 25 | * Eigen::Translation3f(m_translation) 26 | * Eigen::AngleAxisf(m_rotation.x() * M_PI_180, Vector3f::UnitX()) 27 | * Eigen::AngleAxisf(m_rotation.y() * M_PI_180, Vector3f::UnitY()) 28 | * Eigen::AngleAxisf(m_rotation.z() * M_PI_180, Vector3f::UnitZ()) 29 | * Eigen::AlignedScaling3f(Vector3f(1.f, m_scale.x(), m_scale.y())); 30 | 31 | m_normal = (m_transform.linear().inverse().transpose() * Vector3f::UnitX()).normalized(); 32 | 33 | Vector3fMap mapped_data(NULL); 34 | for(size_t i = 0; i < 6; ++i) 35 | { 36 | new (&mapped_data) Vector3fMap((float*) &(m_positions[4 * i + 0])); 37 | mapped_data = m_transform * mapped_data; 38 | } 39 | } 40 | 41 | void QuadLight::illuminate( 42 | RandomGenerator* _random, 43 | const Vector3f& _position, 44 | Vector3f* _direction, 45 | float* _distance, 46 | Colour3f* _radiance, 47 | float* _direct_pdfw 48 | ) const 49 | { 50 | float sample_x = 0.f; 51 | float sample_y = _random->sample() - 0.5f; 52 | float sample_z = _random->sample() - 0.5f; 53 | Vector3f sample = m_transform * Vector3f(sample_x, sample_y, sample_z); 54 | 55 | float cos_theta = (_position - sample).normalized().dot(m_normal); 56 | 57 | if(cos_theta < 0.f) 58 | *_radiance = Colour3f(0.f, 0.f, 0.f); 59 | else 60 | *_radiance = Colour3f(m_intensity, m_intensity, m_intensity); 61 | 62 | cos_theta = (cos_theta < 0.f) ? 0.f : cos_theta; 63 | 64 | *_direction = (sample - _position).normalized(); 65 | *_distance = (sample - _position).norm(); 66 | *_direct_pdfw = ((sample - _position).squaredNorm() / cos_theta) / (m_scale.x() * m_scale.y()); 67 | } 68 | 69 | void QuadLight::radiance( 70 | const Vector3f& _direction, 71 | Colour3f* _radiance, 72 | float* _cos_theta, 73 | float* _direct_pdfa 74 | ) const 75 | { 76 | *_cos_theta = m_normal.dot(_direction * -1.f); 77 | 78 | if(*_cos_theta < 0.f) 79 | *_radiance = Colour3f(0.f, 0.f, 0.f); 80 | else 81 | *_radiance = Colour3f(m_intensity, m_intensity, m_intensity); 82 | 83 | *_direct_pdfa = 1.f / (m_scale.x() * m_scale.y()); 84 | } 85 | 86 | MSC_NAMESPACE_END -------------------------------------------------------------------------------- /src/core/PolygonObject.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | MSC_NAMESPACE_BEGIN 4 | 5 | void PolygonObject::construct() 6 | { 7 | tinyobj::shape_t shape; 8 | std::string err = tinyobj::LoadObj(shape, m_filename.c_str()); 9 | 10 | // if(!err.empty()) 11 | // std::cout << err << std::endl; 12 | 13 | m_normals.swap(shape.mesh.normals); 14 | m_texcoords.swap(shape.mesh.texcoords); 15 | m_indices.swap(shape.mesh.indices); 16 | 17 | Affine3f transform = Affine3f::Identity() 18 | * Eigen::Translation3f(m_translation) 19 | * Eigen::AngleAxisf(m_rotation.x() * M_PI_180, Vector3f::UnitX()) 20 | * Eigen::AngleAxisf(m_rotation.y() * M_PI_180, Vector3f::UnitY()) 21 | * Eigen::AngleAxisf(m_rotation.z() * M_PI_180, Vector3f::UnitZ()) 22 | * Eigen::AlignedScaling3f(m_scale); 23 | 24 | Vector3fMap mapped_normal(NULL); 25 | for(size_t i = 0; i < m_normals.size() / 3; ++i) 26 | { 27 | new (&mapped_normal) Vector3fMap((float*) &(m_normals[3 * i + 0])); 28 | mapped_normal = (transform.linear().inverse().transpose() * mapped_normal).normalized(); 29 | } 30 | 31 | Vector3fMap mapped_position(NULL); 32 | m_positions.resize((shape.mesh.positions.size() / 3) * 4); 33 | for(size_t i = 0; i < shape.mesh.positions.size() / 3; ++i) 34 | { 35 | m_positions[4 * i + 0] = shape.mesh.positions[3 * i + 0]; 36 | m_positions[4 * i + 1] = shape.mesh.positions[3 * i + 1]; 37 | m_positions[4 * i + 2] = shape.mesh.positions[3 * i + 2]; 38 | m_positions[4 * i + 3] = 0.f; 39 | 40 | new (&mapped_position) Vector3fMap((float*) &(m_positions[4 * i + 0])); 41 | mapped_position = transform * mapped_position; 42 | } 43 | } 44 | 45 | void PolygonObject::texture( 46 | const size_t _primitive, 47 | const float _s, 48 | const float _t, 49 | Vector2f* _output 50 | ) const 51 | { 52 | const size_t _index_base = m_indices[3 * _primitive + 0]; 53 | const size_t _index_s = m_indices[3 * _primitive + 1]; 54 | const size_t _index_t = m_indices[3 * _primitive + 2]; 55 | 56 | (*_output)[0] = (1.f - _s - _t) * m_texcoords[2 * _index_base + 0] + 57 | _s * m_texcoords[2 * _index_s + 0] + 58 | _t * m_texcoords[2 * _index_t + 0]; 59 | 60 | (*_output)[1] = (1.f - _s - _t) * m_texcoords[2 * _index_base + 1] + 61 | _s * m_texcoords[2 * _index_s + 1] + 62 | _t * m_texcoords[2 * _index_t + 1]; 63 | } 64 | 65 | void PolygonObject::normal( 66 | const size_t _primitive, 67 | const float _s, 68 | const float _t, 69 | Vector3f* _output 70 | ) const 71 | { 72 | const size_t _index_base = m_indices[3 * _primitive + 0]; 73 | const size_t _index_s = m_indices[3 * _primitive + 1]; 74 | const size_t _index_t = m_indices[3 * _primitive + 2]; 75 | 76 | (*_output)[0] = (1.f - _s - _t) * m_normals[3 * _index_base + 0] + 77 | _s * m_normals[3 * _index_s + 0] + 78 | _t * m_normals[3 * _index_t + 0]; 79 | 80 | (*_output)[1] = (1.f - _s - _t) * m_normals[3 * _index_base + 1] + 81 | _s * m_normals[3 * _index_s + 1] + 82 | _t * m_normals[3 * _index_t + 1]; 83 | 84 | (*_output)[2] = (1.f - _s - _t) * m_normals[3 * _index_base + 2] + 85 | _s * m_normals[3 * _index_s + 2] + 86 | _t * m_normals[3 * _index_t + 2]; 87 | } 88 | 89 | MSC_NAMESPACE_END -------------------------------------------------------------------------------- /cmake/FindEigen3.cmake: -------------------------------------------------------------------------------- 1 | # - Try to find Eigen3 lib 2 | # 3 | # This module supports requiring a minimum version, e.g. you can do 4 | # find_package(Eigen3 3.1.2) 5 | # to require version 3.1.2 or newer of Eigen3. 6 | # 7 | # Once done this will define 8 | # 9 | # EIGEN3_FOUND - system has eigen lib with correct version 10 | # EIGEN3_INCLUDE_DIR - the eigen include directory 11 | # EIGEN3_VERSION - eigen version 12 | 13 | # Copyright (c) 2006, 2007 Montel Laurent, 14 | # Copyright (c) 2008, 2009 Gael Guennebaud, 15 | # Copyright (c) 2009 Benoit Jacob 16 | # Redistribution and use is allowed according to the terms of the 2-clause BSD license. 17 | 18 | if(NOT Eigen3_FIND_VERSION) 19 | if(NOT Eigen3_FIND_VERSION_MAJOR) 20 | set(Eigen3_FIND_VERSION_MAJOR 2) 21 | endif(NOT Eigen3_FIND_VERSION_MAJOR) 22 | if(NOT Eigen3_FIND_VERSION_MINOR) 23 | set(Eigen3_FIND_VERSION_MINOR 91) 24 | endif(NOT Eigen3_FIND_VERSION_MINOR) 25 | if(NOT Eigen3_FIND_VERSION_PATCH) 26 | set(Eigen3_FIND_VERSION_PATCH 0) 27 | endif(NOT Eigen3_FIND_VERSION_PATCH) 28 | 29 | set(Eigen3_FIND_VERSION "${Eigen3_FIND_VERSION_MAJOR}.${Eigen3_FIND_VERSION_MINOR}.${Eigen3_FIND_VERSION_PATCH}") 30 | endif(NOT Eigen3_FIND_VERSION) 31 | 32 | macro(_eigen3_check_version) 33 | file(READ "${EIGEN3_INCLUDE_DIR}/Eigen/src/Core/util/Macros.h" _eigen3_version_header) 34 | 35 | string(REGEX MATCH "define[ \t]+EIGEN_WORLD_VERSION[ \t]+([0-9]+)" _eigen3_world_version_match "${_eigen3_version_header}") 36 | set(EIGEN3_WORLD_VERSION "${CMAKE_MATCH_1}") 37 | string(REGEX MATCH "define[ \t]+EIGEN_MAJOR_VERSION[ \t]+([0-9]+)" _eigen3_major_version_match "${_eigen3_version_header}") 38 | set(EIGEN3_MAJOR_VERSION "${CMAKE_MATCH_1}") 39 | string(REGEX MATCH "define[ \t]+EIGEN_MINOR_VERSION[ \t]+([0-9]+)" _eigen3_minor_version_match "${_eigen3_version_header}") 40 | set(EIGEN3_MINOR_VERSION "${CMAKE_MATCH_1}") 41 | 42 | set(EIGEN3_VERSION ${EIGEN3_WORLD_VERSION}.${EIGEN3_MAJOR_VERSION}.${EIGEN3_MINOR_VERSION}) 43 | if(${EIGEN3_VERSION} VERSION_LESS ${Eigen3_FIND_VERSION}) 44 | set(EIGEN3_VERSION_OK FALSE) 45 | else(${EIGEN3_VERSION} VERSION_LESS ${Eigen3_FIND_VERSION}) 46 | set(EIGEN3_VERSION_OK TRUE) 47 | endif(${EIGEN3_VERSION} VERSION_LESS ${Eigen3_FIND_VERSION}) 48 | 49 | if(NOT EIGEN3_VERSION_OK) 50 | 51 | message(STATUS "Eigen3 version ${EIGEN3_VERSION} found in ${EIGEN3_INCLUDE_DIR}, " 52 | "but at least version ${Eigen3_FIND_VERSION} is required") 53 | endif(NOT EIGEN3_VERSION_OK) 54 | endmacro(_eigen3_check_version) 55 | 56 | if (EIGEN3_INCLUDE_DIR) 57 | 58 | # in cache already 59 | _eigen3_check_version() 60 | set(EIGEN3_FOUND ${EIGEN3_VERSION_OK}) 61 | 62 | else (EIGEN3_INCLUDE_DIR) 63 | 64 | find_path(EIGEN3_INCLUDE_DIR NAMES signature_of_eigen3_matrix_library 65 | PATHS 66 | ${CMAKE_INSTALL_PREFIX}/include 67 | ${KDE4_INCLUDE_DIR} 68 | PATH_SUFFIXES eigen3 eigen 69 | ) 70 | 71 | if(EIGEN3_INCLUDE_DIR) 72 | _eigen3_check_version() 73 | endif(EIGEN3_INCLUDE_DIR) 74 | 75 | include(FindPackageHandleStandardArgs) 76 | find_package_handle_standard_args(Eigen3 DEFAULT_MSG EIGEN3_INCLUDE_DIR EIGEN3_VERSION_OK) 77 | 78 | mark_as_advanced(EIGEN3_INCLUDE_DIR) 79 | 80 | endif(EIGEN3_INCLUDE_DIR) 81 | 82 | -------------------------------------------------------------------------------- /include/core/NullShader.h: -------------------------------------------------------------------------------- 1 | #ifndef _NULLSHADER_H_ 2 | #define _NULLSHADER_H_ 3 | 4 | #include 5 | #include 6 | 7 | MSC_NAMESPACE_BEGIN 8 | 9 | /** 10 | * @brief Inherits from the shader interface and represents a non-contributing surface 11 | * 12 | * Represents a shader that does not contribute to the lighting intergral and is primarily used 13 | * as a simple index toward lights that have geometric representation. 14 | */ 15 | class NullShader : public ShaderInterface 16 | { 17 | public: 18 | /** 19 | * @brief Create polymorphic copy of derived class 20 | * 21 | * @return Is safe to have a covariant return type here 22 | */ 23 | ShaderInterface* clone(); 24 | 25 | /** 26 | * @brief Initialize colour values potentially as vectorized texture lookup 27 | */ 28 | void initialize( 29 | const size_t _size, 30 | std::vector< float >& _u, 31 | std::vector< float >& _v, 32 | TextureSystem _texture_system 33 | ); 34 | 35 | /** 36 | * @brief Get probabilty of bsdf reflectance for russian roulette 37 | * 38 | * @return reflectance probabilty 39 | */ 40 | float continuation() const; 41 | 42 | /** 43 | * @brief Evaluate shader for given input and output directions and differential data 44 | * 45 | * @param[in] _colour_index coeffitient look up index 46 | * @param[in] _input input light direction 47 | * @param[in] _output output light direction 48 | * @param[in] _normal surface normal 49 | * @param _weight resulting bsdf weight 50 | * @param _cos_theta cosine of the angle from input direction 51 | * @param _direct_pdfw probabilty in respect to solid angle 52 | */ 53 | void evaluate( 54 | const size_t _colour_index, 55 | const Vector3f& _input, 56 | const Vector3f& _output, 57 | const Vector3f& _normal, 58 | Colour3f* _weight, 59 | float* _cos_theta, 60 | float* _direct_pdfw = NULL 61 | ) const; 62 | 63 | /** 64 | * @brief Create sample according to pdf and produce bsdf weight 65 | * 66 | * @param _random thread local random generator to prevent mutation 67 | * @param[in] _colour_index index into coefitient look up 68 | * @param[in] _output output light direction 69 | * @param[in] _normal surface normal 70 | * @param _input inpute direction to be created according to pdf 71 | * @param _weight bsdf weight 72 | * @param _cos_theta cosine of the angle between normal and sampled direction 73 | * @param _direct_pdfw probability in respect to solid angle 74 | */ 75 | void sample( 76 | RandomGenerator* _random, 77 | const size_t _colour_index, 78 | const Vector3f& _output, 79 | const Vector3f& _normal, 80 | Vector3f* _input, 81 | Colour3f* _weight, 82 | float* _cos_theta, 83 | float* _direct_pdfw = NULL 84 | ) const; 85 | }; 86 | 87 | MSC_NAMESPACE_END 88 | 89 | YAML_NAMESPACE_BEGIN 90 | 91 | template<> struct convert 92 | { 93 | static bool decode(const Node& node, msc::NullShader& rhs) 94 | { 95 | if(!node.IsMap() || node.size() != 1) 96 | return false; 97 | 98 | return true; 99 | } 100 | }; 101 | 102 | YAML_NAMESPACE_END 103 | 104 | #endif -------------------------------------------------------------------------------- /include/core/Common.h: -------------------------------------------------------------------------------- 1 | #ifndef _COMMON_H_ 2 | #define _COMMON_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | 15 | MSC_NAMESPACE_BEGIN 16 | 17 | inline bool compare(const float _a, const float _b) 18 | { 19 | return fabs(static_cast(_a) - static_cast(_b)) < M_EPSILON; 20 | } 21 | 22 | inline void cartesianToSphericalCoord(const float _x, const float _y, const float _z, float *azimuthal, float *zenith) 23 | { 24 | *azimuthal = atan2(_y, _x); 25 | *zenith = atan(sqrt((_x * _x) + (_y * _y)) / _z); 26 | } 27 | 28 | inline void sphericalToCartesianCoord(const float _azimuthal, const float _zenith, float *x, float *y, float *z) 29 | { 30 | *x = cos(_azimuthal) * sin(_zenith); 31 | *y = sin(_azimuthal) * sin(_zenith); 32 | *z = cos(_zenith); 33 | } 34 | 35 | inline float areaToAngleProbability(const float _area, const float _distance, const float _cosine) 36 | { 37 | return _area * (_distance * _distance) / abs(_cosine); 38 | } 39 | 40 | inline float angleToAreaProbability(const float _angle, const float _distance, const float _cosine) 41 | { 42 | return _angle * abs(_cosine) / (_distance * _distance); 43 | } 44 | 45 | inline float misBalance(const float _first, const float _second) 46 | { 47 | return (_first / (_first + _second)); 48 | } 49 | 50 | template < typename type, int size > struct BoundingBox 51 | { 52 | type min[size]; 53 | type max[size]; 54 | }; 55 | 56 | typedef BoundingBox< float, 3 > BoundingBox3f; 57 | 58 | typedef Eigen::Matrix< float, 2, 1 > Vector2f; 59 | typedef Eigen::Map< msc::Vector2f > Vector2fMap; 60 | typedef Eigen::Matrix< float, 3, 1 > Vector3f; 61 | typedef Eigen::Map< msc::Vector3f > Vector3fMap; 62 | typedef Eigen::Matrix< float, 4, 1 > Vector4f; 63 | typedef Eigen::Map< msc::Vector4f > Vector4fMap; 64 | typedef Eigen::Array< float, 3, 1 > Colour3f; 65 | typedef Eigen::Map< msc::Colour3f > Colour3fMap; 66 | 67 | typedef Eigen::Transform< float, 3, Eigen::Affine > Affine3f; 68 | 69 | MSC_NAMESPACE_END 70 | 71 | YAML_NAMESPACE_BEGIN 72 | 73 | template<> struct convert 74 | { 75 | static bool decode(const Node& node, msc::Vector3f& rhs) 76 | { 77 | if(!node.IsSequence() || node.size() != 3) 78 | { 79 | return false; 80 | } 81 | 82 | rhs.x() = node[0].as(); 83 | rhs.y() = node[1].as(); 84 | rhs.z() = node[2].as(); 85 | return true; 86 | } 87 | }; 88 | 89 | template<> struct convert 90 | { 91 | static bool decode(const Node& node, msc::Vector2f& rhs) 92 | { 93 | if(!node.IsSequence() || node.size() != 2) 94 | { 95 | return false; 96 | } 97 | 98 | rhs.x() = node[0].as(); 99 | rhs.y() = node[1].as(); 100 | return true; 101 | } 102 | }; 103 | 104 | template<> struct convert 105 | { 106 | static bool decode(const Node& node, msc::Colour3f& rhs) 107 | { 108 | if(!node.IsSequence() || node.size() != 3) 109 | { 110 | return false; 111 | } 112 | 113 | rhs[0] = node[0].as(); 114 | rhs[1] = node[1].as(); 115 | rhs[2] = node[2].as(); 116 | return true; 117 | } 118 | }; 119 | 120 | YAML_NAMESPACE_END 121 | 122 | #endif -------------------------------------------------------------------------------- /include/core/PinHoleCamera.h: -------------------------------------------------------------------------------- 1 | #ifndef _PINHOLECAMERA_H_ 2 | #define _PINHOLECAMERA_H_ 3 | 4 | #include 5 | #include 6 | 7 | MSC_NAMESPACE_BEGIN 8 | 9 | /** 10 | * @brief Inherits from the camera interface and represents a pin hole camera 11 | * 12 | * The PinHoleCamera creates a perspective projection through an infinitely small hole and does not 13 | * take into account depth of field. The sample method takes a range of samples from a single pixel 14 | * to improve performance. 15 | */ 16 | class PinHoleCamera : public CameraInterface 17 | { 18 | public: 19 | /** 20 | * @brief Initialiser list for class 21 | */ 22 | PinHoleCamera() 23 | : m_translation(Vector3f(0.f, 0.f, 0.f)) 24 | , m_rotation(Vector3f(0.f, 0.f, 0.f)) 25 | , m_focal_length(55.f) 26 | {;} 27 | 28 | /** 29 | * @brief Getter method for translation 30 | * 31 | * @return translation vector 32 | */ 33 | inline Vector3f translation() const {return m_translation;} 34 | 35 | /** 36 | * @brief Getter method for rotation 37 | * 38 | * @return euler angle vector 39 | */ 40 | inline Vector3f rotation() const {return m_rotation;} 41 | 42 | /** 43 | * @brief Getter method for focal length 44 | * 45 | * @return focal length 46 | */ 47 | inline float focalLength() const {return m_focal_length;} 48 | 49 | /** 50 | * @brief Setter method for translation 51 | * 52 | * @param[in] _translation translation vector 53 | */ 54 | void translation(const Vector3f &_translation){m_translation = _translation;} 55 | 56 | /** 57 | * @brief Setter method for rotation 58 | * 59 | * @param[in] _translation euler angle vector 60 | */ 61 | void rotation(const Vector3f &_rotation){m_rotation = _rotation;} 62 | 63 | /** 64 | * @brief Setter method for focal length 65 | * 66 | * @param[in] _translation focal length 67 | */ 68 | void focalLength(const float _focal_length){m_focal_length = _focal_length;} 69 | 70 | /** 71 | * @brief Precomputes transform 72 | */ 73 | void construct(); 74 | 75 | /** 76 | * @brief Creates primary rays from camera 77 | * 78 | * @param[in] _count sample count to process 79 | * @param _positions positions on film plane of samples 80 | * @param _random thread local random generator to prevent mutation 81 | * @param _ouput output of compressed rays 82 | */ 83 | void sample(const int _count, float* _positions, RandomGenerator* _random, RayCompressed* _ouput) const; 84 | 85 | private: 86 | Vector3f m_translation; 87 | Vector3f m_rotation; 88 | float m_focal_length; 89 | 90 | Affine3f m_transform; 91 | Vector3f m_normal; 92 | }; 93 | 94 | MSC_NAMESPACE_END 95 | 96 | YAML_NAMESPACE_BEGIN 97 | 98 | template<> struct convert 99 | { 100 | static bool decode(const Node& node, msc::PinHoleCamera& rhs) 101 | { 102 | if(!node.IsMap() || node.size() != 4) 103 | return false; 104 | 105 | rhs.translation(node["translation"].as()); 106 | rhs.rotation(node["rotation"].as()); 107 | rhs.focalLength(node["focal length"].as()); 108 | 109 | rhs.construct(); 110 | 111 | return true; 112 | } 113 | }; 114 | 115 | YAML_NAMESPACE_END 116 | 117 | #endif 118 | -------------------------------------------------------------------------------- /thirdparty/tinyobjloader/tiny_obj_loader.h: -------------------------------------------------------------------------------- 1 | /// @brief An object passing module 2 | /// Modified from :- 3 | /// Syoyo Fujita (August 4, 2015). tinyobjloader [online]. 4 | /// [Accessed 2015]. Available from: . 5 | 6 | // 7 | // Copyright 2012-2015, Syoyo Fujita. 8 | // 9 | // Licensed under 2-clause BSD liecense. 10 | // 11 | #ifndef _TINY_OBJ_LOADER_H 12 | #define _TINY_OBJ_LOADER_H 13 | 14 | #include 15 | #include 16 | #include 17 | 18 | namespace tinyobj { 19 | 20 | typedef struct { 21 | std::string name; 22 | 23 | float ambient[3]; 24 | float diffuse[3]; 25 | float specular[3]; 26 | float transmittance[3]; 27 | float emission[3]; 28 | float shininess; 29 | float ior; // index of refraction 30 | float dissolve; // 1 == opaque; 0 == fully transparent 31 | // illumination model (see http://www.fileformat.info/format/material/) 32 | int illum; 33 | 34 | std::string ambient_texname; 35 | std::string diffuse_texname; 36 | std::string specular_texname; 37 | std::string normal_texname; 38 | std::map unknown_parameter; 39 | } material_t; 40 | 41 | typedef struct { 42 | std::vector positions; 43 | std::vector normals; 44 | std::vector texcoords; 45 | std::vector indices; 46 | std::vector material_ids; // per-mesh material ID 47 | } mesh_t; 48 | 49 | typedef struct { 50 | std::string name; 51 | mesh_t mesh; 52 | } shape_t; 53 | 54 | class MaterialReader { 55 | public: 56 | MaterialReader() {} 57 | virtual ~MaterialReader() {} 58 | 59 | virtual std::string operator()(const std::string &matId, 60 | std::vector &materials, 61 | std::map &matMap) = 0; 62 | }; 63 | 64 | class MaterialFileReader : public MaterialReader { 65 | public: 66 | MaterialFileReader(const std::string &mtl_basepath) 67 | : m_mtlBasePath(mtl_basepath) {} 68 | virtual ~MaterialFileReader() {} 69 | virtual std::string operator()(const std::string &matId, 70 | std::vector &materials, 71 | std::map &matMap); 72 | 73 | private: 74 | std::string m_mtlBasePath; 75 | }; 76 | 77 | /// Loads .obj from a file. 78 | /// 'shapes' will be filled with parsed shape data 79 | /// The function returns error string. 80 | /// Returns empty string when loading .obj success. 81 | /// 'mtl_basepath' is optional, and used for base path for .mtl file. 82 | std::string LoadObj(shape_t &output, // [output] 83 | // std::vector &materials, // [output] 84 | const char *filename, const char *mtl_basepath = NULL); 85 | 86 | /// Loads object from a std::istream, uses GetMtlIStreamFn to retrieve 87 | /// std::istream for materials. 88 | /// Returns empty string when loading .obj success. 89 | std::string LoadObj(shape_t &output, // [output] 90 | // std::vector &materials, // [output] 91 | std::istream &inStream, MaterialReader &readMatFn); 92 | 93 | /// Loads materials into std::map 94 | /// Returns an empty string if successful 95 | std::string LoadMtl(std::map &material_map, 96 | std::vector &materials, std::istream &inStream); 97 | } 98 | 99 | #endif // _TINY_OBJ_LOADER_H 100 | -------------------------------------------------------------------------------- /include/core/ShaderInterface.h: -------------------------------------------------------------------------------- 1 | #ifndef _SHADERINTERFACE_H_ 2 | #define _SHADERINTERFACE_H_ 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | MSC_NAMESPACE_BEGIN 11 | 12 | /** 13 | * @brief Abstract interface class for surface shaders 14 | * 15 | * This is an interface for using a shader in a polymorphic sense. Due to the design of the 16 | * integrator the shader will take only a single position on the surface to evaluate at a time. 17 | * It will also be responsible for sampling according to a probability density and returning such 18 | * data and for use with multiple importance sampling. Access to textures across multiple positions 19 | * are pre calculated and cached to improve memory performance. 20 | */ 21 | class ShaderInterface 22 | { 23 | public: 24 | /** 25 | * @brief Virtual destructor required for interface 26 | */ 27 | virtual ~ShaderInterface() {} 28 | 29 | /** 30 | * @brief Create polymorphic copy of derived class 31 | * 32 | * @return is safe to have a covariant return type here 33 | */ 34 | virtual ShaderInterface* clone() = 0; 35 | 36 | /** 37 | * @brief Initialize colour values potentially as vectorized texture lookup 38 | */ 39 | virtual void initialize( 40 | const size_t _size, 41 | std::vector< float >& _u, 42 | std::vector< float >& _v, 43 | TextureSystem _texture_system 44 | ) =0; 45 | 46 | /** 47 | * @brief Get probabilty of bsdf reflectance for russian roulette 48 | * 49 | * @return reflectance probabilty 50 | */ 51 | virtual float continuation() const = 0; 52 | 53 | /** 54 | * @brief Evaluate shader for given input and output directions and differential data 55 | * 56 | * @param[in] _colour_index coeffitient look up index 57 | * @param[in] _input input light direction 58 | * @param[in] _output output light direction 59 | * @param[in] _normal surface normal 60 | * @param _weight resulting bsdf weight 61 | * @param _cos_theta cosine of the angle from input direction 62 | * @param _direct_pdfw probabilty in respect to solid angle 63 | */ 64 | virtual void evaluate( 65 | const size_t _colour_index, 66 | const Vector3f& _input, 67 | const Vector3f& _output, 68 | const Vector3f& _normal, 69 | Colour3f* _weight, 70 | float* _cos_theta, 71 | float* _direct_pdfw = NULL 72 | ) const =0; 73 | 74 | /** 75 | * @brief Create sample according to pdf and produce bsdf weight 76 | * 77 | * @param _random thread local random generator to prevent mutation 78 | * @param[in] _colour_index index into coefitient look up 79 | * @param[in] _output output light direction 80 | * @param[in] _normal surface normal 81 | * @param _input inpute direction to be created according to pdf 82 | * @param _weight bsdf weight 83 | * @param _cos_theta cosine of the angle between normal and sampled direction 84 | * @param _direct_pdfw probability in respect to solid angle 85 | */ 86 | virtual void sample( 87 | RandomGenerator* _random, 88 | const size_t _colour_index, 89 | const Vector3f& _output, 90 | const Vector3f& _normal, 91 | Vector3f* _input, 92 | Colour3f* _weight, 93 | float* _cos_theta, 94 | float* _direct_pdfw = NULL 95 | ) const =0; 96 | }; 97 | 98 | MSC_NAMESPACE_END 99 | 100 | #endif -------------------------------------------------------------------------------- /include/framebuffer/Framebuffer.h: -------------------------------------------------------------------------------- 1 | #ifndef _FRAMEBUFFER_H_ 2 | #define _FRAMEBUFFER_H_ 3 | 4 | #include 5 | 6 | #include 7 | 8 | #define FRM_NAMESPACE_BEGIN namespace frm { 9 | #define FRM_NAMESPACE_END } 10 | 11 | FRM_NAMESPACE_BEGIN 12 | 13 | /** 14 | * @brief Generic framebuffer for visualizing images 15 | * 16 | * Framebuffer that uses OpenGL and GLFW to visualize images. It will take a void pointer to data 17 | * that can then be acceded within key callbacks externally. If a void pointer is not passed then 18 | * default input is used. 19 | */ 20 | class Framebuffer 21 | { 22 | public: 23 | /** 24 | * @brief Initialiser list for class 25 | */ 26 | Framebuffer() 27 | : m_update(true) 28 | , m_pan(false) 29 | , m_resolution_x(700.f) 30 | , m_resolution_y(500.f) 31 | , m_screen_x(0.f) 32 | , m_screen_y(0.f) 33 | , m_state_x(0.f) 34 | , m_state_y(0.f) 35 | , m_trans_x(0.f) 36 | , m_trans_y(0.f) 37 | , m_scale(1.f) 38 | {;} 39 | 40 | /** 41 | * @brief Class destructor for deleting buffers and destroying window 42 | */ 43 | ~Framebuffer(); 44 | 45 | /** 46 | * @brief Initialize framebuffer with parameters and optional control class 47 | * 48 | * @param[in] _resx buffers horizontal resolution 49 | * @param[in] _resy buffers vertical resolution 50 | * @param _input_data optional void pointer to class for mutation when using external callback 51 | * 52 | * @return window pointer to be used to set external key callbacks 53 | */ 54 | GLFWwindow* init(const int _resx, const int _resy, void* _input_data = NULL); 55 | 56 | /** 57 | * @brief Bind data before drawing in case of use with other contexts 58 | */ 59 | void bind(); 60 | 61 | /** 62 | * @brief Draw image to framebuffer 63 | */ 64 | void draw(); 65 | 66 | /** 67 | * @brief Test if window should close 68 | * 69 | * @return boolean value 70 | */ 71 | bool close(); 72 | 73 | /** 74 | * @brief Poll for changed events 75 | */ 76 | void poll(); 77 | 78 | /** 79 | * @brief Set location of image data to be passed onto gpu 80 | * 81 | * @param[in] _image pointer to image data 82 | * @param[in] _resx horizontal resolution 83 | * @param[in] _resy vertical resolution 84 | */ 85 | void image(const unsigned char* _image, const int _resx, const int _resy); 86 | 87 | /** 88 | * @brief Set framebuffer window title to string 89 | * 90 | * @param[in] _title title 91 | */ 92 | void title(const std::string &_title); 93 | 94 | private: 95 | GLFWwindow* m_window; 96 | GLuint m_texture; 97 | GLuint m_shader_program; 98 | GLuint m_vertex_shader; 99 | GLuint m_fragment_shader; 100 | GLuint m_vbo; 101 | GLuint m_vao; 102 | GLint m_pos_attrib; 103 | GLint m_tex_attrib; 104 | GLint m_trans_uniform; 105 | GLint m_scale_uniform; 106 | 107 | void createContext(); 108 | void createSurface(); 109 | static void keyCallback(GLFWwindow* window, int key, int scancode, int action, int mods); 110 | static void scrollCallback(GLFWwindow* window, double xoffset, double yoffset); 111 | static void cursorPositionCallback(GLFWwindow* window, double xpos, double ypos); 112 | static void mouseButtonCallback(GLFWwindow* window, int button, int action, int mods); 113 | 114 | private: 115 | bool m_update; 116 | bool m_pan; 117 | float m_resolution_x, m_resolution_y; 118 | float m_screen_x, m_screen_y; 119 | float m_state_x, m_state_y; 120 | float m_trans_x, m_trans_y; 121 | float m_scale; 122 | }; 123 | 124 | FRM_NAMESPACE_END 125 | 126 | #endif -------------------------------------------------------------------------------- /cmake/FindGLEW.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2013 Pixar 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "Apache License") 5 | # with the following modification; you may not use this file except in 6 | # compliance with the Apache License and the following modification to it: 7 | # Section 6. Trademarks. is deleted and replaced with: 8 | # 9 | # 6. Trademarks. This License does not grant permission to use the trade 10 | # names, trademarks, service marks, or product names of the Licensor 11 | # and its affiliates, except as required to comply with Section 4(c) of 12 | # the License and to reproduce the content of the NOTICE file. 13 | # 14 | # You may obtain a copy of the Apache License at 15 | # 16 | # http://www.apache.org/licenses/LICENSE-2.0 17 | # 18 | # Unless required by applicable law or agreed to in writing, software 19 | # distributed under the Apache License with the above modification is 20 | # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 21 | # KIND, either express or implied. See the Apache License for the specific 22 | # language governing permissions and limitations under the Apache License. 23 | # 24 | 25 | # Try to find GLEW library and include path. 26 | # Once done this will define 27 | # 28 | # GLEW_FOUND 29 | # GLEW_INCLUDE_DIR 30 | # GLEW_LIBRARY 31 | # 32 | 33 | include(FindPackageHandleStandardArgs) 34 | 35 | if (WIN32) 36 | find_path( GLEW_INCLUDE_DIR 37 | NAMES 38 | GL/glew.h 39 | PATHS 40 | "${GLEW_LOCATION}/include" 41 | "$ENV{GLEW_LOCATION}/include" 42 | "$ENV{PROGRAMFILES}/GLEW/include" 43 | "${PROJECT_SOURCE_DIR}/extern/glew/include" 44 | DOC "The directory where GL/glew.h resides" ) 45 | 46 | find_library( GLEW_LIBRARY 47 | NAMES 48 | glew GLEW glew32s glew32 49 | PATHS 50 | "${GLEW_LOCATION}/lib" 51 | "$ENV{GLEW_LOCATION}/lib" 52 | "$ENV{PROGRAMFILES}/GLEW/lib" 53 | "${PROJECT_SOURCE_DIR}/extern/glew/bin" 54 | "${PROJECT_SOURCE_DIR}/extern/glew/lib" 55 | DOC "The GLEW library") 56 | endif () 57 | 58 | if (${CMAKE_HOST_UNIX}) 59 | find_path( GLEW_INCLUDE_DIR 60 | NAMES 61 | GL/glew.h 62 | PATHS 63 | "${GLEW_LOCATION}/include" 64 | "$ENV{GLEW_LOCATION}/include" 65 | /usr/include 66 | /usr/local/include 67 | /sw/include 68 | /opt/local/include 69 | NO_DEFAULT_PATH 70 | DOC "The directory where GL/glew.h resides" 71 | ) 72 | find_library( GLEW_LIBRARY 73 | NAMES 74 | GLEW glew 75 | PATHS 76 | "${GLEW_LOCATION}/lib" 77 | "$ENV{GLEW_LOCATION}/lib" 78 | /usr/lib64 79 | /usr/lib 80 | /usr/lib/${CMAKE_LIBRARY_ARCHITECTURE} 81 | /usr/local/lib64 82 | /usr/local/lib 83 | /sw/lib 84 | /opt/local/lib 85 | NO_DEFAULT_PATH 86 | DOC "The GLEW library") 87 | endif () 88 | 89 | if (GLEW_INCLUDE_DIR AND EXISTS "${GLEW_INCLUDE_DIR}/GL/glew.h") 90 | 91 | file(STRINGS "${GLEW_INCLUDE_DIR}/GL/glew.h" GLEW_4_2 REGEX "^#define GL_VERSION_4_2.*$") 92 | if (GLEW_4_2) 93 | set(OPENGL_4_2_FOUND TRUE) 94 | else () 95 | message(WARNING 96 | "glew-1.7.0 or newer needed for supporting OpenGL 4.2 dependent features" 97 | ) 98 | endif () 99 | 100 | file(STRINGS "${GLEW_INCLUDE_DIR}/GL/glew.h" GLEW_4_3 REGEX "^#define GL_VERSION_4_3.*$") 101 | if (GLEW_4_3) 102 | SET(OPENGL_4_3_FOUND TRUE) 103 | else () 104 | message(WARNING 105 | "glew-1.9.0 or newer needed for supporting OpenGL 4.3 dependent features" 106 | ) 107 | endif () 108 | 109 | endif () 110 | 111 | find_package_handle_standard_args(GLEW 112 | REQUIRED_VARS 113 | GLEW_INCLUDE_DIR 114 | GLEW_LIBRARY 115 | ) 116 | -------------------------------------------------------------------------------- /include/core/Pathtracer.h: -------------------------------------------------------------------------------- 1 | #ifndef _PATHTRACER_H_ 2 | #define _PATHTRACER_H_ 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | MSC_NAMESPACE_BEGIN 25 | 26 | /** 27 | * @brief Rendering engine and interface to external programs 28 | * 29 | * Central class of system exposing main access to external application. It implements each part 30 | * of the paper in a series of parallel and concurrent operations. Batch processing is done for 31 | * example while loading new data into a buffer from disk to avoid thread downtime. The system 32 | * can also render multiple images and combine the results iteratively for fast feedback or produce 33 | * images more efficiently using larger sample counts. Processing can also be queried and terminated 34 | * externally through the public methods. 35 | */ 36 | class Pathtracer 37 | { 38 | public: 39 | /** 40 | * @brief This constructor will construct the scene and initialise libraries 41 | * 42 | * @param[in] _filename file path to the scene description file 43 | */ 44 | Pathtracer(const std::string &_filename); 45 | 46 | /** 47 | * @brief The destructor will delete any files currently on the batch queue and close the cache 48 | */ 49 | ~Pathtracer(); 50 | 51 | /** 52 | * @brief Retrieves internal data on the final image 53 | * 54 | * @param _pixels a pointer to internal pixel data 55 | * @param _with will be set to width of image 56 | * @param _height will be set to height of image 57 | */ 58 | void image(float** _pixels, int* _with, int* _height); 59 | 60 | /** 61 | * @brief Clear internal image data including samples and pixels 62 | */ 63 | void clear(); 64 | 65 | /** 66 | * @brief Check if pathtracer is set to terminate 67 | * 68 | * @return termination state 69 | */ 70 | bool active(); 71 | 72 | /** 73 | * @brief Sets pathtracer to terminate iteration 74 | */ 75 | void terminate(); 76 | 77 | /** 78 | * @brief Compute a single iteration of image 79 | * 80 | * @return current itteration count 81 | */ 82 | int process(); 83 | 84 | private: 85 | boost::scoped_ptr< DirectionalBins > m_bins; 86 | boost::scoped_ptr< Settings > m_settings; 87 | boost::scoped_ptr< Image > m_image; 88 | boost::scoped_ptr< Scene > m_scene; 89 | boost::scoped_ptr< CameraInterface > m_camera; 90 | boost::scoped_ptr< FilterInterface > m_filter; 91 | boost::scoped_ptr< SamplerInterface > m_sampler; 92 | 93 | LocalTextureSystem m_thread_texture_system; 94 | LocalRandomGenerator m_thread_random_generator; 95 | 96 | tbb::concurrent_queue< BatchItem > m_batch_queue; 97 | 98 | boost::atomic< bool > m_terminate; 99 | 100 | void construct(const std::string &_filename); 101 | void cameraSampling(); 102 | bool batchLoading(BatchItem* batch_info); 103 | void fileLoading(const BatchItem& batch_info, RayCompressed* batch_compressed); 104 | void rayDecompressing(const BatchItem& batch_info, RayCompressed* batch_compressed, RayUncompressed* batch_uncompressed); 105 | void raySorting(const BatchItem& batch_info, RayUncompressed* batch_uncompressed); 106 | void sceneTraversal(const BatchItem& batch_info, RayUncompressed* batch_uncompressed); 107 | void hitPointSorting(const BatchItem& batch_info, RayUncompressed* batch_uncompressed); 108 | void surfaceShading(const BatchItem& batch_info, RayUncompressed* batch_uncompressed); 109 | void imageConvolution(); 110 | }; 111 | 112 | MSC_NAMESPACE_END 113 | 114 | #endif -------------------------------------------------------------------------------- /src/core/DirectionalBins.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | MSC_NAMESPACE_BEGIN 4 | 5 | DirectionalBins::DirectionalBins(size_t _exponent) : m_exponent(_exponent) 6 | { 7 | for(size_t index = 0; index < 6; ++index) 8 | { 9 | m_bin[index].size = 0; 10 | 11 | std::string file_location = boost::filesystem::temp_directory_path().string(); 12 | std::string file_name = boost::filesystem::unique_path().string(); 13 | m_bin[index].path = file_location + file_name; 14 | 15 | size_t file_size = pow(2, m_exponent); 16 | 17 | boost::iostreams::mapped_file_params params; 18 | params.path = m_bin[index].path; 19 | params.new_file_size = file_size * sizeof(RayCompressed); 20 | params.mode = std::ios_base::out; 21 | 22 | m_bin[index].outfile.open(params); 23 | m_bin[index].pointer = (RayCompressed*)(m_bin[index].outfile.data()); 24 | m_bin[index].end = m_bin[index].pointer + file_size; 25 | } 26 | } 27 | 28 | DirectionalBins::~DirectionalBins() 29 | { 30 | for(size_t index = 0; index < 6; ++index) 31 | { 32 | m_bin[index].outfile.close(); 33 | boost::filesystem::remove(m_bin[index].path); 34 | } 35 | } 36 | 37 | void DirectionalBins::add(const int _size, const int _cardinal, RayCompressed* _data, tbb::concurrent_queue< BatchItem >* _batch_queue) 38 | { 39 | m_bin[_cardinal].mutex.lock(); 40 | 41 | size_t file_size = pow(2, m_exponent); 42 | 43 | if(m_bin[_cardinal].size + _size > file_size) 44 | { 45 | std::cout << pow(2, m_exponent) << ", " << m_bin[_cardinal].size << std::endl; 46 | m_bin[_cardinal].outfile.close(); 47 | 48 | BatchItem batch; 49 | batch.filename = m_bin[_cardinal].path; 50 | batch.size = m_bin[_cardinal].size; 51 | _batch_queue->push(batch); 52 | 53 | m_bin[_cardinal].size = 0; 54 | 55 | std::string file_location = boost::filesystem::temp_directory_path().string(); 56 | std::string file_name = boost::filesystem::unique_path().string(); 57 | m_bin[_cardinal].path = file_location + file_name; 58 | 59 | boost::iostreams::mapped_file_params params; 60 | params.path = m_bin[_cardinal].path; 61 | params.new_file_size = file_size * sizeof(RayCompressed); 62 | params.mode = std::ios_base::out; 63 | 64 | m_bin[_cardinal].outfile.open(params); 65 | m_bin[_cardinal].pointer = (RayCompressed*)(m_bin[_cardinal].outfile.data()); 66 | m_bin[_cardinal].end = m_bin[_cardinal].pointer + file_size; 67 | } 68 | 69 | m_bin[_cardinal].pointer = std::copy(_data, _data + _size, m_bin[_cardinal].pointer); 70 | m_bin[_cardinal].size = m_bin[_cardinal].size + _size; 71 | 72 | m_bin[_cardinal].mutex.unlock(); 73 | } 74 | 75 | void DirectionalBins::flush(tbb::concurrent_queue< BatchItem >* _batch_queue) 76 | { 77 | size_t bin_size = 0; 78 | size_t bin_index = 0; 79 | for(size_t index = 0; index < 6; ++index) 80 | { 81 | if(m_bin[index].size > bin_size) 82 | { 83 | bin_size = m_bin[index].size; 84 | bin_index = index; 85 | } 86 | } 87 | 88 | if(m_bin[bin_index].size > 0) 89 | { 90 | std::cout << pow(2, m_exponent) << ", " << m_bin[bin_index].size << std::endl; 91 | m_bin[bin_index].outfile.close(); 92 | 93 | BatchItem batch; 94 | batch.filename = m_bin[bin_index].path; 95 | batch.size = m_bin[bin_index].size; 96 | _batch_queue->push(batch); 97 | 98 | m_bin[bin_index].size = 0; 99 | 100 | std::string file_location = boost::filesystem::temp_directory_path().string(); 101 | std::string file_name = boost::filesystem::unique_path().string(); 102 | m_bin[bin_index].path = file_location + file_name; 103 | 104 | size_t file_size = pow(2, m_exponent); 105 | 106 | boost::iostreams::mapped_file_params params; 107 | params.path = m_bin[bin_index].path; 108 | params.new_file_size = file_size * sizeof(RayCompressed); 109 | params.mode = std::ios_base::out; 110 | 111 | m_bin[bin_index].outfile.open(params); 112 | m_bin[bin_index].pointer = (RayCompressed*)(m_bin[bin_index].outfile.data()); 113 | m_bin[bin_index].end = m_bin[bin_index].pointer + file_size; 114 | } 115 | } 116 | 117 | MSC_NAMESPACE_END -------------------------------------------------------------------------------- /src/core/RaySort.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | MSC_NAMESPACE_BEGIN 6 | 7 | void RaySort::operator()() const 8 | { 9 | size_t size = (m_end - m_begin); 10 | 11 | if(size > 4096) 12 | { 13 | int temp = ((m_limits.max[0] - m_limits.min[0]) < (m_limits.max[1] - m_limits.min[1])) ? 1 : 0; 14 | int axis = (temp < (m_limits.max[2] - m_limits.min[2])) ? 2 : temp; 15 | 16 | tbb::parallel_sort(&m_output[m_begin], &m_output[m_end], CompareOrg(axis)); 17 | 18 | size_t middle = m_begin + (size / 2); 19 | size_t lsize = (middle - m_begin); 20 | size_t rsize = (m_end - middle); 21 | 22 | BoundingBox3f llimits; 23 | BoundingBox3f rlimits; 24 | 25 | if(lsize > 4096) 26 | { 27 | llimits = m_limits; 28 | llimits.max[axis] = m_output[middle - 1].org[axis]; 29 | } 30 | else 31 | { 32 | llimits.min[0] = m_output[m_begin].dir[0]; 33 | llimits.min[1] = m_output[m_begin].dir[1]; 34 | llimits.min[2] = m_output[m_begin].dir[2]; 35 | llimits.max[0] = m_output[m_begin].dir[0]; 36 | llimits.max[1] = m_output[m_begin].dir[1]; 37 | llimits.max[2] = m_output[m_begin].dir[2]; 38 | 39 | for(size_t index = m_begin; index < middle; ++index) 40 | { 41 | if(m_output[index].dir[0] < llimits.min[0]) 42 | llimits.min[0] = m_output[index].dir[0]; 43 | if(m_output[index].dir[1] < llimits.min[1]) 44 | llimits.min[1] = m_output[index].dir[1]; 45 | if(m_output[index].dir[2] < llimits.min[2]) 46 | llimits.min[2] = m_output[index].dir[2]; 47 | 48 | if(m_output[index].dir[0] > llimits.max[0]) 49 | llimits.max[0] = m_output[index].dir[0]; 50 | if(m_output[index].dir[1] > llimits.max[1]) 51 | llimits.max[1] = m_output[index].dir[1]; 52 | if(m_output[index].dir[2] > llimits.max[2]) 53 | llimits.max[2] = m_output[index].dir[2]; 54 | } 55 | } 56 | 57 | if(rsize > 4096) 58 | { 59 | rlimits = m_limits; 60 | rlimits.min[axis] = m_output[middle].org[axis]; 61 | } 62 | else 63 | { 64 | rlimits.min[0] = m_output[middle].dir[0]; 65 | rlimits.min[1] = m_output[middle].dir[1]; 66 | rlimits.min[2] = m_output[middle].dir[2]; 67 | rlimits.max[0] = m_output[middle].dir[0]; 68 | rlimits.max[1] = m_output[middle].dir[1]; 69 | rlimits.max[2] = m_output[middle].dir[2]; 70 | 71 | for(size_t index = middle; index < m_end; ++index) 72 | { 73 | if(m_output[index].dir[0] < rlimits.min[0]) 74 | rlimits.min[0] = m_output[index].dir[0]; 75 | if(m_output[index].dir[1] < rlimits.min[1]) 76 | rlimits.min[1] = m_output[index].dir[1]; 77 | if(m_output[index].dir[2] < rlimits.min[2]) 78 | rlimits.min[2] = m_output[index].dir[2]; 79 | 80 | if(m_output[index].dir[0] > rlimits.max[0]) 81 | rlimits.max[0] = m_output[index].dir[0]; 82 | if(m_output[index].dir[1] > rlimits.max[1]) 83 | rlimits.max[1] = m_output[index].dir[1]; 84 | if(m_output[index].dir[2] > rlimits.max[2]) 85 | rlimits.max[2] = m_output[index].dir[2]; 86 | } 87 | } 88 | 89 | RaySort lrange = RaySort(m_begin, middle, llimits, m_output); 90 | RaySort rrange = RaySort(middle, m_end, rlimits, m_output); 91 | 92 | tbb::parallel_invoke(lrange, rrange); 93 | } 94 | else if(size > 64) 95 | { 96 | int temp = ((m_limits.max[0] - m_limits.min[0]) < (m_limits.max[1] - m_limits.min[1])) ? 1 : 0; 97 | int axis = (temp < (m_limits.max[2] - m_limits.min[2])) ? 2 : temp; 98 | 99 | tbb::parallel_sort(&m_output[m_begin], &m_output[m_end], CompareDir(axis)); 100 | 101 | size_t middle = m_begin + (size / 2); 102 | size_t lsize = (middle - m_begin); 103 | size_t rsize = (m_end - middle); 104 | 105 | BoundingBox3f llimits; 106 | BoundingBox3f rlimits; 107 | 108 | llimits = m_limits; 109 | llimits.max[axis] = m_output[middle - 1].dir[axis]; 110 | rlimits = m_limits; 111 | llimits.min[axis] = m_output[middle].dir[axis]; 112 | 113 | RaySort lrange = RaySort(m_begin, middle, llimits, m_output); 114 | RaySort rrange = RaySort(middle, m_end, rlimits, m_output); 115 | 116 | tbb::parallel_invoke(lrange, rrange); 117 | } 118 | } 119 | 120 | MSC_NAMESPACE_END -------------------------------------------------------------------------------- /include/core/ThinLensCamera.h: -------------------------------------------------------------------------------- 1 | #ifndef _THINLENSCAMERA_H_ 2 | #define _THINLENSCAMERA_H_ 3 | 4 | #include 5 | #include 6 | 7 | MSC_NAMESPACE_BEGIN 8 | 9 | /** 10 | * @brief Inherits from the camera interface and represents a lens based camera 11 | * 12 | * This camera creates a perspective while integrating across the area of an aperture and using a 13 | * lens to converge ray direction upon a focal plane. The sample method takes a range of samples 14 | * from a single pixel to improve performance. 15 | */ 16 | class ThinLensCamera : public CameraInterface 17 | { 18 | public: 19 | /** 20 | * @brief Initialiser list for class 21 | */ 22 | ThinLensCamera() 23 | : m_translation(Vector3f(0.f, 0.f, 0.f)) 24 | , m_rotation(Vector3f(0.f, 0.f, 0.f)) 25 | , m_focal_length(55.f) 26 | , m_aperture(5.6f) 27 | , m_focal_distance(1000.f) 28 | {;} 29 | 30 | /** 31 | * @brief Getter method for translation 32 | * 33 | * @return translation vector 34 | */ 35 | inline Vector3f translation() const {return m_translation;} 36 | 37 | /** 38 | * @brief Getter method for rotation 39 | * 40 | * @return euler angle vector 41 | */ 42 | inline Vector3f rotation() const {return m_rotation;} 43 | 44 | /** 45 | * @brief Getter method for focal length 46 | * 47 | * @return focal length 48 | */ 49 | inline float focalLength() const {return m_focal_length;} 50 | 51 | /** 52 | * @brief Getter method for lens aperture 53 | * 54 | * @return aperture 55 | */ 56 | inline float aperture() const {return m_aperture;} 57 | 58 | /** 59 | * @brief Getter method for focal distance 60 | * 61 | * @return focal distance 62 | */ 63 | inline float focalDistance() const {return m_focal_distance;} 64 | 65 | /** 66 | * @brief Setter method for translation 67 | * 68 | * @param[in] _translation translation vector 69 | */ 70 | void translation(const Vector3f &_translation){m_translation = _translation;} 71 | 72 | /** 73 | * @brief Setter method for rotation 74 | * 75 | * @param[in] _translation euler angle vector 76 | */ 77 | void rotation(const Vector3f &_rotation){m_rotation = _rotation;} 78 | 79 | /** 80 | * @brief Setter method for focal length 81 | * 82 | * @param[in] _translation focal length 83 | */ 84 | void focalLength(const float _focal_length){m_focal_length = _focal_length;} 85 | 86 | /** 87 | * @brief Setter method for lens aperture 88 | * 89 | * @param[in] _translation aperture 90 | */ 91 | void aperture(const float _aperture){m_aperture = _aperture;} 92 | 93 | /** 94 | * @brief Setter method for focal distance 95 | * 96 | * @param[in] _translation focal distance 97 | */ 98 | void focalDistance(const float _focal_distance){m_focal_distance = _focal_distance;} 99 | 100 | /** 101 | * @brief Precomputes transform 102 | */ 103 | void construct(); 104 | 105 | /** 106 | * @brief Creates primary rays from camera 107 | * 108 | * @param[in] _count sample count to process 109 | * @param _positions positions on film plane of samples 110 | * @param _random thread local random generator to prevent mutation 111 | * @param _ouput output of compressed rays 112 | */ 113 | void sample(const int _count, float* _positions, RandomGenerator* _random, RayCompressed* _ouput) const; 114 | 115 | private: 116 | Vector3f m_translation; 117 | Vector3f m_rotation; 118 | float m_focal_length; 119 | float m_aperture; 120 | float m_focal_distance; 121 | 122 | Affine3f m_transform; 123 | Vector3f m_normal; 124 | 125 | Vector2f rejectionSampling(RandomGenerator* _random) const; 126 | }; 127 | 128 | MSC_NAMESPACE_END 129 | 130 | YAML_NAMESPACE_BEGIN 131 | 132 | template<> struct convert 133 | { 134 | static bool decode(const Node& node, msc::ThinLensCamera& rhs) 135 | { 136 | if(!node.IsMap() || node.size() != 6) 137 | return false; 138 | 139 | rhs.translation(node["translation"].as()); 140 | rhs.rotation(node["rotation"].as()); 141 | rhs.focalLength(node["focal length"].as()); 142 | rhs.focalDistance(node["focal distance"].as()); 143 | rhs.aperture(node["aperture"].as()); 144 | 145 | rhs.construct(); 146 | 147 | return true; 148 | } 149 | }; 150 | 151 | YAML_NAMESPACE_END 152 | 153 | #endif 154 | -------------------------------------------------------------------------------- /cmake/FindPTex.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2013 Pixar 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "Apache License") 5 | # with the following modification; you may not use this file except in 6 | # compliance with the Apache License and the following modification to it: 7 | # Section 6. Trademarks. is deleted and replaced with: 8 | # 9 | # 6. Trademarks. This License does not grant permission to use the trade 10 | # names, trademarks, service marks, or product names of the Licensor 11 | # and its affiliates, except as required to comply with Section 4(c) of 12 | # the License and to reproduce the content of the NOTICE file. 13 | # 14 | # You may obtain a copy of the Apache License at 15 | # 16 | # http://www.apache.org/licenses/LICENSE-2.0 17 | # 18 | # Unless required by applicable law or agreed to in writing, software 19 | # distributed under the Apache License with the above modification is 20 | # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 21 | # KIND, either express or implied. See the Apache License for the specific 22 | # language governing permissions and limitations under the Apache License. 23 | # 24 | 25 | # Try to find PTex library and include path. 26 | # Once done this will define 27 | # 28 | # PTEX_FOUND 29 | # PTEX_INCLUDE_DIR 30 | # PTEX_LIBRARY 31 | # 32 | 33 | if (WIN32) 34 | find_path( PTEX_INCLUDE_DIR 35 | NAMES 36 | Ptexture.h 37 | HINTS 38 | "${PTEX_LOCATION}/include" 39 | "$ENV{PTEX_LOCATION}/include" 40 | PATHS 41 | "$ENV{PROGRAMFILES}/Ptex/include" 42 | /usr/include 43 | DOC "The directory where Ptexture.h resides") 44 | find_library( PTEX_LIBRARY 45 | NAMES 46 | Ptex32 Ptex32s Ptex 47 | HINTS 48 | "${PTEX_LOCATION}/lib" 49 | "$ENV{PTEX_LOCATION}/lib" 50 | PATHS 51 | "$ENV{PROGRAMFILES}/Ptex/lib" 52 | /usr/lib 53 | /usr/lib/w32api 54 | /usr/local/lib 55 | /usr/X11R6/lib 56 | DOC "The Ptex library") 57 | elseif (APPLE) 58 | find_path( PTEX_INCLUDE_DIR 59 | NAMES 60 | Ptexture.h 61 | HINTS 62 | "${PTEX_LOCATION}/include" 63 | "$ENV{PTEX_LOCATION}/include" 64 | PATHS 65 | DOC "The directory where Ptexture.h resides") 66 | find_library( PTEX_LIBRARY 67 | NAMES 68 | Ptex libPtex.a 69 | PATHS 70 | "${PTEX_LOCATION}/lib" 71 | "$ENV{PTEX_LOCATION}/lib" 72 | DOC "The Ptex Library") 73 | else () 74 | find_path( PTEX_INCLUDE_DIR 75 | NAMES 76 | Ptexture.h 77 | HINTS 78 | "${PTEX_LOCATION}/include" 79 | "${PTEX_LOCATION}/include/wdas" 80 | "$ENV{PTEX_LOCATION}/include" 81 | "$ENV{PTEX_LOCATION}/include/wdas" 82 | PATHS 83 | /usr/include 84 | /usr/local/include 85 | /usr/openwin/share/include 86 | /usr/openwin/include 87 | /usr/X11R6/include 88 | /usr/include/X11 89 | DOC "The directory where Ptexture.h resides") 90 | find_library( PTEX_LIBRARY 91 | NAMES 92 | Ptex wdasPtex 93 | HINTS 94 | "${PTEX_LOCATION}/lib" 95 | "$ENV{PTEX_LOCATION}/lib" 96 | PATHS 97 | /usr/lib 98 | /usr/local/lib 99 | /usr/openwin/lib 100 | /usr/X11R6/lib 101 | DOC "The Ptex library") 102 | endif () 103 | 104 | if (PTEX_INCLUDE_DIR AND EXISTS "${PTEX_INCLUDE_DIR}/Ptexture.h" ) 105 | 106 | file(STRINGS "${PTEX_INCLUDE_DIR}/Ptexture.h" TMP REGEX "^#define PtexAPIVersion.*$") 107 | string(REGEX MATCHALL "[0-9]+" API ${TMP}) 108 | 109 | file(STRINGS "${PTEX_INCLUDE_DIR}/Ptexture.h" TMP REGEX "^#define PtexFileMajorVersion.*$") 110 | string(REGEX MATCHALL "[0-9]+" MAJOR ${TMP}) 111 | 112 | file(STRINGS "${PTEX_INCLUDE_DIR}/Ptexture.h" TMP REGEX "^#define PtexFileMinorVersion.*$") 113 | string(REGEX MATCHALL "[0-9]+" MINOR ${TMP}) 114 | 115 | set(PTEX_VERSION ${API}.${MAJOR}.${MINOR}) 116 | 117 | endif() 118 | 119 | include(FindPackageHandleStandardArgs) 120 | 121 | find_package_handle_standard_args(PTex 122 | REQUIRED_VARS 123 | PTEX_INCLUDE_DIR 124 | PTEX_LIBRARY 125 | VERSION_VAR 126 | PTEX_VERSION 127 | ) 128 | 129 | mark_as_advanced( 130 | PTEX_INCLUDE_DIR 131 | PTEX_LIBRARY 132 | ) 133 | 134 | -------------------------------------------------------------------------------- /include/core/QuadLight.h: -------------------------------------------------------------------------------- 1 | #ifndef _QUADLIGHT_H_ 2 | #define _QUADLIGHT_H_ 3 | 4 | #include 5 | #include 6 | 7 | MSC_NAMESPACE_BEGIN 8 | 9 | /** 10 | * @brief Inherits from the light interface and represents a quad light surface 11 | * 12 | * This represent a physically based quad light that can evaluate a point in space 13 | * as well as sample it's surface and return the probaility density in respect to area. 14 | */ 15 | class QuadLight : public LightInterface 16 | { 17 | public: 18 | /** 19 | * @brief Initialiser list for class 20 | */ 21 | QuadLight() 22 | : m_translation(Vector3f(0.f, 0.f, 0.f)) 23 | , m_rotation(Vector3f(0.f, 0.f, 0.f)) 24 | , m_scale(Vector2f(1.f, 1.f)) 25 | , m_intensity(100.f) 26 | {;} 27 | 28 | /** 29 | * @brief Getter method for translation 30 | * 31 | * @return translation vector 32 | */ 33 | inline Vector3f translation() const {return m_translation;} 34 | 35 | /** 36 | * @brief Getter method for rotation 37 | * 38 | * @return euler angle vector 39 | */ 40 | inline Vector3f rotation() const {return m_rotation;} 41 | 42 | /** 43 | * @brief Getter method for scale 44 | * 45 | * @return scale vector 46 | */ 47 | inline Vector2f scale() const {return m_scale;} 48 | 49 | /** 50 | * @brief Getter method for light intensity 51 | * 52 | * @return intensity 53 | */ 54 | inline float intensity() const {return m_intensity;} 55 | 56 | /** 57 | * @brief Get reference to geometry positions 58 | * 59 | * @return positions reference 60 | */ 61 | inline std::vector& positions() {return m_positions;} 62 | 63 | /** 64 | * @brief Get reference to geometry indices 65 | * 66 | * @return indices reference 67 | */ 68 | inline std::vector& indices() {return m_indices;} 69 | 70 | /** 71 | * @brief Setter method for translation 72 | * 73 | * @param[in] _translation translation vector 74 | */ 75 | void translation(const Vector3f &_translation){m_translation = _translation;} 76 | 77 | /** 78 | * @brief Setter method for rotation 79 | * 80 | * @param[in] _translation euler angle vector 81 | */ 82 | void rotation(const Vector3f &_rotation){m_rotation = _rotation;} 83 | 84 | /** 85 | * @brief Setter method for scale 86 | * 87 | * @param[in] _translation scale vector 88 | */ 89 | void scale(const Vector2f &_scale){m_scale = _scale;} 90 | 91 | /** 92 | * @brief Setter method for light intensity 93 | * 94 | * @param[in] _translation intensity 95 | */ 96 | void intensity(const float _intensity){m_intensity = _intensity;} 97 | 98 | /** 99 | * @brief Precomputes transform and geometry information 100 | */ 101 | void construct(); 102 | 103 | /** 104 | * @brief Illumination of mulitple positions on a geometric surface 105 | * 106 | * @param _random thread local random generator to prevent mutation 107 | * @param _position position data 108 | * @param _direction input directions generated by light for surface evaluation 109 | * @param _distance distance between light sample and surface position 110 | * @param _radiance radiance values for surface postions 111 | * @param _direct_pdfw probabilty in respect to solid angle 112 | */ 113 | void illuminate( 114 | RandomGenerator* _random, 115 | const Vector3f& _position, 116 | Vector3f* _direction, 117 | float* _distance, 118 | Colour3f* _radiance, 119 | float* _direct_pdfw = NULL 120 | ) const; 121 | 122 | /** 123 | * @brief Radiance on light in direction towards surface 124 | * 125 | * @param[in] _direction input direction to be evaluated 126 | * @param _radiance radiance value 127 | * @param _direct_pdfa probability in respect to surface area 128 | */ 129 | void radiance( 130 | const Vector3f& _direction, 131 | Colour3f* _radiance, 132 | float* _cos_theta, 133 | float* _direct_pdfa = NULL 134 | ) const; 135 | 136 | private: 137 | Vector3f m_translation; 138 | Vector3f m_rotation; 139 | Vector2f m_scale; 140 | float m_intensity; 141 | 142 | Affine3f m_transform; 143 | Vector3f m_normal; 144 | 145 | std::vector< float > m_positions; 146 | std::vector< unsigned int > m_indices; 147 | }; 148 | 149 | MSC_NAMESPACE_END 150 | 151 | YAML_NAMESPACE_BEGIN 152 | 153 | template<> struct convert 154 | { 155 | static bool decode(const Node& node, msc::QuadLight& rhs) 156 | { 157 | if(!node.IsMap() || node.size() != 5) 158 | return false; 159 | 160 | rhs.translation(node["translation"].as()); 161 | rhs.rotation(node["rotation"].as()); 162 | rhs.scale(node["scale"].as()); 163 | rhs.intensity(node["intensity"].as()); 164 | 165 | rhs.construct(); 166 | 167 | return true; 168 | } 169 | }; 170 | 171 | YAML_NAMESPACE_END 172 | 173 | #endif 174 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | CMAKE_MINIMUM_REQUIRED( VERSION 2.8 ) 2 | PROJECT( "msc-project" ) 3 | 4 | set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_SOURCE_DIR}/cmake $ENV{CMAKE_MODULE_PATH}) 5 | 6 | SET( FLAGS ) 7 | SET( TYPE RelWithDebInfo ) 8 | 9 | SET( SRC src ) 10 | SET( INC include ) 11 | SET( THR thirdparty ) 12 | 13 | SET( CORE_SOURCES 14 | ${SRC}/core/Pathtracer.cpp 15 | ${SRC}/core/RandomGenerator.cpp 16 | ${SRC}/core/DirectionalBins.cpp 17 | ${SRC}/core/ThinLensCamera.cpp 18 | ${SRC}/core/PinHoleCamera.cpp 19 | ${SRC}/core/QuadLight.cpp 20 | ${SRC}/core/TentFilter.cpp 21 | ${SRC}/core/BoxFilter.cpp 22 | ${SRC}/core/StratifiedSampler.cpp 23 | ${SRC}/core/IndependentSampler.cpp 24 | ${SRC}/core/GridSampler.cpp 25 | ${SRC}/core/Camera.cpp 26 | ${SRC}/core/Integrator.cpp 27 | ${SRC}/core/RaySort.cpp 28 | ${SRC}/core/RayIntersect.cpp 29 | ${SRC}/core/RayDecompress.cpp 30 | ${SRC}/core/RayBoundingbox.cpp 31 | ${SRC}/core/PolygonObject.cpp 32 | ${SRC}/core/LambertShader.cpp 33 | ${SRC}/core/NullShader.cpp 34 | ${SRC}/core/Convolve.cpp 35 | ${SRC}/core/ConstantTexture.cpp 36 | ${SRC}/core/LayeredTexture.cpp 37 | ${SRC}/core/StandardTexture.cpp 38 | ) 39 | 40 | SET( CORE_HEADERS 41 | ${INC}/core/Pathtracer.h 42 | ${INC}/core/Constants.h 43 | ${INC}/core/Common.h 44 | ${INC}/core/EmbreeWrapper.h 45 | ${INC}/core/OpenImageWrapper.h 46 | ${INC}/core/Settings.h 47 | ${INC}/core/Image.h 48 | ${INC}/core/Scene.h 49 | ${INC}/core/RandomGenerator.h 50 | ${INC}/core/Buffer.h 51 | ${INC}/core/DirectionalBins.h 52 | ${INC}/core/CameraInterface.h 53 | ${INC}/core/ThinLensCamera.h 54 | ${INC}/core/PinHoleCamera.h 55 | ${INC}/core/LightInterface.h 56 | ${INC}/core/QuadLight.h 57 | ${INC}/core/FilterInterface.h 58 | ${INC}/core/TentFilter.h 59 | ${INC}/core/BoxFilter.h 60 | ${INC}/core/SamplerInterface.h 61 | ${INC}/core/StratifiedSampler.h 62 | ${INC}/core/IndependentSampler.h 63 | ${INC}/core/GridSampler.h 64 | ${INC}/core/Camera.h 65 | ${INC}/core/Integrator.h 66 | ${INC}/core/RayCompressed.h 67 | ${INC}/core/RayUncompressed.h 68 | ${INC}/core/RaySort.h 69 | ${INC}/core/RayIntersect.h 70 | ${INC}/core/RayDecompress.h 71 | ${INC}/core/RayBoundingbox.h 72 | ${INC}/core/ObjectInterface.h 73 | ${INC}/core/PolygonObject.h 74 | ${INC}/core/ShaderInterface.h 75 | ${INC}/core/NullShader.h 76 | ${INC}/core/LambertShader.h 77 | ${INC}/core/BatchItem.h 78 | ${INC}/core/Convolve.h 79 | ${INC}/core/Singleton.h 80 | ${INC}/core/TextureInterface.h 81 | ${INC}/core/ConstantTexture.h 82 | ${INC}/core/LayeredTexture.h 83 | ${INC}/core/StandardTexture.h 84 | ) 85 | 86 | SET( FRM_SOURCES 87 | ${SRC}/framebuffer/Framebuffer.cpp 88 | ) 89 | 90 | SET( FRM_HEADERS 91 | ${INC}/framebuffer/PlatformSpecification.h 92 | ${INC}/framebuffer/Framebuffer.h 93 | ) 94 | 95 | SET( THIRD_PARTY 96 | ${THR}/tinyobjloader/tiny_obj_loader.cpp 97 | ${THR}/tinyobjloader/tiny_obj_loader.h 98 | ) 99 | 100 | SET( CMAKE_CXX_FLAGS ${FLAGS} ) 101 | SET( CMAKE_BUILD_TYPE ${TYPE} ) 102 | 103 | ADD_EXECUTABLE( ${CMAKE_PROJECT_NAME} 104 | ${SRC}/main.cpp 105 | ) 106 | 107 | ADD_LIBRARY( pathtracer 108 | ${CORE_SOURCES} 109 | ${CORE_HEADERS} 110 | ${THIRD_PARTY} 111 | ) 112 | 113 | ADD_LIBRARY( framebuffer 114 | ${FRM_SOURCES} 115 | ${FRM_HEADERS} 116 | ) 117 | 118 | FIND_PACKAGE( Boost COMPONENTS 119 | system 120 | filesystem 121 | program_options 122 | unit_test_framework 123 | iostreams 124 | thread 125 | chrono 126 | python 127 | atomic 128 | random 129 | REQUIRED ) 130 | FIND_PACKAGE( TBB REQUIRED ) 131 | FIND_PACKAGE( Embree REQUIRED ) 132 | FIND_PACKAGE( Eigen3 REQUIRED ) 133 | FIND_PACKAGE( OpenGL REQUIRED ) 134 | FIND_PACKAGE( GLFW REQUIRED ) 135 | FIND_PACKAGE( YamlCpp REQUIRED ) 136 | FIND_PACKAGE( OpenEXR REQUIRED ) 137 | FIND_PACKAGE( OpenColorIO REQUIRED ) 138 | FIND_PACKAGE( OpenImageIO REQUIRED ) 139 | FIND_PACKAGE( PythonLibs REQUIRED ) 140 | 141 | IF( ${CMAKE_SYSTEM_NAME} MATCHES "Windows" OR ${CMAKE_SYSTEM_NAME} MATCHES "Linux" ) 142 | 143 | FIND_PACKAGE( GLEW REQUIRED ) 144 | 145 | INCLUDE_DIRECTORIES( ${GLEW_INCLUDE_DIR} ) 146 | TARGET_LINK_LIBRARIES( framebuffer ${GLEW_LIBRARY} ) 147 | 148 | ENDIF() 149 | 150 | INCLUDE_DIRECTORIES( 151 | ${INC} 152 | ${THR} 153 | ${Boost_INCLUDE_DIRS} 154 | ${TBB_INCLUDE_DIRS} 155 | ${EMBREE_INCLUDE_DIRS} 156 | ${EIGEN3_INCLUDE_DIR} 157 | ${GLFW_INCLUDE_DIR} 158 | ${YAMLCPP_INCLUDE_DIR} 159 | ${OPENEXR_INCLUDE_PATHS} 160 | ${OCIO_INCLUDES} 161 | ${OIIO_INCLUDES} 162 | ${PYTHON_INCLUDE_DIRS} 163 | ) 164 | 165 | TARGET_LINK_LIBRARIES( ${CMAKE_PROJECT_NAME} 166 | ${Boost_LIBRARIES} 167 | pathtracer 168 | framebuffer 169 | ) 170 | 171 | TARGET_LINK_LIBRARIES( pathtracer 172 | ${Boost_LIBRARIES} 173 | ${TBB_LIBRARIES} 174 | ${EMBREE_LIBRARIES} 175 | ${YAMLCPP_LIBRARY} 176 | ${OPENEXR_LIBRARIES} 177 | ${OCIO_LIBRARIES} 178 | ${OIIO_LIBRARIES} 179 | ${PYTHON_LIBRARIES} 180 | ) 181 | 182 | TARGET_LINK_LIBRARIES( framebuffer 183 | ${GLFW_LIBRARIES} 184 | ${OPENGL_LIBRARIES} 185 | ) 186 | 187 | INSTALL( 188 | TARGETS ${CMAKE_PROJECT_NAME} pathtracer 189 | RUNTIME DESTINATION bin 190 | ARCHIVE DESTINATION lib 191 | ) 192 | 193 | INSTALL( 194 | FILES ${CORE_HEADERS} 195 | PUBLIC_HEADER DESTINATION include/pathtracer 196 | ) 197 | 198 | ENABLE_TESTING() -------------------------------------------------------------------------------- /include/core/PolygonObject.h: -------------------------------------------------------------------------------- 1 | #ifndef _POLYGONOBJECT_H_ 2 | #define _POLYGONOBJECT_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | MSC_NAMESPACE_BEGIN 15 | 16 | /** 17 | * @brief Inherits from the object interface and represents polygon geometry 18 | * 19 | * This is polygon geometric type and store local geometry data such as positions, normals, texture 20 | * coordinates and face indices. It also allows access to this data based upon a primitive 21 | * identification number and some barycentric coordinates. 22 | */ 23 | class PolygonObject : public ObjectInterface 24 | { 25 | public: 26 | /** 27 | * @brief Initialiser list for class 28 | */ 29 | PolygonObject() 30 | : m_translation(Vector3f(0.f, 0.f, 0.f)) 31 | , m_rotation(Vector3f(0.f, 0.f, 0.f)) 32 | , m_scale(Vector3f(1.f, 1.f, 1.f)) 33 | {;} 34 | 35 | /** 36 | * @brief Getter method for filename 37 | * 38 | * @return filename string 39 | */ 40 | inline std::string filename() const {return m_filename;} 41 | 42 | /** 43 | * @brief Getter method for translation 44 | * 45 | * @return translation vector 46 | */ 47 | inline Vector3f translation() const {return m_translation;} 48 | 49 | /** 50 | * @brief Getter method for rotation 51 | * 52 | * @return euler angle vector 53 | */ 54 | inline Vector3f rotation() const {return m_rotation;} 55 | 56 | /** 57 | * @brief Getter method for scale 58 | * 59 | * @return scale vector 60 | */ 61 | inline Vector3f scale() const {return m_scale;} 62 | 63 | /** 64 | * @brief Getter method for shader id 65 | * 66 | * @return shader id 67 | */ 68 | inline int shader() const {return m_shader;} 69 | 70 | /** 71 | * @brief Get reference to geometry positions 72 | * 73 | * @return positions reference 74 | */ 75 | inline std::vector& positions() {return m_positions;} 76 | 77 | /** 78 | * @brief Get reference to geometry indices 79 | * 80 | * @return indices reference 81 | */ 82 | inline std::vector& indices() {return m_indices;} 83 | 84 | /** 85 | * @brief Setter method for filename 86 | * 87 | * @param[in] _filename filename string 88 | */ 89 | void filename(const std::string &_filename){m_filename = _filename;} 90 | 91 | /** 92 | * @brief Setter method for translation 93 | * 94 | * @param[in] _translation translation vector 95 | */ 96 | void translation(const Vector3f &_translation){m_translation = _translation;} 97 | 98 | /** 99 | * @brief Setter method for rotation 100 | * 101 | * @param[in] _rotation euler angle vector 102 | */ 103 | void rotation(const Vector3f &_rotation){m_rotation = _rotation;} 104 | 105 | /** 106 | * @brief Setter method for scale 107 | * 108 | * @param[in] _scale scale vector 109 | */ 110 | void scale(const Vector3f &_scale){m_scale = _scale;} 111 | 112 | /** 113 | * @brief Setter method for shader id 114 | * 115 | * @param[in] _shader shader id 116 | */ 117 | void shader(const int &_shader){m_shader = _shader;} 118 | 119 | /** 120 | * @brief Precomputes transform and geometry information 121 | */ 122 | void construct(); 123 | 124 | /** 125 | * @brief Gets u and v texture coordinates 126 | * 127 | * @param[in] _primitive primitive index value 128 | * @param[in] _s s coordinate 129 | * @param[in] _t t coordinate 130 | * @param _output output uv coordinates 131 | */ 132 | void texture( 133 | const size_t _primitive, 134 | const float _s, 135 | const float _t, 136 | Vector2f* _output 137 | ) const; 138 | 139 | /** 140 | * @brief Gets normal direction 141 | * 142 | * @param[in] _primitive primitive index value 143 | * @param[in] _s s coordinate 144 | * @param[in] _t t coordinate 145 | * @param _output output uv coordinates 146 | */ 147 | void normal( 148 | const size_t _primitive, 149 | const float _s, 150 | const float _t, 151 | Vector3f* _output 152 | ) const; 153 | 154 | private: 155 | std::string m_filename; 156 | Vector3f m_translation; 157 | Vector3f m_rotation; 158 | Vector3f m_scale; 159 | int m_shader; 160 | 161 | std::vector< float > m_positions; 162 | std::vector< float > m_normals; 163 | std::vector< float > m_texcoords; 164 | std::vector< unsigned int > m_indices; 165 | }; 166 | 167 | MSC_NAMESPACE_END 168 | 169 | YAML_NAMESPACE_BEGIN 170 | 171 | template<> struct convert 172 | { 173 | static bool decode(const Node& node, msc::PolygonObject& rhs) 174 | { 175 | if(!node.IsMap() || node.size() != 6) 176 | return false; 177 | 178 | msc::SingletonString& scene_root = msc::SingletonString::instance(); 179 | rhs.filename(scene_root.getData().append("/").append(node["filename"].as())); 180 | rhs.translation(node["translation"].as()); 181 | rhs.rotation(node["rotation"].as()); 182 | rhs.scale(node["scale"].as()); 183 | rhs.shader(node["shader"].as()); 184 | 185 | rhs.construct(); 186 | 187 | return true; 188 | } 189 | }; 190 | 191 | YAML_NAMESPACE_END 192 | 193 | #endif 194 | -------------------------------------------------------------------------------- /include/core/Integrator.h: -------------------------------------------------------------------------------- 1 | #ifndef _INTEGRATOR_H_ 2 | #define _INTEGRATOR_H_ 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | MSC_NAMESPACE_BEGIN 19 | 20 | /** 21 | * @brief A range template that describes a one dimensional range containing an equal comparison 22 | * 23 | * @tparam type Type of data in range that must be comparable 24 | * 25 | * This is a tbb range template to allow for a parallel algorithm to divide it's tasks into groups 26 | * based upon a distinct and comparable property. It will also divide a continuous range into 27 | * smaller ranges if they exceed a given grain size. The range should already be sorted according 28 | * to its comparable property before being processed as this will increase performance. 29 | */ 30 | template < typename type > class RangeGeom { 31 | public: 32 | /** 33 | * @brief Initialiser list for template 34 | */ 35 | RangeGeom(size_t _begin, size_t _end, size_t _grainsize, type _array) 36 | : m_begin(_begin) 37 | , m_end(_end) 38 | , m_grainsize(_grainsize) 39 | , m_array(_array) 40 | {;} 41 | 42 | /** 43 | * @brief Splitting function to allow construction of equal value ranges with tbb 44 | * 45 | * @param r previously constructed range 46 | * @param[in] required to adhere to tbb's specification 47 | */ 48 | RangeGeom(RangeGeom &r, tbb::split) 49 | { 50 | m_array = r.m_array; 51 | m_grainsize = r.m_grainsize; 52 | m_end = r.m_end; 53 | 54 | size_t division = r.m_begin; 55 | for(size_t index = r.m_begin; index < r.m_end; ++index) 56 | { 57 | if(m_array[r.m_begin] != m_array[index]) 58 | { 59 | division = index; 60 | break; 61 | } 62 | else if((index - r.m_begin) == m_grainsize) 63 | { 64 | division = index; 65 | break; 66 | } 67 | } 68 | 69 | m_begin = division; 70 | r.m_end = division; 71 | } 72 | 73 | /** 74 | * @brief Check if range is empty 75 | * 76 | * @return boolean value 77 | */ 78 | bool empty() const {return m_begin == m_end;} 79 | 80 | /** 81 | * @brief Is range currently divisible into sub-ranges 82 | * 83 | * @return boolean value 84 | */ 85 | bool is_divisible() const 86 | { 87 | return (m_array[m_begin] != m_array[m_end - 1]) || ((m_end - m_begin) > m_grainsize); 88 | } 89 | 90 | /** 91 | * @brief Getter method for first index of range 92 | * 93 | * @return first index 94 | */ 95 | size_t begin() const {return m_begin;} 96 | 97 | /** 98 | * @brief Getter method for first index in range 99 | * 100 | * @return last index 101 | */ 102 | size_t end() const {return m_end;} 103 | 104 | static const bool is_splittable_in_proportion = false; 105 | 106 | public: 107 | size_t m_begin; 108 | size_t m_end; 109 | size_t m_grainsize; 110 | type m_array; 111 | }; 112 | 113 | /** 114 | * @brief Lighting integrator for surface intersections 115 | * 116 | * This class is a tbb functor that will integrate the rendering equation using a uni-directional 117 | * path tracing algorithm. It will optimise the process by using next event estimation as well as 118 | * multiple importance sampling of both the light and brdf strategies. Russian roulette is also used 119 | * for path termination within a defined range using a threshold. It is divided into five main 120 | * section that are: no intersection found, intersected light, texture caching/initialization, 121 | * next event estimation and continuation of random walk. This order of operation is influenced by 122 | * the design of the SmallVCM renderer. 123 | */ 124 | class Integrator 125 | { 126 | public: 127 | /** 128 | * @brief Initialiser list for class 129 | */ 130 | Integrator( 131 | Scene* _scene, 132 | Image* _image, 133 | Settings* _settings, 134 | DirectionalBins* _bins, 135 | tbb::concurrent_queue< BatchItem >* _batch_queue, 136 | LocalTextureSystem* _local_thread_storage_texture, 137 | LocalRandomGenerator* _local_thread_storage_random, 138 | RayUncompressed* _batch 139 | ) 140 | : m_scene(_scene) 141 | , m_image(_image) 142 | , m_settings(_settings) 143 | , m_bins(_bins) 144 | , m_batch_queue(_batch_queue) 145 | , m_local_thread_storage_texture(_local_thread_storage_texture) 146 | , m_local_thread_storage_random(_local_thread_storage_random) 147 | , m_batch(_batch) 148 | {;} 149 | 150 | /** 151 | * @brief Operator overloader to allow the class to act as a functor with tbb 152 | * 153 | * @param[in] r a constant range according to geometry id over found hit point 154 | */ 155 | void operator()(const RangeGeom< RayUncompressed* > &r) const; 156 | 157 | private: 158 | Scene* m_scene; 159 | Image* m_image; 160 | Settings* m_settings; 161 | 162 | DirectionalBins* m_bins; 163 | tbb::concurrent_queue< BatchItem >* m_batch_queue; 164 | LocalTextureSystem* m_local_thread_storage_texture; 165 | LocalRandomGenerator* m_local_thread_storage_random; 166 | 167 | RayUncompressed* m_batch; 168 | 169 | mutable Buffer m_buffer; 170 | }; 171 | 172 | MSC_NAMESPACE_END 173 | 174 | #endif -------------------------------------------------------------------------------- /include/core/LambertShader.h: -------------------------------------------------------------------------------- 1 | #ifndef _LAMBERTSHADER_H_ 2 | #define _LAMBERTSHADER_H_ 3 | 4 | #include 5 | 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | MSC_NAMESPACE_BEGIN 16 | 17 | /** 18 | * @brief Inherits from the shader interface and represents a lambertian surface 19 | * 20 | * This shader will evaluate a perfectly diffuse surface and importance sample the hemisphere 21 | * according to the cosine term in the rendering equation. This is required for multiple importance 22 | * sampling within the integrator. It also implements the clone and initialize methods so that 23 | * texture information can be cached with multiple shading points simultaneously. 24 | */ 25 | class LambertShader : public ShaderInterface 26 | { 27 | public: 28 | /** 29 | * @brief Initialiser list for class 30 | */ 31 | LambertShader() 32 | : m_reflectance(1.f) 33 | {;} 34 | 35 | /** 36 | * @brief Getter method for colour coefficient 37 | * 38 | * @return colour coefficient 39 | */ 40 | inline float reflectance() const {return m_reflectance;} 41 | 42 | /** 43 | * @brief Getter method for texture path 44 | * 45 | * @return texture path as string 46 | */ 47 | inline TextureInterface texture() const {return *m_texture;} 48 | 49 | /** 50 | * @brief Setter method for colour coefficient 51 | * 52 | * @param[in] _colour colour coefficient 53 | */ 54 | inline void reflectance(const float _reflectance){m_reflectance = _reflectance;} 55 | 56 | /** 57 | * @brief Setter method for texture path 58 | * 59 | * @param[in] _colour texture path as string 60 | */ 61 | inline void texture(TextureInterface* _texture){m_texture.reset(_texture);} 62 | 63 | /** 64 | * @brief Create polymorphic copy of derived class 65 | * 66 | * @return Is safe to have a covariant return type here 67 | */ 68 | ShaderInterface* clone(); 69 | 70 | /** 71 | * @brief Initialize colour values potentially as vectorized texture lookup 72 | */ 73 | void initialize( 74 | const size_t _size, 75 | std::vector< float >& _u, 76 | std::vector< float >& _v, 77 | TextureSystem _texture_system 78 | ); 79 | 80 | /** 81 | * @brief Get probabilty of bsdf reflectance for russian roulette 82 | * 83 | * @return reflectance probabilty 84 | */ 85 | float continuation() const; 86 | 87 | /** 88 | * @brief Evaluate shader for given input and output directions and differential data 89 | * 90 | * @param[in] _colour_index coeffitient look up index 91 | * @param[in] _input input light direction 92 | * @param[in] _output output light direction 93 | * @param[in] _normal surface normal 94 | * @param _weight resulting bsdf weight 95 | * @param _cos_theta cosine of the angle from input direction 96 | * @param _direct_pdfw probabilty in respect to solid angle 97 | */ 98 | void evaluate( 99 | const size_t _colour_index, 100 | const Vector3f& _input, 101 | const Vector3f& _output, 102 | const Vector3f& _normal, 103 | Colour3f* _weight, 104 | float* _cos_theta, 105 | float* _direct_pdfw = NULL 106 | ) const; 107 | 108 | /** 109 | * @brief Create sample according to pdf and produce bsdf weight 110 | * 111 | * @param _random thread local random generator to prevent mutation 112 | * @param[in] _colour_index index into coefitient look up 113 | * @param[in] _output output light direction 114 | * @param[in] _normal surface normal 115 | * @param _input inpute direction to be created according to pdf 116 | * @param _weight bsdf weight 117 | * @param _cos_theta cosine of the angle between normal and sampled direction 118 | * @param _direct_pdfw probability in respect to solid angle 119 | */ 120 | void sample( 121 | RandomGenerator* _random, 122 | const size_t _colour_index, 123 | const Vector3f& _output, 124 | const Vector3f& _normal, 125 | Vector3f* _input, 126 | Colour3f* _weight, 127 | float* _cos_theta, 128 | float* _direct_pdfw = NULL 129 | ) const; 130 | 131 | private: 132 | boost::shared_ptr< TextureInterface > m_texture; 133 | float m_reflectance; 134 | }; 135 | 136 | MSC_NAMESPACE_END 137 | 138 | YAML_NAMESPACE_BEGIN 139 | 140 | template<> struct convert 141 | { 142 | static bool decode(const Node& node, msc::LambertShader& rhs) 143 | { 144 | if(!node.IsMap() || node.size() != 3) 145 | return false; 146 | 147 | { 148 | if(node["texture"]["type"].as< std::string >() == "Standard") 149 | { 150 | msc::StandardTexture* standard_texture = new msc::StandardTexture(); 151 | *standard_texture = node["texture"].as(); 152 | rhs.texture(standard_texture); 153 | } 154 | 155 | if(node["texture"]["type"].as< std::string >() == "Constant") 156 | { 157 | msc::ConstantTexture* constant_texture = new msc::ConstantTexture(); 158 | *constant_texture = node["texture"].as(); 159 | rhs.texture(constant_texture); 160 | } 161 | 162 | if(node["texture"]["type"].as< std::string >() == "Layered") 163 | { 164 | msc::LayeredTexture* layered_texture = new msc::LayeredTexture(); 165 | *layered_texture = node["texture"].as(); 166 | rhs.texture(layered_texture); 167 | } 168 | } 169 | 170 | rhs.reflectance(node["reflectance"].as()); 171 | 172 | return true; 173 | } 174 | }; 175 | 176 | YAML_NAMESPACE_END 177 | 178 | #endif -------------------------------------------------------------------------------- /include/core/LayeredTexture.h: -------------------------------------------------------------------------------- 1 | #ifndef _LAYEREDTEXTURE_H_ 2 | #define _LAYEREDTEXTURE_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | MSC_NAMESPACE_BEGIN 10 | 11 | /** 12 | * @brief Inherits from the texture interface and represents a layered texturing system 13 | * 14 | * This texture takes two base textures and combines them using a mask texture. Each texture and 15 | * the mask can be of any other texture type, that currently being a constant, standard texture or 16 | * possibly another texture. As there is no integral to be sampled, russian roulette is not used 17 | * as this would introduce variance with minimal performance increase. 18 | */ 19 | class LayeredTexture : public TextureInterface 20 | { 21 | public: 22 | /** 23 | * @brief Getter method for texture path 24 | * 25 | * @return texture path as string 26 | */ 27 | inline TextureInterface upper() const {return *m_upper;} 28 | 29 | /** 30 | * @brief Getter method for texture path 31 | * 32 | * @return texture path as string 33 | */ 34 | inline TextureInterface lower() const {return *m_lower;} 35 | 36 | /** 37 | * @brief Getter method for texture path 38 | * 39 | * @return texture path as string 40 | */ 41 | inline TextureInterface mask() const {return *m_mask;} 42 | 43 | /** 44 | * @brief Setter method for texture path 45 | * 46 | * @param[in] _colour texture path as string 47 | */ 48 | inline void upper(TextureInterface* _upper){m_upper.reset(_upper);} 49 | 50 | /** 51 | * @brief Setter method for texture path 52 | * 53 | * @param[in] _colour texture path as string 54 | */ 55 | inline void lower(TextureInterface* _lower){m_lower.reset(_lower);} 56 | 57 | /** 58 | * @brief Setter method for texture path 59 | * 60 | * @param[in] _colour texture path as string 61 | */ 62 | inline void mask(TextureInterface* _mask){m_mask.reset(_mask);} 63 | 64 | /** 65 | * @brief Create polymorphic copy of derived class 66 | * 67 | * @return Is safe to have a covariant return type here 68 | */ 69 | TextureInterface* clone(); 70 | 71 | /** 72 | * @brief Initialize colour values potentially as vectorized texture lookup 73 | */ 74 | void initialize( 75 | const size_t _size, 76 | std::vector< float >& _u, 77 | std::vector< float >& _v, 78 | TextureSystem _texture_system 79 | ); 80 | 81 | /** 82 | * @brief Gets colour value according to index 83 | * 84 | * @param[in] _index colour index to find value for specific position 85 | * 86 | * @return colour according to index 87 | */ 88 | Colour3f colour(const size_t _index) const; 89 | 90 | private: 91 | boost::shared_ptr< TextureInterface > m_upper; 92 | boost::shared_ptr< TextureInterface > m_lower; 93 | boost::shared_ptr< TextureInterface > m_mask; 94 | std::vector< Colour3f > m_colour; 95 | }; 96 | 97 | MSC_NAMESPACE_END 98 | 99 | YAML_NAMESPACE_BEGIN 100 | 101 | template<> struct convert 102 | { 103 | static bool decode(const Node& node, msc::LayeredTexture& rhs) 104 | { 105 | if(node.size() != 4) 106 | return false; 107 | 108 | { 109 | if(node["upper"]["type"].as< std::string >() == "Standard") 110 | { 111 | msc::StandardTexture* standard_texture = new msc::StandardTexture(); 112 | *standard_texture = node["upper"].as(); 113 | rhs.upper(standard_texture); 114 | } 115 | 116 | if(node["upper"]["type"].as< std::string >() == "Constant") 117 | { 118 | msc::ConstantTexture* constant_texture = new msc::ConstantTexture(); 119 | *constant_texture = node["upper"].as(); 120 | rhs.upper(constant_texture); 121 | } 122 | 123 | if(node["upper"]["type"].as< std::string >() == "Layered") 124 | { 125 | msc::LayeredTexture* layered_texture = new msc::LayeredTexture(); 126 | *layered_texture = node["upper"].as(); 127 | rhs.upper(layered_texture); 128 | } 129 | } 130 | 131 | { 132 | if(node["lower"]["type"].as< std::string >() == "Standard") 133 | { 134 | msc::StandardTexture* standard_texture = new msc::StandardTexture(); 135 | *standard_texture = node["lower"].as(); 136 | rhs.lower(standard_texture); 137 | } 138 | 139 | if(node["lower"]["type"].as< std::string >() == "Constant") 140 | { 141 | msc::ConstantTexture* constant_texture = new msc::ConstantTexture(); 142 | *constant_texture = node["lower"].as(); 143 | rhs.lower(constant_texture); 144 | } 145 | 146 | if(node["lower"]["type"].as< std::string >() == "Layered") 147 | { 148 | msc::LayeredTexture* layered_texture = new msc::LayeredTexture(); 149 | *layered_texture = node["lower"].as(); 150 | rhs.lower(layered_texture); 151 | } 152 | } 153 | 154 | { 155 | if(node["mask"]["type"].as< std::string >() == "Standard") 156 | { 157 | msc::StandardTexture* standard_texture = new msc::StandardTexture(); 158 | *standard_texture = node["mask"].as(); 159 | rhs.mask(standard_texture); 160 | } 161 | 162 | if(node["mask"]["type"].as< std::string >() == "Constant") 163 | { 164 | msc::ConstantTexture* constant_texture = new msc::ConstantTexture(); 165 | *constant_texture = node["mask"].as(); 166 | rhs.mask(constant_texture); 167 | } 168 | 169 | if(node["mask"]["type"].as< std::string >() == "Layered") 170 | { 171 | msc::LayeredTexture* layered_texture = new msc::LayeredTexture(); 172 | *layered_texture = node["mask"].as(); 173 | rhs.mask(layered_texture); 174 | } 175 | } 176 | 177 | return true; 178 | } 179 | }; 180 | 181 | YAML_NAMESPACE_END 182 | 183 | #endif -------------------------------------------------------------------------------- /cmake/FindGLFW.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2013 Pixar 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "Apache License") 5 | # with the following modification; you may not use this file except in 6 | # compliance with the Apache License and the following modification to it: 7 | # Section 6. Trademarks. is deleted and replaced with: 8 | # 9 | # 6. Trademarks. This License does not grant permission to use the trade 10 | # names, trademarks, service marks, or product names of the Licensor 11 | # and its affiliates, except as required to comply with Section 4(c) of 12 | # the License and to reproduce the content of the NOTICE file. 13 | # 14 | # You may obtain a copy of the Apache License at 15 | # 16 | # http://www.apache.org/licenses/LICENSE-2.0 17 | # 18 | # Unless required by applicable law or agreed to in writing, software 19 | # distributed under the Apache License with the above modification is 20 | # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 21 | # KIND, either express or implied. See the Apache License for the specific 22 | # language governing permissions and limitations under the Apache License. 23 | # 24 | 25 | # Try to find GLFW library and include path. 26 | # Once done this will define 27 | # 28 | # GLFW_FOUND 29 | # GLFW_INCLUDE_DIR 30 | # GLFW_LIBRARIES 31 | # 32 | 33 | find_path( GLFW_INCLUDE_DIR 34 | NAMES 35 | GL/glfw.h 36 | GLFW/glfw3.h 37 | PATHS 38 | "${GLFW_LOCATION}/include" 39 | "$ENV{GLFW_LOCATION}/include" 40 | "$ENV{PROGRAMFILES}/GLFW/include" 41 | "${OPENGL_INCLUDE_DIR}" 42 | /usr/openwin/share/include 43 | /usr/openwin/include 44 | /usr/X11R6/include 45 | /usr/include/X11 46 | /opt/graphics/OpenGL/include 47 | /opt/graphics/OpenGL/contrib/libglfw 48 | /usr/local/include 49 | /usr/include/GL 50 | /usr/include 51 | DOC 52 | "The directory where GL/glfw.h resides" 53 | ) 54 | 55 | if (WIN32) 56 | if(CYGWIN) 57 | find_library( GLFW_glfw_LIBRARY 58 | NAMES 59 | glfw32 60 | PATHS 61 | "${GLFW_LOCATION}/lib" 62 | "${GLFW_LOCATION}/lib/x64" 63 | "$ENV{GLFW_LOCATION}/lib" 64 | "${OPENGL_LIBRARY_DIR}" 65 | /usr/lib 66 | /usr/lib/w32api 67 | /usr/local/lib 68 | /usr/X11R6/lib 69 | DOC 70 | "The GLFW library" 71 | ) 72 | else() 73 | find_library( GLFW_glfw_LIBRARY 74 | NAMES 75 | glfw32 76 | glfw32s 77 | glfw 78 | glfw3 79 | PATHS 80 | "${GLFW_LOCATION}/lib" 81 | "${GLFW_LOCATION}/lib/x64" 82 | "${GLFW_LOCATION}/lib-msvc110" 83 | "$ENV{GLFW_LOCATION}/lib" 84 | "$ENV{GLFW_LOCATION}/lib/x64" 85 | "$ENV{GLFW_LOCATION}/lib-msvc110" 86 | "${PROJECT_SOURCE_DIR}/extern/glfw/bin" 87 | "${PROJECT_SOURCE_DIR}/extern/glfw/lib" 88 | "$ENV{PROGRAMFILES}/GLFW/lib" 89 | "${OPENGL_LIBRARY_DIR}" 90 | DOC 91 | "The GLFW library" 92 | ) 93 | endif() 94 | else () 95 | if (APPLE) 96 | find_library( GLFW_glfw_LIBRARY glfw 97 | NAMES 98 | glfw 99 | glfw3 100 | PATHS 101 | "${GLFW_LOCATION}/lib" 102 | "${GLFW_LOCATION}/lib/cocoa" 103 | "$ENV{GLFW_LOCATION}/lib" 104 | "$ENV{GLFW_LOCATION}/lib/cocoa" 105 | /usr/local/lib 106 | ) 107 | set(GLFW_cocoa_LIBRARY "-framework Cocoa" CACHE STRING "Cocoa framework for OSX") 108 | set(GLFW_corevideo_LIBRARY "-framework CoreVideo" CACHE STRING "CoreVideo framework for OSX") 109 | set(GLFW_iokit_LIBRARY "-framework IOKit" CACHE STRING "IOKit framework for OSX") 110 | else () 111 | # (*)NIX 112 | 113 | find_package(X11 REQUIRED) 114 | 115 | if(NOT X11_Xrandr_FOUND) 116 | message(FATAL_ERROR "Xrandr library not found - required for GLFW") 117 | endif() 118 | 119 | if(NOT X11_xf86vmode_FOUND) 120 | message(FATAL_ERROR "xf86vmode library not found - required for GLFW") 121 | endif() 122 | 123 | list(APPEND GLFW_x11_LIBRARY "${X11_Xrandr_LIB}" "${X11_Xxf86vm_LIB}") 124 | 125 | find_library( GLFW_glfw_LIBRARY 126 | NAMES 127 | glfw 128 | glfw3 129 | PATHS 130 | "${GLFW_LOCATION}/lib" 131 | "$ENV{GLFW_LOCATION}/lib" 132 | "${GLFW_LOCATION}/lib/x11" 133 | "$ENV{GLFW_LOCATION}/lib/x11" 134 | /usr/lib64 135 | /usr/lib 136 | /usr/lib/${CMAKE_LIBRARY_ARCHITECTURE} 137 | /usr/local/lib64 138 | /usr/local/lib 139 | /usr/local/lib/${CMAKE_LIBRARY_ARCHITECTURE} 140 | /usr/openwin/lib 141 | /usr/X11R6/lib 142 | DOC 143 | "The GLFW library" 144 | ) 145 | endif (APPLE) 146 | endif (WIN32) 147 | 148 | set( GLFW_FOUND "NO" ) 149 | 150 | if(GLFW_INCLUDE_DIR) 151 | 152 | if(GLFW_glfw_LIBRARY) 153 | set( GLFW_LIBRARIES "${GLFW_glfw_LIBRARY}" 154 | "${GLFW_x11_LIBRARY}" 155 | "${GLFW_cocoa_LIBRARY}" 156 | "${GLFW_iokit_LIBRARY}" 157 | "${GLFW_corevideo_LIBRARY}" ) 158 | set( GLFW_FOUND "YES" ) 159 | set (GLFW_LIBRARY "${GLFW_LIBRARIES}") 160 | set (GLFW_INCLUDE_PATH "${GLFW_INCLUDE_DIR}") 161 | endif(GLFW_glfw_LIBRARY) 162 | 163 | 164 | # Tease the GLFW_VERSION numbers from the lib headers 165 | function(parseVersion FILENAME VARNAME) 166 | 167 | set(PATTERN "^#define ${VARNAME}.*$") 168 | 169 | file(STRINGS "${GLFW_INCLUDE_DIR}/${FILENAME}" TMP REGEX ${PATTERN}) 170 | 171 | string(REGEX MATCHALL "[0-9]+" TMP ${TMP}) 172 | 173 | set(${VARNAME} ${TMP} PARENT_SCOPE) 174 | 175 | endfunction() 176 | 177 | 178 | if(EXISTS "${GLFW_INCLUDE_DIR}/GL/glfw.h") 179 | 180 | parseVersion(GL/glfw.h GLFW_VERSION_MAJOR) 181 | parseVersion(GL/glfw.h GLFW_VERSION_MINOR) 182 | parseVersion(GL/glfw.h GLFW_VERSION_REVISION) 183 | 184 | elseif(EXISTS "${GLFW_INCLUDE_DIR}/GLFW/glfw3.h") 185 | 186 | parseVersion(GLFW/glfw3.h GLFW_VERSION_MAJOR) 187 | parseVersion(GLFW/glfw3.h GLFW_VERSION_MINOR) 188 | parseVersion(GLFW/glfw3.h GLFW_VERSION_REVISION) 189 | 190 | endif() 191 | 192 | if(${GLFW_VERSION_MAJOR} OR ${GLFW_VERSION_MINOR} OR ${GLFW_VERSION_REVISION}) 193 | set(GLFW_VERSION "${GLFW_VERSION_MAJOR}.${GLFW_VERSION_MINOR}.${GLFW_VERSION_REVISION}") 194 | set(GLFW_VERSION_STRING "${GLFW_VERSION}") 195 | mark_as_advanced(GLFW_VERSION) 196 | endif() 197 | 198 | endif(GLFW_INCLUDE_DIR) 199 | 200 | include(FindPackageHandleStandardArgs) 201 | 202 | find_package_handle_standard_args(GLFW 203 | REQUIRED_VARS 204 | GLFW_INCLUDE_DIR 205 | GLFW_LIBRARIES 206 | VERSION_VAR 207 | GLFW_VERSION 208 | ) 209 | 210 | mark_as_advanced( 211 | GLFW_INCLUDE_DIR 212 | GLFW_LIBRARIES 213 | GLFW_glfw_LIBRARY 214 | GLFW_cocoa_LIBRARY 215 | ) 216 | 217 | 218 | -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | #include 14 | 15 | namespace program_options = boost::program_options; 16 | namespace filesystem = boost::filesystem; 17 | 18 | void commands(const int ac, const char *av[], filesystem::path* input, filesystem::path* output) 19 | { 20 | program_options::options_description visible("options"); 21 | visible.add_options() 22 | ("help,h", "produce help message") 23 | ("output,o", program_options::value< filesystem::path >(), "output as file") 24 | ; 25 | 26 | program_options::options_description hidden("hidden options"); 27 | hidden.add_options() 28 | ("input", program_options::value< filesystem::path >()->required(), "input scene file") 29 | ; 30 | 31 | program_options::options_description description("all options"); 32 | description.add(visible).add(hidden); 33 | 34 | program_options::positional_options_description positional; 35 | positional.add("input", -1); 36 | 37 | program_options::variables_map vm; 38 | 39 | try 40 | { 41 | program_options::store( 42 | program_options::command_line_parser(ac, av).options(description).positional(positional).run(), vm); 43 | 44 | if(vm.count("help")) 45 | { 46 | std::cout << "usage: msc-project [options] scene_file.yaml" << std::endl; 47 | std::cout << visible << std::endl; 48 | std::exit(EXIT_SUCCESS); 49 | } 50 | 51 | program_options::notify(vm); 52 | 53 | if(vm.count("output")) 54 | *output = vm["output"].as< filesystem::path >(); 55 | 56 | if(vm.count("input")) 57 | *input = vm["input"].as< filesystem::path >(); 58 | } 59 | catch(program_options::required_option& error) 60 | { 61 | std::cerr << "error: " << "a scene file is required but missing" << std::endl << std::endl; 62 | std::cerr << "usage: msc-project [options] scene_file.yaml" << std::endl; 63 | std::cerr << visible << std::endl; 64 | std::exit(EXIT_FAILURE); 65 | } 66 | catch(program_options::error& error) 67 | { 68 | std::cerr << "error: " << error.what() << std::endl << std::endl; 69 | std::cerr << "usage: msc-project [options] scene_file.yaml" << std::endl; 70 | std::cerr << visible << std::endl; 71 | std::exit(EXIT_FAILURE); 72 | } 73 | 74 | if(!filesystem::exists( *input )) 75 | { 76 | std::cerr << "error: " << "the scene file does not exist" << std::endl << std::endl; 77 | std::cerr << "usage: msc-project [options] scene_file.yaml" << std::endl; 78 | std::cerr << visible << std::endl; 79 | std::exit(EXIT_FAILURE); 80 | } 81 | } 82 | 83 | void keyCallback(GLFWwindow* window, int key, int scancode, int action, int mods) 84 | { 85 | msc::Pathtracer* pathtracer = static_cast(glfwGetWindowUserPointer(window)); 86 | 87 | if(action == GLFW_PRESS) 88 | { 89 | switch(key) 90 | { 91 | case GLFW_KEY_ESCAPE: 92 | pathtracer->terminate(); 93 | break; 94 | } 95 | } 96 | } 97 | 98 | void closeCallback(GLFWwindow* window) 99 | { 100 | msc::Pathtracer* pathtracer = static_cast(glfwGetWindowUserPointer(window)); 101 | pathtracer->terminate(); 102 | } 103 | 104 | void compute(msc::Pathtracer* pathtracer, size_t* iteration) 105 | { 106 | boost::chrono::milliseconds iteration_second( 1000 / 30 ); 107 | 108 | while(pathtracer->active()) 109 | { 110 | boost::chrono::high_resolution_clock::time_point timer_start = boost::chrono::high_resolution_clock::now(); 111 | 112 | *iteration = pathtracer->process(); 113 | 114 | if(*iteration == 0) 115 | break; 116 | 117 | std::cout << "\033[1;31mIteration " << *iteration << " is complete.\033[0m" << std::endl; 118 | 119 | boost::chrono::high_resolution_clock::time_point timer_end = boost::chrono::high_resolution_clock::now(); 120 | boost::chrono::milliseconds iteration_time(boost::chrono::duration_cast 121 | (timer_end - timer_start).count()); 122 | if(iteration_time < iteration_second) 123 | boost::this_thread::sleep_for(iteration_second - iteration_time); 124 | } 125 | } 126 | 127 | int main(int argc, const char *argv[]) 128 | { 129 | filesystem::path input_file; 130 | filesystem::path output_file; 131 | 132 | commands(argc, argv, &input_file, &output_file); 133 | 134 | float* image_pointer; 135 | int width, height; 136 | 137 | msc::Pathtracer* pathtracer = new msc::Pathtracer(input_file.string()); 138 | pathtracer->image(&image_pointer, &width, &height); 139 | 140 | size_t pixel_count = width * height; 141 | 142 | if(output_file.empty()) 143 | { 144 | frm::Framebuffer* framebuffer = new frm::Framebuffer(); 145 | GLFWwindow* window = framebuffer->init(width, height, pathtracer); 146 | 147 | size_t iteration = 0; 148 | size_t check_it = 0; 149 | 150 | glfwSetKeyCallback(window, keyCallback); 151 | glfwSetWindowCloseCallback(window, closeCallback); 152 | 153 | framebuffer->bind(); 154 | framebuffer->poll(); 155 | 156 | unsigned char* image = new unsigned char[pixel_count * 3]; 157 | 158 | boost::thread compute_thread = boost::thread(&compute, pathtracer, &iteration); 159 | 160 | boost::chrono::milliseconds iteration_second( 1000 / 30 ); 161 | 162 | while(pathtracer->active()) 163 | { 164 | boost::chrono::high_resolution_clock::time_point timer_start = boost::chrono::high_resolution_clock::now(); 165 | 166 | if(check_it != iteration) 167 | { 168 | check_it = iteration; 169 | for(size_t i = 0; i < pixel_count; ++i) 170 | { 171 | image[3 * i + 0] = static_cast(std::min(1.f, image_pointer[3 * i + 0] / iteration) * 255.f); 172 | image[3 * i + 1] = static_cast(std::min(1.f, image_pointer[3 * i + 1] / iteration) * 255.f); 173 | image[3 * i + 2] = static_cast(std::min(1.f, image_pointer[3 * i + 2] / iteration) * 255.f); 174 | } 175 | 176 | std::string title = "Pathtracer Iteration: " + boost::lexical_cast(iteration); 177 | 178 | framebuffer->title(title); 179 | framebuffer->image(image, width, height); 180 | } 181 | 182 | framebuffer->draw(); 183 | framebuffer->poll(); 184 | 185 | boost::chrono::high_resolution_clock::time_point timer_end = boost::chrono::high_resolution_clock::now(); 186 | boost::chrono::milliseconds iteration_time(boost::chrono::duration_cast 187 | (timer_end - timer_start).count()); 188 | if(iteration_time < iteration_second) 189 | boost::this_thread::sleep_for(iteration_second - iteration_time); 190 | } 191 | 192 | compute_thread.join(); 193 | 194 | delete[] image; 195 | delete framebuffer; 196 | } 197 | else 198 | { 199 | size_t iteration = pathtracer->process(); 200 | 201 | Imf::Rgba* image = new Imf::Rgba[pixel_count]; 202 | 203 | for(size_t i = 0; i < pixel_count; ++i) 204 | image[i] = Imf::Rgba(image_pointer[i * 3 + 0], image_pointer[i * 3 + 1], image_pointer[i * 3 + 2], 1.f); 205 | 206 | Imf::RgbaOutputFile* file = new Imf::RgbaOutputFile(output_file.c_str(), width, height, Imf::WRITE_RGBA); 207 | file->setFrameBuffer(image, 1, width); 208 | file->writePixels(height); 209 | 210 | std::cout << "\033[1;31mOutput file named " << output_file << " written to working directory.\033[0m" << std::endl; 211 | 212 | delete[] image; 213 | delete file; 214 | } 215 | 216 | delete pathtracer; 217 | 218 | return EXIT_SUCCESS; 219 | } -------------------------------------------------------------------------------- /src/framebuffer/Framebuffer.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | FRM_NAMESPACE_BEGIN 7 | 8 | Framebuffer::~Framebuffer() 9 | { 10 | glDeleteTextures(1, &m_texture); 11 | glDeleteProgram(m_shader_program); 12 | glDeleteShader(m_vertex_shader); 13 | glDeleteShader(m_fragment_shader); 14 | glDeleteBuffers(1, &m_vbo); 15 | glDeleteVertexArrays(1, &m_vao); 16 | 17 | glfwDestroyWindow(m_window); 18 | glfwTerminate(); 19 | } 20 | 21 | GLFWwindow* Framebuffer::init(const int _resolution_x, const int _resolution_y, void* _input_data) 22 | { 23 | m_resolution_x = _resolution_x; 24 | m_resolution_y = _resolution_y; 25 | 26 | createContext(); 27 | createSurface(); 28 | 29 | if(_input_data != NULL) 30 | { 31 | glfwSetWindowUserPointer(m_window, _input_data); 32 | } 33 | else 34 | { 35 | glfwSetWindowUserPointer(m_window, this); 36 | glfwSetKeyCallback(m_window, keyCallback); 37 | glfwSetScrollCallback(m_window, scrollCallback); 38 | glfwSetCursorPosCallback(m_window, cursorPositionCallback); 39 | glfwSetMouseButtonCallback(m_window, mouseButtonCallback); 40 | } 41 | 42 | return m_window; 43 | } 44 | 45 | void Framebuffer::bind() 46 | { 47 | glfwMakeContextCurrent(m_window); 48 | 49 | glUseProgram(m_shader_program); 50 | glBindVertexArray(m_vao); 51 | 52 | glBindBuffer(GL_ARRAY_BUFFER, m_vbo); 53 | glBindTexture(GL_TEXTURE_2D, m_texture); 54 | } 55 | 56 | void Framebuffer::draw() 57 | { 58 | glEnable(GL_FRAMEBUFFER_SRGB); 59 | glClearColor(0.25f, 0.25f, 0.25f, 1.0f); 60 | glClear(GL_COLOR_BUFFER_BIT); 61 | 62 | glDrawArrays(GL_TRIANGLES, 0, 6); 63 | 64 | glfwSwapBuffers(m_window); 65 | 66 | if(m_update) 67 | { 68 | m_update = false; 69 | glUniform2f(m_trans_uniform, m_trans_x, m_trans_y); 70 | glUniform1f(m_scale_uniform, m_scale); 71 | } 72 | } 73 | 74 | bool Framebuffer::close() 75 | { 76 | return glfwWindowShouldClose(m_window); 77 | } 78 | 79 | void Framebuffer::poll() 80 | { 81 | glfwPollEvents(); 82 | } 83 | 84 | void Framebuffer::image(const unsigned char* _image, const int _resolution_x, const int _resolution_y) 85 | { 86 | glBindTexture(GL_TEXTURE_2D, m_texture); 87 | glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, _resolution_x, _resolution_y, GL_RGB, GL_UNSIGNED_BYTE, _image); 88 | } 89 | 90 | void Framebuffer::title(const std::string &_title) 91 | { 92 | glfwSetWindowTitle(m_window, _title.c_str()); 93 | } 94 | 95 | void Framebuffer::createSurface() 96 | { 97 | glGenVertexArrays(1, &m_vao); 98 | glBindVertexArray(m_vao); 99 | 100 | float vertices[] = { 101 | -1.f, 1.f, 0.f, 0.f, 102 | 1.f, 1.f, 1.f, 0.f, 103 | 1.f, -1.f, 1.f, 1.f, 104 | 105 | 1.f, -1.f, 1.f, 1.f, 106 | -1.f, -1.f, 0.f, 1.f, 107 | -1.f, 1.f, 0.f, 0.f 108 | }; 109 | 110 | glGenBuffers(1, &m_vbo); 111 | glBindBuffer(GL_ARRAY_BUFFER, m_vbo); 112 | glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); 113 | 114 | const GLchar* vertex_source = 115 | "#version 330\n" 116 | "in vec2 position;" 117 | "in vec2 coordinate;" 118 | "uniform vec2 translation;" 119 | "uniform float scale;" 120 | "out vec2 Coordinate;" 121 | "void main()" 122 | "{" 123 | " Coordinate = coordinate;" 124 | " gl_Position = vec4((position + translation) * scale, 0.0, 1.0);" 125 | "}"; 126 | 127 | const GLchar* fragment_source = 128 | "#version 330\n" 129 | "in vec2 Coordinate;" 130 | "uniform sampler2D tex;" 131 | "out vec4 outColor;" 132 | "void main()" 133 | "{" 134 | " outColor = texture(tex, Coordinate);" 135 | "}"; 136 | 137 | m_vertex_shader = glCreateShader(GL_VERTEX_SHADER); 138 | glShaderSource(m_vertex_shader, 1, &vertex_source, NULL); 139 | glCompileShader(m_vertex_shader); 140 | 141 | m_fragment_shader = glCreateShader(GL_FRAGMENT_SHADER); 142 | glShaderSource(m_fragment_shader, 1, &fragment_source, NULL); 143 | glCompileShader(m_fragment_shader); 144 | 145 | m_shader_program = glCreateProgram(); 146 | glAttachShader(m_shader_program, m_vertex_shader); 147 | glAttachShader(m_shader_program, m_fragment_shader); 148 | glLinkProgram(m_shader_program); 149 | glUseProgram(m_shader_program); 150 | 151 | m_pos_attrib = glGetAttribLocation(m_shader_program, "position"); 152 | glVertexAttribPointer(m_pos_attrib, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), 0); 153 | glEnableVertexAttribArray(m_pos_attrib); 154 | 155 | m_tex_attrib = glGetAttribLocation(m_shader_program, "coordinate"); 156 | glVertexAttribPointer(m_tex_attrib, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), (void*)(2 * sizeof(GLfloat))); 157 | glEnableVertexAttribArray(m_tex_attrib); 158 | 159 | m_trans_uniform = glGetUniformLocation(m_shader_program, "translation"); 160 | glUniform2f(m_trans_uniform, m_trans_x, m_trans_y); 161 | 162 | m_scale_uniform = glGetUniformLocation(m_shader_program, "scale"); 163 | glUniform1f(m_scale_uniform, m_scale); 164 | 165 | glGenTextures(1, &m_texture); 166 | glBindTexture(GL_TEXTURE_2D, m_texture); 167 | glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, m_resolution_x, m_resolution_y, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); 168 | 169 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 170 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 171 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 172 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 173 | } 174 | 175 | void Framebuffer::createContext() 176 | { 177 | int glfw_error = glfwInit(); 178 | if(glfw_error != GL_TRUE) 179 | { 180 | std::cout << "GLFW error: " << glfw_error << std::endl; 181 | exit(EXIT_FAILURE); 182 | } 183 | 184 | glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); 185 | glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2); 186 | glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); 187 | glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); 188 | glfwWindowHint(GLFW_SRGB_CAPABLE, GL_TRUE); 189 | glfwWindowHint(GLFW_SAMPLES, 2); 190 | glfwWindowHint(GLFW_RESIZABLE, GL_FALSE); 191 | 192 | m_window = glfwCreateWindow(m_resolution_x, m_resolution_y, "Pathtracer Iteration: 0", NULL, NULL); 193 | 194 | glfwMakeContextCurrent(m_window); 195 | glfwSwapInterval(true); 196 | 197 | GLenum opengl_error = glGetError(); 198 | if(opengl_error != GL_NO_ERROR) 199 | { 200 | std::cout << "OpenGL error: " << opengl_error << std::endl; 201 | exit(EXIT_FAILURE); 202 | } 203 | 204 | #ifdef USING_GLEW 205 | glewExperimental = GL_TRUE; 206 | GLenum glew_error = glewInit(); 207 | if(glew_error != GLEW_OK) 208 | { 209 | std::cout << "Glew error: " << glew_error << std::endl; 210 | exit(EXIT_FAILURE); 211 | } 212 | #endif 213 | } 214 | 215 | void Framebuffer::keyCallback(GLFWwindow* window, int key, int scancode, int action, int mods) 216 | { 217 | Framebuffer *framebuffer = static_cast(glfwGetWindowUserPointer(window)); 218 | 219 | if(action == GLFW_PRESS) 220 | { 221 | framebuffer->m_update = true; 222 | switch(key) 223 | { 224 | case GLFW_KEY_ESCAPE: 225 | glfwSetWindowShouldClose(window, GL_TRUE); 226 | break; 227 | case GLFW_KEY_F: 228 | framebuffer->m_trans_x = 0.f; 229 | framebuffer->m_trans_y = 0.f; 230 | framebuffer->m_scale = 1.f; 231 | break; 232 | } 233 | } 234 | } 235 | 236 | void Framebuffer::scrollCallback(GLFWwindow* window, double xoffset, double yoffset) 237 | { 238 | Framebuffer *framebuffer = static_cast(glfwGetWindowUserPointer(window)); 239 | 240 | float scale = framebuffer->m_scale; 241 | scale += scale * yoffset * 0.05f; 242 | if(scale > 0.02f && scale < 20.f) 243 | { 244 | framebuffer->m_update = true; 245 | framebuffer->m_scale += yoffset * scale * 0.05f; 246 | } 247 | } 248 | 249 | void Framebuffer::cursorPositionCallback(GLFWwindow* window, double xpos, double ypos) 250 | { 251 | Framebuffer *framebuffer = static_cast(glfwGetWindowUserPointer(window)); 252 | 253 | if(framebuffer->m_pan) 254 | { 255 | framebuffer->m_update = true; 256 | float scale = 2.f / framebuffer->m_scale; 257 | framebuffer->m_trans_x = framebuffer->m_state_x + ((xpos - framebuffer->m_screen_x) / framebuffer->m_resolution_x) * scale; 258 | framebuffer->m_trans_y = framebuffer->m_state_y + ((framebuffer->m_screen_y - ypos) / framebuffer->m_resolution_y) * scale; 259 | } 260 | } 261 | 262 | void Framebuffer::mouseButtonCallback(GLFWwindow* window, int button, int action, int mods) 263 | { 264 | Framebuffer *framebuffer = static_cast(glfwGetWindowUserPointer(window)); 265 | 266 | if(button == GLFW_MOUSE_BUTTON_LEFT && action == GLFW_PRESS) 267 | { 268 | framebuffer->m_pan = true; 269 | 270 | framebuffer->m_state_x = framebuffer->m_trans_x; 271 | framebuffer->m_state_y = framebuffer->m_trans_y; 272 | 273 | double xpos, ypos; 274 | glfwGetCursorPos(window, &xpos, &ypos); 275 | framebuffer->m_screen_x = xpos; 276 | framebuffer->m_screen_y = ypos; 277 | } 278 | else if(button == GLFW_MOUSE_BUTTON_LEFT && action == GLFW_RELEASE) 279 | { 280 | framebuffer->m_pan = false; 281 | } 282 | } 283 | 284 | FRM_NAMESPACE_END -------------------------------------------------------------------------------- /src/core/Integrator.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | MSC_NAMESPACE_BEGIN 11 | 12 | void Integrator::operator()(const RangeGeom< RayUncompressed* > &r) const 13 | { 14 | LocalRandomGenerator::reference random = m_local_thread_storage_random->local(); 15 | LocalTextureSystem::reference texture_system = m_local_thread_storage_texture->local(); 16 | 17 | if(texture_system == NULL) 18 | texture_system = OpenImageIO::TextureSystem::create(true); 19 | 20 | size_t range_size = (r.end() - r.begin()); 21 | size_t geom_id = m_batch[r.begin()].geomID; 22 | size_t light_count = m_scene->lights.size(); 23 | float light_pick_probability = 1.f / light_count; 24 | 25 | // If nothing was hit 26 | if(geom_id == -1) 27 | return; 28 | 29 | ObjectInterface* object = m_scene->objects[geom_id].get(); 30 | 31 | int intersected_light = -1; 32 | std::map::const_iterator iterator = m_scene->shaders_to_lights.find(object->shader()); 33 | if(iterator != m_scene->shaders_to_lights.end()) 34 | intersected_light = iterator->second; 35 | 36 | // If a light was hit 37 | if(intersected_light >= 0) 38 | { 39 | LightInterface* light = m_scene->lights[intersected_light].get(); 40 | 41 | for(size_t index = r.begin(); index < r.end(); ++index) 42 | { 43 | Vector3f ray_direction = Vector3f( 44 | m_batch[index].dir[0], 45 | m_batch[index].dir[1], 46 | m_batch[index].dir[2] 47 | ).normalized(); 48 | 49 | Colour3f light_radiance; 50 | float light_pdfa; 51 | float cos_theta; 52 | 53 | light->radiance(ray_direction, &light_radiance, &cos_theta, &light_pdfa); 54 | 55 | float mis_balance = 1.0f; 56 | if(m_batch[index].rayDepth > 0) 57 | { 58 | float light_pdfw = areaToAngleProbability(light_pdfa, m_batch[index].tfar, cos_theta); 59 | float last_pdfw = m_batch[index].lastPdf; 60 | mis_balance = misBalance(last_pdfw, light_pdfw * light_pick_probability); 61 | } 62 | // mis_balance = 0.5f; 63 | 64 | if(light_radiance.matrix().maxCoeff() > M_EPSILON) 65 | { 66 | m_image->samples[m_batch[index].sampleID].r += light_radiance[0] 67 | * mis_balance * m_batch[index].weight[0]; 68 | m_image->samples[m_batch[index].sampleID].g += light_radiance[1] 69 | * mis_balance * m_batch[index].weight[1]; 70 | m_image->samples[m_batch[index].sampleID].b += light_radiance[2] 71 | * mis_balance * m_batch[index].weight[2]; 72 | } 73 | } 74 | 75 | return; 76 | } 77 | 78 | ShaderInterface* shader = m_scene->shaders[object->shader()]->clone(); 79 | 80 | // Compute shader coefficients 81 | { 82 | std::vector< float > u(range_size); 83 | std::vector< float > v(range_size); 84 | 85 | for(size_t index = 0; index < range_size; ++index) 86 | { 87 | Vector2f texture; 88 | object->texture( 89 | m_batch[r.begin() + index].primID, 90 | m_batch[r.begin() + index].u, 91 | m_batch[r.begin() + index].v, 92 | &texture 93 | ); 94 | 95 | u[index] = texture[0]; 96 | v[index] = texture[1]; 97 | } 98 | 99 | shader->initialize(range_size, u, v, texture_system); 100 | } 101 | 102 | // Next event estimation 103 | { 104 | for(size_t index = r.begin(); index < r.end(); ++index) 105 | { 106 | size_t colour_index = index - r.begin(); 107 | 108 | size_t ligt_identifier = size_t(light_count * random.sample()); 109 | LightInterface* light = m_scene->lights[ligt_identifier].get(); 110 | 111 | Vector3f ray_origin = Vector3f( 112 | m_batch[index].org[0], 113 | m_batch[index].org[1], 114 | m_batch[index].org[2] 115 | ); 116 | Vector3f ray_direction = Vector3f( 117 | m_batch[index].dir[0], 118 | m_batch[index].dir[1], 119 | m_batch[index].dir[2] 120 | ).normalized(); 121 | Vector3f normal = Vector3f( 122 | m_batch[index].Ng[0], 123 | m_batch[index].Ng[1], 124 | m_batch[index].Ng[2] 125 | ).normalized() * -1.f; 126 | Vector3f position = ray_origin + ray_direction * m_batch[index].tfar; 127 | Vector3f output_dir = ray_direction * -1.f; 128 | Vector3f input_dir; 129 | 130 | Colour3f light_radiance; 131 | float light_pdfw; 132 | float distance; 133 | 134 | light->illuminate(&random, position, &input_dir, &distance, &light_radiance, &light_pdfw); 135 | 136 | if(light_radiance.matrix().maxCoeff() > M_EPSILON) 137 | { 138 | Colour3f bsdf_weight; 139 | float bsdf_pdfw; 140 | float cos_theta; 141 | 142 | shader->evaluate(colour_index, input_dir, output_dir, normal, &bsdf_weight, &cos_theta, &bsdf_pdfw); 143 | 144 | if(bsdf_weight.matrix().maxCoeff() > M_EPSILON) 145 | { 146 | float mis_balance = misBalance(light_pdfw * light_pick_probability, bsdf_pdfw); 147 | // mis_balance = 0.5f; 148 | 149 | Colour3f contribution = (mis_balance 150 | * cos_theta / (light_pdfw * light_pick_probability)) 151 | * (light_radiance * bsdf_weight); 152 | 153 | RayUncompressed shadow_ray; 154 | shadow_ray.tnear = 0.001f; 155 | shadow_ray.tfar = distance; 156 | shadow_ray.mask = 0x0FFFFFFF; 157 | shadow_ray.time = 0.f; 158 | shadow_ray.geomID = RTC_INVALID_GEOMETRY_ID; 159 | shadow_ray.primID = RTC_INVALID_GEOMETRY_ID; 160 | shadow_ray.instID = RTC_INVALID_GEOMETRY_ID; 161 | shadow_ray.org[0] = position[0]; 162 | shadow_ray.org[1] = position[1]; 163 | shadow_ray.org[2] = position[2]; 164 | shadow_ray.dir[0] = input_dir[0]; 165 | shadow_ray.dir[1] = input_dir[1]; 166 | shadow_ray.dir[2] = input_dir[2]; 167 | rtcOccluded(m_scene->rtc_scene, shadow_ray.rtc_ray); 168 | 169 | if(shadow_ray.geomID != 0) 170 | { 171 | m_image->samples[m_batch[index].sampleID].r += contribution[0] * m_batch[index].weight[0]; 172 | m_image->samples[m_batch[index].sampleID].g += contribution[1] * m_batch[index].weight[1]; 173 | m_image->samples[m_batch[index].sampleID].b += contribution[2] * m_batch[index].weight[2]; 174 | } 175 | } 176 | } 177 | } 178 | } 179 | 180 | // Continue random walk 181 | { 182 | for(size_t index = r.begin(); index < r.end(); ++index) 183 | { 184 | if(m_batch[index].rayDepth >= m_settings->max_depth) 185 | continue; 186 | 187 | float tentative_contrib = shader->continuation(); 188 | float cont_probability = fmin(1.f, tentative_contrib / m_settings->threshold); 189 | 190 | if(m_batch[index].rayDepth < m_settings->min_depth) 191 | cont_probability = 1.f; 192 | 193 | if(random.sample() > cont_probability) 194 | continue; 195 | 196 | size_t colour_index = index - r.begin(); 197 | 198 | Vector3f ray_origin = Vector3f( 199 | m_batch[index].org[0], 200 | m_batch[index].org[1], 201 | m_batch[index].org[2] 202 | ); 203 | Vector3f ray_direction = Vector3f( 204 | m_batch[index].dir[0], 205 | m_batch[index].dir[1], 206 | m_batch[index].dir[2] 207 | ).normalized(); 208 | Vector3f normal = Vector3f( 209 | m_batch[index].Ng[0], 210 | m_batch[index].Ng[1], 211 | m_batch[index].Ng[2] 212 | ).normalized() * -1.f; 213 | Vector3f position = ray_origin + ray_direction * m_batch[index].tfar; 214 | Vector3f output_dir = ray_direction * -1.f; 215 | Vector3f input_dir; 216 | 217 | Colour3f bsdf_weight; 218 | float bsdf_pdfw; 219 | float cos_theta; 220 | 221 | shader->sample(&random, colour_index, output_dir, normal, &input_dir, &bsdf_weight, &cos_theta, &bsdf_pdfw); 222 | 223 | RayCompressed input_ray; 224 | input_ray.org[0] = position[0]; 225 | input_ray.org[1] = position[1]; 226 | input_ray.org[2] = position[2]; 227 | input_ray.dir[0] = input_dir[0]; 228 | input_ray.dir[1] = input_dir[1]; 229 | input_ray.dir[2] = input_dir[2]; 230 | input_ray.weight[0] = m_batch[index].weight[0] 231 | * bsdf_weight[0] * (cos_theta / bsdf_pdfw) / cont_probability; 232 | input_ray.weight[1] = m_batch[index].weight[1] 233 | * bsdf_weight[1] * (cos_theta / bsdf_pdfw) / cont_probability; 234 | input_ray.weight[2] = m_batch[index].weight[2] 235 | * bsdf_weight[2] * (cos_theta / bsdf_pdfw) / cont_probability; 236 | input_ray.lastPdf = bsdf_pdfw; 237 | input_ray.rayDepth = m_batch[index].rayDepth + 1; 238 | input_ray.sampleID = m_batch[index].sampleID; 239 | 240 | int max = (fabs(input_ray.dir[0]) < fabs(input_ray.dir[1])) ? 1 : 0; 241 | int axis = (fabs(input_ray.dir[max]) < fabs(input_ray.dir[2])) ? 2 : max; 242 | int cardinal = (input_ray.dir[axis] < 0.f) ? axis : axis + 3; 243 | 244 | m_buffer.direction[cardinal].push_back(input_ray); 245 | } 246 | } 247 | 248 | for(size_t index = 0; index < 6; ++index) 249 | { 250 | if(m_buffer.direction[index].size() > 0) 251 | m_bins->add(m_buffer.direction[index].size(), index, &(m_buffer.direction[index][0]), m_batch_queue); 252 | } 253 | 254 | delete shader; 255 | } 256 | 257 | MSC_NAMESPACE_END -------------------------------------------------------------------------------- /cmake/FindTBB.cmake: -------------------------------------------------------------------------------- 1 | # Locate Intel Threading Building Blocks include paths and libraries 2 | # FindTBB.cmake can be found at https://code.google.com/p/findtbb/ 3 | # Written by Hannes Hofmann 4 | # Improvements by Gino van den Bergen , 5 | # Florian Uhlig , 6 | # Jiri Marsik 7 | 8 | # The MIT License 9 | # 10 | # Copyright (c) 2011 Hannes Hofmann 11 | # 12 | # Permission is hereby granted, free of charge, to any person obtaining a copy 13 | # of this software and associated documentation files (the "Software"), to deal 14 | # in the Software without restriction, including without limitation the rights 15 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 16 | # copies of the Software, and to permit persons to whom the Software is 17 | # furnished to do so, subject to the following conditions: 18 | # 19 | # The above copyright notice and this permission notice shall be included in 20 | # all copies or substantial portions of the Software. 21 | # 22 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 23 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 24 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 25 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 26 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 27 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 28 | # THE SOFTWARE. 29 | 30 | # GvdB: This module uses the environment variable TBB_ARCH_PLATFORM which defines architecture and compiler. 31 | # e.g. "ia32/vc8" or "em64t/cc4.1.0_libc2.4_kernel2.6.16.21" 32 | # TBB_ARCH_PLATFORM is set by the build script tbbvars[.bat|.sh|.csh], which can be found 33 | # in the TBB installation directory (TBB_INSTALL_DIR). 34 | # 35 | # GvdB: Mac OS X distribution places libraries directly in lib directory. 36 | # 37 | # For backwards compatibility, you may explicitely set the CMake variables TBB_ARCHITECTURE and TBB_COMPILER. 38 | # TBB_ARCHITECTURE [ ia32 | em64t | itanium ] 39 | # which architecture to use 40 | # TBB_COMPILER e.g. vc9 or cc3.2.3_libc2.3.2_kernel2.4.21 or cc4.0.1_os10.4.9 41 | # which compiler to use (detected automatically on Windows) 42 | 43 | # This module respects 44 | # TBB_INSTALL_DIR or $ENV{TBB21_INSTALL_DIR} or $ENV{TBB_INSTALL_DIR} 45 | 46 | # This module defines 47 | # TBB_INCLUDE_DIRS, where to find task_scheduler_init.h, etc. 48 | # TBB_LIBRARY_DIRS, where to find libtbb, libtbbmalloc 49 | # TBB_DEBUG_LIBRARY_DIRS, where to find libtbb_debug, libtbbmalloc_debug 50 | # TBB_INSTALL_DIR, the base TBB install directory 51 | # TBB_LIBRARIES, the libraries to link against to use TBB. 52 | # TBB_RUNTIME_LIBRARIES, the runtime libraries - required .dll files for Windows ( for installation ). 53 | # TBB_DEBUG_LIBRARIES, the libraries to link against to use TBB with debug symbols. 54 | # TBB_FOUND, If false, don't try to use TBB. 55 | # TBB_INTERFACE_VERSION, as defined in tbb/tbb_stddef.h 56 | 57 | 58 | if (WIN32) 59 | # has em64t/vc8 em64t/vc9 60 | # has ia32/vc7.1 ia32/vc8 ia32/vc9 61 | set(_TBB_DEFAULT_INSTALL_DIR "C:/Program Files/Intel/TBB" "C:/Program Files (x86)/Intel/TBB") 62 | set(_TBB_LIB_NAME "tbb") 63 | set(_TBB_LIB_MALLOC_NAME "${_TBB_LIB_NAME}malloc") 64 | set(_TBB_LIB_DEBUG_NAME "${_TBB_LIB_NAME}_debug") 65 | set(_TBB_LIB_MALLOC_DEBUG_NAME "${_TBB_LIB_MALLOC_NAME}_debug") 66 | if (MSVC71) 67 | set (_TBB_COMPILER "vc7.1") 68 | endif(MSVC71) 69 | if (MSVC80) 70 | set(_TBB_COMPILER "vc8") 71 | endif(MSVC80) 72 | if (MSVC90) 73 | set(_TBB_COMPILER "vc9") 74 | endif(MSVC90) 75 | if(MSVC10) 76 | set(_TBB_COMPILER "vc10") 77 | endif(MSVC10) 78 | # Todo: add other Windows compilers such as ICL. 79 | set(_TBB_ARCHITECTURE ${TBB_ARCHITECTURE}) 80 | endif (WIN32) 81 | 82 | if (UNIX) 83 | if (APPLE) 84 | # MAC 85 | set(_TBB_DEFAULT_INSTALL_DIR "/Library/Frameworks/Intel_TBB.framework/Versions") 86 | # libs: libtbb.dylib, libtbbmalloc.dylib, *_debug 87 | set(_TBB_LIB_NAME "tbb") 88 | set(_TBB_LIB_MALLOC_NAME "${_TBB_LIB_NAME}malloc") 89 | set(_TBB_LIB_DEBUG_NAME "${_TBB_LIB_NAME}_debug") 90 | set(_TBB_LIB_MALLOC_DEBUG_NAME "${_TBB_LIB_MALLOC_NAME}_debug") 91 | # default flavor on apple: ia32/cc4.0.1_os10.4.9 92 | # Jiri: There is no reason to presume there is only one flavor and 93 | # that user's setting of variables should be ignored. 94 | if(NOT TBB_COMPILER) 95 | set(_TBB_COMPILER "cc4.0.1_os10.4.9") 96 | elseif (NOT TBB_COMPILER) 97 | set(_TBB_COMPILER ${TBB_COMPILER}) 98 | endif(NOT TBB_COMPILER) 99 | if(NOT TBB_ARCHITECTURE) 100 | set(_TBB_ARCHITECTURE "ia32") 101 | elseif(NOT TBB_ARCHITECTURE) 102 | set(_TBB_ARCHITECTURE ${TBB_ARCHITECTURE}) 103 | endif(NOT TBB_ARCHITECTURE) 104 | else (APPLE) 105 | # LINUX 106 | set(_TBB_DEFAULT_INSTALL_DIR "/opt/intel/tbb" "/usr/local/include" "/usr/include") 107 | set(_TBB_LIB_NAME "tbb") 108 | set(_TBB_LIB_MALLOC_NAME "${_TBB_LIB_NAME}malloc") 109 | set(_TBB_LIB_DEBUG_NAME "${_TBB_LIB_NAME}_debug") 110 | set(_TBB_LIB_MALLOC_DEBUG_NAME "${_TBB_LIB_MALLOC_NAME}_debug") 111 | # has em64t/cc3.2.3_libc2.3.2_kernel2.4.21 em64t/cc3.3.3_libc2.3.3_kernel2.6.5 em64t/cc3.4.3_libc2.3.4_kernel2.6.9 em64t/cc4.1.0_libc2.4_kernel2.6.16.21 112 | # has ia32/* 113 | # has itanium/* 114 | set(_TBB_COMPILER ${TBB_COMPILER}) 115 | set(_TBB_ARCHITECTURE ${TBB_ARCHITECTURE}) 116 | endif (APPLE) 117 | endif (UNIX) 118 | 119 | if (CMAKE_SYSTEM MATCHES "SunOS.*") 120 | # SUN 121 | # not yet supported 122 | # has em64t/cc3.4.3_kernel5.10 123 | # has ia32/* 124 | endif (CMAKE_SYSTEM MATCHES "SunOS.*") 125 | 126 | 127 | #-- Clear the public variables 128 | set (TBB_FOUND "NO") 129 | 130 | 131 | #-- Find TBB install dir and set ${_TBB_INSTALL_DIR} and cached ${TBB_INSTALL_DIR} 132 | # first: use CMake variable TBB_INSTALL_DIR 133 | if (TBB_INSTALL_DIR) 134 | set (_TBB_INSTALL_DIR ${TBB_INSTALL_DIR}) 135 | endif (TBB_INSTALL_DIR) 136 | # second: use environment variable 137 | if (NOT _TBB_INSTALL_DIR) 138 | if (NOT "$ENV{TBB_INSTALL_DIR}" STREQUAL "") 139 | set (_TBB_INSTALL_DIR $ENV{TBB_INSTALL_DIR}) 140 | endif (NOT "$ENV{TBB_INSTALL_DIR}" STREQUAL "") 141 | # Intel recommends setting TBB21_INSTALL_DIR 142 | if (NOT "$ENV{TBB21_INSTALL_DIR}" STREQUAL "") 143 | set (_TBB_INSTALL_DIR $ENV{TBB21_INSTALL_DIR}) 144 | endif (NOT "$ENV{TBB21_INSTALL_DIR}" STREQUAL "") 145 | if (NOT "$ENV{TBB22_INSTALL_DIR}" STREQUAL "") 146 | set (_TBB_INSTALL_DIR $ENV{TBB22_INSTALL_DIR}) 147 | endif (NOT "$ENV{TBB22_INSTALL_DIR}" STREQUAL "") 148 | if (NOT "$ENV{TBB30_INSTALL_DIR}" STREQUAL "") 149 | set (_TBB_INSTALL_DIR $ENV{TBB30_INSTALL_DIR}) 150 | endif (NOT "$ENV{TBB30_INSTALL_DIR}" STREQUAL "") 151 | endif (NOT _TBB_INSTALL_DIR) 152 | # third: try to find path automatically 153 | if (NOT _TBB_INSTALL_DIR) 154 | if (_TBB_DEFAULT_INSTALL_DIR) 155 | set (_TBB_INSTALL_DIR ${_TBB_DEFAULT_INSTALL_DIR}) 156 | endif (_TBB_DEFAULT_INSTALL_DIR) 157 | endif (NOT _TBB_INSTALL_DIR) 158 | # sanity check 159 | if (NOT _TBB_INSTALL_DIR) 160 | message ("ERROR: Unable to find Intel TBB install directory. ${_TBB_INSTALL_DIR}") 161 | else (NOT _TBB_INSTALL_DIR) 162 | # finally: set the cached CMake variable TBB_INSTALL_DIR 163 | if (NOT TBB_INSTALL_DIR) 164 | set (TBB_INSTALL_DIR ${_TBB_INSTALL_DIR} CACHE PATH "Intel TBB install directory") 165 | mark_as_advanced(TBB_INSTALL_DIR) 166 | endif (NOT TBB_INSTALL_DIR) 167 | 168 | 169 | #-- A macro to rewrite the paths of the library. This is necessary, because 170 | # find_library() always found the em64t/vc9 version of the TBB libs 171 | macro(TBB_CORRECT_LIB_DIR var_name) 172 | # if (NOT "${_TBB_ARCHITECTURE}" STREQUAL "em64t") 173 | string(REPLACE em64t "${_TBB_ARCHITECTURE}" ${var_name} ${${var_name}}) 174 | # endif (NOT "${_TBB_ARCHITECTURE}" STREQUAL "em64t") 175 | string(REPLACE ia32 "${_TBB_ARCHITECTURE}" ${var_name} ${${var_name}}) 176 | string(REPLACE vc7.1 "${_TBB_COMPILER}" ${var_name} ${${var_name}}) 177 | string(REPLACE vc8 "${_TBB_COMPILER}" ${var_name} ${${var_name}}) 178 | string(REPLACE vc9 "${_TBB_COMPILER}" ${var_name} ${${var_name}}) 179 | string(REPLACE vc10 "${_TBB_COMPILER}" ${var_name} ${${var_name}}) 180 | endmacro(TBB_CORRECT_LIB_DIR var_content) 181 | 182 | 183 | #-- Look for include directory and set ${TBB_INCLUDE_DIR} 184 | set (TBB_INC_SEARCH_DIR ${_TBB_INSTALL_DIR}/include) 185 | # Jiri: tbbvars now sets the CPATH environment variable to the directory 186 | # containing the headers. 187 | find_path(TBB_INCLUDE_DIR 188 | tbb/task_scheduler_init.h 189 | PATHS ${TBB_INC_SEARCH_DIR} ENV CPATH 190 | ) 191 | mark_as_advanced(TBB_INCLUDE_DIR) 192 | 193 | 194 | #-- Look for libraries 195 | # GvdB: $ENV{TBB_ARCH_PLATFORM} is set by the build script tbbvars[.bat|.sh|.csh] 196 | if (NOT $ENV{TBB_ARCH_PLATFORM} STREQUAL "") 197 | set (_TBB_LIBRARY_DIR 198 | ${_TBB_INSTALL_DIR}/lib/$ENV{TBB_ARCH_PLATFORM} 199 | ${_TBB_INSTALL_DIR}/$ENV{TBB_ARCH_PLATFORM}/lib 200 | ) 201 | endif (NOT $ENV{TBB_ARCH_PLATFORM} STREQUAL "") 202 | # Jiri: This block isn't mutually exclusive with the previous one 203 | # (hence no else), instead I test if the user really specified 204 | # the variables in question. 205 | if ((NOT ${TBB_ARCHITECTURE} STREQUAL "") AND (NOT ${TBB_COMPILER} STREQUAL "")) 206 | # HH: deprecated 207 | message(STATUS "[Warning] FindTBB.cmake: The use of TBB_ARCHITECTURE and TBB_COMPILER is deprecated and may not be supported in future versions. Please set \$ENV{TBB_ARCH_PLATFORM} (using tbbvars.[bat|csh|sh]).") 208 | # Jiri: It doesn't hurt to look in more places, so I store the hints from 209 | # ENV{TBB_ARCH_PLATFORM} and the TBB_ARCHITECTURE and TBB_COMPILER 210 | # variables and search them both. 211 | set (_TBB_LIBRARY_DIR "${_TBB_INSTALL_DIR}/${_TBB_ARCHITECTURE}/${_TBB_COMPILER}/lib" ${_TBB_LIBRARY_DIR}) 212 | endif ((NOT ${TBB_ARCHITECTURE} STREQUAL "") AND (NOT ${TBB_COMPILER} STREQUAL "")) 213 | 214 | # GvdB: Mac OS X distribution places libraries directly in lib directory. 215 | list(APPEND _TBB_LIBRARY_DIR ${_TBB_INSTALL_DIR}/lib) 216 | 217 | # Jiri: No reason not to check the default paths. From recent versions, 218 | # tbbvars has started exporting the LIBRARY_PATH and LD_LIBRARY_PATH 219 | # variables, which now point to the directories of the lib files. 220 | # It all makes more sense to use the ${_TBB_LIBRARY_DIR} as a HINTS 221 | # argument instead of the implicit PATHS as it isn't hard-coded 222 | # but computed by system introspection. Searching the LIBRARY_PATH 223 | # and LD_LIBRARY_PATH environment variables is now even more important 224 | # that tbbvars doesn't export TBB_ARCH_PLATFORM and it facilitates 225 | # the use of TBB built from sources. 226 | find_library(TBB_LIBRARY ${_TBB_LIB_NAME} HINTS ${_TBB_LIBRARY_DIR} 227 | PATHS ENV LIBRARY_PATH ENV LD_LIBRARY_PATH) 228 | find_library(TBB_MALLOC_LIBRARY ${_TBB_LIB_MALLOC_NAME} HINTS ${_TBB_LIBRARY_DIR} 229 | PATHS ENV LIBRARY_PATH ENV LD_LIBRARY_PATH) 230 | 231 | #Extract path from TBB_LIBRARY name 232 | get_filename_component(TBB_LIBRARY_DIR ${TBB_LIBRARY} PATH) 233 | 234 | #TBB_CORRECT_LIB_DIR(TBB_LIBRARY) 235 | #TBB_CORRECT_LIB_DIR(TBB_MALLOC_LIBRARY) 236 | mark_as_advanced(TBB_LIBRARY TBB_MALLOC_LIBRARY) 237 | 238 | #-- Look for debug libraries 239 | # Jiri: Changed the same way as for the release libraries. 240 | find_library(TBB_LIBRARY_DEBUG ${_TBB_LIB_DEBUG_NAME} HINTS ${_TBB_LIBRARY_DIR} 241 | PATHS ENV LIBRARY_PATH ENV LD_LIBRARY_PATH) 242 | find_library(TBB_MALLOC_LIBRARY_DEBUG ${_TBB_LIB_MALLOC_DEBUG_NAME} HINTS ${_TBB_LIBRARY_DIR} 243 | PATHS ENV LIBRARY_PATH ENV LD_LIBRARY_PATH) 244 | 245 | # Jiri: Self-built TBB stores the debug libraries in a separate directory. 246 | # Extract path from TBB_LIBRARY_DEBUG name 247 | get_filename_component(TBB_LIBRARY_DEBUG_DIR ${TBB_LIBRARY_DEBUG} PATH) 248 | 249 | #TBB_CORRECT_LIB_DIR(TBB_LIBRARY_DEBUG) 250 | #TBB_CORRECT_LIB_DIR(TBB_MALLOC_LIBRARY_DEBUG) 251 | mark_as_advanced(TBB_LIBRARY_DEBUG TBB_MALLOC_LIBRARY_DEBUG) 252 | 253 | 254 | if (TBB_INCLUDE_DIR) 255 | if (TBB_LIBRARY) 256 | set (TBB_FOUND "YES") 257 | set (TBB_LIBRARIES ${TBB_LIBRARY} ${TBB_MALLOC_LIBRARY} ${TBB_LIBRARIES}) 258 | set (TBB_DEBUG_LIBRARIES ${TBB_LIBRARY_DEBUG} ${TBB_MALLOC_LIBRARY_DEBUG} ${TBB_DEBUG_LIBRARIES}) 259 | set (TBB_INCLUDE_DIRS ${TBB_INCLUDE_DIR} CACHE PATH "TBB include directory" FORCE) 260 | set (TBB_LIBRARY_DIRS ${TBB_LIBRARY_DIR} CACHE PATH "TBB library directory" FORCE) 261 | # Jiri: Self-built TBB stores the debug libraries in a separate directory. 262 | set (TBB_DEBUG_LIBRARY_DIRS ${TBB_LIBRARY_DEBUG_DIR} CACHE PATH "TBB debug library directory" FORCE) 263 | mark_as_advanced(TBB_INCLUDE_DIRS TBB_LIBRARY_DIRS TBB_DEBUG_LIBRARY_DIRS TBB_LIBRARIES TBB_DEBUG_LIBRARIES) 264 | message(STATUS "Found Intel TBB") 265 | endif (TBB_LIBRARY) 266 | endif (TBB_INCLUDE_DIR) 267 | 268 | if (NOT TBB_FOUND) 269 | message("ERROR: Intel TBB NOT found!") 270 | message(STATUS "Looked for Threading Building Blocks in ${_TBB_INSTALL_DIR}") 271 | # do only throw fatal, if this pkg is REQUIRED 272 | if (TBB_FIND_REQUIRED) 273 | message(FATAL_ERROR "Could NOT find TBB library.") 274 | endif (TBB_FIND_REQUIRED) 275 | endif (NOT TBB_FOUND) 276 | 277 | endif (NOT _TBB_INSTALL_DIR) 278 | 279 | if (TBB_FOUND) 280 | set(TBB_INTERFACE_VERSION 0) 281 | FILE(READ "${TBB_INCLUDE_DIRS}/tbb/tbb_stddef.h" _TBB_VERSION_CONTENTS) 282 | STRING(REGEX REPLACE ".*#define TBB_INTERFACE_VERSION ([0-9]+).*" "\\1" TBB_INTERFACE_VERSION "${_TBB_VERSION_CONTENTS}") 283 | set(TBB_INTERFACE_VERSION "${TBB_INTERFACE_VERSION}") 284 | 285 | # create the runtime libraries 286 | if( WIN32 ) 287 | foreach( TBB_LIBRARY ${TBB_LIBRARIES} ) 288 | STRING( REGEX REPLACE "[.]lib" ".dll" TBB_LIBRARY_TMP ${TBB_LIBRARY} ) 289 | STRING( REGEX REPLACE "/lib/" "/bin/" TBB_LIBRARY_DLL ${TBB_LIBRARY_TMP} ) 290 | set( TBB_RUNTIME_LIBRARIES ${TBB_RUNTIME_LIBRARIES} ${TBB_LIBRARY_DLL} ) 291 | endforeach( TBB_LIBRARY ) 292 | else( WIN32 ) 293 | SET( TBB_RUNTIME_LIBRARIES ${TBB_LIBRARIES} ) 294 | endif( WIN32 ) 295 | endif (TBB_FOUND) 296 | --------------------------------------------------------------------------------