自20世纪90年代以来,传统的3D渲染通常使用称为光栅化的过程。栅格化使用从三角形或多边形网格创建的对象来表示对象的3D模型。渲染管线然后将3D模型的每个三角形转换成2D图像平面上的像素。这些像素然后可以在屏幕上的最终显示之前被进一步处理或“着色”。虽然光栅化对于实时生成图像非常有效,但为光栅化管线添加逼真的光照效果会增加复杂性,需要基于给定场景的许多手动调整参数。保持良好的表现通常需要使用可能影响整体现实的捷径或估计。光线追踪是实现更大现实的重要一步。
光线追踪通过模拟光线的物理行为生成高度逼真的图像。光线追踪通过追踪光线从观看者的眼睛穿过虚拟3D场景的路径来计算像素的颜色。光线可能会从一个物体反射到另一个物体(引起反射),被物体阻挡(引起阴影),或穿过透明或半透明物体(模拟半透明或电介质,如玻璃或水)穿过场景。所有这些交互结合起来产生屏幕上显示的像素的最终颜色。如图1所示,保真度可以保持不变,算法可以优雅地实施,但需要大量复杂的计算工作量。
图1. Enrico Cerica使用OctaneRender生成的计算机生成的图像显示了复杂地板表面上的光线追踪阴影和反射
光线追踪直接模拟穿过虚拟环境的光线。图2显示了环境如何由相机,灯光集合,3D几何模型以及这些模型的材质描述组成。然后追踪表示光路或光子的光线,以确定相机传感器在给定方向上看到的光线值。追踪射线通常遵循一系列自然事件:
创建代表从环境到相机的光路反向的光线。
射线与场景相交,确定射线击中哪个物体,如果有的话。
材质着色器或环境着色器计算照明值沿着光线的路径
最后,产生的光照值被写入帧缓冲器。
图2.简化的光线追踪图
第3步通常是通过产生额外的光线来确定入射光在物体上某一点上的位置,从而使光线追踪自然递归算法。
创建真实照片般逼真的图像的能力是为什么光线追踪被视为计算机渲染的未来。今天的光线追踪渲染器主宰虚拟效果制作和动画特效。大规模并行GPU的出现现在扩展了可以使用光线追踪的领域空间。使用GPU的离线渲染现在需要几分钟的时间,而不是使用主流CPU所需的时间。NVIDIA®(英伟达™)GPU搭配NVIDIA先进的光线追踪技术堆栈,现在提供了计算能力和软件框架,可在消费者级工作站上执行有趣的实时光线追踪工作负载。
NVIDIA在本周在GTC上宣布支持新款Quadro®GV100上的RTX技术。开发人员可以通过多种API访问NVIDIA RTX技术,具体取决于他们的需求和开发环境,如图3所示。
图3. NVIDIA RTX技术
微软的DirectX光线追踪(DXR)API。将光线追踪功能完全集成到游戏开发人员使用的行业标准API DirectX中,使光线追踪成为光栅化和计算的替代品,而不是光栅追踪的替代品。DXR专注于通过混合光栅化光线追踪技术启用实时用例。
NVIDIA的Vulkan Ray追踪扩展。即将推出; 可以对Vulkan图形标准进行光线追踪扩展。另一种在跨平台API中紧密耦合光线跟踪和光栅化技术的途径。
NVIDIA的OptiX API。用于在GPU上实现高性能光线追踪的应用程序框架。它为加速光线追踪算法提供了一个简单的,递归的和灵活的流水线。OptiX SDK包含两个可以彼此独立使用的主要组件:用于渲染器开发的光线跟踪引擎和用于显示之前的图像处理的后处理管道。
所有这三种API共享一种描述光线追踪操作的通用方法,使得开发人员可以直接在多个平台上访问RTX。十年来在渲染软件和硬件方面的投资已经导致高度优化的光线追踪解决方案,实现了以前达不到的性能和交互性水平。NVIDIA还大量投资开发工具链,使得GPU编程,调试和分析比以往更容易。
有关DXR的更多信息,请查看关于该主题的博客文章。今年的GTC会议S8521上提供了Vulkan扩展的预览版。现在我们来看看OptiX API。
图4.光线追踪在概念上简单,计算复杂
NVIDIA设计了OptiX API来填补NVIDIA GPU上简单的概念模型和相对高级的执行模型之间的差距,使开发人员可以专注于他们的核心光线追踪算法,如图5所示。OptiX建立在关键的观察中,即大多数射线追踪算法可以使用一小组可编程操作来实现。OptiX提供了一个描述虚拟环境的API和一组用户可编程着色器来实现射线跟踪周期的每个阶段。
图5. OptiX中的用户可编程着色器显示为绿色。横向由OptiX内部控制。
OptiX的核心是一个领域特定的即时编译器。编译器通过结合用户提供的射线生成,材质着色,对象交叉和场景遍历的程序来生成自定义光线跟踪内核。高性能是通过使用紧凑的对象模型和光线跟踪编译器优化实现的,可以有效地映射到新的RTX技术和Volta GPU。
OptiX支持各种各样的用例,包括交互式渲染,批量渲染,碰撞检测系统,人工智能查询以及声音传播或中子传输等科学仿真。OptiX已被集成到各种当前可用的商业软件产品中,并且已经成为近十年来的关键光线追踪SDK。
使用OptiX的主要优点包括:
可编程的GPU加速射线跟踪管线,可根据您的应用需求轻松定制
单线程编程模型提供对递归的全面支持和类似于虚拟函数调用的动态调度机制
最先进的数据结构,用于极快的光线对象交叉
支持渲染大型场景,透过跨多个GPU进行透明缩放,以及通过NVLink自动组合多个GPU内存
OptiX利用最新的GPU架构特性,无需进行应用方面的更改
一种基于AI的去噪器,用于改善用户实时探索的体验
灵活性支持任意着色模型,包括基于物理的MDL材料规范的示例实现
全面的编程指南,参考文档和示例可帮助您将OptiX快速集成到您的应用程序中
NVIDIA®(英伟达™)RTX技术的直观界面以及Volta GPU的强大功能
射线路径中的第一个射线段,通常称为主射线,使用射线生成程序。这跟踪场景中的射线,将追踪结果写入输出缓冲区。下面是一个非常简单的示例射线生成程序。
//用户可以定义一个任意结构来携带与射线相关的数据//并从曲线返回值。struct PerRayData { float4 result ; //结果的输出变量。我们可以根据需要跟踪其他信息。}; rtDeclareVariable (CameraParams ,camera_params ,,); //输入描述//相机型号的参数。rtDeclareVariable (rtObject , scene_root_group ,,); //顶级组//包含场景描述。rtBuffer < float4变量,2 > output_buffer ; //输出缓冲区来存储渲染的图像。 rtDeclareVariable (uint2 ,launch_index ,rtLaunchIndex ,); // OptiX内置变量,包含当前索引到启动网格中。//通常这对应于输出图像中的像素索引。rtDeclareVariable (uint2 ,launch_dim , rtLaunchDim ,); // OptiX内置变量,包含发射网格的大小。通常//这对应于输出图像的维数。 RT_PROGRAM void pinhole_camera (){ //通过针孔相机建模来创建主光线。或者,我们可以读取 //从输入缓冲区预先生成的光线或使用其他方法。const float3 ray_origin = pinholeCameraGetOrigin (camera_params ); Const float3 ray_direction = pinholeCameraComputeDirection (camera_params ,launch_index , launch_dim ); optix :: Ray ray = optix :: make_Ray ( ray_origin ,//摄像头位置 ray_direction ,//从原点到屏幕平面0u 上像素位置的方向,//射线类型(请参阅文档) scene_epsilon ,//最小相交距离 RT_DEFAULT_MAX ); //最大交叉距离 //初始化我们的射线数据结构并调用内置函数rtTrace PerRayData prd ; Prd 。result = make_float4 (0.0f ); rtTrace (top_object ,ray ,prd ); //将结果写入缓冲区。启动完成后,此输出缓冲区通常//被拖动到屏幕上或写入图像文件。 output_buffer [ launch_index ] = prd 。结果;
OptiX利用最先进的空间分区层次数据结构,可以非常快速地剔除虚拟场景中不与给定射线相交的部分。Optix核心编译器控制这些数据结构的创建和遍历。这使得OptiX可以隐藏高度优化的,特定于架构的实现的复杂性,并将多年的NVIDIA研究成果用于遍历加速结构。
可以使用用户定义的相交和边界框程序来实现自定义基元,如球体,曲线或细分修补程序。边界框程序必须计算自定义基元的对象空间轴对齐边界框。根据输入射线是否与基元相交,交集程序返回true或false。下面是每种类型的程序的简单示例,演示如何实现球体基元。
rtDeclareVariable (个float4 ,球体,,); //输入变量给球体中心,半径 rtDeclareVariable (float3 ,normal ,attribute normal ,); //属性变量允许从交集//程序到命中程序的数据传递 rtDeclareVariable (optix :: Ray ,ray ,rtCurrentRay ,); // OptiX提供的内置变量 RT_PROGRAM void intersect_sphere (){ float3 center = make_float3 (sphere ); //提取球体的中心位置float radius = sphere 。w ; //提取球体的半径 float3 n ; //表面法线的输出参数float t ; //相交距离的输出参数 if (intersect_sphere (ray ,center ,radius ,n ,t ))//确定射线是否碰到球体,如果是,//距离多远{ if (rtPotentialIntersection (t ))//告诉OptiX射线与其相交球体。OptiX //将检查相交距离是否位于//当前有效射线间隔内,并相应地返回true / false //。 { normal = n ; //输出属性总是写入// rtPotentialIntersection和rtReportIntersection 之间 const int material_id = 0 ; rtReportIntersection (material_id ); //报告具有物料ID的交集} } } //为多原始几何体(例如三角网格)使用原始索引RT_PROGRAM void bounds (int / * primitive_index * / ,float result [ 6 ]){ const float3 center = make_float3 (sphere ); 常量浮子 半径= make_float3 (球体。瓦特); optix :: Aabb * aabb = (optix :: Aabb *)结果; //将float数组转换为辅助数据类型以便于使用 aabb - > m_min = center - make_float3 (radius ); aabb - > m_max = center + make_float3 (radius ); }
最接近的和任意命中的程序一起工作以作为材质着色器。OptiX允许开发人员指定一种或多种类型的光线(例如,辐射,环境遮挡或阴影光线)。材质可以指定最接近的命中和任意命中程序来描述每个光线类型的对象相交时的着色行为。命中程序通过属性变量从交集程序接收信息。他们通过写入光线有效载荷将信息传递回光线生成程序。
当光线跟踪核心完全穿越场景并找到当前光线有效距离区间内最接近的交点时,将调用最近击的程序。最终着色通常发生在这个阶段。一个全功能的阴影系统可能会评估基于物理的反射函数并生成二次光线来评估反射,折射和光线遮挡。
在遍历场景时发现新的可能最接近的对象时,任何命中的程序都会被调用。任何命中的程序都可以对当前的潜在交叉点采取以下三种操作之一:
通过调用可以忽略交集rtIgnoreIntersection。这可以在诸如透明alpha剪切的情况下拒绝交叉。
射线遍历可以通过调用来终止rtTerminateRay。这通常用于点对点可见性测试,因为在点之间找到的任何对象都是足够的。
交叉点可以被接受,但是遍历是继续的。如果没有rtIgnoreIntersection或被rtTerminateRay调用,这是默认行为。
对于任何给定的物质射线类型的插槽,任何命中或最近命中的程序都可以不受约束。例如,一个不透明的材质可能只需要一个任意点击的阴影射线程序,因为找到光线和阴影点之间的任何交点就足以确定一个点在阴影中。另一方面,不透明材料通常只有一个最受欢迎的程序用于辐射射线。
下面是一个非常简单的一对非常简单的不透明材料击中程序的例子,通过简单地查看它们的表面法线来遮蔽物体。
//通常,任何命中和最近命中的程序都使用不同的光线有效载荷结构,具体取决于他们想要返回到光线生成程序的数据。为了简单起见,我们将使用单一类型。struct PerRayData { float4 result ; //任意击中的最接近命中的光辉值,不透明度}; rtDeclareVariable (PerRayData ,prd ,rtPayload ,); //内置提供对这个ray有效载荷的访问struct rtDeclareVariable (float3 ,normal ,attribute normal ,); //我们的交集程序指定的属性 RT_PROGRAM void normal_shader_closest_hit_radiance (){ //将对象normal转换为世界空间并转换为颜色const float3 world_space_normal = optix :: normalize (rtTransformNormal (RT_OBJECT_TO_WORLD ,normal )); Const float3 color_normal = world_space_normal * 0.5f + 0.5f ; prd 。result = make_float4 (color_normal ,1.0f ); } RT_PROGRAM void normal_shader_any_hit_shadow (){ //这个材质是不透明的,所以它完全衰减了所有的阴影射线 prd_shadow 。result = make_float3 (0.0f ); //我们终止这条射线,因为我们只想知道是否有几何体被击中,而不是最接近的 rtTerminateRay (); }
如果没有几何体被射线击中,则调用未命中程序。可以为每个光线类型指定一个未命中程序,并且可以保持未绑定状态。小姐程序用于实现环境地图或无限远的背景。下面是一个实现用户可指定的常量彩色背景环境的程序。
struct PerRayData { float4 result ; //任意击中的最接近命中的光辉值,不透明度}; rtDeclareVariable (个float4 ,bg_color ,,); //输入背景颜色的变量 rtDeclareVariable (PerRayData ,prd ,rtPayload ,); //内置提供对这个射线的有效载荷结构的访问 RT_PROGRAM void miss (){ prd_radiance 。结果= bg_color ; }
OptiX在一系列NVIDIA GPU上运行,但使用Volta GPU实现最佳性能,如图6所示。
图6. NVIDIA GPU上的OptiX性能
使用NVIDIA OptiX的渲染软件(例如Autodesk Arnold,Chaos Group V-Ray,Isotropix Clarisse,Optis,Pixar RenderMan和Solidworks Visualize)将在NVIDIA Volta架构上运行时自动使用RTX技术。
OptiX AI降噪技术与Quadro GV100和Titan V中新的NVIDIA Tensor Cores相结合,可提供前代GPU性能的3倍,并首次实现无噪声流体交互。
NVIDIA正在改变渲染以及整个设计过程。借助NVIDIA Volta GPU和NVIDIA®RTX™光线追踪技术,您可以通过实时的电影质量渲染提高创造力,从而获得更好的效果并立即做出决策。与您的客户在房间中探索设计,在照片和材料上进行实验,从而以交互方式精确模拟真实世界的照明条件。
全部0条评论
快来发表一下你的评论吧 !