PBRT v4 - Part II: OptiX denoiser

Jan Walter July 17, 2023 [TRACE] #pbrt-v4 #denoise

The last part (PBRT v4 - Part I: Kroken Scene) briefly talked about the imgtool. The README.md file mentions the support for the OptiX denoiser:

The imgtool program that is built as part of pbrt provides support for the OptiX denoiser in the GPU build. The denoiser is capable of operating on RGB-only images, but gives better results with "deep" images that include auxiliary channels like albedo and normal.

CUDA

I ran into some problems regarding the CUDA installation and followed a NVIDIA Rtx 2080 Ti Ubuntu 20.04 Driver Installation instruction, which is more specific to my graphics card and Linux distribution. As root:

# apt install aptitude
# aptitude install nvidia-driver-535 nvidia-settings
# apt-get dist-upgrade

It's not related to the next steps, but I decided to also upgrade from Ubuntu 20.04 LTS to 22.04 LTS:

# uname -mrs
Linux 5.15.0-76-generic x86_64
# lsb_release -a
LSB Version:	core-11.1.0ubuntu4-noarch:security-11.1.0ubuntu4-noarch
Distributor ID:	Ubuntu
Description:	Ubuntu 22.04.2 LTS
Release:	22.04
Codename:	jammy

OptiX

Beside CUDA we need OptiX installed.

# cd ~jan/Downloads/
# sh NVIDIA-OptiX-SDK-7.7.0-linux64-x86_64.sh
...
# cd NVIDIA-OptiX-SDK-7.7.0-linux64-x86_64
# pwd
/home/jan/Downloads/NVIDIA-OptiX-SDK-7.7.0-linux64-x86_64
# ls -1
doc
include
SDK
# chown -R jan:jan .

I did run the commands above as root, which I compensated for by chown. I guess running it as user would have made more sense.

Compiling

I did install CUDA following the guide but that is not enough:

$ cmake --version
cmake version 3.26.4

CMake suite maintained and supported by Kitware (kitware.com/cmake).
$ pwd
/media/datadisk3/git/github/pbrt-v4
$ mkdir build
$ cd build/
$ cmake ..
...
-- Found CUDA: /usr/local/cuda (found version "12.2") 
-- Found CUDA: 12.2.91
CMake Warning at CMakeLists.txt:189 (message):
  Found CUDA but PBRT_OPTIX7_PATH is not set.  Disabling GPU compilation.
...

It can find CUDA, but we need to set the PBRT_OPTIX7_PATH.

Let's try again (after installing OptiX):

$ export PBRT_OPTIX7_PATH=/home/jan/Downloads/NVIDIA-OptiX-SDK-7.7.0-linux64-x86_64
$ cd/media/datadisk3/git/github/pbrt-v4
$ rm -rf build/
$ mkdir build
$ cd build/
$ cmake ..
-- The CXX compiler identification is GNU 11.3.0
-- The C compiler identification is GNU 11.3.0
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /usr/bin/cc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Setting build type to 'Release' as none was specified.
-- Found Git: /home/linuxbrew/.linuxbrew/bin/git (found version "2.41.0") 
-- OpenEXR at commit: 5cfb5dab6dfada731586b0281bdb15ee75e26782
-- OpenVDB at commit: 414bed84c2fc22e188eac7b611aa85c7edd7a5a9
-- Ptex at commit: 4cd8e9a6db2b06e478dfbbd8c26eb6df97f84483
-- double-conversion at commit: cc1f75a114aca8d2af69f73a5a959aecbab0e87a
-- filesystem at commit: c5f9de30142453eb3c6fe991e82dfc2583373116
-- glfw at commit: 4cb36872a5fe448c205d0b46f0e8c8b57530cfe0
-- libdeflate at commit: 1fd0bea6ca2073c68493632dafc4b1ddda1bcbc3
-- lodepng at commit: 8c6a9e30576f07bf470ad6f09458a2dcd7a6a84a
-- qoi at commit: 028c75fd26e5e0758c7c711216c00404994c1ad3
-- stb at commit: af1a5bc352164740c1cc1354942b1c6b72eacb8a
-- utf8proc at commit: 2484e2ed5e1d9c19edcccf392a7d9920ad90dfaf
-- zlib at commit: 54d591eabf9fe0e84c725638f8d5d8d202a093fa
-- Performing Test CMAKE_HAVE_LIBC_PTHREAD
-- Performing Test CMAKE_HAVE_LIBC_PTHREAD - Success
-- Found Threads: TRUE  
-- Found OpenGL: /usr/lib/x86_64-linux-gnu/libOpenGL.so   
-- The ASM compiler identification is GNU
-- Found assembler: /usr/bin/cc
CMake Warning (dev) at src/ext/libdeflate/CMakeLists.txt:12 (option):
  Policy CMP0077 is not set: option() honors normal variables.  Run "cmake
  --help-policy CMP0077" for policy details.  Use the cmake_policy command to
  set the policy and suppress this warning.

  For compatibility with older versions of CMake, option is clearing the
  normal variable 'BUILD_SHARED_LIBS'.
