├── .gitignore ├── Doxyfile ├── LICENSE ├── Lambda.cbp ├── README.md ├── icon ├── 128.png ├── 16.png ├── 256.png ├── 32.png ├── 48.png ├── 64.png └── doxygen_icon.png ├── include ├── cameras │ ├── camera.hpp │ └── perspective.hpp ├── lights │ ├── light.hpp │ └── omni.hpp ├── materials │ ├── cooktorrance.hpp │ ├── diffuse.hpp │ ├── frostedglass.hpp │ ├── material.hpp │ ├── smoothglass.hpp │ └── specular.hpp ├── primitives │ ├── primitive.hpp │ ├── sphere.hpp │ └── triangle.hpp ├── renderer │ └── renderer.hpp ├── scenegraph │ └── bvh.hpp ├── spectral │ ├── blackbody.hpp │ ├── distribution.hpp │ ├── flat.hpp │ ├── peak.hpp │ └── sellmeier.hpp └── util │ ├── aabb.hpp │ ├── cie.hpp │ ├── rtmath.hpp │ └── vec3.hpp ├── render ├── README.md ├── ajax_lucy.png ├── frosted_dragon.png └── metal_lucy.png ├── scenes ├── cornellbox └── spheres └── src ├── cameras ├── camera.cpp └── perspective.cpp ├── lights ├── light.cpp └── omni.cpp ├── main.cpp ├── materials ├── cooktorrance.cpp ├── diffuse.cpp ├── frostedglass.cpp ├── material.cpp ├── smoothglass.cpp └── specular.cpp ├── primitives ├── primitive.cpp ├── sphere.cpp └── triangle.cpp ├── renderer └── renderer.cpp ├── scenegraph └── bvh.cpp ├── spectral ├── blackbody.cpp ├── distribution.cpp └── sellmeier.cpp └── util ├── aabb.cpp └── cie.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | # Never include compiled binaries nor documentation 2 | bin/ 3 | obj/ 4 | doc/ 5 | 6 | # Never include .ppm renders 7 | *.ppm 8 | 9 | # Code::Blocks temporary files 10 | *.layout 11 | *.depend 12 | -------------------------------------------------------------------------------- /Doxyfile: -------------------------------------------------------------------------------- 1 | # Doxyfile 1.7.6.1 2 | 3 | # This file describes the settings to be used by the documentation system 4 | # doxygen (www.doxygen.org) for a project 5 | # 6 | # All text after a hash (#) is considered a comment and will be ignored 7 | # The format is: 8 | # TAG = value [value, ...] 9 | # For lists items can also be appended using: 10 | # TAG += value [value, ...] 11 | # Values that contain spaces should be placed between quotes (" ") 12 | 13 | #--------------------------------------------------------------------------- 14 | # Project related configuration options 15 | #--------------------------------------------------------------------------- 16 | 17 | # This tag specifies the encoding used for all characters in the config file 18 | # that follow. The default is UTF-8 which is also the encoding used for all 19 | # text before the first occurrence of this tag. Doxygen uses libiconv (or the 20 | # iconv built into libc) for the transcoding. See 21 | # http://www.gnu.org/software/libiconv for the list of possible encodings. 22 | 23 | DOXYFILE_ENCODING = UTF-8 24 | 25 | # The PROJECT_NAME tag is a single word (or sequence of words) that should 26 | # identify the project. Note that if you do not use Doxywizard you need 27 | # to put quotes around the project name if it contains spaces. 28 | 29 | PROJECT_NAME = Lambda 30 | 31 | # The PROJECT_NUMBER tag can be used to enter a project or revision number. 32 | # This could be handy for archiving the generated documentation or 33 | # if some version control system is used. 34 | 35 | PROJECT_NUMBER = 36 | 37 | # Using the PROJECT_BRIEF tag one can provide an optional one line description 38 | # for a project that appears at the top of each page and should give viewer 39 | # a quick idea about the purpose of the project. Keep the description short. 40 | 41 | PROJECT_BRIEF = "Spectral Path Tracer" 42 | 43 | # With the PROJECT_LOGO tag one can specify an logo or icon that is 44 | # included in the documentation. The maximum height of the logo should not 45 | # exceed 55 pixels and the maximum width should not exceed 200 pixels. 46 | # Doxygen will copy the logo to the output directory. 47 | 48 | PROJECT_LOGO = /home/ray/Desktop/Lambda/icon/doxygen_icon.png 49 | 50 | # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) 51 | # base path where the generated documentation will be put. 52 | # If a relative path is entered, it will be relative to the location 53 | # where doxygen was started. If left blank the current directory will be used. 54 | 55 | OUTPUT_DIRECTORY = /home/ray/Desktop/Lambda/doc 56 | 57 | # If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 58 | # 4096 sub-directories (in 2 levels) under the output directory of each output 59 | # format and will distribute the generated files over these directories. 60 | # Enabling this option can be useful when feeding doxygen a huge amount of 61 | # source files, where putting all generated files in the same directory would 62 | # otherwise cause performance problems for the file system. 63 | 64 | CREATE_SUBDIRS = NO 65 | 66 | # The OUTPUT_LANGUAGE tag is used to specify the language in which all 67 | # documentation generated by doxygen is written. Doxygen will use this 68 | # information to generate all constant output in the proper language. 69 | # The default language is English, other supported languages are: 70 | # Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, 71 | # Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, 72 | # Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English 73 | # messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, 74 | # Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, 75 | # Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. 76 | 77 | OUTPUT_LANGUAGE = English 78 | 79 | # If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will 80 | # include brief member descriptions after the members that are listed in 81 | # the file and class documentation (similar to JavaDoc). 82 | # Set to NO to disable this. 83 | 84 | BRIEF_MEMBER_DESC = YES 85 | 86 | # If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend 87 | # the brief description of a member or function before the detailed description. 88 | # Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the 89 | # brief descriptions will be completely suppressed. 90 | 91 | REPEAT_BRIEF = YES 92 | 93 | # This tag implements a quasi-intelligent brief description abbreviator 94 | # that is used to form the text in various listings. Each string 95 | # in this list, if found as the leading text of the brief description, will be 96 | # stripped from the text and the result after processing the whole list, is 97 | # used as the annotated text. Otherwise, the brief description is used as-is. 98 | # If left blank, the following values are used ("$name" is automatically 99 | # replaced with the name of the entity): "The $name class" "The $name widget" 100 | # "The $name file" "is" "provides" "specifies" "contains" 101 | # "represents" "a" "an" "the" 102 | 103 | ABBREVIATE_BRIEF = "The $name class" \ 104 | "The $name widget" \ 105 | "The $name file" \ 106 | is \ 107 | provides \ 108 | specifies \ 109 | contains \ 110 | represents \ 111 | a \ 112 | an \ 113 | the 114 | 115 | # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then 116 | # Doxygen will generate a detailed section even if there is only a brief 117 | # description. 118 | 119 | ALWAYS_DETAILED_SEC = NO 120 | 121 | # If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all 122 | # inherited members of a class in the documentation of that class as if those 123 | # members were ordinary class members. Constructors, destructors and assignment 124 | # operators of the base classes will not be shown. 125 | 126 | INLINE_INHERITED_MEMB = NO 127 | 128 | # If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full 129 | # path before files name in the file list and in the header files. If set 130 | # to NO the shortest path that makes the file name unique will be used. 131 | 132 | FULL_PATH_NAMES = YES 133 | 134 | # If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag 135 | # can be used to strip a user-defined part of the path. Stripping is 136 | # only done if one of the specified strings matches the left-hand part of 137 | # the path. The tag can be used to show relative paths in the file list. 138 | # If left blank the directory from which doxygen is run is used as the 139 | # path to strip. 140 | 141 | STRIP_FROM_PATH = 142 | 143 | # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of 144 | # the path mentioned in the documentation of a class, which tells 145 | # the reader which header file to include in order to use a class. 146 | # If left blank only the name of the header file containing the class 147 | # definition is used. Otherwise one should specify the include paths that 148 | # are normally passed to the compiler using the -I flag. 149 | 150 | STRIP_FROM_INC_PATH = 151 | 152 | # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter 153 | # (but less readable) file names. This can be useful if your file system 154 | # doesn't support long names like on DOS, Mac, or CD-ROM. 155 | 156 | SHORT_NAMES = NO 157 | 158 | # If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen 159 | # will interpret the first line (until the first dot) of a JavaDoc-style 160 | # comment as the brief description. If set to NO, the JavaDoc 161 | # comments will behave just like regular Qt-style comments 162 | # (thus requiring an explicit @brief command for a brief description.) 163 | 164 | JAVADOC_AUTOBRIEF = NO 165 | 166 | # If the QT_AUTOBRIEF tag is set to YES then Doxygen will 167 | # interpret the first line (until the first dot) of a Qt-style 168 | # comment as the brief description. If set to NO, the comments 169 | # will behave just like regular Qt-style comments (thus requiring 170 | # an explicit \brief command for a brief description.) 171 | 172 | QT_AUTOBRIEF = NO 173 | 174 | # The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen 175 | # treat a multi-line C++ special comment block (i.e. a block of //! or /// 176 | # comments) as a brief description. This used to be the default behaviour. 177 | # The new default is to treat a multi-line C++ comment block as a detailed 178 | # description. Set this tag to YES if you prefer the old behaviour instead. 179 | 180 | MULTILINE_CPP_IS_BRIEF = NO 181 | 182 | # If the INHERIT_DOCS tag is set to YES (the default) then an undocumented 183 | # member inherits the documentation from any documented member that it 184 | # re-implements. 185 | 186 | INHERIT_DOCS = YES 187 | 188 | # If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce 189 | # a new page for each member. If set to NO, the documentation of a member will 190 | # be part of the file/class/namespace that contains it. 191 | 192 | SEPARATE_MEMBER_PAGES = NO 193 | 194 | # The TAB_SIZE tag can be used to set the number of spaces in a tab. 195 | # Doxygen uses this value to replace tabs by spaces in code fragments. 196 | 197 | TAB_SIZE = 8 198 | 199 | # This tag can be used to specify a number of aliases that acts 200 | # as commands in the documentation. An alias has the form "name=value". 201 | # For example adding "sideeffect=\par Side Effects:\n" will allow you to 202 | # put the command \sideeffect (or @sideeffect) in the documentation, which 203 | # will result in a user-defined paragraph with heading "Side Effects:". 204 | # You can put \n's in the value part of an alias to insert newlines. 205 | 206 | ALIASES = 207 | 208 | # This tag can be used to specify a number of word-keyword mappings (TCL only). 209 | # A mapping has the form "name=value". For example adding 210 | # "class=itcl::class" will allow you to use the command class in the 211 | # itcl::class meaning. 212 | 213 | TCL_SUBST = 214 | 215 | # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C 216 | # sources only. Doxygen will then generate output that is more tailored for C. 217 | # For instance, some of the names that are used will be different. The list 218 | # of all members will be omitted, etc. 219 | 220 | OPTIMIZE_OUTPUT_FOR_C = NO 221 | 222 | # Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java 223 | # sources only. Doxygen will then generate output that is more tailored for 224 | # Java. For instance, namespaces will be presented as packages, qualified 225 | # scopes will look different, etc. 226 | 227 | OPTIMIZE_OUTPUT_JAVA = NO 228 | 229 | # Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran 230 | # sources only. Doxygen will then generate output that is more tailored for 231 | # Fortran. 232 | 233 | OPTIMIZE_FOR_FORTRAN = NO 234 | 235 | # Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL 236 | # sources. Doxygen will then generate output that is tailored for 237 | # VHDL. 238 | 239 | OPTIMIZE_OUTPUT_VHDL = NO 240 | 241 | # Doxygen selects the parser to use depending on the extension of the files it 242 | # parses. With this tag you can assign which parser to use for a given extension. 243 | # Doxygen has a built-in mapping, but you can override or extend it using this 244 | # tag. The format is ext=language, where ext is a file extension, and language 245 | # is one of the parsers supported by doxygen: IDL, Java, Javascript, CSharp, C, 246 | # C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make 247 | # doxygen treat .inc files as Fortran files (default is PHP), and .f files as C 248 | # (default is Fortran), use: inc=Fortran f=C. Note that for custom extensions 249 | # you also need to set FILE_PATTERNS otherwise the files are not read by doxygen. 250 | 251 | EXTENSION_MAPPING = 252 | 253 | # If you use STL classes (i.e. std::string, std::vector, etc.) but do not want 254 | # to include (a tag file for) the STL sources as input, then you should 255 | # set this tag to YES in order to let doxygen match functions declarations and 256 | # definitions whose arguments contain STL classes (e.g. func(std::string); v.s. 257 | # func(std::string) {}). This also makes the inheritance and collaboration 258 | # diagrams that involve STL classes more complete and accurate. 259 | 260 | BUILTIN_STL_SUPPORT = NO 261 | 262 | # If you use Microsoft's C++/CLI language, you should set this option to YES to 263 | # enable parsing support. 264 | 265 | CPP_CLI_SUPPORT = NO 266 | 267 | # Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. 268 | # Doxygen will parse them like normal C++ but will assume all classes use public 269 | # instead of private inheritance when no explicit protection keyword is present. 270 | 271 | SIP_SUPPORT = NO 272 | 273 | # For Microsoft's IDL there are propget and propput attributes to indicate getter 274 | # and setter methods for a property. Setting this option to YES (the default) 275 | # will make doxygen replace the get and set methods by a property in the 276 | # documentation. This will only work if the methods are indeed getting or 277 | # setting a simple type. If this is not the case, or you want to show the 278 | # methods anyway, you should set this option to NO. 279 | 280 | IDL_PROPERTY_SUPPORT = YES 281 | 282 | # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC 283 | # tag is set to YES, then doxygen will reuse the documentation of the first 284 | # member in the group (if any) for the other members of the group. By default 285 | # all members of a group must be documented explicitly. 286 | 287 | DISTRIBUTE_GROUP_DOC = NO 288 | 289 | # Set the SUBGROUPING tag to YES (the default) to allow class member groups of 290 | # the same type (for instance a group of public functions) to be put as a 291 | # subgroup of that type (e.g. under the Public Functions section). Set it to 292 | # NO to prevent subgrouping. Alternatively, this can be done per class using 293 | # the \nosubgrouping command. 294 | 295 | SUBGROUPING = YES 296 | 297 | # When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and 298 | # unions are shown inside the group in which they are included (e.g. using 299 | # @ingroup) instead of on a separate page (for HTML and Man pages) or 300 | # section (for LaTeX and RTF). 301 | 302 | INLINE_GROUPED_CLASSES = NO 303 | 304 | # When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and 305 | # unions with only public data fields will be shown inline in the documentation 306 | # of the scope in which they are defined (i.e. file, namespace, or group 307 | # documentation), provided this scope is documented. If set to NO (the default), 308 | # structs, classes, and unions are shown on a separate page (for HTML and Man 309 | # pages) or section (for LaTeX and RTF). 310 | 311 | INLINE_SIMPLE_STRUCTS = NO 312 | 313 | # When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum 314 | # is documented as struct, union, or enum with the name of the typedef. So 315 | # typedef struct TypeS {} TypeT, will appear in the documentation as a struct 316 | # with name TypeT. When disabled the typedef will appear as a member of a file, 317 | # namespace, or class. And the struct will be named TypeS. This can typically 318 | # be useful for C code in case the coding convention dictates that all compound 319 | # types are typedef'ed and only the typedef is referenced, never the tag name. 320 | 321 | TYPEDEF_HIDES_STRUCT = NO 322 | 323 | # The SYMBOL_CACHE_SIZE determines the size of the internal cache use to 324 | # determine which symbols to keep in memory and which to flush to disk. 325 | # When the cache is full, less often used symbols will be written to disk. 326 | # For small to medium size projects (<1000 input files) the default value is 327 | # probably good enough. For larger projects a too small cache size can cause 328 | # doxygen to be busy swapping symbols to and from disk most of the time 329 | # causing a significant performance penalty. 330 | # If the system has enough physical memory increasing the cache will improve the 331 | # performance by keeping more symbols in memory. Note that the value works on 332 | # a logarithmic scale so increasing the size by one will roughly double the 333 | # memory usage. The cache size is given by this formula: 334 | # 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, 335 | # corresponding to a cache size of 2^16 = 65536 symbols. 336 | 337 | SYMBOL_CACHE_SIZE = 0 338 | 339 | # Similar to the SYMBOL_CACHE_SIZE the size of the symbol lookup cache can be 340 | # set using LOOKUP_CACHE_SIZE. This cache is used to resolve symbols given 341 | # their name and scope. Since this can be an expensive process and often the 342 | # same symbol appear multiple times in the code, doxygen keeps a cache of 343 | # pre-resolved symbols. If the cache is too small doxygen will become slower. 344 | # If the cache is too large, memory is wasted. The cache size is given by this 345 | # formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range is 0..9, the default is 0, 346 | # corresponding to a cache size of 2^16 = 65536 symbols. 347 | 348 | LOOKUP_CACHE_SIZE = 0 349 | 350 | #--------------------------------------------------------------------------- 351 | # Build related configuration options 352 | #--------------------------------------------------------------------------- 353 | 354 | # If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in 355 | # documentation are documented, even if no documentation was available. 356 | # Private class members and static file members will be hidden unless 357 | # the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES 358 | 359 | EXTRACT_ALL = NO 360 | 361 | # If the EXTRACT_PRIVATE tag is set to YES all private members of a class 362 | # will be included in the documentation. 363 | 364 | EXTRACT_PRIVATE = NO 365 | 366 | # If the EXTRACT_STATIC tag is set to YES all static members of a file 367 | # will be included in the documentation. 368 | 369 | EXTRACT_STATIC = NO 370 | 371 | # If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) 372 | # defined locally in source files will be included in the documentation. 373 | # If set to NO only classes defined in header files are included. 374 | 375 | EXTRACT_LOCAL_CLASSES = YES 376 | 377 | # This flag is only useful for Objective-C code. When set to YES local 378 | # methods, which are defined in the implementation section but not in 379 | # the interface are included in the documentation. 380 | # If set to NO (the default) only methods in the interface are included. 381 | 382 | EXTRACT_LOCAL_METHODS = NO 383 | 384 | # If this flag is set to YES, the members of anonymous namespaces will be 385 | # extracted and appear in the documentation as a namespace called 386 | # 'anonymous_namespace{file}', where file will be replaced with the base 387 | # name of the file that contains the anonymous namespace. By default 388 | # anonymous namespaces are hidden. 389 | 390 | EXTRACT_ANON_NSPACES = NO 391 | 392 | # If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all 393 | # undocumented members of documented classes, files or namespaces. 394 | # If set to NO (the default) these members will be included in the 395 | # various overviews, but no documentation section is generated. 396 | # This option has no effect if EXTRACT_ALL is enabled. 397 | 398 | HIDE_UNDOC_MEMBERS = NO 399 | 400 | # If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all 401 | # undocumented classes that are normally visible in the class hierarchy. 402 | # If set to NO (the default) these classes will be included in the various 403 | # overviews. This option has no effect if EXTRACT_ALL is enabled. 404 | 405 | HIDE_UNDOC_CLASSES = NO 406 | 407 | # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all 408 | # friend (class|struct|union) declarations. 409 | # If set to NO (the default) these declarations will be included in the 410 | # documentation. 411 | 412 | HIDE_FRIEND_COMPOUNDS = NO 413 | 414 | # If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any 415 | # documentation blocks found inside the body of a function. 416 | # If set to NO (the default) these blocks will be appended to the 417 | # function's detailed documentation block. 418 | 419 | HIDE_IN_BODY_DOCS = NO 420 | 421 | # The INTERNAL_DOCS tag determines if documentation 422 | # that is typed after a \internal command is included. If the tag is set 423 | # to NO (the default) then the documentation will be excluded. 424 | # Set it to YES to include the internal documentation. 425 | 426 | INTERNAL_DOCS = NO 427 | 428 | # If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate 429 | # file names in lower-case letters. If set to YES upper-case letters are also 430 | # allowed. This is useful if you have classes or files whose names only differ 431 | # in case and if your file system supports case sensitive file names. Windows 432 | # and Mac users are advised to set this option to NO. 433 | 434 | CASE_SENSE_NAMES = NO 435 | 436 | # If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen 437 | # will show members with their full class and namespace scopes in the 438 | # documentation. If set to YES the scope will be hidden. 439 | 440 | HIDE_SCOPE_NAMES = NO 441 | 442 | # If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen 443 | # will put a list of the files that are included by a file in the documentation 444 | # of that file. 445 | 446 | SHOW_INCLUDE_FILES = YES 447 | 448 | # If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen 449 | # will list include files with double quotes in the documentation 450 | # rather than with sharp brackets. 451 | 452 | FORCE_LOCAL_INCLUDES = NO 453 | 454 | # If the INLINE_INFO tag is set to YES (the default) then a tag [inline] 455 | # is inserted in the documentation for inline members. 456 | 457 | INLINE_INFO = YES 458 | 459 | # If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen 460 | # will sort the (detailed) documentation of file and class members 461 | # alphabetically by member name. If set to NO the members will appear in 462 | # declaration order. 463 | 464 | SORT_MEMBER_DOCS = YES 465 | 466 | # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the 467 | # brief documentation of file, namespace and class members alphabetically 468 | # by member name. If set to NO (the default) the members will appear in 469 | # declaration order. 470 | 471 | SORT_BRIEF_DOCS = NO 472 | 473 | # If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen 474 | # will sort the (brief and detailed) documentation of class members so that 475 | # constructors and destructors are listed first. If set to NO (the default) 476 | # the constructors will appear in the respective orders defined by 477 | # SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. 478 | # This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO 479 | # and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. 480 | 481 | SORT_MEMBERS_CTORS_1ST = NO 482 | 483 | # If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the 484 | # hierarchy of group names into alphabetical order. If set to NO (the default) 485 | # the group names will appear in their defined order. 486 | 487 | SORT_GROUP_NAMES = NO 488 | 489 | # If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be 490 | # sorted by fully-qualified names, including namespaces. If set to 491 | # NO (the default), the class list will be sorted only by class name, 492 | # not including the namespace part. 493 | # Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. 494 | # Note: This option applies only to the class list, not to the 495 | # alphabetical list. 496 | 497 | SORT_BY_SCOPE_NAME = NO 498 | 499 | # If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to 500 | # do proper type resolution of all parameters of a function it will reject a 501 | # match between the prototype and the implementation of a member function even 502 | # if there is only one candidate or it is obvious which candidate to choose 503 | # by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen 504 | # will still accept a match between prototype and implementation in such cases. 505 | 506 | STRICT_PROTO_MATCHING = NO 507 | 508 | # The GENERATE_TODOLIST tag can be used to enable (YES) or 509 | # disable (NO) the todo list. This list is created by putting \todo 510 | # commands in the documentation. 511 | 512 | GENERATE_TODOLIST = YES 513 | 514 | # The GENERATE_TESTLIST tag can be used to enable (YES) or 515 | # disable (NO) the test list. This list is created by putting \test 516 | # commands in the documentation. 517 | 518 | GENERATE_TESTLIST = YES 519 | 520 | # The GENERATE_BUGLIST tag can be used to enable (YES) or 521 | # disable (NO) the bug list. This list is created by putting \bug 522 | # commands in the documentation. 523 | 524 | GENERATE_BUGLIST = YES 525 | 526 | # The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or 527 | # disable (NO) the deprecated list. This list is created by putting 528 | # \deprecated commands in the documentation. 529 | 530 | GENERATE_DEPRECATEDLIST= YES 531 | 532 | # The ENABLED_SECTIONS tag can be used to enable conditional 533 | # documentation sections, marked by \if sectionname ... \endif. 534 | 535 | ENABLED_SECTIONS = 536 | 537 | # The MAX_INITIALIZER_LINES tag determines the maximum number of lines 538 | # the initial value of a variable or macro consists of for it to appear in 539 | # the documentation. If the initializer consists of more lines than specified 540 | # here it will be hidden. Use a value of 0 to hide initializers completely. 541 | # The appearance of the initializer of individual variables and macros in the 542 | # documentation can be controlled using \showinitializer or \hideinitializer 543 | # command in the documentation regardless of this setting. 544 | 545 | MAX_INITIALIZER_LINES = 30 546 | 547 | # Set the SHOW_USED_FILES tag to NO to disable the list of files generated 548 | # at the bottom of the documentation of classes and structs. If set to YES the 549 | # list will mention the files that were used to generate the documentation. 550 | 551 | SHOW_USED_FILES = YES 552 | 553 | # If the sources in your project are distributed over multiple directories 554 | # then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy 555 | # in the documentation. The default is NO. 556 | 557 | SHOW_DIRECTORIES = YES 558 | 559 | # Set the SHOW_FILES tag to NO to disable the generation of the Files page. 560 | # This will remove the Files entry from the Quick Index and from the 561 | # Folder Tree View (if specified). The default is YES. 562 | 563 | SHOW_FILES = YES 564 | 565 | # Set the SHOW_NAMESPACES tag to NO to disable the generation of the 566 | # Namespaces page. This will remove the Namespaces entry from the Quick Index 567 | # and from the Folder Tree View (if specified). The default is YES. 568 | 569 | SHOW_NAMESPACES = YES 570 | 571 | # The FILE_VERSION_FILTER tag can be used to specify a program or script that 572 | # doxygen should invoke to get the current version for each file (typically from 573 | # the version control system). Doxygen will invoke the program by executing (via 574 | # popen()) the command , where is the value of 575 | # the FILE_VERSION_FILTER tag, and is the name of an input file 576 | # provided by doxygen. Whatever the program writes to standard output 577 | # is used as the file version. See the manual for examples. 578 | 579 | FILE_VERSION_FILTER = 580 | 581 | # The LAYOUT_FILE tag can be used to specify a layout file which will be parsed 582 | # by doxygen. The layout file controls the global structure of the generated 583 | # output files in an output format independent way. The create the layout file 584 | # that represents doxygen's defaults, run doxygen with the -l option. 585 | # You can optionally specify a file name after the option, if omitted 586 | # DoxygenLayout.xml will be used as the name of the layout file. 587 | 588 | LAYOUT_FILE = 589 | 590 | # The CITE_BIB_FILES tag can be used to specify one or more bib files 591 | # containing the references data. This must be a list of .bib files. The 592 | # .bib extension is automatically appended if omitted. Using this command 593 | # requires the bibtex tool to be installed. See also 594 | # http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style 595 | # of the bibliography can be controlled using LATEX_BIB_STYLE. To use this 596 | # feature you need bibtex and perl available in the search path. 597 | 598 | CITE_BIB_FILES = 599 | 600 | #--------------------------------------------------------------------------- 601 | # configuration options related to warning and progress messages 602 | #--------------------------------------------------------------------------- 603 | 604 | # The QUIET tag can be used to turn on/off the messages that are generated 605 | # by doxygen. Possible values are YES and NO. If left blank NO is used. 606 | 607 | QUIET = NO 608 | 609 | # The WARNINGS tag can be used to turn on/off the warning messages that are 610 | # generated by doxygen. Possible values are YES and NO. If left blank 611 | # NO is used. 612 | 613 | WARNINGS = YES 614 | 615 | # If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings 616 | # for undocumented members. If EXTRACT_ALL is set to YES then this flag will 617 | # automatically be disabled. 618 | 619 | WARN_IF_UNDOCUMENTED = YES 620 | 621 | # If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for 622 | # potential errors in the documentation, such as not documenting some 623 | # parameters in a documented function, or documenting parameters that 624 | # don't exist or using markup commands wrongly. 625 | 626 | WARN_IF_DOC_ERROR = YES 627 | 628 | # The WARN_NO_PARAMDOC option can be enabled to get warnings for 629 | # functions that are documented, but have no documentation for their parameters 630 | # or return value. If set to NO (the default) doxygen will only warn about 631 | # wrong or incomplete parameter documentation, but not about the absence of 632 | # documentation. 633 | 634 | WARN_NO_PARAMDOC = NO 635 | 636 | # The WARN_FORMAT tag determines the format of the warning messages that 637 | # doxygen can produce. The string should contain the $file, $line, and $text 638 | # tags, which will be replaced by the file and line number from which the 639 | # warning originated and the warning text. Optionally the format may contain 640 | # $version, which will be replaced by the version of the file (if it could 641 | # be obtained via FILE_VERSION_FILTER) 642 | 643 | WARN_FORMAT = "$file:$line: $text" 644 | 645 | # The WARN_LOGFILE tag can be used to specify a file to which warning 646 | # and error messages should be written. If left blank the output is written 647 | # to stderr. 648 | 649 | WARN_LOGFILE = 650 | 651 | #--------------------------------------------------------------------------- 652 | # configuration options related to the input files 653 | #--------------------------------------------------------------------------- 654 | 655 | # The INPUT tag can be used to specify the files and/or directories that contain 656 | # documented source files. You may enter file names like "myfile.cpp" or 657 | # directories like "/usr/src/myproject". Separate the files or directories 658 | # with spaces. 659 | 660 | INPUT = /home/ray/Desktop/Lambda 661 | 662 | # This tag can be used to specify the character encoding of the source files 663 | # that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is 664 | # also the default input encoding. Doxygen uses libiconv (or the iconv built 665 | # into libc) for the transcoding. See http://www.gnu.org/software/libiconv for 666 | # the list of possible encodings. 667 | 668 | INPUT_ENCODING = UTF-8 669 | 670 | # If the value of the INPUT tag contains directories, you can use the 671 | # FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp 672 | # and *.h) to filter out the source-files in the directories. If left 673 | # blank the following patterns are tested: 674 | # *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh 675 | # *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py 676 | # *.f90 *.f *.for *.vhd *.vhdl 677 | 678 | FILE_PATTERNS = *.c \ 679 | *.cc \ 680 | *.cxx \ 681 | *.cpp \ 682 | *.c++ \ 683 | *.d \ 684 | *.java \ 685 | *.ii \ 686 | *.ixx \ 687 | *.ipp \ 688 | *.i++ \ 689 | *.inl \ 690 | *.h \ 691 | *.hh \ 692 | *.hxx \ 693 | *.hpp \ 694 | *.h++ \ 695 | *.idl \ 696 | *.odl \ 697 | *.cs \ 698 | *.php \ 699 | *.php3 \ 700 | *.inc \ 701 | *.m \ 702 | *.mm \ 703 | *.dox \ 704 | *.py \ 705 | *.f90 \ 706 | *.f \ 707 | *.for \ 708 | *.vhd \ 709 | *.vhdl 710 | 711 | # The RECURSIVE tag can be used to turn specify whether or not subdirectories 712 | # should be searched for input files as well. Possible values are YES and NO. 713 | # If left blank NO is used. 714 | 715 | RECURSIVE = YES 716 | 717 | # The EXCLUDE tag can be used to specify files and/or directories that should be 718 | # excluded from the INPUT source files. This way you can easily exclude a 719 | # subdirectory from a directory tree whose root is specified with the INPUT tag. 720 | # Note that relative paths are relative to the directory from which doxygen is 721 | # run. 722 | 723 | EXCLUDE = 724 | 725 | # The EXCLUDE_SYMLINKS tag can be used to select whether or not files or 726 | # directories that are symbolic links (a Unix file system feature) are excluded 727 | # from the input. 728 | 729 | EXCLUDE_SYMLINKS = NO 730 | 731 | # If the value of the INPUT tag contains directories, you can use the 732 | # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude 733 | # certain files from those directories. Note that the wildcards are matched 734 | # against the file with absolute path, so to exclude all test directories 735 | # for example use the pattern */test/* 736 | 737 | EXCLUDE_PATTERNS = 738 | 739 | # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names 740 | # (namespaces, classes, functions, etc.) that should be excluded from the 741 | # output. The symbol name can be a fully qualified name, a word, or if the 742 | # wildcard * is used, a substring. Examples: ANamespace, AClass, 743 | # AClass::ANamespace, ANamespace::*Test 744 | 745 | EXCLUDE_SYMBOLS = 746 | 747 | # The EXAMPLE_PATH tag can be used to specify one or more files or 748 | # directories that contain example code fragments that are included (see 749 | # the \include command). 750 | 751 | EXAMPLE_PATH = 752 | 753 | # If the value of the EXAMPLE_PATH tag contains directories, you can use the 754 | # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp 755 | # and *.h) to filter out the source-files in the directories. If left 756 | # blank all files are included. 757 | 758 | EXAMPLE_PATTERNS = * 759 | 760 | # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be 761 | # searched for input files to be used with the \include or \dontinclude 762 | # commands irrespective of the value of the RECURSIVE tag. 763 | # Possible values are YES and NO. If left blank NO is used. 764 | 765 | EXAMPLE_RECURSIVE = NO 766 | 767 | # The IMAGE_PATH tag can be used to specify one or more files or 768 | # directories that contain image that are included in the documentation (see 769 | # the \image command). 770 | 771 | IMAGE_PATH = 772 | 773 | # The INPUT_FILTER tag can be used to specify a program that doxygen should 774 | # invoke to filter for each input file. Doxygen will invoke the filter program 775 | # by executing (via popen()) the command , where 776 | # is the value of the INPUT_FILTER tag, and is the name of an 777 | # input file. Doxygen will then use the output that the filter program writes 778 | # to standard output. If FILTER_PATTERNS is specified, this tag will be 779 | # ignored. 780 | 781 | INPUT_FILTER = 782 | 783 | # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern 784 | # basis. Doxygen will compare the file name with each pattern and apply the 785 | # filter if there is a match. The filters are a list of the form: 786 | # pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further 787 | # info on how filters are used. If FILTER_PATTERNS is empty or if 788 | # non of the patterns match the file name, INPUT_FILTER is applied. 789 | 790 | FILTER_PATTERNS = 791 | 792 | # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using 793 | # INPUT_FILTER) will be used to filter the input files when producing source 794 | # files to browse (i.e. when SOURCE_BROWSER is set to YES). 795 | 796 | FILTER_SOURCE_FILES = NO 797 | 798 | # The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file 799 | # pattern. A pattern will override the setting for FILTER_PATTERN (if any) 800 | # and it is also possible to disable source filtering for a specific pattern 801 | # using *.ext= (so without naming a filter). This option only has effect when 802 | # FILTER_SOURCE_FILES is enabled. 803 | 804 | FILTER_SOURCE_PATTERNS = 805 | 806 | #--------------------------------------------------------------------------- 807 | # configuration options related to source browsing 808 | #--------------------------------------------------------------------------- 809 | 810 | # If the SOURCE_BROWSER tag is set to YES then a list of source files will 811 | # be generated. Documented entities will be cross-referenced with these sources. 812 | # Note: To get rid of all source code in the generated output, make sure also 813 | # VERBATIM_HEADERS is set to NO. 814 | 815 | SOURCE_BROWSER = NO 816 | 817 | # Setting the INLINE_SOURCES tag to YES will include the body 818 | # of functions and classes directly in the documentation. 819 | 820 | INLINE_SOURCES = NO 821 | 822 | # Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct 823 | # doxygen to hide any special comment blocks from generated source code 824 | # fragments. Normal C and C++ comments will always remain visible. 825 | 826 | STRIP_CODE_COMMENTS = YES 827 | 828 | # If the REFERENCED_BY_RELATION tag is set to YES 829 | # then for each documented function all documented 830 | # functions referencing it will be listed. 831 | 832 | REFERENCED_BY_RELATION = NO 833 | 834 | # If the REFERENCES_RELATION tag is set to YES 835 | # then for each documented function all documented entities 836 | # called/used by that function will be listed. 837 | 838 | REFERENCES_RELATION = NO 839 | 840 | # If the REFERENCES_LINK_SOURCE tag is set to YES (the default) 841 | # and SOURCE_BROWSER tag is set to YES, then the hyperlinks from 842 | # functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will 843 | # link to the source code. Otherwise they will link to the documentation. 844 | 845 | REFERENCES_LINK_SOURCE = YES 846 | 847 | # If the USE_HTAGS tag is set to YES then the references to source code 848 | # will point to the HTML generated by the htags(1) tool instead of doxygen 849 | # built-in source browser. The htags tool is part of GNU's global source 850 | # tagging system (see http://www.gnu.org/software/global/global.html). You 851 | # will need version 4.8.6 or higher. 852 | 853 | USE_HTAGS = NO 854 | 855 | # If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen 856 | # will generate a verbatim copy of the header file for each class for 857 | # which an include is specified. Set to NO to disable this. 858 | 859 | VERBATIM_HEADERS = YES 860 | 861 | #--------------------------------------------------------------------------- 862 | # configuration options related to the alphabetical class index 863 | #--------------------------------------------------------------------------- 864 | 865 | # If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index 866 | # of all compounds will be generated. Enable this if the project 867 | # contains a lot of classes, structs, unions or interfaces. 868 | 869 | ALPHABETICAL_INDEX = YES 870 | 871 | # If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then 872 | # the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns 873 | # in which this list will be split (can be a number in the range [1..20]) 874 | 875 | COLS_IN_ALPHA_INDEX = 5 876 | 877 | # In case all classes in a project start with a common prefix, all 878 | # classes will be put under the same header in the alphabetical index. 879 | # The IGNORE_PREFIX tag can be used to specify one or more prefixes that 880 | # should be ignored while generating the index headers. 881 | 882 | IGNORE_PREFIX = 883 | 884 | #--------------------------------------------------------------------------- 885 | # configuration options related to the HTML output 886 | #--------------------------------------------------------------------------- 887 | 888 | # If the GENERATE_HTML tag is set to YES (the default) Doxygen will 889 | # generate HTML output. 890 | 891 | GENERATE_HTML = YES 892 | 893 | # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. 894 | # If a relative path is entered the value of OUTPUT_DIRECTORY will be 895 | # put in front of it. If left blank `html' will be used as the default path. 896 | 897 | HTML_OUTPUT = html 898 | 899 | # The HTML_FILE_EXTENSION tag can be used to specify the file extension for 900 | # each generated HTML page (for example: .htm,.php,.asp). If it is left blank 901 | # doxygen will generate files with .html extension. 902 | 903 | HTML_FILE_EXTENSION = .html 904 | 905 | # The HTML_HEADER tag can be used to specify a personal HTML header for 906 | # each generated HTML page. If it is left blank doxygen will generate a 907 | # standard header. Note that when using a custom header you are responsible 908 | # for the proper inclusion of any scripts and style sheets that doxygen 909 | # needs, which is dependent on the configuration options used. 910 | # It is advised to generate a default header using "doxygen -w html 911 | # header.html footer.html stylesheet.css YourConfigFile" and then modify 912 | # that header. Note that the header is subject to change so you typically 913 | # have to redo this when upgrading to a newer version of doxygen or when 914 | # changing the value of configuration settings such as GENERATE_TREEVIEW! 915 | 916 | HTML_HEADER = 917 | 918 | # The HTML_FOOTER tag can be used to specify a personal HTML footer for 919 | # each generated HTML page. If it is left blank doxygen will generate a 920 | # standard footer. 921 | 922 | HTML_FOOTER = 923 | 924 | # The HTML_STYLESHEET tag can be used to specify a user-defined cascading 925 | # style sheet that is used by each HTML page. It can be used to 926 | # fine-tune the look of the HTML output. If the tag is left blank doxygen 927 | # will generate a default style sheet. Note that doxygen will try to copy 928 | # the style sheet file to the HTML output directory, so don't put your own 929 | # style sheet in the HTML output directory as well, or it will be erased! 930 | 931 | HTML_STYLESHEET = 932 | 933 | # The HTML_EXTRA_FILES tag can be used to specify one or more extra images or 934 | # other source files which should be copied to the HTML output directory. Note 935 | # that these files will be copied to the base HTML output directory. Use the 936 | # $relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these 937 | # files. In the HTML_STYLESHEET file, use the file name only. Also note that 938 | # the files will be copied as-is; there are no commands or markers available. 939 | 940 | HTML_EXTRA_FILES = 941 | 942 | # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. 943 | # Doxygen will adjust the colors in the style sheet and background images 944 | # according to this color. Hue is specified as an angle on a colorwheel, 945 | # see http://en.wikipedia.org/wiki/Hue for more information. 946 | # For instance the value 0 represents red, 60 is yellow, 120 is green, 947 | # 180 is cyan, 240 is blue, 300 purple, and 360 is red again. 948 | # The allowed range is 0 to 359. 949 | 950 | HTML_COLORSTYLE_HUE = 220 951 | 952 | # The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of 953 | # the colors in the HTML output. For a value of 0 the output will use 954 | # grayscales only. A value of 255 will produce the most vivid colors. 955 | 956 | HTML_COLORSTYLE_SAT = 100 957 | 958 | # The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to 959 | # the luminance component of the colors in the HTML output. Values below 960 | # 100 gradually make the output lighter, whereas values above 100 make 961 | # the output darker. The value divided by 100 is the actual gamma applied, 962 | # so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2, 963 | # and 100 does not change the gamma. 964 | 965 | HTML_COLORSTYLE_GAMMA = 80 966 | 967 | # If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML 968 | # page will contain the date and time when the page was generated. Setting 969 | # this to NO can help when comparing the output of multiple runs. 970 | 971 | HTML_TIMESTAMP = YES 972 | 973 | # If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, 974 | # files or namespaces will be aligned in HTML using tables. If set to 975 | # NO a bullet list will be used. 976 | 977 | HTML_ALIGN_MEMBERS = YES 978 | 979 | # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML 980 | # documentation will contain sections that can be hidden and shown after the 981 | # page has loaded. For this to work a browser that supports 982 | # JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox 983 | # Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). 984 | 985 | HTML_DYNAMIC_SECTIONS = NO 986 | 987 | # If the GENERATE_DOCSET tag is set to YES, additional index files 988 | # will be generated that can be used as input for Apple's Xcode 3 989 | # integrated development environment, introduced with OSX 10.5 (Leopard). 990 | # To create a documentation set, doxygen will generate a Makefile in the 991 | # HTML output directory. Running make will produce the docset in that 992 | # directory and running "make install" will install the docset in 993 | # ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find 994 | # it at startup. 995 | # See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html 996 | # for more information. 997 | 998 | GENERATE_DOCSET = NO 999 | 1000 | # When GENERATE_DOCSET tag is set to YES, this tag determines the name of the 1001 | # feed. A documentation feed provides an umbrella under which multiple 1002 | # documentation sets from a single provider (such as a company or product suite) 1003 | # can be grouped. 1004 | 1005 | DOCSET_FEEDNAME = "Doxygen generated docs" 1006 | 1007 | # When GENERATE_DOCSET tag is set to YES, this tag specifies a string that 1008 | # should uniquely identify the documentation set bundle. This should be a 1009 | # reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen 1010 | # will append .docset to the name. 1011 | 1012 | DOCSET_BUNDLE_ID = org.doxygen.Project 1013 | 1014 | # When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify 1015 | # the documentation publisher. This should be a reverse domain-name style 1016 | # string, e.g. com.mycompany.MyDocSet.documentation. 1017 | 1018 | DOCSET_PUBLISHER_ID = org.doxygen.Publisher 1019 | 1020 | # The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher. 1021 | 1022 | DOCSET_PUBLISHER_NAME = Publisher 1023 | 1024 | # If the GENERATE_HTMLHELP tag is set to YES, additional index files 1025 | # will be generated that can be used as input for tools like the 1026 | # Microsoft HTML help workshop to generate a compiled HTML help file (.chm) 1027 | # of the generated HTML documentation. 1028 | 1029 | GENERATE_HTMLHELP = NO 1030 | 1031 | # If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can 1032 | # be used to specify the file name of the resulting .chm file. You 1033 | # can add a path in front of the file if the result should not be 1034 | # written to the html output directory. 1035 | 1036 | CHM_FILE = 1037 | 1038 | # If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can 1039 | # be used to specify the location (absolute path including file name) of 1040 | # the HTML help compiler (hhc.exe). If non-empty doxygen will try to run 1041 | # the HTML help compiler on the generated index.hhp. 1042 | 1043 | HHC_LOCATION = 1044 | 1045 | # If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag 1046 | # controls if a separate .chi index file is generated (YES) or that 1047 | # it should be included in the master .chm file (NO). 1048 | 1049 | GENERATE_CHI = NO 1050 | 1051 | # If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING 1052 | # is used to encode HtmlHelp index (hhk), content (hhc) and project file 1053 | # content. 1054 | 1055 | CHM_INDEX_ENCODING = 1056 | 1057 | # If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag 1058 | # controls whether a binary table of contents is generated (YES) or a 1059 | # normal table of contents (NO) in the .chm file. 1060 | 1061 | BINARY_TOC = NO 1062 | 1063 | # The TOC_EXPAND flag can be set to YES to add extra items for group members 1064 | # to the contents of the HTML help documentation and to the tree view. 1065 | 1066 | TOC_EXPAND = NO 1067 | 1068 | # If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and 1069 | # QHP_VIRTUAL_FOLDER are set, an additional index file will be generated 1070 | # that can be used as input for Qt's qhelpgenerator to generate a 1071 | # Qt Compressed Help (.qch) of the generated HTML documentation. 1072 | 1073 | GENERATE_QHP = NO 1074 | 1075 | # If the QHG_LOCATION tag is specified, the QCH_FILE tag can 1076 | # be used to specify the file name of the resulting .qch file. 1077 | # The path specified is relative to the HTML output folder. 1078 | 1079 | QCH_FILE = 1080 | 1081 | # The QHP_NAMESPACE tag specifies the namespace to use when generating 1082 | # Qt Help Project output. For more information please see 1083 | # http://doc.trolltech.com/qthelpproject.html#namespace 1084 | 1085 | QHP_NAMESPACE = org.doxygen.Project 1086 | 1087 | # The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating 1088 | # Qt Help Project output. For more information please see 1089 | # http://doc.trolltech.com/qthelpproject.html#virtual-folders 1090 | 1091 | QHP_VIRTUAL_FOLDER = doc 1092 | 1093 | # If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to 1094 | # add. For more information please see 1095 | # http://doc.trolltech.com/qthelpproject.html#custom-filters 1096 | 1097 | QHP_CUST_FILTER_NAME = 1098 | 1099 | # The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the 1100 | # custom filter to add. For more information please see 1101 | # 1102 | # Qt Help Project / Custom Filters. 1103 | 1104 | QHP_CUST_FILTER_ATTRS = 1105 | 1106 | # The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this 1107 | # project's 1108 | # filter section matches. 1109 | # 1110 | # Qt Help Project / Filter Attributes. 1111 | 1112 | QHP_SECT_FILTER_ATTRS = 1113 | 1114 | # If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can 1115 | # be used to specify the location of Qt's qhelpgenerator. 1116 | # If non-empty doxygen will try to run qhelpgenerator on the generated 1117 | # .qhp file. 1118 | 1119 | QHG_LOCATION = 1120 | 1121 | # If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files 1122 | # will be generated, which together with the HTML files, form an Eclipse help 1123 | # plugin. To install this plugin and make it available under the help contents 1124 | # menu in Eclipse, the contents of the directory containing the HTML and XML 1125 | # files needs to be copied into the plugins directory of eclipse. The name of 1126 | # the directory within the plugins directory should be the same as 1127 | # the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before 1128 | # the help appears. 1129 | 1130 | GENERATE_ECLIPSEHELP = NO 1131 | 1132 | # A unique identifier for the eclipse help plugin. When installing the plugin 1133 | # the directory name containing the HTML and XML files should also have 1134 | # this name. 1135 | 1136 | ECLIPSE_DOC_ID = org.doxygen.Project 1137 | 1138 | # The DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) 1139 | # at top of each HTML page. The value NO (the default) enables the index and 1140 | # the value YES disables it. Since the tabs have the same information as the 1141 | # navigation tree you can set this option to NO if you already set 1142 | # GENERATE_TREEVIEW to YES. 1143 | 1144 | DISABLE_INDEX = NO 1145 | 1146 | # The GENERATE_TREEVIEW tag is used to specify whether a tree-like index 1147 | # structure should be generated to display hierarchical information. 1148 | # If the tag value is set to YES, a side panel will be generated 1149 | # containing a tree-like index structure (just like the one that 1150 | # is generated for HTML Help). For this to work a browser that supports 1151 | # JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). 1152 | # Windows users are probably better off using the HTML help feature. 1153 | # Since the tree basically has the same information as the tab index you 1154 | # could consider to set DISABLE_INDEX to NO when enabling this option. 1155 | 1156 | GENERATE_TREEVIEW = NO 1157 | 1158 | # The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values 1159 | # (range [0,1..20]) that doxygen will group on one line in the generated HTML 1160 | # documentation. Note that a value of 0 will completely suppress the enum 1161 | # values from appearing in the overview section. 1162 | 1163 | ENUM_VALUES_PER_LINE = 4 1164 | 1165 | # By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories, 1166 | # and Class Hierarchy pages using a tree view instead of an ordered list. 1167 | 1168 | USE_INLINE_TREES = NO 1169 | 1170 | # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be 1171 | # used to set the initial width (in pixels) of the frame in which the tree 1172 | # is shown. 1173 | 1174 | TREEVIEW_WIDTH = 250 1175 | 1176 | # When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open 1177 | # links to external symbols imported via tag files in a separate window. 1178 | 1179 | EXT_LINKS_IN_WINDOW = NO 1180 | 1181 | # Use this tag to change the font size of Latex formulas included 1182 | # as images in the HTML documentation. The default is 10. Note that 1183 | # when you change the font size after a successful doxygen run you need 1184 | # to manually remove any form_*.png images from the HTML output directory 1185 | # to force them to be regenerated. 1186 | 1187 | FORMULA_FONTSIZE = 10 1188 | 1189 | # Use the FORMULA_TRANPARENT tag to determine whether or not the images 1190 | # generated for formulas are transparent PNGs. Transparent PNGs are 1191 | # not supported properly for IE 6.0, but are supported on all modern browsers. 1192 | # Note that when changing this option you need to delete any form_*.png files 1193 | # in the HTML output before the changes have effect. 1194 | 1195 | FORMULA_TRANSPARENT = YES 1196 | 1197 | # Enable the USE_MATHJAX option to render LaTeX formulas using MathJax 1198 | # (see http://www.mathjax.org) which uses client side Javascript for the 1199 | # rendering instead of using prerendered bitmaps. Use this if you do not 1200 | # have LaTeX installed or if you want to formulas look prettier in the HTML 1201 | # output. When enabled you also need to install MathJax separately and 1202 | # configure the path to it using the MATHJAX_RELPATH option. 1203 | 1204 | USE_MATHJAX = NO 1205 | 1206 | # When MathJax is enabled you need to specify the location relative to the 1207 | # HTML output directory using the MATHJAX_RELPATH option. The destination 1208 | # directory should contain the MathJax.js script. For instance, if the mathjax 1209 | # directory is located at the same level as the HTML output directory, then 1210 | # MATHJAX_RELPATH should be ../mathjax. The default value points to the 1211 | # mathjax.org site, so you can quickly see the result without installing 1212 | # MathJax, but it is strongly recommended to install a local copy of MathJax 1213 | # before deployment. 1214 | 1215 | MATHJAX_RELPATH = http://www.mathjax.org/mathjax 1216 | 1217 | # The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension 1218 | # names that should be enabled during MathJax rendering. 1219 | 1220 | MATHJAX_EXTENSIONS = 1221 | 1222 | # When the SEARCHENGINE tag is enabled doxygen will generate a search box 1223 | # for the HTML output. The underlying search engine uses javascript 1224 | # and DHTML and should work on any modern browser. Note that when using 1225 | # HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets 1226 | # (GENERATE_DOCSET) there is already a search function so this one should 1227 | # typically be disabled. For large projects the javascript based search engine 1228 | # can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution. 1229 | 1230 | SEARCHENGINE = YES 1231 | 1232 | # When the SERVER_BASED_SEARCH tag is enabled the search engine will be 1233 | # implemented using a PHP enabled web server instead of at the web client 1234 | # using Javascript. Doxygen will generate the search PHP script and index 1235 | # file to put on the web server. The advantage of the server 1236 | # based approach is that it scales better to large projects and allows 1237 | # full text search. The disadvantages are that it is more difficult to setup 1238 | # and does not have live searching capabilities. 1239 | 1240 | SERVER_BASED_SEARCH = NO 1241 | 1242 | #--------------------------------------------------------------------------- 1243 | # configuration options related to the LaTeX output 1244 | #--------------------------------------------------------------------------- 1245 | 1246 | # If the GENERATE_LATEX tag is set to YES (the default) Doxygen will 1247 | # generate Latex output. 1248 | 1249 | GENERATE_LATEX = NO 1250 | 1251 | # The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. 1252 | # If a relative path is entered the value of OUTPUT_DIRECTORY will be 1253 | # put in front of it. If left blank `latex' will be used as the default path. 1254 | 1255 | LATEX_OUTPUT = latex 1256 | 1257 | # The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be 1258 | # invoked. If left blank `latex' will be used as the default command name. 1259 | # Note that when enabling USE_PDFLATEX this option is only used for 1260 | # generating bitmaps for formulas in the HTML output, but not in the 1261 | # Makefile that is written to the output directory. 1262 | 1263 | LATEX_CMD_NAME = latex 1264 | 1265 | # The MAKEINDEX_CMD_NAME tag can be used to specify the command name to 1266 | # generate index for LaTeX. If left blank `makeindex' will be used as the 1267 | # default command name. 1268 | 1269 | MAKEINDEX_CMD_NAME = makeindex 1270 | 1271 | # If the COMPACT_LATEX tag is set to YES Doxygen generates more compact 1272 | # LaTeX documents. This may be useful for small projects and may help to 1273 | # save some trees in general. 1274 | 1275 | COMPACT_LATEX = NO 1276 | 1277 | # The PAPER_TYPE tag can be used to set the paper type that is used 1278 | # by the printer. Possible values are: a4, letter, legal and 1279 | # executive. If left blank a4wide will be used. 1280 | 1281 | PAPER_TYPE = a4 1282 | 1283 | # The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX 1284 | # packages that should be included in the LaTeX output. 1285 | 1286 | EXTRA_PACKAGES = 1287 | 1288 | # The LATEX_HEADER tag can be used to specify a personal LaTeX header for 1289 | # the generated latex document. The header should contain everything until 1290 | # the first chapter. If it is left blank doxygen will generate a 1291 | # standard header. Notice: only use this tag if you know what you are doing! 1292 | 1293 | LATEX_HEADER = 1294 | 1295 | # The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for 1296 | # the generated latex document. The footer should contain everything after 1297 | # the last chapter. If it is left blank doxygen will generate a 1298 | # standard footer. Notice: only use this tag if you know what you are doing! 1299 | 1300 | LATEX_FOOTER = 1301 | 1302 | # If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated 1303 | # is prepared for conversion to pdf (using ps2pdf). The pdf file will 1304 | # contain links (just like the HTML output) instead of page references 1305 | # This makes the output suitable for online browsing using a pdf viewer. 1306 | 1307 | PDF_HYPERLINKS = YES 1308 | 1309 | # If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of 1310 | # plain latex in the generated Makefile. Set this option to YES to get a 1311 | # higher quality PDF documentation. 1312 | 1313 | USE_PDFLATEX = YES 1314 | 1315 | # If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. 1316 | # command to the generated LaTeX files. This will instruct LaTeX to keep 1317 | # running if errors occur, instead of asking the user for help. 1318 | # This option is also used when generating formulas in HTML. 1319 | 1320 | LATEX_BATCHMODE = NO 1321 | 1322 | # If LATEX_HIDE_INDICES is set to YES then doxygen will not 1323 | # include the index chapters (such as File Index, Compound Index, etc.) 1324 | # in the output. 1325 | 1326 | LATEX_HIDE_INDICES = NO 1327 | 1328 | # If LATEX_SOURCE_CODE is set to YES then doxygen will include 1329 | # source code with syntax highlighting in the LaTeX output. 1330 | # Note that which sources are shown also depends on other settings 1331 | # such as SOURCE_BROWSER. 1332 | 1333 | LATEX_SOURCE_CODE = NO 1334 | 1335 | # The LATEX_BIB_STYLE tag can be used to specify the style to use for the 1336 | # bibliography, e.g. plainnat, or ieeetr. The default style is "plain". See 1337 | # http://en.wikipedia.org/wiki/BibTeX for more info. 1338 | 1339 | LATEX_BIB_STYLE = plain 1340 | 1341 | #--------------------------------------------------------------------------- 1342 | # configuration options related to the RTF output 1343 | #--------------------------------------------------------------------------- 1344 | 1345 | # If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output 1346 | # The RTF output is optimized for Word 97 and may not look very pretty with 1347 | # other RTF readers or editors. 1348 | 1349 | GENERATE_RTF = NO 1350 | 1351 | # The RTF_OUTPUT tag is used to specify where the RTF docs will be put. 1352 | # If a relative path is entered the value of OUTPUT_DIRECTORY will be 1353 | # put in front of it. If left blank `rtf' will be used as the default path. 1354 | 1355 | RTF_OUTPUT = rtf 1356 | 1357 | # If the COMPACT_RTF tag is set to YES Doxygen generates more compact 1358 | # RTF documents. This may be useful for small projects and may help to 1359 | # save some trees in general. 1360 | 1361 | COMPACT_RTF = NO 1362 | 1363 | # If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated 1364 | # will contain hyperlink fields. The RTF file will 1365 | # contain links (just like the HTML output) instead of page references. 1366 | # This makes the output suitable for online browsing using WORD or other 1367 | # programs which support those fields. 1368 | # Note: wordpad (write) and others do not support links. 1369 | 1370 | RTF_HYPERLINKS = NO 1371 | 1372 | # Load style sheet definitions from file. Syntax is similar to doxygen's 1373 | # config file, i.e. a series of assignments. You only have to provide 1374 | # replacements, missing definitions are set to their default value. 1375 | 1376 | RTF_STYLESHEET_FILE = 1377 | 1378 | # Set optional variables used in the generation of an rtf document. 1379 | # Syntax is similar to doxygen's config file. 1380 | 1381 | RTF_EXTENSIONS_FILE = 1382 | 1383 | #--------------------------------------------------------------------------- 1384 | # configuration options related to the man page output 1385 | #--------------------------------------------------------------------------- 1386 | 1387 | # If the GENERATE_MAN tag is set to YES (the default) Doxygen will 1388 | # generate man pages 1389 | 1390 | GENERATE_MAN = NO 1391 | 1392 | # The MAN_OUTPUT tag is used to specify where the man pages will be put. 1393 | # If a relative path is entered the value of OUTPUT_DIRECTORY will be 1394 | # put in front of it. If left blank `man' will be used as the default path. 1395 | 1396 | MAN_OUTPUT = man 1397 | 1398 | # The MAN_EXTENSION tag determines the extension that is added to 1399 | # the generated man pages (default is the subroutine's section .3) 1400 | 1401 | MAN_EXTENSION = .3 1402 | 1403 | # If the MAN_LINKS tag is set to YES and Doxygen generates man output, 1404 | # then it will generate one additional man file for each entity 1405 | # documented in the real man page(s). These additional files 1406 | # only source the real man page, but without them the man command 1407 | # would be unable to find the correct page. The default is NO. 1408 | 1409 | MAN_LINKS = NO 1410 | 1411 | #--------------------------------------------------------------------------- 1412 | # configuration options related to the XML output 1413 | #--------------------------------------------------------------------------- 1414 | 1415 | # If the GENERATE_XML tag is set to YES Doxygen will 1416 | # generate an XML file that captures the structure of 1417 | # the code including all documentation. 1418 | 1419 | GENERATE_XML = NO 1420 | 1421 | # The XML_OUTPUT tag is used to specify where the XML pages will be put. 1422 | # If a relative path is entered the value of OUTPUT_DIRECTORY will be 1423 | # put in front of it. If left blank `xml' will be used as the default path. 1424 | 1425 | XML_OUTPUT = xml 1426 | 1427 | # The XML_SCHEMA tag can be used to specify an XML schema, 1428 | # which can be used by a validating XML parser to check the 1429 | # syntax of the XML files. 1430 | 1431 | XML_SCHEMA = 1432 | 1433 | # The XML_DTD tag can be used to specify an XML DTD, 1434 | # which can be used by a validating XML parser to check the 1435 | # syntax of the XML files. 1436 | 1437 | XML_DTD = 1438 | 1439 | # If the XML_PROGRAMLISTING tag is set to YES Doxygen will 1440 | # dump the program listings (including syntax highlighting 1441 | # and cross-referencing information) to the XML output. Note that 1442 | # enabling this will significantly increase the size of the XML output. 1443 | 1444 | XML_PROGRAMLISTING = YES 1445 | 1446 | #--------------------------------------------------------------------------- 1447 | # configuration options for the AutoGen Definitions output 1448 | #--------------------------------------------------------------------------- 1449 | 1450 | # If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will 1451 | # generate an AutoGen Definitions (see autogen.sf.net) file 1452 | # that captures the structure of the code including all 1453 | # documentation. Note that this feature is still experimental 1454 | # and incomplete at the moment. 1455 | 1456 | GENERATE_AUTOGEN_DEF = NO 1457 | 1458 | #--------------------------------------------------------------------------- 1459 | # configuration options related to the Perl module output 1460 | #--------------------------------------------------------------------------- 1461 | 1462 | # If the GENERATE_PERLMOD tag is set to YES Doxygen will 1463 | # generate a Perl module file that captures the structure of 1464 | # the code including all documentation. Note that this 1465 | # feature is still experimental and incomplete at the 1466 | # moment. 1467 | 1468 | GENERATE_PERLMOD = NO 1469 | 1470 | # If the PERLMOD_LATEX tag is set to YES Doxygen will generate 1471 | # the necessary Makefile rules, Perl scripts and LaTeX code to be able 1472 | # to generate PDF and DVI output from the Perl module output. 1473 | 1474 | PERLMOD_LATEX = NO 1475 | 1476 | # If the PERLMOD_PRETTY tag is set to YES the Perl module output will be 1477 | # nicely formatted so it can be parsed by a human reader. This is useful 1478 | # if you want to understand what is going on. On the other hand, if this 1479 | # tag is set to NO the size of the Perl module output will be much smaller 1480 | # and Perl will parse it just the same. 1481 | 1482 | PERLMOD_PRETTY = YES 1483 | 1484 | # The names of the make variables in the generated doxyrules.make file 1485 | # are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. 1486 | # This is useful so different doxyrules.make files included by the same 1487 | # Makefile don't overwrite each other's variables. 1488 | 1489 | PERLMOD_MAKEVAR_PREFIX = 1490 | 1491 | #--------------------------------------------------------------------------- 1492 | # Configuration options related to the preprocessor 1493 | #--------------------------------------------------------------------------- 1494 | 1495 | # If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will 1496 | # evaluate all C-preprocessor directives found in the sources and include 1497 | # files. 1498 | 1499 | ENABLE_PREPROCESSING = YES 1500 | 1501 | # If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro 1502 | # names in the source code. If set to NO (the default) only conditional 1503 | # compilation will be performed. Macro expansion can be done in a controlled 1504 | # way by setting EXPAND_ONLY_PREDEF to YES. 1505 | 1506 | MACRO_EXPANSION = NO 1507 | 1508 | # If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES 1509 | # then the macro expansion is limited to the macros specified with the 1510 | # PREDEFINED and EXPAND_AS_DEFINED tags. 1511 | 1512 | EXPAND_ONLY_PREDEF = NO 1513 | 1514 | # If the SEARCH_INCLUDES tag is set to YES (the default) the includes files 1515 | # pointed to by INCLUDE_PATH will be searched when a #include is found. 1516 | 1517 | SEARCH_INCLUDES = YES 1518 | 1519 | # The INCLUDE_PATH tag can be used to specify one or more directories that 1520 | # contain include files that are not input files but should be processed by 1521 | # the preprocessor. 1522 | 1523 | INCLUDE_PATH = 1524 | 1525 | # You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard 1526 | # patterns (like *.h and *.hpp) to filter out the header-files in the 1527 | # directories. If left blank, the patterns specified with FILE_PATTERNS will 1528 | # be used. 1529 | 1530 | INCLUDE_FILE_PATTERNS = 1531 | 1532 | # The PREDEFINED tag can be used to specify one or more macro names that 1533 | # are defined before the preprocessor is started (similar to the -D option of 1534 | # gcc). The argument of the tag is a list of macros of the form: name 1535 | # or name=definition (no spaces). If the definition and the = are 1536 | # omitted =1 is assumed. To prevent a macro definition from being 1537 | # undefined via #undef or recursively expanded use the := operator 1538 | # instead of the = operator. 1539 | 1540 | PREDEFINED = 1541 | 1542 | # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then 1543 | # this tag can be used to specify a list of macro names that should be expanded. 1544 | # The macro definition that is found in the sources will be used. 1545 | # Use the PREDEFINED tag if you want to use a different macro definition that 1546 | # overrules the definition found in the source code. 1547 | 1548 | EXPAND_AS_DEFINED = 1549 | 1550 | # If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then 1551 | # doxygen's preprocessor will remove all references to function-like macros 1552 | # that are alone on a line, have an all uppercase name, and do not end with a 1553 | # semicolon, because these will confuse the parser if not removed. 1554 | 1555 | SKIP_FUNCTION_MACROS = YES 1556 | 1557 | #--------------------------------------------------------------------------- 1558 | # Configuration::additions related to external references 1559 | #--------------------------------------------------------------------------- 1560 | 1561 | # The TAGFILES option can be used to specify one or more tagfiles. 1562 | # Optionally an initial location of the external documentation 1563 | # can be added for each tagfile. The format of a tag file without 1564 | # this location is as follows: 1565 | # TAGFILES = file1 file2 ... 1566 | # Adding location for the tag files is done as follows: 1567 | # TAGFILES = file1=loc1 "file2 = loc2" ... 1568 | # where "loc1" and "loc2" can be relative or absolute paths or 1569 | # URLs. If a location is present for each tag, the installdox tool 1570 | # does not have to be run to correct the links. 1571 | # Note that each tag file must have a unique name 1572 | # (where the name does NOT include the path) 1573 | # If a tag file is not located in the directory in which doxygen 1574 | # is run, you must also specify the path to the tagfile here. 1575 | 1576 | TAGFILES = 1577 | 1578 | # When a file name is specified after GENERATE_TAGFILE, doxygen will create 1579 | # a tag file that is based on the input files it reads. 1580 | 1581 | GENERATE_TAGFILE = 1582 | 1583 | # If the ALLEXTERNALS tag is set to YES all external classes will be listed 1584 | # in the class index. If set to NO only the inherited external classes 1585 | # will be listed. 1586 | 1587 | ALLEXTERNALS = NO 1588 | 1589 | # If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed 1590 | # in the modules index. If set to NO, only the current project's groups will 1591 | # be listed. 1592 | 1593 | EXTERNAL_GROUPS = YES 1594 | 1595 | # The PERL_PATH should be the absolute path and name of the perl script 1596 | # interpreter (i.e. the result of `which perl'). 1597 | 1598 | PERL_PATH = /usr/bin/perl 1599 | 1600 | #--------------------------------------------------------------------------- 1601 | # Configuration options related to the dot tool 1602 | #--------------------------------------------------------------------------- 1603 | 1604 | # If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will 1605 | # generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base 1606 | # or super classes. Setting the tag to NO turns the diagrams off. Note that 1607 | # this option also works with HAVE_DOT disabled, but it is recommended to 1608 | # install and use dot, since it yields more powerful graphs. 1609 | 1610 | CLASS_DIAGRAMS = NO 1611 | 1612 | # You can define message sequence charts within doxygen comments using the \msc 1613 | # command. Doxygen will then run the mscgen tool (see 1614 | # http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the 1615 | # documentation. The MSCGEN_PATH tag allows you to specify the directory where 1616 | # the mscgen tool resides. If left empty the tool is assumed to be found in the 1617 | # default search path. 1618 | 1619 | MSCGEN_PATH = 1620 | 1621 | # If set to YES, the inheritance and collaboration graphs will hide 1622 | # inheritance and usage relations if the target is undocumented 1623 | # or is not a class. 1624 | 1625 | HIDE_UNDOC_RELATIONS = YES 1626 | 1627 | # If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is 1628 | # available from the path. This tool is part of Graphviz, a graph visualization 1629 | # toolkit from AT&T and Lucent Bell Labs. The other options in this section 1630 | # have no effect if this option is set to NO (the default) 1631 | 1632 | HAVE_DOT = NO 1633 | 1634 | # The DOT_NUM_THREADS specifies the number of dot invocations doxygen is 1635 | # allowed to run in parallel. When set to 0 (the default) doxygen will 1636 | # base this on the number of processors available in the system. You can set it 1637 | # explicitly to a value larger than 0 to get control over the balance 1638 | # between CPU load and processing speed. 1639 | 1640 | DOT_NUM_THREADS = 0 1641 | 1642 | # By default doxygen will use the Helvetica font for all dot files that 1643 | # doxygen generates. When you want a differently looking font you can specify 1644 | # the font name using DOT_FONTNAME. You need to make sure dot is able to find 1645 | # the font, which can be done by putting it in a standard location or by setting 1646 | # the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the 1647 | # directory containing the font. 1648 | 1649 | DOT_FONTNAME = Helvetica 1650 | 1651 | # The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. 1652 | # The default size is 10pt. 1653 | 1654 | DOT_FONTSIZE = 10 1655 | 1656 | # By default doxygen will tell dot to use the Helvetica font. 1657 | # If you specify a different font using DOT_FONTNAME you can use DOT_FONTPATH to 1658 | # set the path where dot can find it. 1659 | 1660 | DOT_FONTPATH = 1661 | 1662 | # If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen 1663 | # will generate a graph for each documented class showing the direct and 1664 | # indirect inheritance relations. Setting this tag to YES will force the 1665 | # CLASS_DIAGRAMS tag to NO. 1666 | 1667 | CLASS_GRAPH = YES 1668 | 1669 | # If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen 1670 | # will generate a graph for each documented class showing the direct and 1671 | # indirect implementation dependencies (inheritance, containment, and 1672 | # class references variables) of the class with other documented classes. 1673 | 1674 | COLLABORATION_GRAPH = YES 1675 | 1676 | # If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen 1677 | # will generate a graph for groups, showing the direct groups dependencies 1678 | 1679 | GROUP_GRAPHS = YES 1680 | 1681 | # If the UML_LOOK tag is set to YES doxygen will generate inheritance and 1682 | # collaboration diagrams in a style similar to the OMG's Unified Modeling 1683 | # Language. 1684 | 1685 | UML_LOOK = NO 1686 | 1687 | # If set to YES, the inheritance and collaboration graphs will show the 1688 | # relations between templates and their instances. 1689 | 1690 | TEMPLATE_RELATIONS = NO 1691 | 1692 | # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT 1693 | # tags are set to YES then doxygen will generate a graph for each documented 1694 | # file showing the direct and indirect include dependencies of the file with 1695 | # other documented files. 1696 | 1697 | INCLUDE_GRAPH = YES 1698 | 1699 | # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and 1700 | # HAVE_DOT tags are set to YES then doxygen will generate a graph for each 1701 | # documented header file showing the documented files that directly or 1702 | # indirectly include this file. 1703 | 1704 | INCLUDED_BY_GRAPH = YES 1705 | 1706 | # If the CALL_GRAPH and HAVE_DOT options are set to YES then 1707 | # doxygen will generate a call dependency graph for every global function 1708 | # or class method. Note that enabling this option will significantly increase 1709 | # the time of a run. So in most cases it will be better to enable call graphs 1710 | # for selected functions only using the \callgraph command. 1711 | 1712 | CALL_GRAPH = NO 1713 | 1714 | # If the CALLER_GRAPH and HAVE_DOT tags are set to YES then 1715 | # doxygen will generate a caller dependency graph for every global function 1716 | # or class method. Note that enabling this option will significantly increase 1717 | # the time of a run. So in most cases it will be better to enable caller 1718 | # graphs for selected functions only using the \callergraph command. 1719 | 1720 | CALLER_GRAPH = NO 1721 | 1722 | # If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen 1723 | # will generate a graphical hierarchy of all classes instead of a textual one. 1724 | 1725 | GRAPHICAL_HIERARCHY = YES 1726 | 1727 | # If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES 1728 | # then doxygen will show the dependencies a directory has on other directories 1729 | # in a graphical way. The dependency relations are determined by the #include 1730 | # relations between the files in the directories. 1731 | 1732 | DIRECTORY_GRAPH = YES 1733 | 1734 | # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images 1735 | # generated by dot. Possible values are svg, png, jpg, or gif. 1736 | # If left blank png will be used. If you choose svg you need to set 1737 | # HTML_FILE_EXTENSION to xhtml in order to make the SVG files 1738 | # visible in IE 9+ (other browsers do not have this requirement). 1739 | 1740 | DOT_IMAGE_FORMAT = png 1741 | 1742 | # If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to 1743 | # enable generation of interactive SVG images that allow zooming and panning. 1744 | # Note that this requires a modern browser other than Internet Explorer. 1745 | # Tested and working are Firefox, Chrome, Safari, and Opera. For IE 9+ you 1746 | # need to set HTML_FILE_EXTENSION to xhtml in order to make the SVG files 1747 | # visible. Older versions of IE do not have SVG support. 1748 | 1749 | INTERACTIVE_SVG = NO 1750 | 1751 | # The tag DOT_PATH can be used to specify the path where the dot tool can be 1752 | # found. If left blank, it is assumed the dot tool can be found in the path. 1753 | 1754 | DOT_PATH = 1755 | 1756 | # The DOTFILE_DIRS tag can be used to specify one or more directories that 1757 | # contain dot files that are included in the documentation (see the 1758 | # \dotfile command). 1759 | 1760 | DOTFILE_DIRS = 1761 | 1762 | # The MSCFILE_DIRS tag can be used to specify one or more directories that 1763 | # contain msc files that are included in the documentation (see the 1764 | # \mscfile command). 1765 | 1766 | MSCFILE_DIRS = 1767 | 1768 | # The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of 1769 | # nodes that will be shown in the graph. If the number of nodes in a graph 1770 | # becomes larger than this value, doxygen will truncate the graph, which is 1771 | # visualized by representing a node as a red box. Note that doxygen if the 1772 | # number of direct children of the root node in a graph is already larger than 1773 | # DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note 1774 | # that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. 1775 | 1776 | DOT_GRAPH_MAX_NODES = 50 1777 | 1778 | # The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the 1779 | # graphs generated by dot. A depth value of 3 means that only nodes reachable 1780 | # from the root by following a path via at most 3 edges will be shown. Nodes 1781 | # that lay further from the root node will be omitted. Note that setting this 1782 | # option to 1 or 2 may greatly reduce the computation time needed for large 1783 | # code bases. Also note that the size of a graph can be further restricted by 1784 | # DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. 1785 | 1786 | MAX_DOT_GRAPH_DEPTH = 0 1787 | 1788 | # Set the DOT_TRANSPARENT tag to YES to generate images with a transparent 1789 | # background. This is disabled by default, because dot on Windows does not 1790 | # seem to support this out of the box. Warning: Depending on the platform used, 1791 | # enabling this option may lead to badly anti-aliased labels on the edges of 1792 | # a graph (i.e. they become hard to read). 1793 | 1794 | DOT_TRANSPARENT = NO 1795 | 1796 | # Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output 1797 | # files in one run (i.e. multiple -o and -T options on the command line). This 1798 | # makes dot run faster, but since only newer versions of dot (>1.8.10) 1799 | # support this, this feature is disabled by default. 1800 | 1801 | DOT_MULTI_TARGETS = NO 1802 | 1803 | # If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will 1804 | # generate a legend page explaining the meaning of the various boxes and 1805 | # arrows in the dot generated graphs. 1806 | 1807 | GENERATE_LEGEND = YES 1808 | 1809 | # If the DOT_CLEANUP tag is set to YES (the default) Doxygen will 1810 | # remove the intermediate dot files that are used to generate 1811 | # the various graphs. 1812 | 1813 | DOT_CLEANUP = YES 1814 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright Thomas BENETEAU. 2 | 3 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 4 | 5 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 6 | 7 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 8 | 9 | THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 10 | 11 | The views and conclusions contained in the software and documentation are those of the authors and should not be interpreted as representing official policies, either expressed or implied. 12 | -------------------------------------------------------------------------------- /Lambda.cbp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 97 | 98 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Lambda 2 | ============== 3 | 4 | Spectral Path Tracer 5 | -------------- 6 | 7 |

