IE盒子

搜索
查看: 116|回复: 0

三十六、NVIDIA Falcor

[复制链接]

1

主题

6

帖子

11

积分

新手上路

Rank: 1

积分
11
发表于 2023-3-5 04:20:43 | 显示全部楼层 |阅读模式
在前两节,通过分析几个导入C++源码的Slang源码文件,大致了解了slang源码的结构与作用。
这里,我们重点关注C++和Slang源码是如何进行交互的。
GeneratePaths.cs.slang

先来回忆一下这个Slang文件干了什么:
路径生成,用gScene.camera.computeRayPinhole(pixel, params.frameDim)来计算从相机出发的光线路径。
用前缀和来计算样本偏移量查找表gSamplesOffset。
如果光线与场景没有交点:如果每个像素只固定采样一个,那么直接把颜色写入outputColor;否则,像素偏移量为outIdx,样本索引为i,那么写入sampleColor[outIdx+i]。
那么,在C++源码中是如何调用这个文件,让它起效果,同时管理它的数据,便于之后步骤使用的呢?
接下来更加仔细地分析一下PathTracer::generatePaths():
void PathTracer::generatePaths(RenderContext* pRenderContext, const RenderData& renderData)
{
    ...

    // Bind resources.
    auto var = mpGeneratePaths->getRootVar()["CB"]["gPathGenerator"];
    setShaderData(var, renderData, false);
    // ---------- Part 1 over ----------
    mpGeneratePaths["gScene"] = mpScene->getParameterBlock();

    if (mpRTXDI) mpRTXDI->setShaderData(mpGeneratePaths->getRootVar());
    // ---------- Part 2 over ----------
    // Launch one thread per pixel.
    // The dimensions are padded to whole tiles to allow re-indexing the threads in the shader.
    mpGeneratePaths->execute(pRenderContext, { mParams.screenTiles.x * tileSize, mParams.screenTiles.y, 1u });
    // ---------- Part 3 over ----------
}
变量管理 - getRootVar()

/** PathTracer::generatePaths() **/

// Bind resources.
auto var = mpGeneratePaths->getRootVar()["CB"]["gPathGenerator"];
setShaderData(var, renderData, false);
看第一行这里:mpGeneratePaths->getRootVar()["CB"]["gPathGenerator"]。一个很合理的推想,这个CB正是三十六、NVIDIA Falcor - slang源码分析(一)中提到的cbuffer,里面正声明了一个变量gPathGenerator。大胆推测,getRootVar()之后可以用方括号来对应Slang源码中的变量。
也就是说,gPathGenerator(Slang)被绑定到了var(C++)中,并且作为setShaderData的输入传入。继续看setShaderData(),就豁然开朗:
void PathTracer::setShaderData(const ShaderVar& var, const RenderData& renderData, bool useLightSampling) const
{
    // Bind static resources that don't change per frame.
    if (mVarsChanged)
    {
        if (useLightSampling && mpEnvMapSampler) mpEnvMapSampler->setShaderData(var["envMapSampler"]);

        var["sampleOffset"] = mpSampleOffset; // Can be nullptr
        var["sampleColor"] = mpSampleColor;
        var["sampleGuideData"] = mpSampleGuideData;
    }

    // Bind runtime data.
    setNRDData(var["outputNRD"], renderData);

    Texture::SharedPtr pViewDir;
    if (mpScene->getCamera()->getApertureRadius() > 0.f)
    {
        pViewDir = renderData.getTexture(kInputViewDir);
        if (!pViewDir) logWarning("Depth-of-field requires the '{}' input. Expect incorrect rendering.", kInputViewDir);
    }

    Texture::SharedPtr pSampleCount;
    if (!mFixedSampleCount)
    {
        pSampleCount = renderData.getTexture(kInputSampleCount);
        if (!pSampleCount) throw RuntimeError("PathTracer: Missing sample count input texture");
    }

    var["params"].setBlob(mParams); // --- 分析见下
    var["vbuffer"] = renderData.getTexture(kInputVBuffer);
    var["viewDir"] = pViewDir; // Can be nullptr
    var["sampleCount"] = pSampleCount; // Can be nullptr
    var["outputColor"] = renderData.getTexture(kOutputColor);

    if (useLightSampling && mpEmissiveSampler)
    {
        // TODO: Do we have to bind this every frame?
        mpEmissiveSampler->setShaderData(var["emissiveSampler"]);
    }
}
很显然这里var方括号取出的都是Slang中PathGenerator这个结构体的成员。顺带一提,setBlob()就是设置这块变量的二进制数据。
绑定Scene