This warning is for project developers.  Use -Wno-dev to suppress it.

-- Performing Test DEFLATE_LINT_WALL
-- Performing Test DEFLATE_LINT_WALL - Success
-- Performing Test DEFLATE_LINT_WUNDEF
-- Performing Test DEFLATE_LINT_WUNDEF - Success
-- Performing Test DEFLATE_LINT_PEDANTIC
-- Performing Test DEFLATE_LINT_PEDANTIC - Success
-- Performing Test DEFLATE_LINT_DECLARATION_AFTER_STATEMENT
-- Performing Test DEFLATE_LINT_DECLARATION_AFTER_STATEMENT - Success
-- Performing Test DEFLATE_LINT_MISSING_PROTOTYPES
-- Performing Test DEFLATE_LINT_MISSING_PROTOTYPES - Success
-- Performing Test DEFLATE_LINT_STRICT_PROTOTYPES
-- Performing Test DEFLATE_LINT_STRICT_PROTOTYPES - Success
-- Performing Test DEFLATE_LINT_VLA
-- Performing Test DEFLATE_LINT_VLA - Success
-- Performing Test DEFLATE_LINT_IMPLICIT_FALLTHROUGH
-- Performing Test DEFLATE_LINT_IMPLICIT_FALLTHROUGH - Success
-- Found ZLIB: /usr/lib/x86_64-linux-gnu/libz.so (found version "1.2.11")  
-- Could NOT find Imath (missing: Imath_DIR)
-- Found PkgConfig: /home/linuxbrew/.linuxbrew/bin/pkg-config (found version "0.29.2") 
-- Found OpenEXR: /usr/include (found suitable version "2.5.7", minimum required is "2.3") 
-- Found OpenEXR version 2.5.7
CMake Deprecation Warning at src/ext/ptex/CMakeLists.txt:1 (cmake_minimum_required):
  Compatibility with CMake < 2.8.12 will be removed from a future version of
  CMake.

  Update the VERSION argument <min> value or use a ...<max> suffix to tell
  CMake that the project does not need compatibility with older versions.


