DirectX 12 Raytracing(DXR)实战示例全解析:DirectX-Graphics-Samples 中的教程与高级场景指南
示例工程【免费下载链接】DirectX-Graphics-SamplesThis repo contains the DirectX Graphics samples that demonstrate how to build graphics intensive applications on Windows.项目地址https://gitcode.com/gh_mirrors/di/DirectX-Graphics-Samples点击查看免费下载本文围绕当前仓库中 Samples/Desktop/D3D12Raytracing/readme.md 这一官方集合说明展开系统梳理其中 7 个教程示例与 2 个高级示例的技术脉络并深入剖析每个示例背后的 DXR 管线搭建、着色器表布局、Shader Execution Reordering、Opacity Micromaps 等关键概念。读完本文你将掌握 DXR 从零开始的入门路径、各示例的运行方式与命令行参数并理解每个示例对应的源码实现细节可作为学习与二次开发的路线图。一、集合概述一套循序渐进的 DXR 入门与进阶教程该示例集合的定位是DirectX RaytracingDXR的入门介绍。集合被划分为两类教程示例Tutorial Samples共 7 个每个示例只引入少量新的 DXR 概念建议按编号顺序学习高级示例Advanced Samples共 2 个演示更复杂的技术与光追应用场景。所有示例均基于 C页面元数据中声明languages: cpp并假设读者已具备 Direct3D 12 编程基础。示例工程统一位于 Samples/Desktop/D3D12Raytracing/src 目录其中D3D12Raytracing.slnx为集合解决方案文件各示例的详细说明分别存放在各自子目录的readme.md中。二、运行环境与硬件要求官方明确列出的最低要求非常简洁GPU 与驱动必须支持 DirectX 12 Ultimate包含 DXR、Mesh Shader、Sampler Feedback 等特性。部分示例还额外声明了 Windows 版本要求归纳如下示例Windows 版本要求Hello World、Simple Lighting、Procedural GeometryWindows 10 2018 年 10 月更新或更高Library SubobjectsWindows 10 2019 年 5 月更新或更高Hello SER、Sakura Forest SER、Opacity MicromapsWindows 10 2019 年 10 月更新或更高各示例的启动方式一致直接运行对应目录下的 exe可附带可选参数[-forceAdapter ID]来指定使用哪块 GPU 适配器创建设备默认使用适配器 0该参数行为在 D3D12RaytracingHelloWorld/readme.md 等子文档中均有说明。三、已知问题构建失败与修复线索官方文档特别提示部分示例在不同 Visual Studio 版本下可能编译失败典型错误包括The system cannot find the path specified. *.hlsl.herror MSB6006: dxc.exe exited with code 1.这两类错误均与 HLSL 着色器经dxc.exe编译生成*.hlsl.h头文件的构建步骤相关常见诱因是 dxc 编译环境变量或依赖路径配置差异。官方给出的是排查方向而非逐个打补丁可参考上游仓库对应 issue编号为 #657中社区讨论的修复做法并结合本机 Visual Studio 版本调整dxc.exe的调用环境。本文不再展开具体补丁细节遇到该问题时建议优先核对构建工具链版本与 HLSL 编译目标。四、教程示例逐个深入1. Hello World搭建第一条光线追踪管线D3D12RaytracingHelloWorld 是整个集合的起点演示了如何搭建光追管线并在屏幕空间渲染一个三角形。管线初始化Raytracing Initialization初始化集中在CreateDeviceDependentResources()中完成包含四个核心步骤查询支持光追的 device 与 command list对应 DXR 的 device 特性查询与ID3D12GraphicsCommandList4接口获取创建光追加速结构Acceleration Structure即场景的 BVH 数据创建光线追踪管线状态对象Raytracing Pipeline State ObjectRTPSO创建着色器表Shader Table与一块用于接收光追输出的 2D 纹理资源。渲染流程Rendering每帧渲染发生在OnRender()中流程为以与后缓冲backbuffer分辨率一致的 2D 网格尺寸执行DispatchRays()将光追结果复制到后缓冲最后呈现到屏幕。该示例只实现了三个着色器ray generation射线生成、closest hit最近命中、miss未命中。射线生成着色器通过DispatchRays()对整个渲染目标执行若某像素对应的射线索引落在模板窗口stencil window内则向场景发射射线窗口外的像素则直接基于射线的 xy 分派坐标自左上角起算输出颜色。命中三角形的射线输出射线命中位置在该三角形内的重心坐标barycentric coordinates未命中的射线输出黑色。标题栏信息UI运行时标题栏展示示例名称、FPS、每秒百万主光线数Million Primary Rays/s基于 FPS 换算、GPU[ID]: 名称。2. Simple Lighting动态相机与漫反射光照D3D12RaytracingSimpleLighting 在 Hello World 基础上演示两件事为动态透视相机生成射线、为立方体计算来自动态点光源的简单漫反射着色。它假设读者已掌握 Hello World 引入的 DXR 概念。着色器分工射线生成着色器为后缓冲中每个像素对应的分派射线计算世界空间相机射线。做法是取像素屏幕位置经逆相机视图投影矩阵变换得到世界空间射线方向最近命中着色器计算射线命中点的漫反射着色。通过命中点指向光源的方向与命中三角形法线的点积再乘以光源颜色与立方体颜色得到未命中着色器直接存储背景色。着色器访问的资源输入数据全部来自常量缓冲区与缓冲资源共两块常量缓冲区CubeConstantBuffer存放立方体颜色经着色器记录shader record传入命中着色器SceneConstantBuffer存放场景级相机与光源参数经全局根签名global root signature暴露。三角形法线从显式传入最近命中着色器的索引缓冲与顶点缓冲中读取先从16 位索引缓冲加载命中三角形的三个顶点索引再用索引在顶点缓冲中取法线——每个三角形顶点均重复存储一份法线。控制ALTENTER在窗口与全屏间切换。3. Procedural Geometry程序化几何与着色器表索引D3D12RaytracingProceduralGeometry 是集合中技术含量最高的教程之一讲解用 intersection shader相交着色器实现程序化几何并引入覆盖多几何体与多个底层加速结构bottom-level ASBLAS的扩展着色器表布局与索引射线递归与两种射线类型radiance 与 shadow 射线。场景构成场景由三角形几何与程序化几何混合构成三角形几何为地面平面四边形程序化几何为地面以上的所有物体。由于 DXR 不允许在单个 BLAS 内混用三角形与程序化几何类型两者被分别存放在独立的 BLAS 中。程序化几何的定义方式程序化几何由**轴对齐包围盒AABB**加一个 intersection shader 定义。AABB 定义了 BLAS 对象空间内的几何范围射线命中 AABB 时系统调用该 AABB 命中组hit group关联的 intersection shader由其判断射线是否与内部几何相交若相交则调用ReportHit()。示例实现了三个 intersection shader每个 shader 下挂多个不同的图元Intersection Shader几何内容Analytic geometry解析几何多个球体与一个轴对齐盒子Volumetric geometry体几何Metaballs元球等值面即blobsSigned distance geometry有符号距离几何六个不同图元与一个分形金字塔射线/图元测试均假定图元局部空间AABB 隐含为-1,1。应用为每个图元施加缩放变换以放大 AABB。由于射线只能以**世界空间WorldRay*()内建函数**或 **BLAS 对象空间ObjectRay*()内建函数**获取应用需向 intersection shader 传入 BLAS 对象空间与图元局部空间之间互相转换的变换矩阵。shader 被调用时先将对象空间射线变换到局部空间再调用射线/图元相交测试例如MyIntersectionShader_AnalyticPrimitive中的RayAnalyticGeometryIntersectionTest// Get ray in AABBs local space. Ray GetRayInAABBPrimitiveLocalSpace() { PrimitiveInstancePerFrameBuffer attr g_AABBPrimitiveAttributes[l_aabbCB.instanceIndex]; // Retrieve a ray origin position and direction in bottom level AS space // and transform them into the AABB primitives local space. Ray ray; ray.origin mul(float4(ObjectRayOrigin(), 1), attr.bottomLevelASToLocalSpace).xyz; ray.direction mul(ObjectRayDirection(), (float3x3) attr.bottomLevelASToLocalSpace); return ray; } [shader(intersection)] void MyIntersectionShader_AnalyticPrimitive() { Ray localRay GetRayInAABBPrimitiveLocalSpace(); AnalyticPrimitive::Enum primitiveType (AnalyticPrimitive::Enum) l_aabbCB.primitiveType; float thit; ProceduralPrimitiveAttributes attr; if (RayAnalyticGeometryIntersectionTest(localRay, primitiveType, thit, attr)) ...测试返回命中时间thit与局部空间表面法线后shader 需将法线变换到世界空间再交给ReportHit()决定接受或拒绝命中... if (RayAnalyticGeometryIntersectionTest(localRay, primitiveType, thit, attr)) { PrimitiveInstancePerFrameBuffer aabbAttribute g_AABBPrimitiveAttributes[l_aabbCB.instanceIndex]; attr.normal mul(attr.normal, (float3x3) aabbAttribute.localSpaceToBottomLevelAS); attr.normal normalize(mul((float3x3) ObjectToWorld3x4(), attr.normal)); ReportHit(thit, /*hitKind*/ 0, attr); } }为提高效率示例在相交测试中直接按合法全局时间范围与RayFlags()校验命中而不是立即返回后依赖ReportHit()复验并重做全部设置数学。这也让示例无需为ReportHit()之后的求值定义任何命中着色器// Test if a hit is culled based on specified RayFlags. bool IsCulled(in Ray ray, in float3 hitSurfaceNormal) { float rayDirectionNormalDot dot(ray.direction, hitSurfaceNormal); bool isCulled ((RayFlags() RAY_FLAG_CULL_BACK_FACING_TRIANGLES) (rayDirectionNormalDot 0)) || ((RayFlags() RAY_FLAG_CULL_FRONT_FACING_TRIANGLES) (rayDirectionNormalDot 0)); return isCulled; } // Test if a hit is valid based on specified RayFlags and RayTMin, RayTCurrent range. bool IsAValidHit(in Ray ray, in float thit, in float3 hitSurfaceNormal) { return IsInRange(thit, RayTMin(), RayTCurrent()) !IsCulled(ray, hitSurfaceNormal); }三类程序化几何的算法要点解析几何直接求射线与球体、AABB 的解析解体几何Metaballs等值面位于点源形成的势场内。每个源有其影响范围势场由随到源中心距离平滑衰减的势多项式函数定义多源时各源贡献的势值求和等值面由应用指定的阈值定义。求交时射线在 AABB 内沿场逐步推进ray marching逐步累加总势能直到触及阈值或退出 AABB有符号距离几何由有符号距离函数定义函数返回从特定位置到几何体的最近距离。由于该距离未必沿射线方向求交需迭代式 ray marching 并在每步计算有符号距离直到足够接近表面——即sphere tracing球体追踪算法其收敛速度快于固定步长推进。有符号距离函数支持不同逻辑运算符与变换可组合简单图元形成复杂几何分形金字塔即由此而来。几何更新程序化几何的动画或修改只要 AABB 不变就无需更新加速结构。示例即以此方式动画化部分几何每帧仅更新传入 shader 的旋转变换矩阵Metaballs 场景还会传入应用时间在各自 AABB 内动画化场源位置。两种射线类型Radiance辐射射线用于TraceRay()的主射线与次级反射射线调用为每次几何命中计算着色并在多次弹跳间聚合颜色贡献Shadow阴影射线仅做朝向光源的可见性/遮挡测试只需返回是否命中。实践中仅需 miss shader不需要 any hit 与 closest hit shader——初始化射线载荷为命中标记并用RayFlags()跳过除 miss 之外的所有 shader// Initialize shadow ray payload. // Set the initial value to true since closest and any hit shaders are skipped. // Shadow miss shader, if called, will set it to false. ShadowRayPayload shadowPayload { true }; TraceRay(g_scene, RAY_FLAG_CULL_BACK_FACING_TRIANGLES | RAY_FLAG_ACCEPT_FIRST_HIT_AND_END_SEARCH | RAY_FLAG_FORCE_OPAQUE // ~skip any hit shaders | RAY_FLAG_SKIP_CLOSEST_HIT_SHADER, // ~skip closest hit shaders, ...若射线未命中任何几何miss shader 将布尔值置为 false[shader(miss)] void MyMissShader_ShadowRay(inout ShadowRayPayload rayPayload) { rayPayload.hit false; }着色器表与索引重点射线命中几何或需调用 miss shader 时GPU 按下式索引应用提供的着色器表Miss shader table index MissShaderIndex ~ from shader: TraceRay() Hit group shader table index RayContributionToHitGroupIndex ~ from shader: TraceRay() MultiplierForGeometryContributionToHitGroupIndex ~ from shader: TraceRay() * GeometryContributionToHitGroupIndex ~ system generated index of geometry in BLAS InstanceContributionToHitGroupIndex ~ from BLAS instance desc由于每种射线类型在 shader 中执行不同动作、每种几何也需要独立 shader 记录再加上同类型下多个几何变体通过局部根签名传参又各需一条 shader 记录示例最终形成如下布局Miss shader 表两条记录每种射线类型一条Shader table - MissShaderTable | [0]: MyMissShader ~ Radiance ray | [1]: MyMissShader_ShadowRay ~ Shadow rayHit group shader 表每条几何两条记录每射线类型一条示例会在调试输出中完整打印该表作为设置索引参数的参考。前几条记录如下Shader table - HitGroupShaderTable: | [0]: MyHitGroup_Triangle ~ Triangle geometry in 1st BLAS | [1]: MyHitGroup_Triangle_ShadowRay | [2]: MyHitGroup_AABB_AnalyticPrimitive ~ 1st Analytic AABB geometry in 2nd BLAS | [3]: MyHitGroup_AABB_AnalyticPrimitive_ShadowRay | [4]: MyHitGroup_AABB_AnalyticPrimitive ~ 2nd Analytic AABB geometry in 2nd BLAS | [5]: MyHitGroup_AABB_AnalyticPrimitive_ShadowRay | [6]: MyHitGroup_AABB_VolumetricPrimitive ~ 1st Volumetric AABB geometry in 2nd BLAS | [7]: MyHitGroup_AABB_VolumetricPrimitive_ShadowRay | [8]: MyHitGroup_AABB_SignedDistancePrimitive ~ 1st Signed distance AABB geometry in 2nd BLAS | [9]: MyHitGroup_AABB_SignedDistancePrimitive_ShadowRay | ..据此各索引参数的取值为MissShaderIndexradiance 射线为 0shadow 射线为 1RayContributionToHitGroupIndexradiance 与 shadow 分别为 0 和 1同一几何的两种射线记录在表中相邻存储MultiplierForGeometryContributionToHitGroupIndex为 2每个几何 ID 后紧邻两条记录GeometryContributionToHitGroupIndex系统为每个 BLAS 内几何生成的几何 ID直接对应应用传入的GeometryDesc数组顺序即{0, 1, 2, ...}InstanceContributionToHitGroupIndexBLAS 实例之间的偏移。三角形几何 BLAS 在最前故为 0AABB BLAS 设为 2三角形 BLAS 的平面几何占用了 radiance 与 shadow 两条记录。索引示例shadow 射线命中第二个 AABB 几何GeometryContributionToHitGroupIndex 1位于第二个 BLASInstanceContributionToHitGroupIndex 2则命中组着色器表索引为 51 // ~ RayContributionToHitGroupIndex - from TraceRay() 2 // ~ MultiplierForGeometryContributionToHitGroupIndex - from TraceRay() * 1 // ~ GeometryContributionToHitGroupIndex - from runtime, 2nd geometry ID:1 2 // ~ InstanceContributionToHitGroupIndex - from BLAS instance desc控制ALTENTER窗口/全屏C开关相机动画G开关几何动画L开关光源动画。标题栏额外显示DispatchRays()的 GPU 执行时间。4. Library Subobjects在 DXIL 库中声明状态对象子对象D3D12RaytracingLibrarySubobjects 是对 Simple Lighting 的改造演示如何在DXIL 库的 HLSL 着色器代码中直接定义D3D12_STATE_SUBOBJECTS并在 C 侧用其创建光追状态对象。这种子对象声明方式更简单、模块化且可复用——着色器与其属性封装在同一个 shader 内。对 Simple Lighting 的改动思路原示例除局部根签名外都在状态对象作用域使用了隐式默认子对象。改为库子对象后除 DXIL 库之外的所有子对象都可移除并移入库内成为库子对象。由于所有 shader 都在同一个 DXIL 库中库作用域上现有的隐式默认子对象会作用于库内全部 shader。在 HLSL 中声明子对象库子对象含局部根签名关联在Raytracing.hlsl中用编译期内建语法定义GlobalRootSignature MyGlobalRootSignature { DescriptorTable( UAV( u0 ) ), // Output texture SRV( t0 ), // Acceleration structure CBV( b0 ), // Scene constants DescriptorTable( SRV( t1, numDescriptors 2 ) ) // Static index and vertex buffers. }; LocalRootSignature MyLocalRootSignature { RootConstants( num32BitConstants 4, b1 ) // Cube constants }; TriangleHitGroup MyHitGroup { , // AnyHit MyClosestHitShader, // ClosestHit }; SubobjectToExportsAssociation MyLocalRootSignatureAssociation { MyLocalRootSignature, // subobject name MyHitGroup // export association }; RaytracingShaderConfig MyShaderConfig { 16, // max payload size 8 // max attribute size }; RaytracingPipelineConfig MyPipelineConfig { 1 // max trace recursion depth };C 侧导出子对象库中子对象名需从库子对象中导出不做重命名之后所有导出子对象在CreateStateObject调用期间被处理、关联被解析。导出在D3D12RaytracingLibrarySubobjects.cpp中完成// Library subobject names const wchar_t* D3D12RaytracingLibrarySubobjects::c_globalRootSignatureName LMyGlobalRootSignature; const wchar_t* D3D12RaytracingLibrarySubobjects::c_localRootSignatureName LMyLocalRootSignature; const wchar_t* D3D12RaytracingLibrarySubobjects::c_localRootSignatureAssociationName LMyLocalRootSignatureAssociation; const wchar_t* D3D12RaytracingLibrarySubobjects::c_shaderConfigName LMyShaderConfig; const wchar_t* D3D12RaytracingLibrarySubobjects::c_pipelineConfigName LMyPipelineConfig; { lib-DefineExport(c_globalRootSignatureName); lib-DefineExport(c_localRootSignatureName); lib-DefineExport(c_localRootSignatureAssociationName); lib-DefineExport(c_shaderConfigName); lib-DefineExport(c_pipelineConfigName); lib-DefineExport(c_hitGroupName); }从库字节码直接创建根签名由于库内已定义唯一的全局根签名可直接用CreateRootSignatureAPI 从库字节码创建此处当作计算根签名使用// A unique global root signature is defined in hlsl library g_pRaytracing. For such scenario we can create // compute root signature can directly from the library bytecode, using CreateRootSignature API. ThrowIfFailed(device-CreateRootSignature(1, g_pRaytracing, ARRAYSIZE(g_pRaytracing), IID_PPV_ARGS(m_raytracingGlobalRootSignature)));5. Hello Shader Execution Reordering最小化 SER 演示D3D12RaytracingHelloShaderExecutionReordering 是 Hello World 的微调版本用于最小化演示Shader Execution ReorderingSER。实现方式很直接对全屏四边形做光追射线执行人为构造的工作负载一个循环其中部分射线执行更昂贵的循环做额外工作的射线渲染为白色。SER 被用来尝试按工作负载成本对线程重排序。Raytracing.hlsl中有一批可调整的#define便于实验不同行为。由于示例在启动时编译着色器因此两次运行之间即可修改着色器做快速对比无需重新构建应用。6. Sakura Forest SER复杂场景下的线程分组提示D3D12RaytracingSakuraForestSER 在一个风格化的樱花森林场景中演示 SER场景由多种几何类型组成树干、花朵、灌木与地板立方体。SER 用于给 GPU 提供分组线程的提示以提升执行效率支持三种模式Sort by HitObject按命中对象分组Sort by reflectHint按自定义键分组——该键源自对地板纹理的采样用于识别反射区域如形似水面的暗色缝隙与空间中的随机立方体Sort by Both结合 HitObject 与 reflectHint。reflectHint的算法是在估计命中位置采样地板纹理若采样颜色足够暗则将该表面视为反射面触发 Fresnel 反射等额外着色逻辑以此模拟阴影区域的细微积水效果。文档特别说明的性能观察按原文记录该场景对天空盒施加了重负载使其比典型游戏场景更昂贵这正是 SER 收益差异的重要来源。尤其是透过树冠缝隙能看到天空的视点其着色成本变化很大这种变化性正是 SER 能带来收益的场景。reflectHint上的MaybeReorderThread()用于演示另一种潜在的变化属性例如反射远重于简单光照计算官方在该示例上的测试显示此属性在 RTX 5070 上收益甚微但在更高端的老架构 GPU如 RTX 4080、4090上没有明显负面影响。该结论仅针对本示例与文中提到的测试环境不应外推为普遍规律。控制P开关 SERH/M/B分别切换 HitObject / reflectHint / 两者结合的MaybeReorderThread()依据WASD移动W 前、A 左、S 后、D 右Q/E垂直升降相机Q 下、E 上方向键环视。标题栏额外显示SER: ON/OFF状态。7. Opacity Micromaps树叶镂空与透明度加速D3D12RaytracingOpacityMicromaps 演示如何在 D3D12 中使用Opacity MicromapsOMM场景为一棵树木模型。渲染方式主可见性经光追计算每像素投一条阴影射线模型由 3 个几何体构成Trunk树干、Branches树枝、Leaves树叶只有 Leaves 应用 OMMTrunk 与 Branches 为非 OMM 几何OMM 数组、BLAS 与 TLAS 在第 0 帧构建此后仅在需要重建的帧上重建。键盘控制映射到 DXR 特性键作用底层机制O开关 OMM以D3D12_RAYTRACING_INSTANCE_FLAG_DISABLE_OMMS重建 TLASQ/W在 1–12 之间切换最大细分级别OMM 数据离线构建了 24 次2-state / 4-state × Subdiv 1–12修改后下一帧重建 OMM 数组连带重建 BLAS 与 TLAS本示例未实现 OMM linkage update 替代方案F在 2-state 与 4-state OMM 间切换同上会触发 OMM 数组、BLAS、TLAS 重建示例刻意同时提供 2 位与 4 位 OMM因为后者有额外内存开销R开关相机环绕模型—Z/X调整相机视场角FOV支持对几何极限放大—A开关 Any-Hit ShaderAHS动态增删主/阴影射线的D3D12_RAY_FLAG_FORCE_OPAQUE高细分级别无需 AHS 即可获得高精度的树叶镂空H将至少执行过一次 AHS 的像素/主射线染成品红色用于可视化 AHS 调用位置B开关每帧重建 OMM/BLAS/TLAS便于对加速结构构建过程做 PIX 抓帧否则仅在 Frame 0 或选项被切换的帧上构建注意事项按原文归纳NVIDIA OMM SDK 会自动将 OMM 折叠到表达所需图案的最低细分级别允许使用细分级别 12 不代表一定会用满因此细分级别 9–12 可能与 8 在视觉上难以区分其他内容可能受益于更高细分OMM没有 mip 概念远处会产生锯齿伪影高细分级别尤其明显该模型需要约120 个 OMM数组成本仅约 3KBOMM 索引数组每三角形 4 字节全模型约 2.5MB。SDK 目前只输出 4 字节索引但对少于约 65000 个 OMM 的模型 2 字节索引已足够可省 50% 索引内存本示例未演示OMM Linkage Updates而是按需重建 OMM/BLAS/TLAS示例沿用 Wavefront OBJ 的位置、法线、纹理坐标分缓冲含索引缓冲做法官方注明这对游戏内容并非最佳实践仅为便利。已知问题示例用射线/UV 导数计算纹理 mip 级别但阴影射线始终采样 Mip 0可能引发锯齿且模型的纹理混合、UV 缩放/旋转未忠实复刻 Blender 原模型对 OMM 演示不必要。五、高级示例1. Real-Time Denoised Ambient Occlusion实时降噪与镜面路径追踪D3D12RaytracingRealTimeDenoisedAmbientOcclusion 实现一个用于 1 spp每像素一条样本光线追踪环境光遮蔽AO的实时降噪器同时演示基于物理的镜面路径追踪实现与动态几何支持。它对应高级示例的定位在单一场景中同时处理降噪、物理着色与几何动态更新三类工程难题适合作为 DXR 落地到真实渲染器的参考。2. MiniEngine Sample光线追踪融入完整引擎D3D12RaytracingMiniEngineSample 是MiniEngine 的改造版MiniEngine 本体位于仓库 MiniEngine 目录将 DirectX Raytracing 集成进其 Model Viewer并演示一系列光追用途。按数字键1–7可循环切换模式也可按 Backspace 打开 MiniEngine 调试菜单经 Application/Raytracing/RaytraceMode 切换键模式说明1Off全光栅化2Bary Rays主射线返回命中三角形的重心坐标3Refl Bary次级反射射线返回命中三角形的重心坐标4Shadow Rays次级阴影射线命中与否输出黑/白5Diffuse ShadowMaps主射线计算漫反射光照并使用光栅化的阴影贴图6Diffuse ShadowRays全光追通道主射线做漫反射光照并递归发射阴影射线7Reflection Rays混合通道光栅化渲染主漫反射检测到地面平面时发射反射射线控制WASD/左摇杆移动E/Q或扳机键升降相机鼠标/右摇杆控制偏航与俯仰F 冻结相机左右键循环预设机位左摇杆按下或 LShift 慢速移动Backspace/返回键打开调试菜单。已知限制官方原文阴影通道因射线生成不正确而存在 bugmipmap 计算不正确远处物体使用的 LOD 过低运行时输出一条可忽略的调试层错误D3D12 ERROR: ID3D12Device::CopyDescriptors: Source ranges and dest ranges overlap, which results in undefined behavior.——源于 SM 6.0 驱动上的调试层问题。六、进一步学习路线与反馈官方进一步资源指向 NVIDIA 的 DXR 教程系列游戏行业常用补充材料。集合作者欢迎一切关于 DXR 的反馈、提问与讨论官方社区渠道为 DirectX 官方 Discord 服务器。需要再次强调所有示例都以 Samples/Desktop/D3D12Raytracing/readme.md 为总入口本文涉及的各子示例说明、源码工程与着色器文件均可在 Samples/Desktop/D3D12Raytracing/src 下对应目录中查阅集合解决方案文件为src下的D3D12Raytracing.slnx。建议的学习顺序是Hello World → Simple Lighting → Procedural Geometry → Library Subobjects → SER 两个示例 → Opacity Micromaps再进入高级示例运行时若遇 dxc 编译类报错优先核对本文第三节列出的已知问题与修复方向。赞分享示例工程【免费下载链接】DirectX-Graphics-SamplesThis repo contains the DirectX Graphics samples that demonstrate how to build graphics intensive applications on Windows.项目地址https://gitcode.com/gh_mirrors/di/DirectX-Graphics-Samples点击查看免费下载相关推荐大麦自动抢票5分钟完整指南从跑通到配好Web端与移动端大麦自动抢票5分钟完整指南从跑通到配好Web端与移动端 倒计时归零立即购买按钮还是灰的等你手动选完城市、票价和观演人页面只剩已售罄四个字。这是抢示例工程NVIDIA GameWorks DirectX Raytracing (DXR) Tutorials 指南NVIDIA GameWorks DirectX Raytracing DXR Tutorials 指南 本指南旨在帮助开发者理解并快速上手 NVIDIA GaDirectX 12保留资源技术基于DirectX-Graphics-Samples的高级特性DirectX 12保留资源技术基于DirectX Graphics Samples的高级特性 DirectX 12保留资源技术是现代图形编程中的高级特性能示例工程上一篇5分钟搞定 Mac 到 Android 文件传输OpenMTP 完整上手指南下一篇GHelper 完整指南轻量化工具接管华硕笔记本的硬件控制与性能调校创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考