PBRT
Tuesday, February 3, 2026
PBRT is an impressive photorealistic rendering system:
From movies to video games, computer-rendered images are pervasive today. Physically Based Rendering introduces the concepts and theory of photorealistic rendering hand in hand with the source code for a sophisticated renderer.
The fourth edition of their book is now available on Amazon as well as freely available online.
I thought it would be fun to explore the PBRT v4 file format using Factor.
Here’s a short example pbrt file from their website:
LookAt 3 4 1.5 # eye
.5 .5 0 # look at point
0 0 1 # up vector
Camera "perspective" "float fov" 45
Sampler "halton" "integer pixelsamples" 128
Integrator "volpath"
Film "rgb" "string filename" "simple.png"
"integer xresolution" [400] "integer yresolution" [400]
WorldBegin
# uniform blue-ish illumination from all directions
LightSource "infinite" "rgb L" [ .4 .45 .5 ]
# approximate the sun
LightSource "distant" "point3 from" [ -30 40 100 ]
"blackbody L" 3000 "float scale" 1.5
AttributeBegin
Material "dielectric"
Shape "sphere" "float radius" 1
AttributeEnd
AttributeBegin
Texture "checks" "spectrum" "checkerboard"
"float uscale" [16] "float vscale" [16]
"rgb tex1" [.1 .1 .1] "rgb tex2" [.8 .8 .8]
Material "diffuse" "texture reflectance" "checks"
Translate 0 0 -1
Shape "bilinearmesh"
"point3 P" [ -20 -20 0 20 -20 0 -20 20 0 20 20 0 ]
"point2 uv" [ 0 0 1 0 1 1 0 1 ]
AttributeEnd
And this is what it might look like:
Using our new pbrt vocabulary, we can convert that text into a set of tuples that we could do computations on, or potentially look into rendering or processing. And, of course, it also supports round-tripping back and forth from text to tuples.
{
T{ pbrt-look-at
{ eye-x 3 }
{ eye-y 4 }
{ eye-z 1.5 }
{ look-x 0.5 }
{ look-y 0.5 }
{ look-z 0 }
{ up-x 0 }
{ up-y 0 }
{ up-z 1 }
}
T{ pbrt-camera
{ type "perspective" }
{ params
{
T{ pbrt-param
{ type "float" }
{ name "fov" }
{ values { 45 } }
}
}
}
}
T{ pbrt-sampler
{ type "halton" }
{ params
{
T{ pbrt-param
{ type "integer" }
{ name "pixelsamples" }
{ values { 128 } }
}
}
}
}
T{ pbrt-integrator { type "volpath" } { params { } } }
T{ pbrt-film
{ type "rgb" }
{ params
{
T{ pbrt-param
{ type "string" }
{ name "filename" }
{ values { "simple.png" } }
}
T{ pbrt-param
{ type "integer" }
{ name "xresolution" }
{ values { 400 } }
}
T{ pbrt-param
{ type "integer" }
{ name "yresolution" }
{ values { 400 } }
}
}
}
}
T{ pbrt-world-begin }
T{ pbrt-light-source
{ type "infinite" }
{ params
{
T{ pbrt-param
{ type "rgb" }
{ name "L" }
{ values { 0.4 0.45 0.5 } }
}
}
}
}
T{ pbrt-light-source
{ type "distant" }
{ params
{
T{ pbrt-param
{ type "point3" }
{ name "from" }
{ values { -30 40 100 } }
}
T{ pbrt-param
{ type "blackbody" }
{ name "L" }
{ values { 3000 } }
}
T{ pbrt-param
{ type "float" }
{ name "scale" }
{ values { 1.5 } }
}
}
}
}
T{ pbrt-attribute-begin }
T{ pbrt-material { type "dielectric" } { params { } } }
T{ pbrt-shape
{ type "sphere" }
{ params
{
T{ pbrt-param
{ type "float" }
{ name "radius" }
{ values { 1 } }
}
}
}
}
T{ pbrt-attribute-end }
T{ pbrt-attribute-begin }
T{ pbrt-texture
{ name "checks" }
{ value-type "spectrum" }
{ class "checkerboard" }
{ params
{
T{ pbrt-param
{ type "float" }
{ name "uscale" }
{ values { 16 } }
}
T{ pbrt-param
{ type "float" }
{ name "vscale" }
{ values { 16 } }
}
T{ pbrt-param
{ type "rgb" }
{ name "tex1" }
{ values { 0.1 0.1 0.1 } }
}
T{ pbrt-param
{ type "rgb" }
{ name "tex2" }
{ values { 0.8 0.8 0.8 } }
}
}
}
}
T{ pbrt-material
{ type "diffuse" }
{ params
{
T{ pbrt-param
{ type "texture" }
{ name "reflectance" }
{ values { "checks" } }
}
}
}
}
T{ pbrt-translate { x 0 } { y 0 } { z -1 } }
T{ pbrt-shape
{ type "bilinearmesh" }
{ params
{
T{ pbrt-param
{ type "point3" }
{ name "P" }
{ values
{ -20 -20 0 20 -20 0 -20 20 0 20 20 0 }
}
}
T{ pbrt-param
{ type "point2" }
{ name "uv" }
{ values { 0 0 1 0 1 1 0 1 } }
}
}
}
}
T{ pbrt-attribute-end }
}
This is available now in the development version of Factor!