-- Could NOT find Doxygen (missing: DOXYGEN_EXECUTABLE) 
-- Including X11 support
-- Found X11: /usr/include   
-- Looking for XOpenDisplay in /usr/lib/x86_64-linux-gnu/libX11.so;/usr/lib/x86_64-linux-gnu/libXext.so
-- Looking for XOpenDisplay in /usr/lib/x86_64-linux-gnu/libX11.so;/usr/lib/x86_64-linux-gnu/libXext.so - found
-- Looking for gethostbyname
-- Looking for gethostbyname - found
-- Looking for connect
-- Looking for connect - found
-- Looking for remove
-- Looking for remove - found
-- Looking for shmat
-- Looking for shmat - found
-- Looking for IceConnectionNumber in ICE
-- Looking for IceConnectionNumber in ICE - found
-- Unable to find -lprofiler
-- Looking for a CUDA compiler
-- Looking for a CUDA compiler - /usr/local/cuda/bin/nvcc
-- Found CUDA: /usr/local/cuda (found version "12.2") 
-- Found CUDA: 12.2.91
-- The CUDA compiler identification is NVIDIA 12.2.91
-- Detecting CUDA compiler ABI info
-- Detecting CUDA compiler ABI info - done
-- Check for working CUDA compiler: /usr/local/cuda/bin/nvcc - skipped
-- Detecting CUDA compile features
-- Detecting CUDA compile features - done
-- Detected CUDA Architecture: sm_75
-- Performing Test COMPILER_SUPPORTS_MARCH_NATIVE
-- Performing Test COMPILER_SUPPORTS_MARCH_NATIVE - Success
-- Performing Test HAVE_MMAP
-- Performing Test HAVE_MMAP - Success
-- Performing Test HAS_INTRIN_H
-- Performing Test HAS_INTRIN_H - Failed
-- Performing Test HAVE_DECLSPEC_NOINLINE
-- Performing Test HAVE_DECLSPEC_NOINLINE - Failed
-- Performing Test HAVE_ATTRIBUTE_NOINLINE
-- Performing Test HAVE_ATTRIBUTE_NOINLINE - Success
-- Performing Test HAVE_PRE_POST_BAR_RESTRICT
-- Performing Test HAVE_PRE_POST_BAR_RESTRICT - Success
-- Performing Test HAVE_PRE_BAR_RESTRICT
-- Performing Test HAVE_PRE_BAR_RESTRICT - Success
-- Performing Test HAVE__ALIGNED_MALLOC
-- Performing Test HAVE__ALIGNED_MALLOC - Failed
-- Performing Test HAVE_POSIX_MEMALIGN
-- Performing Test HAVE_POSIX_MEMALIGN - Success
-- Performing Test INT64_IS_OWN_TYPE
-- Performing Test INT64_IS_OWN_TYPE - Failed
-- Configuring done (11.4s)
CMake Warning (dev) in CMakeLists.txt:
  Policy CMP0104 is not set: CMAKE_CUDA_ARCHITECTURES now detected for NVCC,
  empty CUDA_ARCHITECTURES not allowed.  Run "cmake --help-policy CMP0104"
  for policy details.  Use the cmake_policy command to set the policy and
  suppress this warning.

  CUDA_ARCHITECTURES is empty for target "optix.cu".
This warning is for project developers.  Use -Wno-dev to suppress it.

CMake Warning (dev) in CMakeLists.txt:
  Policy CMP0104 is not set: CMAKE_CUDA_ARCHITECTURES now detected for NVCC,
  empty CUDA_ARCHITECTURES not allowed.  Run "cmake --help-policy CMP0104"
  for policy details.  Use the cmake_policy command to set the policy and
  suppress this warning.

  CUDA_ARCHITECTURES is empty for target "pbrt_lib".
This warning is for project developers.  Use -Wno-dev to suppress it.

CMake Warning (dev) in CMakeLists.txt:
  Policy CMP0104 is not set: CMAKE_CUDA_ARCHITECTURES now detected for NVCC,
  empty CUDA_ARCHITECTURES not allowed.  Run "cmake --help-policy CMP0104"
  for policy details.  Use the cmake_policy command to set the policy and
  suppress this warning.

  CUDA_ARCHITECTURES is empty for target "pbrt_lib".
This warning is for project developers.  Use -Wno-dev to suppress it.

-- Generating done (0.1s)
-- Build files have been written to: /media/datadisk3/git/github/pbrt-v4/build
$ cmake --build .
...

imgtool

After a successful compilation there should be an command for denoising:

$ ./imgtool --help |& grep denoise -A 2
denoise-optix: Denoises the image using NVIDIA's OptiX denoiser which is
    based on a deep neural network. The provided image should
    be a multi-channel EXR as generated by pbrt's "gbuffer" film.

Denoising

So, after rendering the camera-1 with only a few samples per pixel (--spp 16):

# time /media/datadisk3/git/github/pbrt-v4/build/pbrt --stats --spp 16 --display-server localhost:14158 camera-1.pbrt
pbrt version 4 (built Jul 17 2023 at 10:07:34)
Copyright (c)1998-2021 Matt Pharr, Wenzel Jakob, and Greg Humphreys.
The source code to pbrt (but *not* the book contents) is covered by the Apache 2.0 License.
See the file LICENSE.txt for the conditions of the license.
Warning: lights.pbrt:7:4: Converting non-RGB "L" parameter to RGB so that a portal light can be used.
Rendering: [+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++]  (15.4s)       
Statistics:
  BVH
    Interior nodes                                              287361520
    Leaf nodes                                                  287361531
    Nodes visited                                              6629373242
    Primitives per leaf node                     287902422 /    287361531 (1.00x)
  Geometry
    Spheres                                                             2
    Triangles added from displacement mapping                   247702869
    Buffer cache hits                                  239 /          955 (25.03%)
    Triangles per mesh                           287904585 /          248 (1160905.58x)
  Integrator
    Camera rays traced                                            9000000
    Surface interactions                                         34527288
    Volume interactions                                             80435
  Intersections
    Regular ray intersection tests                               60905400
    Ray-Triangle intersection tests               73770948 /    338834471 (0.22x)
  Memory
    BVH                                                             19.27 GiB
    Film pixels                                                    103.00 MiB
    Image maps                                                     159.38 MiB
    Light BVH                                                      184.91 kB
    Primitives                                                       4.29 GiB
    Redundant vertex and index buffers                             347.69 MiB
    Tokenizer buffers                                              244.50 kB
    Triangles                                                        2.15 GiB
    Unreported / unused                                             20.18 GiB
  Scene
    AreaLights                                                       2175
    Lights                                                           2176
    Materials                                                          80
    Object instances created                                           10
    Textures                                                          164

