This document covers a variety of topics related to working with pbrt-v3,the rendering system described in the third edition ofPhysically Based Rendering: From Theory to Implementation,by Matt Pharr,Wenzel Jakob,and Greg Humphreys.Because most users of pbrt are also developers who also work with thesystem’s source code, this guide also includes coverage of a number oftopics related to the system’s structure and organization.
If you find errors in this text or have ideas for topics that should bediscussed, please either submit a bug inthe pbrt issue tracker,or send an emailto [emailprotected].
Note: this document is still a work in progress; a number of sections areeither unwritten or incomplete.
The system has seen many changes since the second edition. To figure outhow to use the new features, you may want to look at the example scenefiles and read through the source code to figure out the parameters anddetails of the following.
- Bidirectional path tracing:
Integrator "bdpt"
does proper bidirectionalpath tracing with multiple importance sampling. - Metropolis sampling:
Integrator "mlt"
uses the bidirectional pathtracer with Hachisuka et al.'s “Multiplexed Metropolis Light Transport”technique. - Improved numerical robustness for intersection calculations: epsilons aresmall and provably conservative.
- Subsurface scattering: all new implementation, integrated into the pathtracing integrator. See the
head
directory inthe scenes distribution. - Curve shape: thin ribbons described by bicubic Bezier curves. Great forhair, fur, and grass.
- PLY mesh support: meshes in PLY format can be used directly:
Shape "plymesh" "string filename" "mesh.ply"
- Realistic camera model: tracing rays through lenses to make images!
- Participating media: the boundaries of shapes are now used to delineatethe extent of regions of participating media in the scene.
- New samplers: a much-improved Halton sampler, and an all-new Sobol’sampler are both quite effective for path tracing and bidirectional pathtracing.
- Fourier representation of measured materials: an implementation of Jakobet al’s A Comprehensive Framework for Rendering LayeredMaterials.
- New versions of the BSDF files it uses can be generated withlayerlab.
- Improved microfacet models: specular transmission through microfacets,and Heitz’s improved importance sampling.
- No external dependencies: thanks toLode Vandevenne’s lodepng,Diego Nehab’s rply,and Emil Mikulic’s TARGA library, noexternal libraries need to be compiled to build pbrt.The only slightly bigger dependency is OpenEXR,and its build system is fully integrated with that of pbrt.
Many other small things have been improved (parallelization scheme, imageupdates, statistics system, overall cleanliness of interfaces); see thesource code (and the book) for details.
File format
We’ve tried to keep the scene description file format as unchangedfrom pbrt-v2 as much as possible. However,progress in other parts of the system required changes to the scenedescription format.
First, the “Renderer”, “SurfaceIntegrator”, and “VolumeIntegrator”directives have all been unified under “Integrator”; only a singleintegrator now needs to be specified.
The following specific implementations were removed:
- Accelerator “grid”
- Use “bvh” or “kdtree” instead.
- Material “measured”, “shinymetal”
- The new “fourier” material should now be used for measured BRDFs.
- Use “uber” in place of “shinymetal”.
- VolumeRegion: all
- Use the new participating media representation described above
- SurfaceIntegrator: photonmap, irradiancecache, igi, dipolesubsurface,ambientocclusion, useprobes, diffuseprt, glossyprt
- Use “sppm” for the “photonmap”.
- The “path” integrator now handles subsurface scattering directly.
- The others aren’t as good as path tracing anyway. :-)
- VolumeIntegrator: single, emission
- Use the “volpath” path tracing integrator.
- Sampler: bestcandidate
- Use any other sampler.
- Renderer: all
- Use “Integrator”, as described above.
Building pbrt
Please seethe README.mdfile in the pbrt-v3 distribution forgeneral information about how to check out and compile the system.
Porting to different targets
pbrt should compute out of the box for semi-modern versions of Linux,FreeBSD, OpenBSD, OS X, and Windows. A C++ compiler with good support forC++11 is required. (Therefore, pbrt definitely won’t compile with anyversions of MSVC earlier than 2013, any versions of g++ before 4.8, or anyversions of clang before 3.1).
The CMakeLists.txtfile does its best to automatically determine the capabilities andlimitations of the system's compiler and to determine which header filesare available. If pbrt doesn't build out of the box on your system andyou're able to figure out the changes needed inthe CMakeLists.txt file, we'd be delighted toreceive a github pull request. Alternatively, opena bug in the issuetracker that includes the compiler output from your failed build andwe'll try to help get it running.
Note that if extensive changes to pbrt are required to build it on a newtarget, we may not accept the pull request, as it’s also important that thesource code on github be as close as possible to the source code in thephysical book. Thus, for example, we wouldn’t be interested in a pullrequest that removed most of the usage of C++11 to get the system to buildwith MSVC 2012 or earlier.
Branches
We maintain two branches of the pbrt-v3 system. The first, “book”corresponds as closely as possible to the source code as printed in thephysical book, Physically Based Rendering. The only differences betweenthe two come from cases where there was a bug in the code aspublished.
The second branch is available in “master”. It includes all of the bugfixes in the “book” branch, but also includes some useful new functionalitythat isn’t in the code as presented in the book. In general, we don’t wantthis branch to diverge from the contents of the book too much, but given asufficiently useful new feature and in particular, given one that can beadded without substantially changing the structure of the rest of thesystem, we’ll add it to this branch. (It’s likely that most of thisadditional functionality will be included in an eventual fourth edition ofthe book.) This added code is much more extensively commented than thecode that is documented in the book.
Here is the main new functionality in the “master” branch:
- New files
src/core/lightdistrib.*
thatprovide a better approach for sampling light sources with scenes that havethousands of lights than the methods for sampling lights described in thebook. We added this functionality in order to be able to efficientlyrender the “Measure One” scenes in the pbrt scenes distribution, as theyinclude tens of thousands of emitters; the preexisting sampling methodswere unable to render these scenes without a prohibitive number of samplesper pixel. - Use of the Google logging library for assertions and runtime logging(described in more detail in the next section).
- The "pixelbounds" parameter for many integrators (described inthe Debugging section below).
- Support for two-sided area light sources viathe DiffuseAreaLight "boolean twosided"parameter (rather than always emitting from the side oriented with thesurface normal).
- A number of performance optimizations to the Curve shape intersectionroutines.
- Support for Curves described using the b-spline basis as well assupport for 2nd degree spline curves (in addition to 3rd degree asbefore).
- A new "hair" Material and BxDF for rendering hair.
- An implementation of the "Disney" BSDF asdescribed hereand here.
Assertions and logging
The original version of pbrt (as still present in the “book” branch) uses acustom Assert()
macro for runtime assertions. This macro is disabled forrelease builds, as some of its checks require meaningful amounts ofcomputation.
In the “master” branch, we have replaced Assert()
withglog, the Google Logging system. Itincludes both improved assertion checks as well as the ability to logsystem execution; we have found the logging functionality to be frequentlyuseful when debugging the system.
For assertions, a variety of checks are available. The simplest isCHECK()
, which is essentially a replacement for Assert()
(or regularassert()
for that matter); an error and the current stacktrace are printed. There is also a DCHECK()
, which is similar,but is only enabled for debug builds. Furthermore, additional informationabout the failure can be provided using C++ output streams:
CHECK(foo.x == bar.y) << "Unexpected inequality: foo = " << foo << ", bar = " << bar;
When possible, it’s better to use macros that separately take the valuebeing checked and the expected value. For example, CHECK_EQ()
takes two values and tests whether they are equal, including the two valuesin the error message if they are not. Similarly, CHECK_NE()
checks for inequality,and CHECK_LT()
, CHECK_LE()
, CHECK_GT()
,and CHECK_GE()
check for less than, less than or equal,greater than, and greater than or equal, respectively. There aredebug-only variants of these that also are prefixed with “D”.
The glog system also includes a rich logging infrastructure, which makes itpossible information about “interesting” program events. In addition to thein addition to the string provided by the user, a fine-grained time stampand thread id are included in the log, which are also often helpful:
LOG(INFO) << "Starting film tile " << tileBounds;
There are four logging levels: INFO
, WARNING
, ERROR
, and FATAL
.Normally logs are stored in the system temporary directory (either asspecified by the TMPDIR
environment variable, or in a system default like/tmp
), but this can be overridden usingpbrt’s --logdir
command-line option. pbrt has the commandline option --logtostderr
, which causes logging information tobe printed to standard error at runtime.
(Note that on OSX, TMPDIR
is set to a unique per-sessiontemporary directory; you won’t find your logs if you look for themin /tmp
.)
We have removed the Info()
and Severe()
functions from pbrt (which were essentially used for this form of logging).However, we have retainedWarning()
and Error()
: the distinction is that those two continue to beused for user-facing error messages (parameters not recognized in inputfiles and so forth), while the logging functionality is used only forinformation that is only useful for developers.
Sometimes verbose logging is useful for debugging. glog also offersVLOG()
, which takes an integer logging level as an argument. Then, the--v
command-line option to pbrt can be used to enable various verboselogging levels.
Debugging
Debugging a ray-tracer can be its own special kind of fun. When the systemcrashes, it may take hours of computation to reach the point where thecrash occurs. When an incorrect image is generated, chasing down why it isthat the image is usually-but-not-always correct can be a very trickyexercise.
When trouble strikes, it’s usually best to start by rendering the sceneagain using a debug build of pbrt. Debug builds of the system not onlyinclude debugging symbols and aren’t highly optimized (so that the programcan be effectively debugged in a debugger), but also include more runtimeassertions, which may help narrow down the issue. We find that debug buildsare generally three to five times slower than optimized builds; thus, ifyou’re not debugging, make sure you’re not using a debug build! (Seethe pbrt-v3README.mdfile for information about how to create a debug build.)
(Depending on how easy it is to work with multi-threaded programs in yourdebugger, you may find it helpful to give pbrt --nthreads=1
as acommand-line argument when debugging. Program execution will be evenslower, but tracing program execution in a single thread is ofteneasier. However, if a bug disappears when you use a single thread, you mayhave a data race or other multithreading-related issue.)
One of the best cases is if an assertion is failing. This at least gives aninitial clue to the problem–assuming that the assertion is not itselfbuggy, then the debugging task is just to figure out the sequence of eventsthat led to it failing. In general, we’ve found that taking the time to addcarefully-considered assertions to the system more than pays off in termsof reducing future time working backward when things go wrong.
If the system crashes outright (e.g., with a segmentation violation), thenthe issue is likely corruption in the memory heap or another problemrelated to dynamic memory management. For these sorts of bugs,we've found valgrindand addresssanitizer to be effective.
If the crash happens intermittently and especially if it doesn't presentitself when running with a single thread (--nthreads=1
), theissue is likely due to a race condition or other issue related toparallel execution. We have found that thehelgrind toolto be very useful for debugging threading-related bugs. (Seealso ThreadSanitizer.)
For help with chasing down more subtle errors, many of the classes in thesystem both have implementations of operator<<
for printing to C++ostreams and also have a ToString()
method that returns a std::stringdescribing the values stored in an object. Both of these can be useful whenprinting out debugging information, possibly in conjunction with thelogging system described in Section [Assertions and Logging]. (Note,however, that output will be garbled if multiple threads concurrently printto std::cout or std::cerr; either use a single thread, or use the loggingmechanism.) If you find it useful to add these methods to a class thatdoesn’t currently have them implemented, please send us a pull request withthe corresponding changes so that they can be made available to other pbrtusers.
For images of complex scenes with many samples per pixel, it may benecessary for pbrt to run for a long time before it gets to the point wherea bug manifests itself, which in turn can make debugging slow going. Ifyou can figure out the pixel coordinates of the pixel where a bug occurs,there is a “pixelbounds” parameter that limits rendering to a given rangeof pixels that can greatly speed up this process; this parameter issupported by all of the integrators other than SPPMIntegrator
andMLTIntegrator
.
The pixel bounds are specified by four integer values, corresponding (inorder) to starting x, ending x, starting y, and ending y pixelcoordinates. If specified, pbrt will do minimal work for the other imagepixels, but will ensure (as much as possible) that the program state isconsistent with how it would be for those pixels if the entire image wasrendered. (Note that the RandomSampler
won’t have the correct startingstate if this parameter is used, though this sampler generally shouldn’t beused anyway.)
Unit tests
We have written unit tests for some parts of the system (primarily for newfunctionality added with pbrt-v3, but some to test pre-existingfunctionality). Running the pbrt_test
executable, which is built as partof the regular build process, causes all tests to be executed. Unit testsare written using the Google C++ TestingFramework, which is included withthe pbrt distribution.See the Google TestPrimerfor more information about how to write new test.
We have found these tests to be quite useful when developing new features,testing the system after code changes, and when porting the system to newtargets. Over time, we plan to add more tests and are also always happy toreceive pull requests with additions to the system’s tests.
Pull requests
We’re always happy to get pull requests or patches that improvepbrt. However, we are unlikely to accept pull requests that significantlychange the system’s structure, as we don’t want the “master” branch todiverge too far from the contents of the book. (In this cases, however,we certainly encourage you to maintain a separate fork of the system ongithub and to let people know about it on the pbrt mailing list.)
Pull requests that fix bugs in the system or improve portability are alwayswelcome. (If you have an itch to write unit tests and add new ones tosrc/tests
, we’re also happy to expand the test coverage of the system!)Finally, if you write a converter that makes it easier to export scenesfrom other file formats or modeling systems to pbrt’s format, we’d happilyinclude it in the pbrt distribution.
Example scenes
Over 8GB of example scenes that exercise awide range of pbrt's functionality (and make pretty images) are availablefor download. (Many are new and weren’t available with previous versionsof pbrt.)
Converting Scenes to pbrt’s format
Given an amazing scene in another 3D file format, there are a fewoptions for converting it to be used in pbrt. (We’re always happy to havehelp with improvements in this area!)
Cinema 4D
The exporters/cinema4d
directory in the pbrt-v3 distribution provides anexporter from Cinema 4D. This exporter was developed to export the amazing“landscape” scene that is on the book’s front cover from Cinema 4D, so thusis up to date with respect to pbrt’s material models and renderingsettings. We have seen good results with using this exporter for otherCinema 4D scenes.
Wavefront OBJ
The pbrt-v3 distribution includes a converter from the Wavefront OBJformat, obj2pbrt
, that is built when the rest of the system is compiled.To run it, provide the path to an OBJ file and a filename for a new pbrtfile:
$ obj2pbrt scene.obj scene.pbrt
If there is an accompanying material description file (e.g. scene.mtl
),the values in it will be roughly mapped to corresponding pbrt materials.You will likely need to manually edit and tune the materials in thegenerated pbrt file in order to achieve reasonably good-lookingresults.
Note that OBJ files only describe scene geometry; they don’t include cameraspecifications or descriptions of light sources. (Thus, the generated pbrtinput file only includes shape and material specifications that you’ll needto add inside the WorldBegin
/WorldEnd
block of a full pbrt input file.)Unless you have camera and light source information separately, you’ll needto specify both on your own (see “General Tips” below for some ideas abouthow to do this.)
Blender
Many very nice scenes have been modeled inBlender and are freely available. (See, forexample, the BlendSwap website for manyscenes that can be used via a Creative Commons license.) Our experience hasbeen that the best approach to export scenes from Blender is to useBlender’s native OBJ export (available via the File/Export menu item) andthen to use the obj2pbrt utility described above to convert to pbrt’sformat.
More recently, Giulio Jiang has developed a nativeBlenderexporter for pbrt; see also theexporter's githubpage.
Blender scene files may have texture maps for the scene included directlyin their .blend
file. Choose “File/External Data/Unpack into Files” inBlender to save those files independently on disk. (Note that if thetextures aren’t PNG or TGA format, you’ll need to convert to one of thosefor pbrt to be able to use them.)
Maya
PBRTForMaya, a Mayaplugin to export scenes in pbrt's format, has been developedby Haarm-Pieter Duiker.
Houdini
A Houdiniexporter for pbrt, an exporter from SideFX'samazing Houdini system, has beenwritten by Jim Price.
Old exporters
The pbrt-v2 distribution includesexporters for 2010era 3DS Max (which was used for the model used for the cover image for thesecond edition of the book), Blender, Mathematica, and StructureSynth. All of these are very muchout of date, both due to changes over the past six years in in the systemsthey exported from as well as changes in pbrt. Some of these may be usefulfor developing updated exporters for the corresponding systems for pbrt-v3.
General tips
A scene exported using one of the above exporters is certain to notimmediately render beautifully as is. Here are some suggestions for how totake an initial export and turn it into something that looks great.
First, you may find it useful to run
$ pbrt --toply scene.pbrt > newscene.pbrt
This will convert triangle meshes into more compact binary PLY files,giving you a much smaller pbrt scene file to edit.
Next, if the exporter doesn’t include camera information, the first thingto do is to find a good view. The “environment” camera (which renders animage in all directions) can be useful for finding a good initial positionfor the camera. Keep rendering images and adjusting the camera position totaste. (For efficiency, use as few pixel samples as you can tolerate andlearn to squint and interpret noisy renderings!) Then, you can use theorigin you’ve chosen as the basis for specifying a LookAt
transformationfor a more conventional camera model.
While placing the camera, it can be helpful to have a point light source atthe camera’s position. Adding a light source like the following to yourscene file does this in a way that ensures that the light movesappropriately to wherever the camera has been placed. (You may need toscale the intensity up or down for good results–remember theradius-squared falloff!
AttributeBeginCoordSysTransform "camera"LightSource "point" "color I" [10 10 10]AttributeEnd
Once the camera is placed, we have found that it’s next useful to set upapproximate light sources. For outdoor scenes, a good HDR environment mapis often all that is needed for lighting. (You may want to consider usingimgtool makesky
to make a realistic HDR sky environment map.)
For indoor scenes, you may want a combination of an environment map for theoutside and point and/or area light sources for interior lights. You mayfind it useful to examine the scene in the modeling system that it camefrom to determine which geometry corresponds to area light sources and totry adding AreaLightSource
properties to those. (Note that in pbrt, arealight sources only emit lights on the side that the surface normal points;you may need a ReverseOrientation
directive to make the light come out inthe right direction.)
Given good lighting, the next step is to tune the materials (or set themfrom scratch). It can be helpful to pick a material and set it to anextreme value (such as a “matte” material that is pure red) and render thescene; this quickly shows which geometric models have that materialassociated with it. Alternatively, consider applying thispatch to your pbrt source tree; after rebuildingpbrt, if you set the PBRT_MTL_HACK
environment variable and render thescene, pbrt will generate a separate image for each NamedMaterial
in the scene, with a filename corresponding to the material name. Eachof these images will only include the objects with that material, whichmakes it easier to see what’s what.
As you figure out which material names correspond to what geometry, watchfor objects that are missing texture maps and add Texture
specificationsfor them and use them in the materials. (The good news is that such objectsgenerally do have correct texture coordinates with them, so this mostlyjust works.)
Submitting updates
We’d love to increase the scope (and quality) of scenes available for usewith pbrt
. If you have a nice scene in pbrt
's format that you’d like tohave included in this distribution, or if you have improvements to thecurrent set of scenes, we’d love to have them! (Even finding additionalgood camera locations for the existing scenes or generating variants ofsome of the existing scenes with different lighting setups is helpful.)
We’re particularly interested in adding scenes that include complex andrealistic character models as well as scenes with realistic distributionsof hair or fur.
If you have a scene to share, please post the resulting file onlinesomewhere that we can access it and send us a pointer at[emailprotected]).