射线追踪是embarrassingly parallel/perfectly parallel/pleasingly parallel的问题,就是说基本不用费劲就可以并行化。
射线追踪是指从某点发射射线,判断其与几何结构的交点,根据交点对图像进行渲染,或者计算。
nvidia optix是基于cuda的api,可充分利用gpu的计算能力对射线追踪进行加速。
主要概念和步骤:
cpu端
首先建立场景/环境context,就是进行射线追踪的环境。
RT_CHECK_ERROR( rtContextCreate( &context ) );
RT_CHECK_ERROR( rtContextSetRayTypeCount( context, 1 ) );//设置射线类型
射线一般关联一个payload数据结构,用于存储射线追踪过程的数据,如颜色等等。因此,不同payload的射线可以有不同的类型。另外,不同用途的射线也可以设置不同的类型,例如有的用在closest hit中,有的用在any hit中。
RT_CHECK_ERROR( rtContextSetEntryPointCount( context, 1 ) );
设置入口点个数。一个入口点和一个射线生成程序关联。当调用rtContextLaunchnD时,射线生成程序是首先执行的入口点,它的功能类似c语言中的main函数。射线生成程序是并行执行的。每个thread有一个rtLaunchIndex,可用来区分thread。
RT_CHECK_ERROR( rtBufferCreate( context, RT_BUFFER_OUTPUT, &buffer ) );
RT_CHECK_ERROR( rtBufferSetFormat( buffer, RT_FORMAT_FLOAT4 ) );
RT_CHECK_ERROR( rtBufferSetSize2D( buffer, width, height ) );
RT_CHECK_ERROR( rtContextDeclareVariable( context, "result_buffer", &result_buffer ) );
RT_CHECK_ERROR( rtVariableSetObject( result_buffer, buffer ) );
buffer缓冲区用来在host和gpu之间交换数据。buffer只能由host创建。
variable变量用来在程序间交互数据。variables可以在各个层级声明,例如context、program、geometry等。
const char *ptx = sutil::getPtxString( "optixHello", "draw_color.cu" );//读取ptx文件
RT_CHECK_ERROR( rtProgramCreateFromPTXString( context, ptx, "draw_solid_color", &ray_gen_program) );
把ptx文件中draw_solid_color的函数绑定到程序对象ray_gen_program上。
RT_CHECK_ERROR( rtProgramDeclareVariable( ray_gen_program, "draw_color", &draw_color ) );
声明一个叫做draw_color的变量,绑定到ray_gen_program上。
RT_CHECK_ERROR( rtVariableSet3f( draw_color, 0.462f, 0.725f, 0.0f ) );
RT_CHECK_ERROR( rtContextSetRayGenerationProgram( context, 0, ray_gen_program ) );//将draw_solid_color函数绑定到ray_gen_program
/* Run */
RT_CHECK_ERROR( rtContextValidate( context ) );
RT_CHECK_ERROR( rtContextLaunch2D( context, 0 /* entry point */, width, height ) );
contextLaunch_n_D就是生成1维、2维、3维的逻辑计算网格(线程数?),每生成一个计算网格调用一次ray_gen_program,计算结果写入buffer。因此一般buffer的大小和计算网格的大小相同。
/* Clean up */
RT_CHECK_ERROR( rtBufferDestroy( buffer ) );
RT_CHECK_ERROR( rtProgramDestroy( ray_gen_program ) );
RT_CHECK_ERROR( rtContextDestroy( context ) );
然后设置几何,可以是简单几何体组合、变换,也可以是三角网格。
在gpu端,编写射线求交和渲染的程序。求交点的情况包括求最近交点closest hit、求任意交点any hit。closest hit是在射线与场景所有几何体求交后,得到距离射线起点最近的交点;any hit可能有几种情况:交点被忽略,例如射线经过透明介质;求交结束,此时求交只是为了计算两个表面是否可见;返回交点,并继续求交,这是any hit程序的默认定义。
示例程序
gpu端
1 产生射线
建立简单几何形状和包围盒
求交点
#include
#include
using namespace optix;
rtDeclareVariable(uint2, launch_index, rtLaunchIndex, );
gpu的program还可以通过变量与Host进行交互。上述定义了一个launch_index的变量,它等同于OptiX内置的rtLaunchIndex。launch_index在本program内部使用。定义语法为:rtDeclareVariable(type,name,semantic,annotation )。
rtLaunchIndex是thread的索引号。
rtBuffer
定义了一个float4的二维数组,result_buffer。
rtDeclareVariable(float3, draw_color, , );
RT_PROGRAM void draw_solid_color()
{
result_buffer[launch_index] = make_float4(draw_color, 0.f);
}
optix prime专门用于射线与三角形求交点的高性能计算,而不具备着色等功能。