real	2m22,187s
user	37m21,370s
sys	1m4,984s

I get an image, which looks good for trying the OptiX denoiser:

AOVs needed for denoising

In the lower part you see the 10 available AOVs, or according to the README.md file:

The denoiser is capable of operating on RGB-only images, but gives better results with "deep" images that include auxiliary channels like albedo and normal. Setting the scene's "Film" type to be "gbuffer" when rendering and using EXR for the image format causes pbrt to generate such a "deep" image. In either case, using the denoiser is straightforward:

$ imgtool denoise-optix noisy.exr --outfile denoised.exr

There was a bug which made the imgtool crash:

$ /media/datadisk3/git/github/pbrt-v4/build/imgtool denoise-optix camera-1.exr --outfile camera-1-denoised.exr
[ tid 38281 @     0.000s cmd/imgtool.cpp:2285 ] FATAL Check failed: desc
(/media/datadisk3/git/github/pbrt-v4/build/imgtool)	0x0x555f0f3df77a - pbrt::PrintStackTrace() + 0x3a
(/media/datadisk3/git/github/pbrt-v4/build/imgtool)	0x0x555f0f3dfa11 - pbrt::CheckCallbackScope::Fail() + 0x21
(/media/datadisk3/git/github/pbrt-v4/build/imgtool)	0x0x555f0f450692 - pbrt::LogFatal(pbrt::LogLevel, char const*, int, char const*) + 0xf2
(/media/datadisk3/git/github/pbrt-v4/build/imgtool)	0x0x555f0f23385c - void pbrt::LogFatal<char const (&) [5]>(pbrt::LogLevel, char const*, int, char const*, char const (&) [5]) + 0x5c
(/media/datadisk3/git/github/pbrt-v4/build/imgtool)	0x0x555f0f210810 - denoise_optix(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >) + 0x16a0
(/media/datadisk3/git/github/pbrt-v4/build/imgtool)	0x0x555f0f1f1b74 - main + 0x4a4
(/lib/x86_64-linux-gnu/libc.so.6         )	0x0x7fba5476fd90 - (unknown) + 0x29d90
(/lib/x86_64-linux-gnu/libc.so.6         )	0x0x7fba5476fe40 - __libc_start_main + 0x80
(/media/datadisk3/git/github/pbrt-v4/build/imgtool)	0x0x555f0f1f8845 - _start + 0x25

But that bug is fixed now:

$ /media/datadisk3/git/github/pbrt-v4/build/imgtool denoise-optix camera-1.exr --outfile camera-1-denoised.exr

So, the denoised image looks like this:

Denoised version

To get a better denoised image you have to go up with the samples per pixel (spp). Just to give you an impression about the render times involved here some timings.

512 spp

