A Gentle Introduction to DirectX Raytracing 13


本节我们将应用 Falcor 的色调映射器以显示高动态范围输出

In Tutorials 10 and 12, we added high dynamic range environment maps and indirect illumination. With these two additions, we sometimes get renderngs that are perfectly correct but might be too dark or bright to clearly display on our monitors. As we add more complex materials (and, eventually, area lighting using actual measured light power) these problems quickly become worse.

教程 10 和 12中,我们添加了高动态范围环境贴图和间接照明。通过这两个添加,我们有时会得到完全正确的渲染,但可能太暗或太亮而无法在我们的显示器上清晰显示。随着我们添加更复杂的材料(最终,使用实际测量的光功率进行区域照明),这些问题很快变得更糟。

This tutorial takes a quick detour to add a pass to tone map our rendered output. Tone mapping and high dynamic range imaging are widely studied areas. Rather than dive into details, I suggest you find a textbook on the topic (perhaps this one) for a guide on picking the right algorithm for your needs.


Falcor has a built-in tone mapping utility, and we are simply going to expose this utility in a new SimpleToneMappingPass.

Falcor有一个内置的色调映射实用程序,我们只是要在一个新的 SimpleToneMappingPass.

A Render Pass Leveraging Falcor’s Tone Mapper

Unlike the last few tutorials, let’s start again from the beginning: the main() function in Tutor13-SimpleToneMapping.cpp. This this tutorial, we are adding a fourth render pass to out pipeline:

与上几篇教程不同,让我们从头开始:main(). Tutor13-SimpleToneMapping.cpp在本教程中,我们将向输出管道添加第四个渲染通道:

pipeline->setPass(0, LightProbeGBufferPass::create());
pipeline->setPass(1, SimpleDiffuseGIPass::create("HDRColorOutput"));
pipeline->setPass(2, SimpleAccumulationPass::create("HDRColorOutput"));
pipeline->setPass(3, SimpleToneMappingPass::create("HDRColorOutput",

Here what we are doing is:

  • Creating our G-buffer
  • Rendering our one-bounce diffuse global illumination into the HDRColorOutput texture
  • Temporally accumulating from and storing the accumualted result into HDRColorOutput
  • Tone mapping the result from HDRColorOutput into our final output kOutputChannel


  • 创建我们的 G 缓冲区
  • 将我们的单次反射漫反射全局照明渲染到 HDRColorOutput 纹理中
  • 临时累加并将累加的结果存储到 HDRColorOutput
  • 将结果从色调映射 HDRColorOutput 到我们的最终输出 kOutputChannel

Defining the Tone Mapping Render Pass

Our render pass definition in SimpleToneMappingPass.h is mostly boilerplate, with the key data being:

我们的渲染通道定义 SimpleToneMappingPass.h,关键数据是:

std::string                 mInChannel;    // Input texture for tonemapping
std::string mOutChannel; // Output texure from tonemapping
GraphicsState::SharedPtr mpGfxState; // DirectX raster state
ToneMapping::UniquePtr mpToneMapper; // Falcor's tonemapping utility

Here mInputChannel and mOutputChannel are input and output buffers, copied from the constructor (so based on the initialization in main(), these are "HDRColorOutput" and kOutputChannel).

这里 mInputChannelmOutputChannel 是输入和输出缓冲区,从构造函数复制(因此基于 中的初始化 main(),它们是 "HDRColorOutput"kOutputChannel)。

mpGfxState is a default DirectX pipeline state, as we used in Tutorial 2.

mpGfxState 是我们在教程 2中使用的默认 DirectX 管道状态。

mpToneMapper is an instantiation of Falcor’s tone mapping utility class. There are a number of methods to configure the tonemapping, including setOperator(), setExposureKey(), etc. The tone mapper class also provides a GUI, so the user can configure the settings dynamically at run time.

mpToneMapper是 Falcor 的色调映射实用程序类的实例。配置色调映射的方法有很多,包括setOperator()setExposureKey()等。色调映射器类还提供了一个 GUI,因此用户可以在运行时动态配置设置。

Applying our Tone Mapping

The key operations in SimpleToneMappingPass::initialize() include:

关键操作 SimpleToneMappingPass::initialize() 包括:

mpToneMapper = ToneMapping::create( ToneMapping::Operator::Clamp );
mpGfxState = GraphicsState::create();

The first line instantiates the class and initializes it to use a clamping operator. The clamp operator does no tone mapping, essentially copying the input texture to the output. The second line initializes a default DirectX raster state (needed while tone mapping).

第一行实例化该类并将其初始化为使用钳位运算符。钳位操作符不进行色调映射,本质上是将输入纹理复制到输出。第二行初始化默认的 DirectX 光栅状态(色调映射时需要)。

To perform tone mapping, our SimpleToneMappingPass::execute() looks as follows:

为了执行色调映射,我们 SimpleToneMappingPass::execute() 看起来如下:

void SimpleToneMappingPass::execute(RenderContext::SharedPtr pRenderContext)
Fbo::SharedPtr srcFbo = mpResManager->createManagedFbo({ mInChannel });
Fbo::SharedPtr dstFbo = mpResManager->createManagedFbo({ mOutChannel });

mpToneMapper->execute(pRenderContext.get(), srcFbo, dstFbo);

The first two lines get our input and output buffers as frame buffer objects (as required by mpToneMapper). mpToneMapper->execute() performs tone mapping, and the pushGraphicsState() and popGraphicsState() ensure changes in the tone mapper don’t affect the rest of our program.

前两行将我们的输入和输出缓冲区作为帧缓冲区对象(根据 要求 mpToneMapper)。 mpToneMapper->execute() 执行色调映射,pushGraphicsState()popGraphicsState() 确保色调映射器中的更改不会影响我们程序的其余部分。

One last observation: in order to expose the class parameters in the UI, we need to add mpToneMapper->renderUI() to our renderGui() method:

最后一个观察:为了在 UI 中公开类参数,我们需要在 mpToneMapper->renderUI() 我们的 renderGui() 方法中添加:

void SimpleToneMappingPass::renderGui(Gui* pGui)
mpToneMapper->renderUI(pGui, nullptr);

What Does it Look Like?

That covers the important points of this tutorial. When running, you get the following result:


With this tutorial, you can apply Falcor’s built-in tone mapping to allow rendering of very dark or very bright environments.

通过本教程,您可以应用 Falcor 的内置色调映射来渲染非常黑暗或非常明亮的环境。

Tutorial 14 changes our Lambertian material model to use Falcor’s standard GGX materials and extends our one-bounce global illumination to an arbitrary, user-controllable number of bounces.

教程 14将我们的 Lambertian 材质模型更改为使用 Falcor 的标准GGX 材质,并将我们的单反射全局照明扩展到任意的、用户可控数量的反射。