mpGeneratePaths["gScene"] = mpScene->getParameterBlock();

if (mpRTXDI) mpRTXDI->setShaderData(mpGeneratePaths->getRootVar());
我们看到这部分绑定和上面绑定PathGenerator的情况不尽相同。
这里,gScene是定义在Falcor提供的Slang库文件中的:
// Falcor/Scene/Scene.slang
ParameterBlock<Scene> gScene;
一个猜想是,用ParameterBlock声明的变量均不用getRootVar()来绑定,而是直接把ParameterBlock赋过去。
执行Slang脚本

// Launch one thread per pixel.
// The dimensions are padded to whole tiles to allow re-indexing the threads in the shader.
mpGeneratePaths->execute(pRenderContext, { mParams.screenTiles.x * tileSize, mParams.screenTiles.y, 1u });
TracePass.rt.slang

上面说,mpGeneratePaths执行过一次setShaderData(),即把PathGenerator中的各变量进行了绑定。
对于mpPathTracerBlock,同样也执行过一次setShaderData()。之后,mpPathTracerBlock会被绑定到tracePass.pVars->getRootVar()['gPathTracer']中。
在这里,不会在C++源码里执行类似tracePass.execute()的代码。回忆三十六、NVIDIA Falcor - slang源码分析(二),这里定义的shader组应该是到光线追踪的某个阶段被调用,而不是我们去主动调用它。需要提供的shader包括:raygen,miss,hit group shader。其中hit group包括any, closest, intersection shader。
最终执行:
// Full screen dispatch.
mpScene->raytrace(pRenderContext, tracePass.pProgram.get(), tracePass.pVars, uint3(mParams.frameDim, 1));
绑定关系

C++slang
pProgram的各shaderTracePass.rt.slang
mpPathTracerBlockgPathTracer
同时,setShaderData()会把一些变量绑定到TracePass与GeneratePaths中,包括:sampleOffset, sampleColor, sampleCount, outputColor等,它们同样会被绑定到ResolvePass中。另有一些变量包括:vbuffer, viewDir。
总结

来仔细回想一下我们的PathTracer是怎么工作的。
通过C++代码控制Slang代码,并且为它绑定变量,实现不同Slang步骤的联系。
PathTracer最终输出其中的一个端口是kOutputColor,正是在上面绑定到Slang源码中去的。
首先生成路径并且生成偏移量查找表。
在TracePass中,实际去追踪路径。
最终在ResolvePass中决定输出颜色。
相关链接

目录:

  • 零、素论派学习目录
C++源码分析部分:

  • 三十三、NVIDIA Falcor源码分析(一) - PathTracer概述
  • 三十三、NVIDIA Falcor源码分析(二) - Pass与Program
  • 三十三、NVIDIA Falcor源码分析(三) - 缓冲区与资源绑定
  • 三十三、NVIDIA Falcor源码分析(四) - Var
  • 三十三、NVIDIA Falcor源码分析(五) - 总结
Slang源码分析部分:

  • 三十六、NVIDIA Falcor - slang源码分析(一)
  • 三十六、NVIDIA Falcor - slang源码分析(二)
  • 三十六、NVIDIA Falcor - slang源码分析(三)
参考


  • NVIDIAGameWorks/Falcor: Real-Time Rendering Framework (github.com)
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

快速回复 返回顶部 返回列表