8 | Featured Render 9 |

10 | 11 | Lambda is a simple spectral path tracer, written in C++. Some parts of the code are still written in C and don't take advantage of C++ features for the moment. This is a work in progress as many features are still missing, but it is quite functional. Please note Lambda uses C++11 libraries, so you will need a compliant toolchain (for instance, GCC 4.6 and later). 12 | 13 | ## Currently implemented: 14 | 15 | - Unidirectional path tracing with russian roulette 16 | - Spectral Distributions 17 | 18 | Blackbody emission spectrum 19 | 20 | Sellmeier refractive index 21 | 22 | "Flat" spectrum (which is usually used for a wavelength-independent spectral response) 23 | 24 | "Peak" spectrum (which is basically a bell curve at some peak wavelength) 25 | 26 | - Materials 27 | 28 | Lambertian diffuse (importance-sampled) 29 | 30 | Ideal specular (importance-sampled) 31 | 32 | Ideal refractive (importance-sampled, unfinished) 33 | 34 | Rough refractive (importance-sampled) 35 | 36 | Cook-Torrance (importance-sampled, w/ Beckmann) 37 | 38 | - Lights 39 | 40 | Omni light (i.e. isotropic emittance) 41 | 42 | - Primitives 43 | 44 | Spheres 45 | 46 | Triangles 47 | 48 | - Gamma correction 49 | - Reinhard tone-mapping 50 | - Multiple available color spaces 51 | - Scalable multithreading via OpenMP 52 | - Robust pseudorandom number generation (C++11 mersenne twister) 53 | - Very efficient bounding volume hierarchy acceleration structure (many thanks to [Brandon Pelfrey](https://github.com/brandonpelfrey)) 54 | 55 | ## Missing features 56 | 57 | - Bidirectional path tracing 58 | - More of everything else 59 | - ... 60 | 61 | ## How to build 62 | 63 | There is a Code::Blocks project included, but if you don't want to use that, I haven't done a Makefile yet. To compile, you don't need anything special, but if you want to use OpenMP for multithreading, you'll need to link to the "gomp" library and pass the -fopenmp flag to your compiler. 64 | 65 | ## How to use 66 | 67 | Lambda works on the basis of "scene files", which contain everything needed to render a given scene. These need to follow a certain format, which is fairly obvious to work out if you look at the loading code. I provide some sample scene files in the repository, though some of them are necessarily quite large due to the amount of triangles required. You can also create your own scenes, I intend to provide helper functions to ease this task later on. 68 | 69 | ## Where are the scenes files? 70 | 71 | There are some rather generic ones in the scenes/ folder. The other, high-detail ones, because of their large size, are located in the [Downloads](https://github.com/TomCrypto/Lambda/downloads) section of the repository in compressed form (7z). 72 | 73 | ## Where is the result? 74 | 75 | Lambda produces its output in gamma-corrected, tone-mapped PPM format. If you are under Linux, you should be able to view it without issues. Under Windows, you can use any PPM reader, such as IrfanView or other (and you can then convert it to a PNG, for instance). 76 | 77 | ## Compatibility 78 | 79 | Lambda is compatible with C++11 compliant compilers and uses only standard libraries. As such, it is portable, and has been tested under 64-bit Linux and 64-bit Windows. Note the vector code requires SSE3 instructions, but you really should have those. 80 | 81 | ## Misc. 82 | 83 | Note most implementations in this repository are untested when it comes to physically-based correctness. We try to implement things correctly, but it is very difficult to distinguish "correct" from "almost correct" without reference renders, which we unfortunately do not have. 84 | -------------------------------------------------------------------------------- /icon/128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TomCrypto/Lambda/7b1fb0cae05de9d88f3d848d65b7366e64409781/icon/128.png -------------------------------------------------------------------------------- /icon/16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TomCrypto/Lambda/7b1fb0cae05de9d88f3d848d65b7366e64409781/icon/16.png -------------------------------------------------------------------------------- /icon/256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TomCrypto/Lambda/7b1fb0cae05de9d88f3d848d65b7366e64409781/icon/256.png -------------------------------------------------------------------------------- /icon/32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TomCrypto/Lambda/7b1fb0cae05de9d88f3d848d65b7366e64409781/icon/32.png -------------------------------------------------------------------------------- /icon/48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TomCrypto/Lambda/7b1fb0cae05de9d88f3d848d65b7366e64409781/icon/48.png -------------------------------------------------------------------------------- /icon/64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TomCrypto/Lambda/7b1fb0cae05de9d88f3d848d65b7366e64409781/icon/64.png -------------------------------------------------------------------------------- /icon/doxygen_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TomCrypto/Lambda/7b1fb0cae05de9d88f3d848d65b7366e64409781/icon/doxygen_icon.png -------------------------------------------------------------------------------- /include/cameras/camera.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CAMERA_H 2 | #define CAMERA_H 3 | 4 | /* Some scene file ID's for cameras. */ 5 | #define ID_PERSPECTIVE 0 6 | 7 | /* We need vector math, and files. */ 8 | #include 9 | #include 10 | #include 11 | 12 | /* This is the base class for a camera. */ 13 | class Camera 14 | { 15 | public: 16 | /* This function returns the camera ray corresponding to the normalized screen coordinates (u, v). */ 17 | virtual Ray Trace(float u, float v) = 0; 18 | }; 19 | 20 | /* This creates the correct camera type based on a scene file entity subtype. */ 21 | Camera* GetCamera(uint32_t subtype, std::fstream& file); 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /include/cameras/perspective.hpp: -------------------------------------------------------------------------------- 1 | #ifndef PERSPECTIVECG_H 2 | #define PERSPECTIVECG_H 3 | 4 | #include 5 | 6 | /* This represents a standard perspective camera, with no advanced features such as depth of field. */ 7 | class Perspective : public Camera 8 | { 9 | private: 10 | /* The camera position. */ 11 | Vector position; 12 | 13 | /* The focal plane. */ 14 | Vector focalPlane[4]; 15 | 16 | /* Build the focal plane. */ 17 | void buildFocalPlane(Vector target, float fieldOfView); 18 | public: 19 | /* Creates the perspective camera from a scene file. */ 20 | Perspective(std::fstream& file); 21 | 22 | /* This will trace the camera ray. */ 23 | virtual Ray Trace(float u, float v); 24 | }; 25 | 26 | #endif // PERSPECTIVECG_H 27 | -------------------------------------------------------------------------------- /include/lights/light.hpp: -------------------------------------------------------------------------------- 1 | #ifndef LIGHT_H 2 | #define LIGHT_H 3 | 4 | /* Some scene file ID's for lights. */ 5 | #define ID_OMNI 0 6 | 7 | /* We need vector math, and spectral distributions. */ 8 | #include 9 | #include 10 | 11 | /* This is the base class from which all light sources are derived. */ 12 | class Light 13 | { 14 | public: 15 | /* This function returns the emittance of the light. */ 16 | virtual double Emittance(Vector incident, Vector normal, double wavelength) = 0; 17 | }; 18 | 19 | /* This creates the correct light type based on a scene file entity subtype. */ 20 | Light* GetLight(uint32_t subtype, std::fstream& file, std::vector* distributions); 21 | 22 | #endif // LIGHT_H 23 | 24 | -------------------------------------------------------------------------------- /include/lights/omni.hpp: -------------------------------------------------------------------------------- 1 | #ifndef OMNI_H 2 | #define OMNI_H 3 | 4 | #include 5 | 6 | /* This is an omni light source with isotropic emittance. */ 7 | class Omni : public Light 8 | { 9 | private: 10 | /* The spectral emittance spectrum. */ 11 | Distribution* emittance; 12 | public: 13 | /* Creates the omni light from a scene file. */ 14 | Omni(std::fstream& file, std::vector* distributions); 15 | 16 | /* This function returns the emittance of the light. */ 17 | virtual double Emittance(Vector incident, Vector normal, double wavelength) { return this->emittance->Lookup(wavelength); } 18 | }; 19 | 20 | #endif // OMNI_H 21 | 22 | 23 | -------------------------------------------------------------------------------- /include/materials/cooktorrance.hpp: -------------------------------------------------------------------------------- 1 | #ifndef COOKTORRANCE_H 2 | #define COOKTORRANCE_H 3 | 4 | #include 5 | 6 | /* This is a Cook-Torrance BRDF. It is assumed that the external refractive index is 1. */ 7 | class CookTorrance : public Material 8 | { 9 | private: 10 | /* Spectral reflectance and refractive index distribution. */ 11 | Distribution* reflectance; 12 | Distribution* refractiveIndex; 13 | /* Surface roughness. */ 14 | float roughness; 15 | public: 16 | /* Creates the material from a scene file. */ 17 | CookTorrance(std::fstream& file, std::vector* distributions); 18 | 19 | /* This function returns an importance-sampled exitant vector. */ 20 | virtual Vector Sample(Vector* origin, Vector incident, Vector normal, float wavelength, std::mt19937* prng); 21 | 22 | /* This returns the reflectance for an incident and exitant vector. */ 23 | virtual float Reflectance(Vector incident, Vector exitant, Vector normal, float wavelength, bool sampled); 24 | }; 25 | 26 | #endif 27 | 28 | 29 | -------------------------------------------------------------------------------- /include/materials/diffuse.hpp: -------------------------------------------------------------------------------- 1 | #ifndef DIFFUSE_H 2 | #define DIFFUSE_H 3 | 4 | #include 5 | 6 | /* This is a diffuse BRDF. */ 7 | class Diffuse : public Material 8 | { 9 | private: 10 | /* Spectral reflectance distribution. */ 11 | Distribution* reflectance; 12 | public: 13 | /* Creates the diffuse material from a scene file. */ 14 | Diffuse(std::fstream& file, std::vector* distributions); 15 | 16 | /* This function returns an importance-sampled exitant vector. */ 17 | virtual Vector Sample(Vector* origin, Vector incident, Vector normal, float wavelength, std::mt19937* prng); 18 | 19 | /* This returns the reflectance for an incident and exitant vector. */ 20 | virtual float Reflectance(Vector incident, Vector exitant, Vector normal, float wavelength, bool sampled); 21 | }; 22 | 23 | #endif // DIFFUSE_H 24 | 25 | 26 | -------------------------------------------------------------------------------- /include/materials/frostedglass.hpp: -------------------------------------------------------------------------------- 1 | #ifndef FROSTEDGLASS_H 2 | #define FROSTEDGLASS_H 3 | 4 | #include 5 | 6 | /* This is a frosted glass BRDF. It is assumed that the external refractive index is 1. */ 7 | class FrostedGlass : public Material 8 | { 9 | private: 10 | /* Spectral refractive index distribution. */ 11 | Distribution* refractiveIndex; 12 | /* Glass roughness. */ 13 | float roughness; 14 | public: 15 | /* Creates the material from a scene file. */ 16 | FrostedGlass(std::fstream& file, std::vector* distributions); 17 | 18 | /* This function returns an importance-sampled exitant vector. */ 19 | virtual Vector Sample(Vector* origin, Vector incident, Vector normal, float wavelength, std::mt19937* prng); 20 | 21 | /* This returns the reflectance for an incident and exitant vector. */ 22 | virtual float Reflectance(Vector incident, Vector exitant, Vector normal, float wavelength, bool sampled); 23 | }; 24 | 25 | #endif 26 | 27 | -------------------------------------------------------------------------------- /include/materials/material.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @file material.hpp 3 | * 4 | * \brief Material interface 5 | * 6 | * This is a common interface for materials, including BRDF's and BTDF's. 7 | */ 8 | 9 | #ifndef MATERIAL_H 10 | #define MATERIAL_H 11 | 12 | /* Some scene file ID's for materials. */ 13 | #define ID_DIFFUSE 0 14 | #define ID_SPECULAR 1 15 | #define ID_SMOOTHGLASS 2 16 | #define ID_FROSTEDGLASS 3 17 | #define ID_COOKTORRANCE 4 18 | 19 | /* We need vectors, pseudorandom number generation, and spectral distributions. */ 20 | #include 21 | #include 22 | #include 23 | 24 | /*! \class Material 25 | * This is the base class from which all materials are derived. */ 26 | class Material 27 | { 28 | private: 29 | public: 30 | /*! This is the "outside" extinction coefficient (of the medium the primitive's normal is pointing towards). */ 31 | float e1; 32 | /*! This is the "inside" extinction coefficient. */ 33 | float e2; 34 | 35 | /*! Creates a material from a scene file. */ 36 | Material(std::fstream& file); 37 | 38 | /*! This method returns an importance-sampled exitant light ray from an incident and normal vector. This 39 | * method is wavelength-dependent. 40 | \param origin A pointer to the intersection point. 41 | \param incident The incident vector. 42 | \param normal The surface normal. 43 | \param wavelength The ray's wavelength. 44 | \return Returns an importance-sampled exitant vector. 45 | \remark The origin will be slightly displaced by this method to prevent self-intersection due to 46 | floating-point inaccuracies. This is important to prevent geometry intersection artifacts. */ 47 | virtual Vector Sample(Vector* origin, Vector incident, Vector normal, float wavelength, std::mt19937* prng) = 0; 48 | 49 | /*! This method evaluates the material's reflectance function for an incident and exitant vector. This method 50 | * is wavelength-dependent. 51 | \param incident The incident vector. 52 | \param exitant The exitant vector. 53 | \param normal The surface normal. 54 | \param wavelength The ray's wavelength. 55 | \param sampled Whether the exitant vector was importance-sampled using the incident vector. 56 | \return Returns the incident-exitant reflectance. 57 | \remark This function must always return values in the interval [0, 1). Note 1 is exclusive, to ensure 58 | the light path always terminates eventually (and no surface reflects exactly 100% of incoming radiance). */ 59 | virtual float Reflectance(Vector incident, Vector exitant, Vector normal, float wavelength, bool sampled) = 0; 60 | }; 61 | 62 | /* This creates the correct material type based on a scene file entity subtype. */ 63 | Material* GetMaterial(uint32_t subtype, std::fstream& file, std::vector* distributions); 64 | 65 | #endif 66 | -------------------------------------------------------------------------------- /include/materials/smoothglass.hpp: -------------------------------------------------------------------------------- 1 | #ifndef SMOOTHGLASS_H 2 | #define SMOOTHGLASS_H 3 | 4 | #include 5 | 6 | /* This is a smooth glass BRDF. It is assumed that the external refractive index is 1. */ 7 | class SmoothGlass : public Material 8 | { 9 | private: 10 | /* Spectral refractive index distribution. */ 11 | Distribution* refractiveIndex; 12 | public: 13 | /* Creates the material from a scene file. */ 14 | SmoothGlass(std::fstream& file, std::vector* distributions); 15 | 16 | /* This function returns an importance-sampled exitant vector. */ 17 | virtual Vector Sample(Vector* origin, Vector incident, Vector normal, float wavelength, std::mt19937* prng); 18 | 19 | /* This returns the reflectance for an incident and exitant vector. */ 20 | virtual float Reflectance(Vector incident, Vector exitant, Vector normal, float wavelength, bool sampled); 21 | }; 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /include/materials/specular.hpp: -------------------------------------------------------------------------------- 1 | #ifndef SPECULAR_H 2 | #define SPECULAR_H 3 | 4 | #include 5 | 6 | /* This is a specular BRDF. */ 7 | class Specular : public Material 8 | { 9 | private: 10 | /* Spectral reflectance distribution. */ 11 | Distribution* reflectance; 12 | public: 13 | /* Creates the specular material from a scene file. */ 14 | Specular(std::fstream& file, std::vector* distributions); 15 | 16 | /* This function returns an importance-sampled exitant vector. */ 17 | virtual Vector Sample(Vector* origin, Vector incident, Vector normal, float wavelength, std::mt19937* prng); 18 | 19 | /* This returns the reflectance for an incident and exitant vector. */ 20 | virtual float Reflectance(Vector incident, Vector exitant, Vector normal, float wavelength, bool sampled); 21 | }; 22 | 23 | #endif // DIFFUSE_H 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /include/primitives/primitive.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @file primitive.hpp 3 | * 4 | * \brief Geometric primitive interface 5 | * 6 | * This is a common interface for geometric primitives, such as triangles, spheres, etc... 7 | * To be implementable, all primitives need to fulfill the following conditions: \n 8 | * - the primitive must be bounded (infinitely large primitives such as planes are not supported as they cannot be 9 | * queried by the bounding volume hierarchy acceleration structure). \n 10 | * - there must exist a computable ray-primitive intersection algorithm for this primitive. It need not be analytical, 11 | * but it probably should be for performance. \n 12 | * - if the primitive is to be used as a light source, it must be possible to select a random point on the primitive's 13 | * surface uniformily. 14 | * - the surface normal at any point on the primitive's surface must be computable. \n 15 | * - the primitive must have a well-defined centroid. 16 | */ 17 | 18 | #ifndef PRIMITIVE_H 19 | #define PRIMITIVE_H 20 | 21 | /* Some scene file ID's for primitives. */ 22 | #define ID_SPHERE 0 23 | #define ID_TRIANGLE 1 24 | 25 | /* We need vector and AABB math, as well as material and light references. */ 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | /* Forward declaration for the intersection information record. */ 32 | class Primitive; 33 | 34 | /*! \brief Ray-geometry intersection record. 35 | * 36 | * This is a structure containing information about a ray-geometry intersection. It contains a reference to the 37 | * primitive intersected, and the intersection's distance along the ray, starting from the ray's origin. */ 38 | struct Intersection { 39 | /*! The primitive which was intersected. */ 40 | Primitive* primitive; 41 | /*! The intersection's distance. */ 42 | float t; 43 | }; 44 | 45 | /*! \class Primitive 46 | * This is the base class from which all geometric primitives are derived. */ 47 | class Primitive 48 | { 49 | public: 50 | /*! Points to the primitive's material, if it has one. */ 51 | Material* material; 52 | /*! Points to the primitive's light, if it has one. */ 53 | Light* light; 54 | 55 | /*! Creates a primitive, from a scene file and a list of materials and lights. */ 56 | Primitive(std::fstream& file, std::vector* materials, std::vector* lights); 57 | 58 | /*! This method returns the closest intersection of a ray with the primitive. 59 | \param ray The ray to test intersection with. 60 | \returns The closest distance along the ray where an intersection occurs. If this is a negative value, the 61 | ray does not intersect the primitive. */ 62 | virtual float Intersect(const Ray& ray) = 0; 63 | 64 | /*! This method returns the surface normal of the primitive at any given point on its surface. 65 | \param point The point, on the primitive's surface, to obtain the normal of. 66 | \return The surface normal at the desired point. */ 67 | virtual Vector Normal(Vector point) = 0; 68 | 69 | /*! This method returns the axis-aligned bounding box of the primitive. 70 | \return The primitive's bounding box. 71 | \remark The bounding box need not be ideal, but the bounding volume hierarchy is more efficient if the 72 | returned bounding box tightly fits the primitive. The same bounding box must always be returned. */ 73 | virtual AABB BoundingBox() = 0; 74 | 75 | /*! This method returns the centroid of the primitive. 76 | \return The primitive's centroid. 77 | \remark If the centroid is not well-defined, pass the best one and the bounding volume hierarchy will do its 78 | best to handle it. The same centroid must always be returned. */ 79 | virtual Vector Centroid() = 0; 80 | }; 81 | 82 | /* This creates the correct primitive type based on a scene file entity subtype. */ 83 | Primitive* GetPrimitive(uint32_t subtype, std::fstream& file, std::vector* materials, std::vector* lights); 84 | 85 | #endif 86 | -------------------------------------------------------------------------------- /include/primitives/sphere.hpp: -------------------------------------------------------------------------------- 1 | #ifndef SPHERE_H 2 | #define SPHERE_H 3 | 4 | #include 5 | 6 | class Sphere : public Primitive 7 | { 8 | private: 9 | /* The sphere's center. */ 10 | Vector center; 11 | 12 | /* The sphere's radius. */ 13 | float radius; 14 | 15 | /* The sphere's square radius. */ 16 | float radiusSquared; 17 | 18 | /* The sphere's bounding box. */ 19 | AABB boundingBox; 20 | public: 21 | /* Creates the sphere from a scene file. */ 22 | Sphere(std::fstream& file, std::vector* materials, std::vector* lights); 23 | 24 | /* This function returns the closest intersection of a ray with the sphere. */ 25 | virtual float Intersect(const Ray& ray); 26 | 27 | /* This function returns the surface normal of the sphere at a given point. */ 28 | virtual Vector Normal(Vector point); 29 | 30 | /* This function returns the bounding box of the sphere. */ 31 | virtual AABB BoundingBox(){ return this->boundingBox; } 32 | 33 | /* This function returns the centroid of the sphere. */ 34 | virtual Vector Centroid(){ return this->center; } 35 | }; 36 | 37 | #endif // SPHERE_H 38 | -------------------------------------------------------------------------------- /include/primitives/triangle.hpp: -------------------------------------------------------------------------------- 1 | #ifndef TRIANGLE_H 2 | #define TRIANGLE_H 3 | 4 | #include 5 | 6 | class Triangle : public Primitive 7 | { 8 | private: 9 | /* The triangle's three vertices. */ 10 | Vector p1, p2, p3; 11 | 12 | /* The triangle's precomputed edges, normal and centroid. */ 13 | Vector edge1, edge2, normal, centroid; 14 | 15 | /* The triangle's bounding box. */ 16 | AABB boundingBox; 17 | public: 18 | /* Creates the triangle from a scene file. */ 19 | Triangle(std::fstream& file, std::vector* materials, std::vector* lights); 20 | 21 | /* This function returns the closest intersection of a ray with the triangle. */ 22 | virtual float Intersect(const Ray& ray); 23 | 24 | /* This function returns the surface normal of the triangle at a given point. */ 25 | virtual Vector Normal(Vector point); 26 | 27 | /* This function returns the bounding box of the triangle. */ 28 | virtual AABB BoundingBox(){ return this->boundingBox; } 29 | 30 | /* This function returns the centroid of the triangle. */ 31 | virtual Vector Centroid(){ return this->centroid; } 32 | }; 33 | 34 | #endif // TRIANGLE_H 35 | 36 | -------------------------------------------------------------------------------- /include/renderer/renderer.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @file renderer.hpp 3 | * 4 | * \brief Renderer interface 5 | * 6 | * This is the renderer's interface. 7 | */ 8 | 9 | #ifndef RENDERER_H 10 | #define RENDERER_H 11 | 12 | /* We'll need every single header file. */ 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | /* And a few standard includes, too. */ 36 | #include 37 | #include 38 | 39 | /*! This contains global rendering information such as the width and height of the render. */ 40 | #pragma pack(1) 41 | struct RenderParams 42 | { 43 | /*! The width of the render. */ 44 | int32_t width; 45 | /*! The height of the render. */ 46 | int32_t height; 47 | /*! THe number of samples in the render. */ 48 | int32_t samples; 49 | }; 50 | 51 | /*! \class Renderer 52 | * This is the main renderer class which drives the rendering algorithm. */ 53 | class Renderer 54 | { 55 | private: 56 | /*! This is a list of all spectral distributions in use. */ 57 | std::vector* distributions; 58 | /*! This is a list of all the primitives in the scene. */ 59 | std::vector* primitives; 60 | /*! These are all the materials used in the scene. */ 61 | std::vector* materials; 62 | /*! These are all the lights used in the scene. */ 63 | std::vector* lights; 64 | /*! The render parameters to use to render. */ 65 | RenderParams renderParams; 66 | /*! The color system to use for rendering. */ 67 | ColorSystem colorSystem; 68 | /*! This is the camera to render from. */ 69 | Camera* camera; 70 | /*! This is the bounding volume hierarchy. */ 71 | BVH* bvh; 72 | /*! This applies the Reinhard tonemapping operator to a pixel array. */ 73 | void TonemapRender(Vector* pixels); 74 | /*! This gamma-corrects a pixel array. */ 75 | void GammaCorrectRender(Vector* pixels); 76 | /*! Saves a pixel array to a PPM file. */ 77 | void SaveToPPM(Vector* pixels, std::string render, time_t elapsedTime); 78 | /*! Returns a radiance sample along a light ray. */ 79 | float Radiance(Ray ray, float wavelength, std::mt19937* prng); 80 | /*! Number of pixels in the render. */ 81 | size_t pixelCount; 82 | public: 83 | /*! This constructor initializes the renderer from a scene file. 84 | \param scene The scene file to open. */ 85 | Renderer(std::string scene); 86 | 87 | /*! This method renders the scene into a PPM file. 88 | \param threads The number of threads to use. */ 89 | void Render(std::string render, size_t threads); 90 | 91 | /*! This destructor will free all resources used by the renderer. */ 92 | ~Renderer(); 93 | }; 94 | 95 | #endif 96 | -------------------------------------------------------------------------------- /include/scenegraph/bvh.hpp: -------------------------------------------------------------------------------- 1 | // from https://github.com/brandonpelfrey/Fast-BVH 2 | 3 | #ifndef BVH_h 4 | #define BVH_h 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | //! Node descriptor for the flattened tree 12 | struct BVHFlatNode { 13 | AABB bbox; 14 | uint32_t start, nPrims, rightOffset; 15 | }; 16 | 17 | //! \author Brandon Pelfrey 18 | //! A Bounding Volume Hierarchy system for fast Ray-Object intersection tests 19 | class BVH { 20 | uint32_t leafSize; 21 | std::vector* build_prims; 22 | 23 | //! Build the BVH tree out of build_prims 24 | void build(); 25 | 26 | // Fast Traversal System 27 | BVHFlatNode *flatTree; 28 | 29 | public: 30 | uint32_t nNodes, nLeafs; 31 | BVH(std::vector* objects, uint32_t leafSize=4); 32 | bool getIntersection(const Ray& ray, Intersection *intersection, bool occlusion) const ; 33 | 34 | ~BVH(); 35 | }; 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /include/spectral/blackbody.hpp: -------------------------------------------------------------------------------- 1 | #ifndef BLACKBODY_H 2 | #define BLACKBODY_H 3 | 4 | #include 5 | 6 | /* This is a black-body emittance spectral power distribution. */ 7 | class BlackBody : public Distribution 8 | { 9 | private: 10 | /* The black-body's temperature. */ 11 | float temperature; 12 | public: 13 | /* This method creates a spectral distribution from scene file information. */ 14 | BlackBody(std::fstream& file); 15 | 16 | /* This function returns the distribution value at a given wavelength. The exact nature of the result 17 | * depends on the type of spectral distribution (it could be power, refractive index, reflectance, ...) */ 18 | virtual float Lookup(float wavelength); 19 | }; 20 | 21 | #endif 22 | -------------------------------------------------------------------------------- /include/spectral/distribution.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @file distribution.hpp 3 | * 4 | * \brief Spectral distribution interface 5 | * 6 | * This is a common interface for spectral distributions, which are used to describe quantities that vary with 7 | * wavelength, such as reflectance, refractive index, absorption, etc... These basically behave as lookup tables 8 | * and can be implemented either analytically (such as the black-body emission spectrum) or derived from sampled 9 | * data. 10 | */ 11 | 12 | #ifndef DISTRIBUTION_H 13 | #define DISTRIBUTION_H 14 | 15 | /* Some scene file ID's for spectral distributions. */ 16 | #define ID_BLACKBODY 0 17 | #define ID_FLAT 1 18 | #define ID_PEAK 2 19 | #define ID_SELLMEIER 3 20 | 21 | /* We need vector math and files. */ 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | /*! \class Distribution 28 | * This is the base class from which all spectral distributions are derived. */ 29 | class Distribution 30 | { 31 | public: 32 | /*! This method evaluates the spectral distribution at any given wavelength. 33 | \param wavelength The wavelength to evaluate the distribution at. 34 | \return The value of the spectral distribution at the desired wavelength. The exact nature of this value 35 | depends on the type of the distribution. 36 | \remark The wavelength should be in nanometers and range between 380 and 780, i.e. the visible spectrum. */ 37 | virtual float Lookup(float wavelength) = 0; 38 | }; 39 | 40 | /* This creates the correct distribution type based on a scene file entity subtype. */ 41 | Distribution* GetDistribution(uint32_t subtype, std::fstream& file); 42 | 43 | #endif 44 | -------------------------------------------------------------------------------- /include/spectral/flat.hpp: -------------------------------------------------------------------------------- 1 | #ifndef FLAT_H 2 | #define FLAT_H 3 | 4 | #include 5 | 6 | /* This is a flat (constant) spectral distribution. */ 7 | class Flat : public Distribution 8 | { 9 | private: 10 | float constant; 11 | public: 12 | /* This method creates a spectral distribution from scene file information. */ 13 | Flat(std::fstream& file){ file.read((char*)&this->constant, sizeof(float)); } 14 | virtual float Lookup(float wavelength){ return this->constant; } 15 | }; 16 | 17 | #endif // FLAT_H 18 | 19 | 20 | -------------------------------------------------------------------------------- /include/spectral/peak.hpp: -------------------------------------------------------------------------------- 1 | #ifndef PEAK_H 2 | #define PEAK_H 3 | 4 | #include 5 | 6 | /* This is a peak (almost monochromatic) spectral distribution. */ 7 | class Peak : public Distribution 8 | { 9 | private: 10 | float peakWavelength; 11 | public: 12 | /* Specify the desired peak here. */ 13 | Peak(std::fstream& file){ file.read((char*)&this->peakWavelength, sizeof(float)); } 14 | virtual float Lookup(float wavelength){ return exp(-pow(wavelength - this->peakWavelength, 2.0f) * 0.002f); } 15 | }; 16 | 17 | #endif // PEAK_H 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /include/spectral/sellmeier.hpp: -------------------------------------------------------------------------------- 1 | #ifndef SELLMEIER_H 2 | #define SELLMEIER_H 3 | 4 | #include 5 | 6 | /* This is a Sellmeier-based spectral refractive index distribution. */ 7 | class Sellmeier : public Distribution 8 | { 9 | private: 10 | /* The Sellmeier coefficients. */ 11 | float B[3], C[3]; 12 | public: 13 | /* This method creates a spectral distribution from scene file information. */ 14 | Sellmeier(std::fstream& file); 15 | 16 | /* This function returns the distribution value at a given wavelength The exact nature of the result 17 | * depends on the type of spectral distribution (it could be power, refractive index, reflectance, ...) */ 18 | virtual float Lookup(float wavelength); 19 | }; 20 | 21 | #endif 22 | -------------------------------------------------------------------------------- /include/util/aabb.hpp: -------------------------------------------------------------------------------- 1 | // from https://github.com/brandonpelfrey/Fast-BVH 2 | 3 | #ifndef BBox_h 4 | #define BBox_h 5 | 6 | #include 7 | #include 8 | 9 | struct AABB { 10 | Vector min, max, extent; 11 | AABB() { } 12 | AABB(const Vector& min, const Vector& max); 13 | AABB(const Vector& p); 14 | 15 | bool intersect(const Ray& ray, float *tnear, float *tfar) const; 16 | void expandToInclude(const Vector& p); 17 | void expandToInclude(const AABB& b); 18 | uint32_t maxDimension() const; 19 | float surfaceArea() const; 20 | }; 21 | 22 | #endif 23 | -------------------------------------------------------------------------------- /include/util/cie.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CIE_H 2 | #define CIE_H 3 | 4 | #include 5 | #include 6 | 7 | /* This is the resolution of the color-matching curves, in nanometers per sample. */ 8 | #define RESOLUTION 5 9 | 10 | /* The number of wavelengths used per pixel sample. */ 11 | #define WAVELENGTHS (1 + 400 / RESOLUTION) 12 | 13 | /* These are some scene file definitions for color systems. */ 14 | #define ID_EBU 0 15 | #define ID_SMPTE 1 16 | #define ID_HDTV 2 17 | #define ID_REC709 3 18 | #define ID_NTSC 4 19 | #define ID_CIE 5 20 | 21 | /* This is a color system. */ 22 | typedef struct ColorSystem{ 23 | double xRed, yRed; /* Red x, y */ 24 | double xGreen, yGreen; /* Green x, y */ 25 | double xBlue, yBlue; /* Blue x, y */ 26 | double xWhite, yWhite; /* White point x, y */ 27 | double gamma; /* Gamma correction for system */ 28 | } ColorSystem; 29 | 30 | /* These are some relatively common illuminants (white points). */ 31 | #define IlluminantC 0.3101, 0.3162 /* For NTSC television */ 32 | #define IlluminantD65 0.3127, 0.3291 /* For EBU and SMPTE */ 33 | #define IlluminantE 0.33333333, 0.33333333 /* CIE equal-energy illuminant */ 34 | 35 | /* 0 represents a special gamma function. */ 36 | #define GAMMA_REC709 0 37 | 38 | /* These are some standard color systems. */ 39 | const ColorSystem /* xRed yRed xGreen yGreen xBlue yBlue White point Gamma */ 40 | EBUSystem = {0.64, 0.33, 0.29, 0.60, 0.15, 0.06, IlluminantD65, GAMMA_REC709}, 41 | SMPTESystem = {0.630, 0.340, 0.310, 0.595, 0.155, 0.070, IlluminantD65, GAMMA_REC709}, 42 | HDTVSystem = {0.670, 0.330, 0.210, 0.710, 0.150, 0.060, IlluminantD65, GAMMA_REC709}, 43 | Rec709System = {0.64, 0.33, 0.30, 0.60, 0.15, 0.06, IlluminantD65, GAMMA_REC709}, 44 | NTSCSystem = {0.67, 0.33, 0.21, 0.71, 0.14, 0.08, IlluminantC, GAMMA_REC709}, 45 | CIESystem = {0.7355, 0.2645, 0.2658, 0.7243, 0.1669, 0.0085, IlluminantE, GAMMA_REC709}; 46 | 47 | /* A static array of standard color systems. */ 48 | const ColorSystem ColorSystems[6] = {EBUSystem, SMPTESystem, HDTVSystem, Rec709System, NTSCSystem, CIESystem}; 49 | 50 | /* Converts a spectral radiance distribution to an RGB color. */ 51 | Vector SpectrumToRGB(float spectralRadiance[WAVELENGTHS], ColorSystem colorSystem); 52 | 53 | /* Returns the luminance of an RGB color according to a given color system. */ 54 | float Luminance(Vector rgb, ColorSystem colorSystem); 55 | 56 | /* Gamma corrects an RGB color according to a given color system. */ 57 | Vector GammaCorrect(Vector rgb, ColorSystem colorSystem); 58 | 59 | #endif 60 | -------------------------------------------------------------------------------- /include/util/rtmath.hpp: -------------------------------------------------------------------------------- 1 | #ifndef RTMATH_H 2 | #define RTMATH_H 3 | 4 | /* This contains some extra math/utility definitions for ray tracing. */ 5 | 6 | /* Delta function - equals 1 if x equals zero, 0 otherwise. Note the very generous delta epsilon. */ 7 | #define delta(x) (float)(std::abs(x) <= 1e-3f) 8 | 9 | /* Uniform number generation (for C++11 PRNG's only). */ 10 | #define RandomVariable(x) (((*x)() - x->min()) / (float)x->max()) 11 | 12 | #endif 13 | -------------------------------------------------------------------------------- /include/util/vec3.hpp: -------------------------------------------------------------------------------- 1 | // from https://github.com/brandonpelfrey/Fast-BVH 2 | 3 | #ifndef VEC3_H 4 | #define VEC3_H 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | /* Single-precision epsilon. */ 12 | #define EPSILON 1e-5f 13 | 14 | /* Pi. */ 15 | #define PI 3.14159265f 16 | 17 | /* Handy sign function. */ 18 | #define sign(x) ((x > 0.0) - (x < 0.0)) 19 | 20 | /* Zero vector. */ 21 | #define ZERO Vector(0.0f, 0.0f, 0.0f) 22 | 23 | /* Conventional upwards vector. */ 24 | #define UPWARDS Vector(0.0f, 1.0f, 0.0f) 25 | 26 | 27 | 28 | // SSE Vector object 29 | struct Vector { 30 | union __attribute__((aligned(16))) { 31 | struct { float x,y,z,w; }; 32 | __m128 m128; 33 | }; 34 | 35 | Vector() { } 36 | Vector(float x, float y, float z, float w=0.f) : m128(_mm_set_ps(w,z,y,x)) { } 37 | Vector(const __m128& m128) : m128(m128) { } 38 | 39 | void operator+=(Vector a) { *this = *this + a; } 40 | void operator-=(Vector a) { *this = *this - a; } 41 | void operator*=(float a) { *this = *this * a; } 42 | 43 | Vector operator+(const Vector& b) const { return _mm_add_ps(m128, b.m128); } 44 | Vector operator-(const Vector& b) const { return _mm_sub_ps(m128, b.m128); } 45 | Vector operator*(float b) const { return _mm_mul_ps(m128, _mm_set_ps(b,b,b,b)); } 46 | Vector operator/(float b) const { return _mm_div_ps(m128, _mm_set_ps(b,b,b,b)); } 47 | 48 | // Component-wise multiply and divide 49 | Vector cmul(const Vector& b) const { return _mm_mul_ps(m128, b.m128); } 50 | Vector cdiv(const Vector& b) const { return _mm_div_ps(m128, b.m128); } 51 | 52 | // dot (inner) product 53 | float operator*(const Vector& b) const { 54 | return x*b.x + y*b.y + z*b.z; 55 | } 56 | 57 | // Cross Product 58 | Vector operator^(const Vector& b) const { 59 | return _mm_sub_ps( 60 | _mm_mul_ps( 61 | _mm_shuffle_ps(m128, m128, _MM_SHUFFLE(3, 0, 2, 1)), 62 | _mm_shuffle_ps(b.m128, b.m128, _MM_SHUFFLE(3, 1, 0, 2))), 63 | _mm_mul_ps( 64 | _mm_shuffle_ps(m128, m128, _MM_SHUFFLE(3, 1, 0, 2)), 65 | _mm_shuffle_ps(b.m128, b.m128, _MM_SHUFFLE(3, 0, 2, 1))) 66 | ); 67 | } 68 | 69 | Vector operator/(const Vector& b) const { return _mm_div_ps(m128, b.m128); } 70 | 71 | // Handy component indexing 72 | float& operator[](const unsigned int i) { return (&x)[i]; } 73 | const float& operator[](const unsigned int i) const { return (&x)[i]; } 74 | }; 75 | 76 | inline Vector operator*(float a, const Vector&b) { return _mm_mul_ps(_mm_set1_ps(a), b.m128); } 77 | 78 | // Component-wise min 79 | inline Vector min(const Vector& a, const Vector& b) { 80 | return _mm_min_ps(a.m128, b.m128); 81 | } 82 | 83 | // Component-wise max 84 | inline Vector max(const Vector& a, const Vector& b) { 85 | return _mm_max_ps(a.m128, b.m128); 86 | } 87 | 88 | // Length of a vector 89 | inline float length(const Vector& a) { 90 | return sqrtf(a*a); 91 | } 92 | 93 | // Make a vector unit length 94 | inline Vector normalize(const Vector& in) { 95 | Vector a = in; 96 | a.w = 0.f; 97 | 98 | __m128 D = a.m128; 99 | D = _mm_mul_ps(D, D); 100 | D = _mm_hadd_ps(D, D); 101 | D = _mm_hadd_ps(D, D); 102 | 103 | // 1 iteration of Newton-raphson -- Idea from Intel's Embree. 104 | __m128 r = _mm_rsqrt_ps(D); 105 | r = _mm_add_ps( 106 | _mm_mul_ps(_mm_set_ps(1.5f, 1.5f, 1.5f, 1.5f), r), 107 | _mm_mul_ps(_mm_mul_ps(_mm_mul_ps(D, _mm_set_ps(-0.5f, -0.5f, -0.5f, -0.5f)), r), _mm_mul_ps(r, r))); 108 | 109 | return _mm_mul_ps( a.m128, r ); 110 | } 111 | 112 | inline Vector lerp(Vector a, Vector b, float t) 113 | { 114 | return a + (b - a) * t; 115 | } 116 | 117 | /* Returns a unit vector from a pair of spherical coordinates, azimuth and inclination. */ 118 | inline Vector spherical(float phi, float theta) 119 | { 120 | return Vector{cosf(phi) * sinf(theta), cosf(theta), sinf(phi) * sinf(theta)}; 121 | } 122 | 123 | /* Rotates a unit vector around a normal vector - more accurately, transforms the vector from world coordinates to 124 | * normal coordinates defined by the orthonormal basis described by the normal vector as the upwards axis. */ 125 | inline Vector rotate(Vector a, Vector n) 126 | { 127 | /* If the normal vector is already the world space upwards (or downwards) vector, don't do anything. */ 128 | if (!delta(1 - std::abs(n * UPWARDS))) 129 | { 130 | /* Build the orthonormal basis of the normal vector. */ 131 | Vector bX = normalize(n ^ UPWARDS); 132 | Vector bZ = normalize(n ^ bX); 133 | 134 | /* Transform the unit vector to this basis. */ 135 | return bX * a.x + n * a.y + bZ * a.z; 136 | } else return a * sign(a * n); 137 | } 138 | 139 | /* Returns the reflection of a vector on a normal. */ 140 | inline Vector reflect(Vector i, Vector n) 141 | { 142 | return i - n * (2 * (i * n)); 143 | } 144 | 145 | /* This is a ray. */ 146 | struct Ray { 147 | Vector o; // Ray Origin 148 | Vector d; // Ray Direction 149 | Vector inv_d; // Inverse of each Ray Direction component 150 | 151 | Ray(const Vector& o, const Vector& d) 152 | : o(o), d(d), inv_d(Vector(1,1,1).cdiv(d)) { } 153 | }; 154 | 155 | #endif 156 | -------------------------------------------------------------------------------- /render/README.md: -------------------------------------------------------------------------------- 1 | Gallery 2 | ============== 3 | 4 | These are some high resolution renders produced by Lambda. 5 | 6 |