$ time /media/datadisk3/git/github/pbrt-v4/build/pbrt --stats --spp 512 --display-server localhost:14158 camera-1.pbrt
pbrt version 4 (built Jul 17 2023 at 10:07:34)
Copyright (c)1998-2021 Matt Pharr, Wenzel Jakob, and Greg Humphreys.
The source code to pbrt (but *not* the book contents) is covered by the Apache 2.0 License.
See the file LICENSE.txt for the conditions of the license.
Warning: lights.pbrt:7:4: Converting non-RGB "L" parameter to RGB so that a portal light can be used.
Rendering: [+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++]  (484.4s)         
Statistics:
  BVH
    Interior nodes                                              287361520
    Leaf nodes                                                  287361531
    Nodes visited                                            212010387147
    Primitives per leaf node                     287902422 /    287361531 (1.00x)
  Geometry
    Spheres                                                             2
    Triangles added from displacement mapping                   247702869
    Buffer cache hits                                  239 /          955 (25.03%)
    Triangles per mesh                           287904585 /          248 (1160905.58x)
  Integrator
    Camera rays traced                                          288000000
    Surface interactions                                       1105085147
    Volume interactions                                           2583979
  Intersections
    Regular ray intersection tests                             1946897492
    Ray-Triangle intersection tests             2358479334 /  10860335472 (0.22x)
  Memory
    BVH                                                             19.27 GiB
    Film pixels                                                    103.00 MiB
    Image maps                                                     159.38 MiB
    Light BVH                                                      184.91 kB
    Primitives                                                       4.29 GiB
    Redundant vertex and index buffers                             347.69 MiB
    Tokenizer buffers                                              244.50 kB
    Triangles                                                        2.15 GiB
    Unreported / unused                                             17.34 GiB
  Scene
    AreaLights                                                       2175
    Lights                                                           2176
    Materials                                                          80
    Object instances created                                           10
    Textures                                                          164

real	9m40,461s
user	251m16,214s
sys	1m20,055s

4096 spp

$ time /media/datadisk3/git/github/pbrt-v4/build/pbrt --stats --spp 4096 --display-server localhost:14158 camera-1.pbrt
pbrt version 4 (built Jul 17 2023 at 10:07:34)
Copyright (c)1998-2021 Matt Pharr, Wenzel Jakob, and Greg Humphreys.
The source code to pbrt (but *not* the book contents) is covered by the Apache 2.0 License.
See the file LICENSE.txt for the conditions of the license.
Warning: lights.pbrt:7:4: Converting non-RGB "L" parameter to RGB so that a portal light can be used.
Rendering: [+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++]  (3905.8s)          
Statistics:
  BVH
    Interior nodes                                              287361520
    Leaf nodes                                                  287361531
    Nodes visited                                            1696150927268
    Primitives per leaf node                     287902422 /    287361531 (1.00x)
  Geometry
    Spheres                                                             2
    Triangles added from displacement mapping                   247702869
    Buffer cache hits                                  239 /          955 (25.03%)
    Triangles per mesh                           287904585 /          248 (1160905.58x)
  Integrator
    Camera rays traced                                         2304000000
    Surface interactions                                       8840927010
    Volume interactions                                          20661349
  Intersections
    Regular ray intersection tests                            15575563124
    Ray-Triangle intersection tests            18868365257 /  86881430559 (0.22x)
  Memory
    BVH                                                             19.27 GiB
    Film pixels                                                    103.00 MiB
    Image maps                                                     159.38 MiB
    Light BVH                                                      184.91 kB
    Primitives                                                       4.29 GiB
    Redundant vertex and index buffers                             347.69 MiB
    Tokenizer buffers                                              244.50 kB
    Triangles                                                        2.15 GiB
    Unreported / unused                                             16.88 GiB
  Scene
    AreaLights                                                       2175
    Lights                                                           2176
    Materials                                                          80
    Object instances created                                           10
    Textures                                                          164

real	66m40,878s
user	1799m14,847s
sys	1m34,903s

This is pretty much the same image we rendered the last time using --spp 4096 (samples per pixel), but this time we denoise it during the conversion from OpenEXR to PNG:

$ cp camera-1.exr camera-1-4096spp.exr
$ /media/datadisk3/git/github/pbrt-v4/build/imgtool denoise-optix camera-1-4096spp.exr --outfile camera-1-4096spp.png
Warning: camera-1-4096spp.png: 75309 out of gamut pixel channels clamped to [0,1].

Denoised version with 4096 samples per pixel

The difference is a bit hard to catch by eye, but the imf_diff tool helps to see it, using false-color:

$ imf_diff -d -f camera-1-4096spp.png ../rnd-pbrt-v4-001/kroken-001.png diff-001.jpg
differing pixels:	 19.980% (112387 of 562500)
average difference:	  1.529%
maximum difference:	 18.573%
Summary: Many pixels differ.
== "camera-1-4096spp.png" and "../rnd-pbrt-v4-001/kroken-001.png" are different

Using imf_diff from mental images

Most prominent is the difference in the black background of the head sculpture on the upper left shelf, and the wall behind the glasses.

Back to top