7 | Frosted Glass Dragon 8 |

9 | This is the ubiquitous Stanford Dragon using a frosted glass material, with a statue of Lucy in the background. The scene totals 625k polygons (100k triangles for the dragon, 525k for the angel) and took 9h21m to render with 1024 samples per pixel at 512x512 (unidirectional path tracing). 10 | 11 |

12 | Glass Ajax & Lucy 13 |

14 | This is a demonstration of the frosted glass BTDF, with high resolution Lucy and Ajax statues. There were about 1.1 million triangles. This render has been amended once, if you saw the previous one, it was using the unfinished BTDF, this one is now physically correct (the difference is very subtle). 15 | 16 |

17 | Metallic Lucy 18 |

19 | This is a demonstration of the Cook-Torrance BRDF, with a refractive index of 3.85 along with a glass cup. The cup shows Fresnel reflection very clearly. 20 | -------------------------------------------------------------------------------- /render/ajax_lucy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TomCrypto/Lambda/7b1fb0cae05de9d88f3d848d65b7366e64409781/render/ajax_lucy.png -------------------------------------------------------------------------------- /render/frosted_dragon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TomCrypto/Lambda/7b1fb0cae05de9d88f3d848d65b7366e64409781/render/frosted_dragon.png -------------------------------------------------------------------------------- /render/metal_lucy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TomCrypto/Lambda/7b1fb0cae05de9d88f3d848d65b7366e64409781/render/metal_lucy.png -------------------------------------------------------------------------------- /scenes/cornellbox: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TomCrypto/Lambda/7b1fb0cae05de9d88f3d848d65b7366e64409781/scenes/cornellbox -------------------------------------------------------------------------------- /scenes/spheres: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TomCrypto/Lambda/7b1fb0cae05de9d88f3d848d65b7366e64409781/scenes/spheres -------------------------------------------------------------------------------- /src/cameras/camera.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | /* All camera types. */ 4 | #include 5 | 6 | /* This creates the correct camera type based on a scene file entity subtype. */ 7 | Camera* GetCamera(uint32_t subtype, std::fstream& file) 8 | { 9 | switch (subtype) 10 | { 11 | case ID_PERSPECTIVE: return new Perspective(file); 12 | } 13 | 14 | /* Unknown subtype. */ 15 | return nullptr; 16 | } 17 | -------------------------------------------------------------------------------- /src/cameras/perspective.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | /* Perspective CG camera definition. */ 4 | #pragma pack(1) 5 | struct PerspectiveCGDefinition 6 | { 7 | /* Camera position and target, and field of view (in radians). */ 8 | float pos[3], tar[3]; 9 | float fieldOfView; 10 | }; 11 | 12 | /* Creates the perspective camera from a scene file. */ 13 | Perspective::Perspective(std::fstream& file) 14 | { 15 | /* Read the camera definition from the scene file. */ 16 | PerspectiveCGDefinition definition; 17 | file.read((char*)&definition, sizeof(PerspectiveCGDefinition)); 18 | 19 | /* Save the camera's position. */ 20 | this->position = Vector(definition.pos[0], definition.pos[1], definition.pos[2]); 21 | Vector target = Vector(definition.tar[0], definition.tar[1], definition.tar[2]); 22 | 23 | /* Build the focal plane. */ 24 | buildFocalPlane(target, definition.fieldOfView); 25 | } 26 | 27 | void Perspective::buildFocalPlane(Vector target, float fieldOfView) 28 | { 29 | /* Define the orthonormal basis for this lookat vector. */ 30 | Vector zAxis = normalize(target - this->position); 31 | Vector xAxis = normalize(UPWARDS ^ zAxis); 32 | Vector yAxis = normalize(zAxis ^ xAxis); 33 | 34 | /* Compute the inverse view matrix from the orthonormal basis. */ 35 | Vector inverseViewMatrix[3] = { 36 | Vector{xAxis.x, yAxis.x, zAxis.x}, 37 | Vector{xAxis.y, yAxis.y, zAxis.y}, 38 | Vector{xAxis.z, yAxis.z, zAxis.z} 39 | }; 40 | 41 | /* Scale the field of view accordingly. */ 42 | float FOV = tan(fieldOfView * 0.5f); 43 | 44 | /* Compute the focal plane corners. */ 45 | Vector multiplicand = Vector(-FOV, -FOV, 1); 46 | this->focalPlane[0] = Vector(multiplicand * inverseViewMatrix[0], 47 | multiplicand * inverseViewMatrix[1], 48 | multiplicand * inverseViewMatrix[2]); 49 | 50 | multiplicand = Vector(+FOV, -FOV, 1); 51 | this->focalPlane[1] = Vector(multiplicand * inverseViewMatrix[0], 52 | multiplicand * inverseViewMatrix[1], 53 | multiplicand * inverseViewMatrix[2]); 54 | 55 | multiplicand = Vector(+FOV, +FOV, 1); 56 | this->focalPlane[2] = Vector(multiplicand * inverseViewMatrix[0], 57 | multiplicand * inverseViewMatrix[1], 58 | multiplicand * inverseViewMatrix[2]); 59 | 60 | multiplicand = Vector(-FOV, +FOV, 1); 61 | this->focalPlane[3] = Vector(multiplicand * inverseViewMatrix[0], 62 | multiplicand * inverseViewMatrix[1], 63 | multiplicand * inverseViewMatrix[2]); 64 | } 65 | 66 | /* Traces the camera ray. */ 67 | Ray Perspective::Trace(float u, float v) 68 | { 69 | /* Simply interpolate the ray's direction. */ 70 | return Ray(this->position, 71 | normalize(lerp(lerp(this->focalPlane[0], this->focalPlane[1], (u + 1.0f) * 0.5f), 72 | lerp(this->focalPlane[3], this->focalPlane[2], (u + 1.0f) * 0.5f), (1.0f - v) * 0.5f))); 73 | } 74 | -------------------------------------------------------------------------------- /src/lights/light.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | /* All light types. */ 4 | #include 5 | 6 | /* This creates the correct light type based on a scene file entity subtype. */ 7 | Light* GetLight(uint32_t subtype, std::fstream& file, std::vector* distributions) 8 | { 9 | switch(subtype) 10 | { 11 | case ID_OMNI: return new Omni(file, distributions); 12 | } 13 | 14 | /* Unknown subtype. */ 15 | return nullptr; 16 | } 17 | 18 | -------------------------------------------------------------------------------- /src/lights/omni.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | /* Omni light scene file definition. */ 4 | #pragma pack(1) 5 | struct OmniDefinition 6 | { 7 | /* The index of the emittance distribution. */ 8 | uint32_t emittance; 9 | }; 10 | 11 | /* Creates the omni light from a scene file. */ 12 | Omni::Omni(std::fstream& file, std::vector* distributions) 13 | { 14 | /* Read the light definition from the scene file. */ 15 | OmniDefinition definition; 16 | file.read((char*)&definition, sizeof(OmniDefinition)); 17 | 18 | /* Get the appropriate distribution from the distribution vector. */ 19 | this->emittance = distributions->at(definition.emittance); 20 | } 21 | -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | int main(int argc, char* argv[]) 6 | { 7 | /* Ask the user for a scene file if not passed. */ 8 | string sceneFile; 9 | if (argc > 3) sceneFile = argv[1]; else 10 | { 11 | cout << "[+] Scene file to render: "; 12 | getline(cin, sceneFile); 13 | } 14 | 15 | /* Ask the user for an output file, if not passed. */ 16 | string renderFile; 17 | if (argc > 3) renderFile = argv[2]; else 18 | { 19 | cout << "[+] Output file: "; 20 | getline(cin, renderFile); 21 | } 22 | 23 | /* Ask the user for a number of threads if unspecified. */ 24 | size_t threadCount; 25 | if (argc > 3) threadCount = atoi(argv[3]); else 26 | { 27 | cout << "[+] Thread count: "; 28 | cin >> threadCount; 29 | } 30 | 31 | /* Line break (this is just for aesthetics). */ 32 | if (argc <= 3) cout << endl; 33 | 34 | /* Initialize the renderer. */ 35 | Renderer* renderer = new Renderer(sceneFile); 36 | 37 | /* Render the scene. */ 38 | renderer->Render(renderFile, threadCount); 39 | 40 | /* Free everything. */ 41 | delete renderer; 42 | return 0; 43 | } 44 | -------------------------------------------------------------------------------- /src/materials/cooktorrance.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | /* Cook-Torrance material scene file definition. */ 4 | #pragma pack(1) 5 | struct CookTorranceDefinition 6 | { 7 | /* The index of the reflectance, and refractive index, distributions. */ 8 | uint32_t reflectance, refractiveIndex; 9 | /* The roughness of the surface. */ 10 | float roughness; 11 | }; 12 | 13 | /* Creates the material from a scene file. */ 14 | CookTorrance::CookTorrance(std::fstream& file, std::vector* distributions) : Material(file) 15 | { 16 | /* Read the material definition from the scene file. */ 17 | CookTorranceDefinition definition; 18 | file.read((char*)&definition, sizeof(CookTorranceDefinition)); 19 | 20 | /* Get the appropriate distribution from the distribution vector. */ 21 | this->reflectance = distributions->at(definition.reflectance); 22 | this->refractiveIndex = distributions->at(definition.refractiveIndex); 23 | this->roughness = definition.roughness; 24 | } 25 | 26 | Vector CookTorrance::Sample(Vector* origin, Vector incident, Vector normal, float wavelength, std::mt19937* prng) 27 | { 28 | /* Align the normal with the incident vector. */ 29 | if (incident * normal > 0.0f) normal = ZERO - normal; 30 | 31 | /* Move the origin outside the surface slightly. */ 32 | (*origin) = (*origin) + normal * EPSILON; 33 | 34 | /* Generate a random microfacet normal based on the Beckmann distribution with the given roughness. */ 35 | float r1 = RandomVariable(prng); 36 | float r2 = RandomVariable(prng); 37 | float theta = atan(-pow(this->roughness, 2.0f) * log(1.0f - r1)); 38 | float phi = 2.0f * PI * r2; 39 | Vector m = spherical(phi, theta); 40 | m = rotate(m, normal); 41 | 42 | /* Reflect the incident vector accordingly. */ 43 | return reflect(incident, m); 44 | } 45 | 46 | /* This returns the reflectance for an incident and exitant vector. */ 47 | float CookTorrance::Reflectance(Vector incident, Vector exitant, Vector normal, float wavelength, bool sampled) 48 | { 49 | /* Compute the half-angle vector. */ 50 | Vector H = normalize(exitant - incident); 51 | 52 | /* If the ray was not importance-sampled, we need to take into account the distribution. */ 53 | float D = 1.0f; 54 | if (!sampled) 55 | { 56 | /* Get the half angle vector's angle with the normal. */ 57 | float alpha = acos(H * normal); 58 | 59 | /* Compute the Beckmann distribution. */ 60 | D = exp(-pow(tanf(alpha) / this->roughness, 2.0f)); 61 | } 62 | 63 | /* Align the normal with the incident vector. */ 64 | if (incident * normal > 0.0f) normal = ZERO - normal; 65 | 66 | /* Compute the refractive indices. */ 67 | float n2 = this->refractiveIndex->Lookup(wavelength); 68 | float n1 = 1.0f; 69 | 70 | /* Compute the theoretical reflected and refracted angles. */ 71 | float cosI = std::abs(incident * normal); 72 | float cosT = sqrtf(1.0f - pow(n1 / n2, 2.0f) * (1.0f - pow(cosI, 2.0f))); 73 | 74 | /* Compute the Fresnel term for the incident vector. */ 75 | float F = (pow((n1 * cosI - n2 * cosT) / (n1 * cosI + n2 * cosT), 2.0f) + pow((n2 * cosI - n1 * cosT) / (n1 * cosT + n2 * cosI), 2.0f)) * 0.5f; 76 | 77 | /* Compute the geometric attenuation term. */ 78 | float NdL = std::abs(normal * exitant); 79 | float VdH = std::abs(incident * H); 80 | float NdH = std::abs(normal * H); 81 | float NdV = cosI; 82 | float G = std::min(1.0f, std::min(2.0f * NdH * NdV / VdH, 2.0f * NdH * NdL / VdH)); 83 | 84 | /* Compute the microfacet normalization term. */ 85 | float norm = 1.0f / (PI * pow(this->roughness, 2.0f) * pow(NdH, 4.0f)); 86 | 87 | /* Compute the reflectance (note the lambertian term cancels a dot product out). */ 88 | return norm * this->reflectance->Lookup(wavelength) * (F * D * G) / (NdV); 89 | } 90 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /src/materials/diffuse.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | /* Diffuse material scene file definition. */ 4 | #pragma pack(1) 5 | struct DiffuseDefinition 6 | { 7 | /* The index of the reflectance distribution. */ 8 | uint32_t reflectance; 9 | }; 10 | 11 | /* Creates the diffuse material from a scene file. */ 12 | Diffuse::Diffuse(std::fstream& file, std::vector* distributions) : Material(file) 13 | { 14 | /* Read the material definition from the scene file. */ 15 | DiffuseDefinition definition; 16 | file.read((char*)&definition, sizeof(DiffuseDefinition)); 17 | 18 | /* Get the appropriate distribution from the distribution vector. */ 19 | this->reflectance = distributions->at(definition.reflectance); 20 | } 21 | 22 | Vector Diffuse::Sample(Vector* origin, Vector incident, Vector normal, float wavelength, std::mt19937* prng) 23 | { 24 | /* Align the normal with the incident vector. */ 25 | if (incident * normal > 0.0f) normal = ZERO - normal; 26 | 27 | /* Move the origin outside the surface slightly. */ 28 | (*origin) = (*origin) + normal * EPSILON; 29 | 30 | /* Get two random numbers. */ 31 | float u1 = RandomVariable(prng); 32 | float u2 = RandomVariable(prng); 33 | 34 | /* Compute a cosine-weighted vector. */ 35 | float theta = 2.0f * PI * u2; 36 | float r = sqrtf(u1); 37 | 38 | /* Get the unit vector. */ 39 | Vector direction = Vector(r * cosf(theta), sqrtf(1.0f - u1), r * sinf(theta)); 40 | 41 | /* Rotate the vector with the normal. */ 42 | return rotate(direction, normal); 43 | } 44 | 45 | /* This returns the reflectance for an incident and exitant vector. */ 46 | float Diffuse::Reflectance(Vector incident, Vector exitant, Vector normal, float wavelength, bool sampled) 47 | { 48 | /* If the exitant ray was importance-sampled... */ 49 | if (sampled) 50 | { 51 | /* This is just a constant by definition, but we are using a cosine-weighted distribution so we divide 52 | * the reflectance by the cosine-weighted PDF (which happens to be cos(exitant, normal)). Note the 53 | * ubiquitous 1/pi factor happens to cancel out cleanly due to the sampling scheme. */ 54 | return std::max(this->reflectance->Lookup(wavelength), 0.0f); 55 | } 56 | else 57 | { 58 | /* Otherwise, use the uniform sampling formulation. */ 59 | return std::max(2.0f * this->reflectance->Lookup(wavelength) * std::abs(exitant * normal), 0.0f); 60 | } 61 | 62 | 63 | } 64 | -------------------------------------------------------------------------------- /src/materials/frostedglass.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | /* Frosted glass material scene file definition. */ 4 | #pragma pack(1) 5 | struct FrostedGlassDefinition 6 | { 7 | /* The index of the refractive index distribution. */ 8 | uint32_t refractiveIndex; 9 | /* The roughness of the glass. */ 10 | float roughness; 11 | }; 12 | 13 | /* Creates the material from a scene file. */ 14 | FrostedGlass::FrostedGlass(std::fstream& file, std::vector* distributions) : Material(file) 15 | { 16 | /* Read the material definition from the scene file. */ 17 | FrostedGlassDefinition definition; 18 | file.read((char*)&definition, sizeof(FrostedGlassDefinition)); 19 | 20 | /* Get the appropriate distribution from the distribution vector. */ 21 | this->refractiveIndex = distributions->at(definition.refractiveIndex); 22 | this->roughness = definition.roughness; 23 | } 24 | 25 | Vector FrostedGlass::Sample(Vector* origin, Vector incident, Vector normal, float wavelength, std::mt19937* prng) 26 | { 27 | /* Generate a random microfacet normal based on the Beckmann distribution with the given roughness. */ 28 | float r1 = RandomVariable(prng); 29 | float r2 = RandomVariable(prng); 30 | float theta = atan(-pow(this->roughness, 2.0f) * log(1.0f - r1)); 31 | float phi = 2.0f * PI * r2; 32 | Vector m = spherical(phi, theta); 33 | 34 | /* Rotate the microfacet normal according to the actual surface normal. */ 35 | m = rotate(m, normal); 36 | 37 | /* Work out the correct n1 and n2 depending on the incident vector's direction relative to the normal. */ 38 | float cosI = incident * normal; 39 | float n1, n2; 40 | if (cosI > 0) 41 | { 42 | /* Incident and normal have the same direction, ray is inside the material. */ 43 | n1 = this->refractiveIndex->Lookup(wavelength); 44 | n2 = 1.0f; 45 | 46 | /* Flip the microfacet normal around. */ 47 | m = ZERO - m; 48 | } 49 | else 50 | { 51 | /* Incident and normal have opposite directions, so the ray is outside the material. */ 52 | n2 = this->refractiveIndex->Lookup(wavelength); 53 | n1 = 1.0f; 54 | 55 | /* Make the cosine positive. */ 56 | cosI = -cosI; 57 | } 58 | 59 | /* Calculate the refracted angle's cosine. */ 60 | float cosT = 1.0f - pow(n1 / n2, 2.0f) * (1.0f - pow(cosI, 2.0f)); 61 | 62 | /* Check for total internal reflection. */ 63 | if (cosT < 0.0f) 64 | { 65 | /* Total internal reflection occurred. */ 66 | (*origin) = (*origin) + m * EPSILON; 67 | return reflect(incident, m); 68 | } 69 | 70 | /* Otherwise, finish computing the angle. */ 71 | cosT = sqrt(cosT); 72 | 73 | /* Now, compute the Fresnel coefficients for reflection and refraction for a randomly polarized ray. */ 74 | float R = (pow((n1 * cosI - n2 * cosT) / (n1 * cosI + n2 * cosT), 2.0f) + pow((n2 * cosI - n1 * cosT) / (n1 * cosT + n2 * cosI), 2.0f)) * 0.5f; 75 | 76 | /* Perform a random trial to decide whether to reflect or refract the ray. */ 77 | if (RandomVariable(prng) < R) 78 | { 79 | /* Reflection. */ 80 | (*origin) = (*origin) + m * EPSILON; 81 | return reflect(incident, m); 82 | } 83 | else 84 | { 85 | /* Refraction. */ 86 | (*origin) = (*origin) - m * EPSILON; 87 | return incident * (n1 / n2) + m * ((n1 / n2) * cosI - cosT); 88 | } 89 | } 90 | 91 | /* This returns the reflectance for an incident and exitant vector. */ 92 | float FrostedGlass::Reflectance(Vector incident, Vector exitant, Vector normal, float wavelength, bool sampled) 93 | { 94 | /* Work out the refractive indices. */ 95 | float n1, n2; 96 | if (incident * normal) 97 | { 98 | /* Incident and normal have the same direction, ray is inside the material. */ 99 | n1 = this->refractiveIndex->Lookup(wavelength); 100 | n2 = 1.0f; 101 | 102 | /* Flip the microfacet normal around. */ 103 | normal = ZERO - normal; 104 | } 105 | else 106 | { 107 | /* Incident and normal have opposite directions, so the ray is outside the material. */ 108 | n2 = this->refractiveIndex->Lookup(wavelength); 109 | n1 = 1.0f; 110 | } 111 | 112 | /* Check whether reflection or refraction occurred. */ 113 | Vector H; 114 | float D = 1.0f; 115 | if (incident * exitant < 0.0f) 116 | { 117 | /* Reflection occurred, find the half-angle vector. */ 118 | H = normalize(exitant - incident); 119 | 120 | /* If the ray was not importance-sampled, we need to take into account the distribution. */ 121 | if (!sampled) 122 | { 123 | /* Get the half angle vector's angle with the normal. */ 124 | float alpha = acos(H * normal); 125 | 126 | /* Compute the Beckmann distribution. */ 127 | D = exp(-pow(tanf(alpha) / this->roughness, 2.0f)); 128 | } 129 | } 130 | else 131 | { 132 | /* Refraction occurred, we have to find the microfacet normal. */ 133 | float cI = std::abs(incident * normal); 134 | float cT = 1.0f - pow(n1 / n2, 2.0f) * (1.0f - pow(cI, 2.0f)); 135 | H = (incident * (n1 / n2) - exitant) / ((n1 / n2) * cI - cT); 136 | 137 | /* If the ray was not importance-sampled, we need to take into account the distribution. */ 138 | if (!sampled) 139 | { 140 | /* Get the half angle vector's angle with the normal. */ 141 | float alpha = acos(H * normal); 142 | 143 | /* Compute the Beckmann distribution. */ 144 | D = exp(-pow(tanf(alpha) / this->roughness, 2.0f)); 145 | } 146 | } 147 | 148 | /* Compute the geometric attenuation term. */ 149 | float NdV = std::abs(incident * normal); 150 | float NdL = std::abs(normal * exitant); 151 | float VdH = std::abs(incident * H); 152 | float NdH = std::abs(normal * H); 153 | float G = std::min(1.0f, std::min(2.0f * NdH * NdV / VdH, 2.0f * NdH * NdL / VdH)); 154 | 155 | /* Compute the microfacet normalization term. */ 156 | float norm = 1.0f / (PI * pow(this->roughness, 2.0f) * pow(NdH, 4.0f)); 157 | 158 | /* Compute the reflectance (note the lambertian term cancels a dot product out). 159 | * Also note we do NOT use the fresnel term if the ray was importance-sampled, 160 | * since we were already weighting the probability of reflection and refraction 161 | * with it when sampling the BTDF. */ 162 | return norm * (D * G) / (NdV); 163 | } 164 | 165 | 166 | -------------------------------------------------------------------------------- /src/materials/material.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | /* All material types. */ 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | /* This is a material scene file header. */ 11 | struct MaterialDefinition 12 | { 13 | /* The outside and inside extinction coefficients. */ 14 | float e1, e2; 15 | }; 16 | 17 | /* Creates a material from a scene file. */ 18 | Material::Material(std::fstream& file) 19 | { 20 | /* Read the material header from the scene file. */ 21 | MaterialDefinition definition; 22 | file.read((char*)&definition, sizeof(MaterialDefinition)); 23 | 24 | /* Set the appropriate class fields. */ 25 | this->e1 = definition.e1; 26 | this->e2 = definition.e2; 27 | } 28 | 29 | /* This creates the correct material type based on a scene file entity subtype. */ 30 | Material* GetMaterial(uint32_t subtype, std::fstream& file, std::vector* distributions) 31 | { 32 | switch(subtype) 33 | { 34 | case ID_DIFFUSE: return new Diffuse(file, distributions); 35 | case ID_SPECULAR: return new Specular(file, distributions); 36 | case ID_SMOOTHGLASS: return new SmoothGlass(file, distributions); 37 | case ID_FROSTEDGLASS: return new FrostedGlass(file, distributions); 38 | case ID_COOKTORRANCE: return new CookTorrance(file, distributions); 39 | } 40 | 41 | /* Unknown subtype. */ 42 | return nullptr; 43 | } 44 | -------------------------------------------------------------------------------- /src/materials/smoothglass.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | /* Smooth glass material scene file definition. */ 4 | #pragma pack(1) 5 | struct SmoothGlassDefinition 6 | { 7 | /* The index of the refractive index distribution. */ 8 | uint32_t refractiveIndex; 9 | }; 10 | 11 | /* Creates the diffuse material from a scene file. */ 12 | SmoothGlass::SmoothGlass(std::fstream& file, std::vector* distributions) : Material(file) 13 | { 14 | /* Read the material definition from the scene file. */ 15 | SmoothGlassDefinition definition; 16 | file.read((char*)&definition, sizeof(SmoothGlassDefinition)); 17 | 18 | /* Get the appropriate distribution from the distribution vector. */ 19 | this->refractiveIndex = distributions->at(definition.refractiveIndex); 20 | } 21 | 22 | Vector SmoothGlass::Sample(Vector* origin, Vector incident, Vector normal, float wavelength, std::mt19937* prng) 23 | { 24 | /* Work out the correct n1 and n2 depending on the incident vector's direction relative to the normal. */ 25 | float cosI = incident * normal; 26 | float n1, n2; 27 | if (cosI > 0) 28 | { 29 | /* Incident and normal have the same direction, ray is inside the material. */ 30 | n1 = this->refractiveIndex->Lookup(wavelength); 31 | n2 = 1.0f; 32 | 33 | /* Flip the normal around. */ 34 | normal = ZERO - normal; 35 | } 36 | else 37 | { 38 | /* Incident and normal have opposite directions, so the ray is outside the material. */ 39 | n2 = this->refractiveIndex->Lookup(wavelength); 40 | n1 = 1.0f; 41 | 42 | /* Make the cosine positive. */ 43 | cosI = -cosI; 44 | } 45 | 46 | /* Calculate the refracted angle's cosine. */ 47 | float cosT = 1.0f - pow(n1 / n2, 2.0f) * (1.0f - pow(cosI, 2.0f)); 48 | 49 | /* Check for total internal reflection. */ 50 | if (cosT < 0.0f) 51 | { 52 | /* Total internal reflection occurred. */ 53 | (*origin) = (*origin) + normal * EPSILON; 54 | return reflect(incident, normal); 55 | } 56 | 57 | /* Otherwise, finish computing the angle. */ 58 | cosT = sqrt(cosT); 59 | 60 | /* Now, compute the Fresnel coefficients for reflection and refraction for a randomly polarized ray. */ 61 | float R = (pow((n1 * cosI - n2 * cosT) / (n1 * cosI + n2 * cosT), 2.0f) + pow((n2 * cosI - n1 * cosT) / (n1 * cosT + n2 * cosI), 2.0f)) * 0.5f; 62 | 63 | /* Perform a random trial to decide whether to reflect or refract the ray. */ 64 | if (RandomVariable(prng) < R) 65 | { 66 | /* Reflection. */ 67 | (*origin) = (*origin) + normal * EPSILON; 68 | return reflect(incident, normal); 69 | } 70 | else 71 | { 72 | /* Refraction. */ 73 | (*origin) = (*origin) - normal * EPSILON; 74 | return incident * (n1 / n2) + normal * ((n1 / n2) * cosI - cosT); 75 | } 76 | } 77 | 78 | /* This returns the reflectance for an incident and exitant vector. */ 79 | float SmoothGlass::Reflectance(Vector incident, Vector exitant, Vector normal, float wavelength, bool sampled) 80 | { 81 | /* If the exitant ray was importance sampled... */ 82 | if (sampled) 83 | { 84 | /* The reflectance will here be constant, because we've already weighted the 85 | * reflection/refraction probability according to the Fresnel equations. */ 86 | return 1.0f; 87 | } 88 | else 89 | { 90 | /* Otherwise, use delta functions to decide whether the incident and exitant rays are coherent. */ 91 | // not done 92 | return 0; 93 | } 94 | } 95 | 96 | -------------------------------------------------------------------------------- /src/materials/specular.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | /* Specular material scene file definition. */ 4 | #pragma pack(1) 5 | struct SpecularDefinition 6 | { 7 | /* The index of the reflectance distribution. */ 8 | uint32_t reflectance; 9 | }; 10 | 11 | /* Creates the specular material from a scene file. */ 12 | Specular::Specular(std::fstream& file, std::vector* distributions) : Material(file) 13 | { 14 | /* Read the material definition from the scene file. */ 15 | SpecularDefinition definition; 16 | file.read((char*)&definition, sizeof(SpecularDefinition)); 17 | 18 | /* Get the appropriate distribution from the distribution vector. */ 19 | this->reflectance = distributions->at(definition.reflectance); 20 | } 21 | 22 | Vector Specular::Sample(Vector* origin, Vector incident, Vector normal, float wavelength, std::mt19937* prng) 23 | { 24 | /* Align the normal with the incident vector. */ 25 | if (incident * normal > 0) normal = ZERO - normal; 26 | 27 | /* Move the origin outside the surface slightly. */ 28 | (*origin) = (*origin) + normal * EPSILON; 29 | 30 | /* Just return the reflected angle. */ 31 | return reflect(incident, normal); 32 | } 33 | 34 | /* This returns the reflectance for an incident and exitant vector. */ 35 | float Specular::Reflectance(Vector incident, Vector exitant, Vector normal, float wavelength, bool sampled) 36 | { 37 | /* If the exitant ray was importance-sampled... */ 38 | if (sampled) 39 | { 40 | /* Then we know it satisfies the law of reflection, so return the reflectance. */ 41 | return std::max(this->reflectance->Lookup(wavelength), 0.0f); 42 | } 43 | else 44 | { 45 | /* Otherwise, find the expected reflected vector. */ 46 | Vector expected = reflect(incident, normal); 47 | 48 | /* Return full reflectance if the exitant vector is the expected vector, otherwise zero. */ 49 | if (!delta(1.0f - expected * exitant)) return 0.0f; 50 | else return std::max(this->reflectance->Lookup(wavelength), 0.0f); 51 | } 52 | } 53 | 54 | -------------------------------------------------------------------------------- /src/primitives/primitive.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | /* All primitive types. */ 4 | #include 5 | #include 6 | 7 | /* This is a primitive scene file header. */ 8 | struct PrimitiveDefinition 9 | { 10 | /* The primitive's material (negative if it has none). */ 11 | int32_t material; 12 | /* The primitive's light (negative if it has none). */ 13 | int32_t light; 14 | }; 15 | 16 | /* Creates a primitive, from a scene file and a list of materials and lights. */ 17 | Primitive::Primitive(std::fstream& file, std::vector* materials, std::vector* lights) 18 | { 19 | /* Read the primitive header from the scene file. */ 20 | PrimitiveDefinition definition; 21 | file.read((char*)&definition, sizeof(PrimitiveDefinition)); 22 | 23 | /* Set the appropriate materials and lights from the passed vectors. */ 24 | this->material = (definition.material >= 0) ? materials->at(definition.material) : nullptr; 25 | this->light = (definition.light >= 0) ? lights->at(definition.light) : nullptr; 26 | } 27 | 28 | /* This creates the correct primitive type based on a scene file entity subtype. */ 29 | Primitive* GetPrimitive(uint32_t subtype, std::fstream& file, std::vector* materials, std::vector* lights) 30 | { 31 | switch(subtype) 32 | { 33 | case ID_SPHERE: return new Sphere(file, materials, lights); 34 | case ID_TRIANGLE: return new Triangle(file, materials, lights); 35 | } 36 | 37 | /* Unknown subtype. */ 38 | return nullptr; 39 | } 40 | -------------------------------------------------------------------------------- /src/primitives/sphere.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | /* This defines a sphere primitive. */ 4 | #pragma pack(1) 5 | struct SphereDefinition 6 | { 7 | float center[3]; 8 | float radius; 9 | }; 10 | 11 | /* Creates the sphere from a scene file. */ 12 | Sphere::Sphere(std::fstream& file, std::vector* materials, std::vector* lights) : Primitive(file, materials, lights) 13 | { 14 | /* Read the sphere definition from the scene file. */ 15 | SphereDefinition definition; 16 | file.read((char*)&definition, sizeof(SphereDefinition)); 17 | 18 | /* Read the geometric center and radius of the sphere. */ 19 | this->center = Vector(definition.center[0], definition.center[1], definition.center[2]); 20 | this->radius = definition.radius; 21 | 22 | /* Compute the sphere's radius squared. */ 23 | this->radiusSquared = this->radius * this->radius; 24 | 25 | /* Compute the sphere's bounding box. */ 26 | Vector radiusVector = Vector(this->radius, this->radius, this->radius); 27 | this->boundingBox = AABB(this->center - radiusVector, this->center + radiusVector); 28 | } 29 | 30 | /* Returns the closest intersection of a ray with the sphere, returns a negative value if no intersection. */ 31 | float Sphere::Intersect(const Ray& ray) 32 | { 33 | Vector s = this->center - ray.o; 34 | float sd = s * ray.d; 35 | float ss = s * s; 36 | 37 | // Compute discriminant 38 | float disc = sd*sd - ss + this->radiusSquared; 39 | 40 | // Complex values: No intersection 41 | if( disc < 0.f ) return -1.0f; 42 | 43 | // Assume we are not in a sphere... The first hit is the lesser valued 44 | float p1 = sd - sqrt(disc); 45 | float p2 = sd + sqrt(disc); 46 | if (p1 < 0) return p2; 47 | if (p2 < 0) return p1; 48 | return std::min(p1, p2); 49 | 50 | //return sd - sqrt(disc); 51 | 52 | #if 0 53 | 54 | /* Transform the ray's origin into the sphere's object space. */ 55 | Vector origin = ray.o - this->definition.center; 56 | 57 | /* Compute the intersection quadratic equation's coefficients. */ 58 | float a = ray.d * ray.d; 59 | float b = 2 * (ray.d * origin); 60 | float c = (origin * origin) - this->radiusSquared; 61 | 62 | /* Compute the squared discriminant to discard the no-intersection case. */ 63 | float delta = b * b - 4 * a * c; 64 | if (delta < 0) return false; 65 | 66 | /* Otherwise, take the square root of the discriminant and solve the quadratic. */ 67 | delta = sqrtf(delta); 68 | float p1 = (-b - delta) / (2 * a); 69 | float p2 = (-b + delta) / (2 * a); 70 | 71 | /* Use short-circuit rejection to eliminate cases one by one. */ 72 | if ((p1 <= EPSILON) && (p2 <= EPSILON)) return false; 73 | intersection->object = this; 74 | 75 | if (p1 <= EPSILON) intersection->t = p2; else 76 | if (p2 <= EPSILON) intersection->t = p1; else 77 | intersection->t = std::min(p1, p2); 78 | return (intersection->t >= EPSILON); 79 | #endif 80 | } 81 | 82 | /* Returns the surface normal at any point on the sphere. */ 83 | Vector Sphere::Normal(Vector point) 84 | { 85 | return (point - this->center) / this->radius; 86 | } 87 | -------------------------------------------------------------------------------- /src/primitives/triangle.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | /* This defines a triangle. */ 4 | #pragma pack(1) 5 | struct TriangleDefinition 6 | { 7 | /* The three vertices. */ 8 | float p1[3], p2[3], p3[3]; 9 | }; 10 | 11 | /* Creates the triangle from a scene file. */ 12 | Triangle::Triangle(std::fstream& file, std::vector* materials, std::vector* lights) : Primitive(file, materials, lights) 13 | { 14 | /* Read the triangle definition from the scene file. */ 15 | TriangleDefinition definition; 16 | file.read((char*)&definition, sizeof(TriangleDefinition)); 17 | 18 | /* Read the vertices from the definition. */ 19 | this->p1 = Vector(definition.p1[0], definition.p1[1], definition.p1[2]); 20 | this->p2 = Vector(definition.p2[0], definition.p2[1], definition.p2[2]); 21 | this->p3 = Vector(definition.p3[0], definition.p3[1], definition.p3[2]); 22 | 23 | /* Precompute the normal and edges. */ 24 | edge1 = this->p2 - this->p1; 25 | edge2 = this->p3 - this->p1; 26 | normal = normalize(edge1 ^ edge2); 27 | 28 | /* Compute the triangle's bounding box. */ 29 | Vector lo = Vector(std::min(this->p1.x, std::min(this->p2.x, this->p3.x)), 30 | std::min(this->p1.y, std::min(this->p2.y, this->p3.y)), 31 | std::min(this->p1.z, std::min(this->p2.z, this->p3.z))); 32 | Vector hi = Vector(std::max(this->p1.x, std::max(this->p2.x, this->p3.x)), 33 | std::max(this->p1.y, std::max(this->p2.y, this->p3.y)), 34 | std::max(this->p1.z, std::max(this->p2.z, this->p3.z))); 35 | this->boundingBox = AABB(lo, hi); 36 | 37 | /* Compute the triangle's centroid. */ 38 | this->centroid = (this->p1 + this->p2 + this->p3) / 3.0f; 39 | } 40 | /* Returns the closest intersection of a ray with the triangle, returns a negative value if no intersection. */ 41 | float Triangle::Intersect(const Ray& ray) 42 | { 43 | /* Compute some initial values. */ 44 | Vector distance = ray.o - this->p1; 45 | Vector s = ray.d ^ edge2; 46 | float d = 1.0 / (s * edge1); 47 | 48 | /* Calculate the first barycentric coordinate. */ 49 | float u = (distance * s) * d; 50 | 51 | /* Reject the intersection if the barycentric coordinate is out of range. */ 52 | if ((u <= -EPSILON) || (u >= 1 + EPSILON)) return -1.0f; 53 | 54 | /* Calculate the second barycentric coordinate. */ 55 | s = distance ^ edge1; 56 | float v = (ray.d * s) * d; 57 | 58 | /* Reject the intersection if the barycentric coordinate is out of range. */ 59 | if ((v <= -EPSILON) || (u + v >= 1 + EPSILON)) return -1.0f; 60 | 61 | /* Compute the final intersection point. */ 62 | return (edge2 * s) * d; 63 | } 64 | 65 | /* Returns the surface normal at any point on the triangle. */ 66 | Vector Triangle::Normal(Vector point) 67 | { 68 | return normal; 69 | } 70 | -------------------------------------------------------------------------------- /src/renderer/renderer.cpp: -------------------------------------------------------------------------------- 1 | /* Bunch of required includes (most of them are in the header). */ 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | /* Some OpenMP convenience macros. */ 10 | #define threadID omp_get_thread_num() 11 | 12 | /* This is the BVH's leaf size. It should be set for best performance, 13 | * but this heavily depends on hardware factors. 2 is usually best. */ 14 | #define LEAFSIZE 2 15 | 16 | /* These are scene entity types, which indicate the nature of the next object in the scene file. */ 17 | enum EntityType { COLORSYSTEM = 0, CAMERA = 1, DISTRIBUTION = 2, MATERIAL = 3, LIGHT = 4, PRIMITIVE = 5 }; 18 | 19 | /* This is an entity header. */ 20 | #pragma pack(1) 21 | struct EntityHeader 22 | { 23 | /* The entity type. */ 24 | EntityType type; 25 | /* The subtype. */ 26 | uint32_t subtype; 27 | }; 28 | 29 | /* Just for readability. */ 30 | using namespace std; 31 | 32 | /* Utility function to read a scene file entity header from a file. */ 33 | bool ReadHeader(fstream& file, EntityHeader* header) 34 | { 35 | file.read((char*)header, sizeof(EntityHeader)); 36 | return (!file.eof()); 37 | } 38 | 39 | Renderer::Renderer(string scene) 40 | { 41 | /* Open the scene file. */ 42 | fstream file; 43 | file.open(scene, ios::in | ios::binary); 44 | cout << "[+] Opening <" << scene << ">..." << endl << endl; 45 | 46 | /* Read the render information. */ 47 | file.read((char*)&renderParams, sizeof(RenderParams)); 48 | cout << "[+] Scene file header:" << endl; 49 | cout << " | " << renderParams.width << "×" << renderParams.height << "." << endl; 50 | cout << " | " << renderParams.samples << " spp." << endl; 51 | cout << endl << "[+] Parsing scene entities..." << flush; 52 | pixelCount = renderParams.width * renderParams.height; 53 | 54 | /* Create all the storage vectors. */ 55 | distributions = new vector(); 56 | primitives = new vector(); 57 | materials = new vector(); 58 | lights = new vector(); 59 | 60 | /* Read every scene entity in the file. */ 61 | EntityHeader header; 62 | while (ReadHeader(file, &header)) 63 | { 64 | /* Check the entity type to know what to do. */ 65 | switch(header.type) 66 | { 67 | case DISTRIBUTION: distributions->push_back(GetDistribution(header.subtype, file)); break; 68 | case MATERIAL: materials->push_back(GetMaterial(header.subtype, file, distributions)); break; 69 | case LIGHT: lights->push_back(GetLight(header.subtype, file, distributions)); break; 70 | case PRIMITIVE: primitives->push_back(GetPrimitive(header.subtype, file, materials, lights)); break; 71 | case COLORSYSTEM: colorSystem = ColorSystems[header.subtype]; break; 72 | case CAMERA: camera = GetCamera(header.subtype, file); break; 73 | } 74 | } 75 | 76 | /* Print out statistics. */ 77 | cout << " complete!" << endl << endl << "[+] Scene statistics:" << endl; 78 | cout << " | " << primitives->size() << " geometric primitive(s)." << endl; 79 | cout << " | " << distributions->size() << " spectral distribution(s)." << endl; 80 | cout << " | " << materials->size() << " material(s)." << endl; 81 | cout << " | " << lights->size() << " light(s)." << endl; 82 | 83 | /* Build the bounding volume hierarchy. */ 84 | cout << endl << "[+] Building acceleration structure..." << flush; 85 | bvh = new BVH(primitives, LEAFSIZE); 86 | cout << " built!" << endl << " | " << bvh->nLeafs << " leaves over " << bvh->nNodes << " nodes." << endl; 87 | 88 | /* Close the file. */ 89 | cout << endl << "[+] Scene successfully loaded!" << endl << endl; 90 | file.close(); 91 | } 92 | 93 | void Renderer::TonemapRender(Vector* pixels) 94 | { 95 | /* Sum up the luminance logarithms over the whole render... */ 96 | float avgLuminance = 0.0f; 97 | for (size_t t = 0; t < pixelCount; ++t) 98 | { 99 | /* Compute the luminance and add its logarithm to the sum. */ 100 | float luminance = Luminance(pixels[t], colorSystem); 101 | avgLuminance += log(luminance + EPSILON); 102 | } 103 | 104 | /* Get the log-average luminance. */ 105 | avgLuminance = exp(avgLuminance / pixelCount); 106 | 107 | /* Compute the tonemapping key using an exposure of 0.18. */ 108 | float key = 0.18f / avgLuminance; 109 | 110 | /* Go over each pixel... */ 111 | for (size_t t = 0; t < pixelCount; ++t) 112 | { 113 | /* Apply the Reinhard operator. */ 114 | float luminance = Luminance(pixels[t], colorSystem); 115 | pixels[t] = pixels[t] * (key / (1.0f + luminance * key)); 116 | } 117 | } 118 | 119 | void Renderer::GammaCorrectRender(Vector* pixels) 120 | { 121 | /* Apply the gamma correction operator on each pixel. */ 122 | for (size_t t = 0; t < pixelCount; ++t) pixels[t] = GammaCorrect(pixels[t], colorSystem); 123 | } 124 | 125 | void Renderer::SaveToPPM(Vector* pixels, string render, time_t elapsedTime) 126 | { 127 | /* Create the destination file. */ 128 | FILE* file = fopen(render.c_str(), "w"); 129 | if (file == 0) return; 130 | 131 | /* Write a short header. */ 132 | fprintf(file, "P3\n\n# Generated by Lambda.\n# Rendered in %dh%dm%ds.\n\n%d %d 255\n", 133 | (int)elapsedTime / 3600, (int)(elapsedTime % 3600) / 60, (int)elapsedTime % 60, 134 | renderParams.width, renderParams.height); 135 | 136 | /* Write the pixel buffer in. */ 137 | for (size_t t = 0; t < pixelCount; ++t) 138 | fprintf(file, "%d %d %d ", (int)(min(pixels[t].x, 1.0f) * 255.0f), 139 | (int)(min(pixels[t].y, 1.0f) * 255.0f), 140 | (int)(min(pixels[t].z, 1.0f) * 255.0f)); 141 | 142 | /* Close the file. */ 143 | fclose(file); 144 | } 145 | 146 | float Renderer::Radiance(Ray ray, float wavelength, mt19937* prng) 147 | { 148 | /* Light path loop. */ 149 | while (true) 150 | { 151 | /* Intersect the ray with the scene. */ 152 | Intersection intersection; 153 | if (!bvh->getIntersection(ray, &intersection, false)) return 0.0f; 154 | 155 | /* Move the ray forward to the intersection point. */ 156 | Vector point = ray.o + ray.d * intersection.t; 157 | Vector incident = ray.d; 158 | 159 | /* Get the surface normal at the intersection point. */ 160 | Vector normal = intersection.primitive->Normal(point); 161 | 162 | /* If the geometry intersected is a light source, return the emitted light. */ 163 | if (intersection.primitive->light) 164 | { 165 | /* Note we assume light sources do not reflect light, this is usually correct. */ 166 | return intersection.primitive->light->Emittance(incident, normal, wavelength); 167 | } 168 | 169 | /* Otherwise, compute the incoming radiance using the Rendering Equation. To do this elegantly, we 170 | * compute an importance-sampled ray, then calculate the correct reflectance (if the importance 171 | * sampling was perfect, the reflectance would be constant, but this is not required). Note the 172 | * cosine term from Lambert's cosine law is folded into the Reflectance method for efficiency. */ 173 | Vector exitant = intersection.primitive->material->Sample(&point, incident, normal, wavelength, prng); 174 | float radiance = intersection.primitive->material->Reflectance(incident, exitant, normal, wavelength, true); 175 | 176 | /* Apply the Beer-Lambert Law to attenuate the radiance as the ray travels through the medium. We just find 177 | * which medium the light ray is actually in, by comparing its last direction with the direction of the 178 | * normal of the object it last intersected, and compute the amount of loss using the extinction coeff. */ 179 | if (incident * normal > 0.0f) radiance *= exp(-intersection.t * intersection.primitive->material->e2); 180 | else radiance *= exp(-intersection.t * intersection.primitive->material->e1); 181 | 182 | /* Russian roulette for unbiased depth. Note this means the loop is guaranteed to terminate, since the 183 | * reflectance is defined as being strictly less than 1. */ 184 | if (RandomVariable(prng) > radiance) return 0.0f; 185 | 186 | /* Go to the next ray bounce. */ 187 | ray = Ray(point, normalize(exitant)); 188 | } 189 | 190 | /* No light path formed. */ 191 | return 0.0f; 192 | } 193 | 194 | void Renderer::Render(string render, size_t threads) 195 | { 196 | /* First, we need to allocate a large enough pixel buffer. */ 197 | Vector* pixels = new Vector[pixelCount]; 198 | 199 | /* Set the number of OpenMP threads. If zero was passed, default to the number 200 | * of execution units available on the system for maximum performance. */ 201 | omp_set_num_threads((threads == 0) ? omp_get_num_procs() : threads); 202 | if (threads == 0) { 203 | threads = omp_get_num_procs(); 204 | } 205 | cout << "[+] Initializing, " << threads << " threads scheduled..." << flush; 206 | 207 | /* Now, create PRNG states for each thread. Note the seeds are actually 208 | * deterministic to thread count, which can often be an advantage. */ 209 | vector* threadPRNG = new vector(); 210 | for (size_t t = 0; t < threads; ++t) 211 | { 212 | mt19937* prng = new mt19937(); 213 | prng->seed(0x530FD819 * (t + 1)); 214 | threadPRNG->push_back(prng); 215 | } 216 | 217 | /* We're all set, record the starting time. */ 218 | time_t startTime = time(nullptr); 219 | cout << " ready!" << endl; 220 | cout << "[+] Raytracing..." << flush; 221 | time_t lastTime = startTime; 222 | size_t lastProgress = 0; 223 | float lastSpeed = 0.0f; 224 | size_t progress = 0; 225 | 226 | /* Go over each pixel in the image, in parallel. */ 227 | #pragma omp parallel for schedule(dynamic, 1) 228 | for (size_t t = 0; t < pixelCount; ++t) 229 | { 230 | /* Get the current thread's PRNG state. */ 231 | mt19937* prng = threadPRNG->at(threadID); 232 | 233 | /* Get this pixel's position. */ 234 | int x = t % renderParams.width; 235 | int y = t / renderParams.width; 236 | 237 | /* Create a spectral radiance array. */ 238 | float radiance[WAVELENGTHS] = {0.0f}; 239 | 240 | /* Iterate for the number of desired samples... */ 241 | for (int s = 0; s < renderParams.samples; ++s) 242 | { 243 | /* Normalize the pixel's coordinates with jitter. */ 244 | float u = 2.0f * ((float)x + RandomVariable(prng) - 0.5f) / renderParams.width - 1.0f; 245 | float v = 2.0f * ((float)y + RandomVariable(prng) - 0.5f) / renderParams.height - 1.0f; 246 | 247 | /* Multiply the u-coordinate by the aspect ratio. */ 248 | u *= (float)renderParams.width / (float)renderParams.height; 249 | 250 | /* Get a camera ray. */ 251 | Ray ray = camera->Trace(u, v); 252 | 253 | /* Go over each wavelength. */ 254 | for (int w = 0; w < WAVELENGTHS; ++w) 255 | { 256 | /* Get a radiance sample for this wavelength. */ 257 | float wavelength = 380.0f + RESOLUTION * w; 258 | radiance[w] += Radiance(ray, wavelength, prng); 259 | } 260 | } 261 | 262 | /* Convert the spectral radiance distribution to an RGB color. */ 263 | pixels[t] = SpectrumToRGB(radiance, colorSystem) / (renderParams.samples * WAVELENGTHS); 264 | 265 | /* We display progress here, so we really only want one thread at a time. */ 266 | #pragma omp critical 267 | { 268 | /* This is a shared variable indicating how many pixels 269 | * of the render have been completed so far. */ 270 | ++progress; 271 | 272 | /* Update every second, if at least some progress has been done. */ 273 | if ((progress > 0) && ((float)difftime(time(nullptr), lastTime) >= 1.0f)) 274 | { 275 | /* Find the current progress, as a fraction. */ 276 | float completion = (progress - 1) / (float)pixelCount; 277 | 278 | /* Average the render speed with exponential smoothing (alpha = 0.8 works well). */ 279 | float speed = (float)(progress - lastProgress) / difftime(time(nullptr), lastTime); 280 | if (lastProgress > 0) speed = 0.8f * lastSpeed + 0.2f * speed; 281 | 282 | /* Compute the estimated completion time. */ 283 | int remaining = (int)((pixelCount - progress) / speed); 284 | 285 | /* Display the current progress. */ 286 | printf("\r[+] Raytracing... %04.1f%% [ETC %.3dh%.2dm%.2ds]", completion * 100.0f, 287 | remaining / 3600, (remaining % 3600) / 60, remaining % 60); 288 | 289 | /* Reset the last time and flush the console. */ 290 | lastTime = time(nullptr); 291 | lastProgress = progress; 292 | lastSpeed = speed; 293 | cout << flush; 294 | } 295 | } 296 | } 297 | 298 | /* Tonemap, and then gamma-correct the render. */ 299 | TonemapRender(pixels); 300 | GammaCorrectRender(pixels); 301 | 302 | /* We're finished raytracing, display time taken. */ 303 | int elapsedTime = (int)difftime(time(nullptr), startTime); 304 | printf("\r[+] Raytracing complete, time taken: %.2dh%.2dm%.2ds.\n", 305 | elapsedTime / 3600, (elapsedTime % 3600) / 60, elapsedTime % 60); 306 | 307 | /* Save the pixel buffer to a PPM file. */ 308 | cout << endl << "[+] Saving final render in <" << render << ">." << endl; 309 | SaveToPPM(pixels, render, difftime(time(nullptr), startTime)); 310 | cout << endl << "[+] Render finished!" << endl; 311 | 312 | /* We're done, clean up. */ 313 | for (size_t t = 0; t < threads; ++t) delete threadPRNG->at(t); 314 | delete threadPRNG; 315 | delete[] pixels; 316 | } 317 | 318 | Renderer::~Renderer() 319 | { 320 | /* Delete everything we used. */ 321 | for (size_t t = 0; t < distributions->size(); ++t) delete distributions->at(t); 322 | for (size_t t = 0; t < primitives->size(); ++t) delete primitives->at(t); 323 | for (size_t t = 0; t < materials->size(); ++t) delete materials->at(t); 324 | for (size_t t = 0; t < lights->size(); ++t) delete lights->at(t); 325 | delete distributions; 326 | delete primitives; 327 | delete materials; 328 | delete lights; 329 | delete camera; 330 | delete bvh; 331 | } 332 | -------------------------------------------------------------------------------- /src/scenegraph/bvh.cpp: -------------------------------------------------------------------------------- 1 | // from https://github.com/brandonpelfrey/Fast-BVH 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | //! Node for storing state information during traversal. 8 | struct BVHTraversal { 9 | uint32_t i; // Node 10 | float mint; // Minimum hit time for this node. 11 | BVHTraversal() { } 12 | BVHTraversal(int _i, float _mint) : i(_i), mint(_mint) { } 13 | }; 14 | 15 | //! - Compute the nearest intersection of all objects within the tree. 16 | //! - Return true if hit was found, false otherwise. 17 | //! - In the case where we want to find out of there is _ANY_ intersection at all, 18 | //! set occlusion == true, in which case we exit on the first hit, rather 19 | //! than find the closest. 20 | bool BVH::getIntersection(const Ray& ray, Intersection* intersection, bool occlusion) const { 21 | /* Initialize intersection. */ 22 | intersection->t = std::numeric_limits::infinity(); 23 | intersection->primitive = nullptr; 24 | float bbhits[4]; 25 | int32_t closer, other; 26 | 27 | // Working set 28 | BVHTraversal todo[64]; 29 | int32_t stackptr = 0; 30 | 31 | // "Push" on the root node to the working set 32 | todo[stackptr].i = 0; 33 | todo[stackptr].mint = -std::numeric_limits::infinity(); 34 | 35 | while(stackptr>=0) { 36 | // Pop off the next node to work on. 37 | int ni = todo[stackptr].i; 38 | float near = todo[stackptr].mint; 39 | stackptr--; 40 | const BVHFlatNode &node(flatTree[ ni ]); 41 | 42 | // If this node is further than the closest found intersection, continue 43 | if(near > intersection->t) 44 | continue; 45 | 46 | // Is leaf -> Intersect 47 | if( node.rightOffset == 0 ) { 48 | for(uint32_t o=0;oIntersect(ray); 51 | if ((distance >= 0) && (distance < intersection->t)) 52 | { 53 | intersection->primitive = primitive; 54 | intersection->t = distance; 55 | 56 | /* If we just want occlusion, any intersection is sufficient. */ 57 | if (occlusion) return true; 58 | } 59 | } 60 | 61 | } else { // Not a leaf 62 | 63 | bool hitc0 = flatTree[ni+1].bbox.intersect(ray, bbhits, bbhits+1); 64 | bool hitc1 = flatTree[ni+node.rightOffset].bbox.intersect(ray, bbhits+2, bbhits+3); 65 | 66 | // Did we hit both nodes? 67 | if(hitc0 && hitc1) { 68 | 69 | // We assume that the left child is a closer hit... 70 | closer = ni+1; 71 | other = ni+node.rightOffset; 72 | 73 | // ... If the right child was actually closer, swap the relavent values. 74 | if(bbhits[2] < bbhits[0]) { 75 | std::swap(bbhits[0], bbhits[2]); 76 | std::swap(bbhits[1], bbhits[3]); 77 | std::swap(closer,other); 78 | } 79 | 80 | // It's possible that the nearest object is still in the other side, but we'll 81 | // check the further-awar node later... 82 | 83 | // Push the farther first 84 | todo[++stackptr] = BVHTraversal(other, bbhits[2]); 85 | 86 | // And now the closer (with overlap test) 87 | todo[++stackptr] = BVHTraversal(closer, bbhits[0]); 88 | } 89 | 90 | else if (hitc0) { 91 | todo[++stackptr] = BVHTraversal(ni+1, bbhits[0]); 92 | } 93 | 94 | else if(hitc1) { 95 | todo[++stackptr] = BVHTraversal(ni + node.rightOffset, bbhits[2]); 96 | } 97 | 98 | } 99 | } 100 | 101 | // If we hit something, 102 | //if(intersection->primitive != NULL) 103 | //intersection->hit = ray.o + ray.d * intersection->t; 104 | 105 | return intersection->primitive != NULL; 106 | } 107 | 108 | BVH::~BVH() { 109 | delete[] flatTree; 110 | } 111 | 112 | BVH::BVH(std::vector* objects, uint32_t leafSize) 113 | : leafSize(leafSize), build_prims(objects), flatTree(NULL), nNodes(0), nLeafs(0) { 114 | 115 | // Build the tree based on the input object data set. 116 | build(); 117 | } 118 | 119 | struct BVHBuildEntry { 120 | // If non-zero then this is the index of the parent. (used in offsets) 121 | uint32_t parent; 122 | // The range of objects in the object list covered by this node. 123 | uint32_t start, end; 124 | }; 125 | 126 | /*! Build the BVH, given an input data set 127 | * - Handling our own stack is quite a bit faster than the recursive style. 128 | * - Each build stack entry's parent field eventually stores the offset 129 | * to the parent of that node. Before that is finally computed, it will 130 | * equal exactly three other values. (These are the magic values Untouched, 131 | * Untouched-1, and TouchedTwice). 132 | * - The partition here was also slightly faster than std::partition. 133 | */ 134 | void BVH::build() 135 | { 136 | BVHBuildEntry todo[128]; 137 | uint32_t stackptr = 0; 138 | const uint32_t Untouched = 0xffffffff; 139 | const uint32_t TouchedTwice = 0xfffffffd; 140 | 141 | // Push the root 142 | todo[stackptr].start = 0; 143 | todo[stackptr].end = build_prims->size(); 144 | todo[stackptr].parent = 0xfffffffc; 145 | stackptr++; 146 | 147 | BVHFlatNode node; 148 | std::vector buildnodes; 149 | buildnodes.reserve(build_prims->size()*2); 150 | 151 | while(stackptr > 0) { 152 | // Pop the next item off of the stack 153 | BVHBuildEntry &bnode( todo[--stackptr] ); 154 | uint32_t start = bnode.start; 155 | uint32_t end = bnode.end; 156 | uint32_t nPrims = end - start; 157 | 158 | nNodes++; 159 | node.start = start; 160 | node.nPrims = nPrims; 161 | node.rightOffset = Untouched; 162 | 163 | // Calculate the bounding box for this node 164 | AABB bb( (*build_prims)[start]->BoundingBox()); 165 | AABB bc( (*build_prims)[start]->Centroid()); 166 | for(uint32_t p = start+1; p < end; ++p) { 167 | bb.expandToInclude( (*build_prims)[p]->BoundingBox()); 168 | bc.expandToInclude( (*build_prims)[p]->Centroid()); 169 | } 170 | node.bbox = bb; 171 | 172 | // If the number of primitives at this point is less than the leaf 173 | // size, then this will become a leaf. (Signified by rightOffset == 0) 174 | if(nPrims <= leafSize) { 175 | node.rightOffset = 0; 176 | nLeafs++; 177 | } 178 | 179 | buildnodes.push_back(node); 180 | 181 | // Child touches parent... 182 | // Special case: Don't do this for the root. 183 | if(bnode.parent != 0xfffffffc) { 184 | buildnodes[bnode.parent].rightOffset --; 185 | 186 | // When this is the second touch, this is the right child. 187 | // The right child sets up the offset for the flat tree. 188 | if( buildnodes[bnode.parent].rightOffset == TouchedTwice ) { 189 | buildnodes[bnode.parent].rightOffset = nNodes - 1 - bnode.parent; 190 | } 191 | } 192 | 193 | // If this is a leaf, no need to subdivide. 194 | if(node.rightOffset == 0) 195 | continue; 196 | 197 | // Set the split dimensions 198 | uint32_t split_dim = bc.maxDimension(); 199 | 200 | // Split on the center of the longest axis 201 | float split_coord = .5f * (bc.min[split_dim] + bc.max[split_dim]); 202 | 203 | // Partition the list of objects on this split 204 | uint32_t mid = start; 205 | for(uint32_t i=start;iCentroid()[split_dim] < split_coord ) { 207 | std::swap( (*build_prims)[i], (*build_prims)[mid] ); 208 | ++mid; 209 | } 210 | } 211 | 212 | // If we get a bad split, just choose the center... 213 | if(mid == start || mid == end) { 214 | mid = start + (end-start)/2; 215 | } 216 | 217 | // Push right child 218 | todo[stackptr].start = mid; 219 | todo[stackptr].end = end; 220 | todo[stackptr].parent = nNodes-1; 221 | stackptr++; 222 | 223 | // Push left child 224 | todo[stackptr].start = start; 225 | todo[stackptr].end = mid; 226 | todo[stackptr].parent = nNodes-1; 227 | stackptr++; 228 | } 229 | 230 | // Copy the temp node data to a flat array 231 | flatTree = new BVHFlatNode[nNodes]; 232 | for(uint32_t n=0; n 2 | 3 | /* This method creates a spectral distribution from scene file information. */ 4 | BlackBody::BlackBody(std::fstream& file) 5 | { 6 | file.read((char*)&this->temperature, sizeof(float)); 7 | } 8 | 9 | float BlackBody::Lookup(float wavelength) 10 | { 11 | /* Convert the wavelength to meters. */ 12 | wavelength *= 1e-9f; 13 | 14 | /* Apply Plank's Law. */ 15 | float powerTerm = 3.74183e-16f * pow(wavelength, -5.0f); 16 | return powerTerm / (exp(1.4388e-2f / (wavelength * this->temperature)) - 1.0f); 17 | } 18 | -------------------------------------------------------------------------------- /src/spectral/distribution.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | /* All spectral distribution types. */ 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | /* This creates the correct distribution type based on a scene file entity subtype. */ 10 | Distribution* GetDistribution(uint32_t subtype, std::fstream& file) 11 | { 12 | switch (subtype) 13 | { 14 | case ID_BLACKBODY: return new BlackBody(file); 15 | case ID_FLAT: return new Flat(file); 16 | case ID_PEAK: return new Peak(file); 17 | case ID_SELLMEIER: return new Sellmeier(file); 18 | } 19 | 20 | /* Unknown subtype. */ 21 | return nullptr; 22 | } 23 | 24 | -------------------------------------------------------------------------------- /src/spectral/sellmeier.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | /* Sellmeier distribution scene file information. */ 4 | #pragma pack(1) 5 | struct SellmeierDefinition 6 | { 7 | /* The Sellmeier coefficients. */ 8 | float B[3], C[3]; 9 | }; 10 | 11 | /* This method creates a spectral distribution from scene file information. */ 12 | Sellmeier::Sellmeier(std::fstream& file) 13 | { 14 | /* Just read the definition. */ 15 | SellmeierDefinition definition; 16 | file.read((char*)&definition, sizeof(SellmeierDefinition)); 17 | 18 | /* And save the coefficients. */ 19 | for (int t =0; t < 3; ++t) 20 | { 21 | this->B[t] = definition.B[t]; 22 | this->C[t] = definition.C[t]; 23 | } 24 | } 25 | 26 | float Sellmeier::Lookup(float wavelength) 27 | { 28 | /* Convert the wavelength to micrometers. */ 29 | wavelength *= 1e-3f; 30 | 31 | /* Compute the refractive index using the Sellmeier formula. */ 32 | float index = 1.0f; 33 | for (int t = 0; t < 3; ++t) index += (this->B[t] * pow(wavelength, 2.0f)) / (pow(wavelength, 2.0f) - this->C[t]); 34 | return sqrt(index); 35 | } 36 | 37 | -------------------------------------------------------------------------------- /src/util/aabb.cpp: -------------------------------------------------------------------------------- 1 | // from https://github.com/brandonpelfrey/Fast-BVH 2 | 3 | #include 4 | #include 5 | 6 | AABB::AABB(const Vector& min, const Vector& max) 7 | : min(min), max(max) { extent = max - min; } 8 | 9 | AABB::AABB(const Vector& p) 10 | : min(p), max(p) { extent = max - min; } 11 | 12 | void AABB::expandToInclude(const Vector& p) { 13 | min = ::min(min, p); 14 | max = ::max(max, p); 15 | extent = max - min; 16 | } 17 | 18 | void AABB::expandToInclude(const AABB& b) { 19 | min = ::min(min, b.min); 20 | max = ::max(max, b.max); 21 | extent = max - min; 22 | } 23 | 24 | uint32_t AABB::maxDimension() const { 25 | uint32_t result = 0; 26 | if(extent.y > extent.x) result = 1; 27 | if(extent.z > extent.y) result = 2; 28 | return result; 29 | } 30 | 31 | float AABB::surfaceArea() const { 32 | return 2.f*( extent.x*extent.z + extent.x*extent.y + extent.y*extent.z ); 33 | } 34 | 35 | // http://www.flipcode.com/archives/SSE_RayBox_Intersection_Test.shtml 36 | // turn those verbose intrinsics into something readable. 37 | #define loadps(mem) _mm_load_ps((const float * const)(mem)) 38 | #define storess(ss,mem) _mm_store_ss((float * const)(mem),(ss)) 39 | #define minss _mm_min_ss 40 | #define maxss _mm_max_ss 41 | #define minps _mm_min_ps 42 | #define maxps _mm_max_ps 43 | #define mulps _mm_mul_ps 44 | #define subps _mm_sub_ps 45 | #define rotatelps(ps) _mm_shuffle_ps((ps),(ps), 0x39) // a,b,c,d -> b,c,d,a 46 | #define muxhps(low,high) _mm_movehl_ps((low),(high)) // low{a,b,c,d}|high{e,f,g,h} = {c,d,g,h} 47 | static const float flt_plus_inf = -logf(0); // let's keep C and C++ compilers happy. 48 | static const float __attribute__((aligned(16))) 49 | ps_cst_plus_inf[4] = { flt_plus_inf, flt_plus_inf, flt_plus_inf, flt_plus_inf }, 50 | ps_cst_minus_inf[4] = { -flt_plus_inf, -flt_plus_inf, -flt_plus_inf, -flt_plus_inf }; 51 | bool AABB::intersect(const Ray& ray, float *tnear, float *tfar) const { 52 | 53 | // you may already have those values hanging around somewhere 54 | const __m128 55 | plus_inf = loadps(ps_cst_plus_inf), 56 | minus_inf = loadps(ps_cst_minus_inf); 57 | 58 | // use whatever's apropriate to load. 59 | const __m128 60 | box_min = loadps(&min), 61 | box_max = loadps(&max), 62 | pos = loadps(&ray.o), 63 | inv_dir = loadps(&ray.inv_d); 64 | 65 | // use a div if inverted directions aren't available 66 | const __m128 l1 = mulps(subps(box_min, pos), inv_dir); 67 | const __m128 l2 = mulps(subps(box_max, pos), inv_dir); 68 | 69 | // the order we use for those min/max is vital to filter out 70 | // NaNs that happens when an inv_dir is +/- inf and 71 | // (box_min - pos) is 0. inf * 0 = NaN 72 | const __m128 filtered_l1a = minps(l1, plus_inf); 73 | const __m128 filtered_l2a = minps(l2, plus_inf); 74 | 75 | const __m128 filtered_l1b = maxps(l1, minus_inf); 76 | const __m128 filtered_l2b = maxps(l2, minus_inf); 77 | 78 | // now that we're back on our feet, test those slabs. 79 | __m128 lmax = maxps(filtered_l1a, filtered_l2a); 80 | __m128 lmin = minps(filtered_l1b, filtered_l2b); 81 | 82 | // unfold back. try to hide the latency of the shufps & co. 83 | const __m128 lmax0 = rotatelps(lmax); 84 | const __m128 lmin0 = rotatelps(lmin); 85 | lmax = minss(lmax, lmax0); 86 | lmin = maxss(lmin, lmin0); 87 | 88 | const __m128 lmax1 = muxhps(lmax,lmax); 89 | const __m128 lmin1 = muxhps(lmin,lmin); 90 | lmax = minss(lmax, lmax1); 91 | lmin = maxss(lmin, lmin1); 92 | 93 | const bool ret = _mm_comige_ss(lmax, _mm_setzero_ps()) & _mm_comige_ss(lmax,lmin); 94 | 95 | storess(lmin, tnear); 96 | storess(lmax, tfar); 97 | 98 | return ret; 99 | } 100 | -------------------------------------------------------------------------------- /src/util/cie.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | /* The CIE color matching curve, at 5nm intervals. */ 4 | static Vector ColorMatchingCurve[81] = { 5 | Vector(0.0014,0.0000,0.0065), Vector(0.0022,0.0001,0.0105), Vector(0.0042,0.0001,0.0201), 6 | Vector(0.0076,0.0002,0.0362), Vector(0.0143,0.0004,0.0679), Vector(0.0232,0.0006,0.1102), 7 | Vector(0.0435,0.0012,0.2074), Vector(0.0776,0.0022,0.3713), Vector(0.1344,0.0040,0.6456), 8 | Vector(0.2148,0.0073,1.0391), Vector(0.2839,0.0116,1.3856), Vector(0.3285,0.0168,1.6230), 9 | Vector(0.3483,0.0230,1.7471), Vector(0.3481,0.0298,1.7826), Vector(0.3362,0.0380,1.7721), 10 | Vector(0.3187,0.0480,1.7441), Vector(0.2908,0.0600,1.6692), Vector(0.2511,0.0739,1.5281), 11 | Vector(0.1954,0.0910,1.2876), Vector(0.1421,0.1126,1.0419), Vector(0.0956,0.1390,0.8130), 12 | Vector(0.0580,0.1693,0.6162), Vector(0.0320,0.2080,0.4652), Vector(0.0147,0.2586,0.3533), 13 | Vector(0.0049,0.3230,0.2720), Vector(0.0024,0.4073,0.2123), Vector(0.0093,0.5030,0.1582), 14 | Vector(0.0291,0.6082,0.1117), Vector(0.0633,0.7100,0.0782), Vector(0.1096,0.7932,0.0573), 15 | Vector(0.1655,0.8620,0.0422), Vector(0.2257,0.9149,0.0298), Vector(0.2904,0.9540,0.0203), 16 | Vector(0.3597,0.9803,0.0134), Vector(0.4334,0.9950,0.0087), Vector(0.5121,1.0000,0.0057), 17 | Vector(0.5945,0.9950,0.0039), Vector(0.6784,0.9786,0.0027), Vector(0.7621,0.9520,0.0021), 18 | Vector(0.8425,0.9154,0.0018), Vector(0.9163,0.8700,0.0017), Vector(0.9786,0.8163,0.0014), 19 | Vector(1.0263,0.7570,0.0011), Vector(1.0567,0.6949,0.0010), Vector(1.0622,0.6310,0.0008), 20 | Vector(1.0456,0.5668,0.0006), Vector(1.0026,0.5030,0.0003), Vector(0.9384,0.4412,0.0002), 21 | Vector(0.8544,0.3810,0.0002), Vector(0.7514,0.3210,0.0001), Vector(0.6424,0.2650,0.0000), 22 | Vector(0.5419,0.2170,0.0000), Vector(0.4479,0.1750,0.0000), Vector(0.3608,0.1382,0.0000), 23 | Vector(0.2835,0.1070,0.0000), Vector(0.2187,0.0816,0.0000), Vector(0.1649,0.0610,0.0000), 24 | Vector(0.1212,0.0446,0.0000), Vector(0.0874,0.0320,0.0000), Vector(0.0636,0.0232,0.0000), 25 | Vector(0.0468,0.0170,0.0000), Vector(0.0329,0.0119,0.0000), Vector(0.0227,0.0082,0.0000), 26 | Vector(0.0158,0.0057,0.0000), Vector(0.0114,0.0041,0.0000), Vector(0.0081,0.0029,0.0000), 27 | Vector(0.0058,0.0021,0.0000), Vector(0.0041,0.0015,0.0000), Vector(0.0029,0.0010,0.0000), 28 | Vector(0.0020,0.0007,0.0000), Vector(0.0014,0.0005,0.0000), Vector(0.0010,0.0004,0.0000), 29 | Vector(0.0007,0.0002,0.0000), Vector(0.0005,0.0002,0.0000), Vector(0.0003,0.0001,0.0000), 30 | Vector(0.0002,0.0001,0.0000), Vector(0.0002,0.0001,0.0000), Vector(0.0001,0.0000,0.0000), 31 | Vector(0.0001,0.0000,0.0000), Vector(0.0001,0.0000,0.0000), Vector(0.0000,0.0000,0.0000)}; 32 | 33 | /* Converts a spectral radiance distribution to an RGB color. */ 34 | Vector SpectrumToRGB(float spectralRadiance[WAVELENGTHS], ColorSystem colorSystem) 35 | { 36 | /* Simply integrate the color-matching curve. */ 37 | float radiance = 0; 38 | Vector color = Vector(0, 0, 0); 39 | for (int w = 0; w < WAVELENGTHS; w++) 40 | { 41 | color = color + ColorMatchingCurve[w * (RESOLUTION / 5)] * spectralRadiance[w]; 42 | radiance += spectralRadiance[w]; 43 | } 44 | 45 | /* Normalize the XYZ color. */ 46 | float sum = color.x + color.y + color.z; 47 | if (sum > EPSILON) color = color / sum; 48 | 49 | /* Decode the color system. */ 50 | float xr = colorSystem.xRed; float yr = colorSystem.yRed; float zr = 1 - (xr + yr); 51 | float xg = colorSystem.xGreen; float yg = colorSystem.yGreen; float zg = 1 - (xg + yg); 52 | float xb = colorSystem.xBlue; float yb = colorSystem.yBlue; float zb = 1 - (xb + yb); 53 | float xw = colorSystem.xWhite; float yw = colorSystem.yWhite; float zw = 1 - (xw + yw); 54 | 55 | /* Compute the XYZ to RGB matrix. */ 56 | float rx = (yg * zb) - (yb * zg); 57 | float ry = (xb * zg) - (xg * zb); 58 | float rz = (xg * yb) - (xb * yg); 59 | float gx = (yb * zr) - (yr * zb); 60 | float gy = (xr * zb) - (xb * zr); 61 | float gz = (xb * yr) - (xr * yb); 62 | float bx = (yr * zg) - (yg * zr); 63 | float by = (xg * zr) - (xr * zg); 64 | float bz = (xr * yg) - (xg * yr); 65 | 66 | /* Compute the RGB luminance scaling factor. */ 67 | float rw = ((rx * xw) + (ry * yw) + (rz * zw)) / yw; 68 | float gw = ((gx * xw) + (gy * yw) + (gz * zw)) / yw; 69 | float bw = ((bx * xw) + (by * yw) + (bz * zw)) / yw; 70 | 71 | /* Scale the XYZ to RGB matrix to white. */ 72 | rx = rx / rw; ry = ry / rw; rz = rz / rw; 73 | gx = gx / gw; gy = gy / gw; gz = gz / gw; 74 | bx = bx / bw; by = by / bw; bz = bz / bw; 75 | 76 | /* Calculate the desired RGB. */ 77 | Vector rgb = Vector((rx * color.x) + (ry * color.y) + (rz * color.z), 78 | (gx * color.x) + (gy * color.y) + (gz * color.z), 79 | (bx * color.x) + (by * color.y) + (bz * color.z)); 80 | 81 | /* Constrain the RGB color within the RGB gamut. */ 82 | float w = std::min(0.0f, std::min(rgb.x, std::min(rgb.y, rgb.z))); 83 | rgb = rgb - Vector(w, w, w); 84 | 85 | /* Multiply the final RGB color by the pixel's radiance. */ 86 | return rgb * radiance; 87 | } 88 | 89 | /* Returns the luminance of an RGB color according to a given color system. */ 90 | float Luminance(Vector rgb, ColorSystem colorSystem) 91 | { 92 | return rgb.x * colorSystem.yRed + rgb.y * colorSystem.yGreen + rgb.z * colorSystem.yBlue; 93 | } 94 | 95 | /* Gamma corrects an RGB color according to a given color system. */ 96 | Vector GammaCorrect(Vector rgb, ColorSystem colorSystem) 97 | { 98 | /* If we're using the special REC709 gamma formula... */ 99 | if (colorSystem.gamma == GAMMA_REC709) 100 | { 101 | /* Use the special piecewise formula. */ 102 | if (rgb.x >= 0.018) rgb.x = (1.099 * pow(rgb.x, 0.45)) - 0.099; 103 | else rgb.x *= ((1.099 * pow(0.018, 0.45)) - 0.099) / 0.018; 104 | if (rgb.y >= 0.018) rgb.y = (1.099 * pow(rgb.y, 0.45)) - 0.099; 105 | else rgb.y *= ((1.099 * pow(0.018, 0.45)) - 0.099) / 0.018; 106 | if (rgb.z >= 0.018) rgb.z = (1.099 * pow(rgb.z, 0.45)) - 0.099; 107 | else rgb.z *= ((1.099 * pow(0.018, 0.45)) - 0.099) / 0.018; 108 | 109 | /* Return the gamma-corrected color. */ 110 | return rgb; 111 | } 112 | else 113 | { 114 | /* Otherwise, use a standard gamma power curve. */ 115 | float power = 1.0f / colorSystem.gamma; 116 | return Vector(powf(rgb.x, power), powf(rgb.y, power), powf(rgb.z, power)); 117 | } 118 | } 119 | --------------------------------------------------------------------------------