OptiX入门(三)

发布于

本人初学者,如有错误和更好的表述,请指出

这次我们看optixSphere程序。

同样分为optixSphere.cppoptixSphere.hoptixSphere.cu文件。

optixSphere.h文件

把摄像机参数放到了RayGenData中,基本没区别。

optixSphere.cpp文件

主要是加速结构这里有很大变化。

  • buildFlags变为了OPTIX_BUILD_FLAG_ALLOW_COMPACTION|OPTIX_BUILD_FLAG_ALLOW_RANDOM_VERTEX_ACCESS

    其中OPTIX_BUILD_FLAG_ALLOW_COMPACTION主要目的是减少内存使用,同时需要额外配置,我暂时将他当做黑盒使用,细节详见[文档5.8。](5.8 - Compacting acceleration structures (nvidia.com))

    OPTIX_BUILD_FLAG_ALLOW_RANDOM_VERTEX_ACCESS可以查询三角形信息,这里启用主要是cu文件中optixGetSphereData函数需要启用这个flag,细节详见文档12.9

  • inputtype变成了OPTIX_BUILD_INPUT_TYPE_SPHERES,这个很好理解,因为这个程序目的是画圆,并只有一个圆心顶点

  • 接下来构建加速结构时多出了compact的内容,我试了试将其变为Traingle时的加速结构也同样能运行,应该只是性能优化

创建module时的pipeline_compile_options.usesPrimitiveTypeFlagsbuiltin_is_options.builtinISModuleType都变成了sphere相关。

其他的都大同小异。

optixSphere.cu文件

摄像机,raygenmiss函数都大同小异

主要看closesthit函数

首先调用的是optixGetRayTmax函数,这个在文档中可以找到,在closesthit中是最近交点的hitT

optixGetWorldRayOriginoptixGetWorldRayDirection函数顾名思义,分别获取光线起点和光线方向。

optixGetPrimitiveIndex获取的是碰撞图元的下标,如果是三角形,可以直接通过prim_idx*3+0prim_idx*3+1prim_idx*3+2获取三个顶点位置的下标(这个在optixPathTracer.cu及其他文件中可以看见)。

optixGetSbtGASIndex在这里获取的也是图元下标。

注意optixGetPrimitiveIndexoptixGetSbtGASIndex在不同的函数中的效果不一样,在closesthit中都是获取图元下标,这个可以从两个函数的文档中看到。

optixGetSphereData可以获取圆在对象空间中的圆心坐标和半径。

然后是获取法线,根据法线填充payload进而在raygen函数中填充颜色。

extern "C" __global__ void __closesthit__ch()
{
    float  t_hit = optixGetRayTmax(); //当前的hitT
    // Backface hit not used.
    //float  t_hit2 = __uint_as_float( optixGetAttribute_0() ); 

    const float3 ray_orig = optixGetWorldRayOrigin(); //光线起点
    const float3 ray_dir  = optixGetWorldRayDirection(); //光线方向

    const unsigned int           prim_idx    = optixGetPrimitiveIndex(); //碰撞的图元下标
    const OptixTraversableHandle gas         = optixGetGASTraversableHandle();
    const unsigned int           sbtGASIndex = optixGetSbtGASIndex(); //这里碰撞的也是图元下标

    float4 q;
    // sphere center (q.x, q.y, q.z), sphere radius q.w
    optixGetSphereData( gas, prim_idx, sbtGASIndex, 0.f, &q ); //这里获得的是对象空间圆心坐标和半径
    float3 world_raypos = ray_orig + t_hit * ray_dir;
    float3 obj_raypos   = optixTransformPointFromWorldToObjectSpace( world_raypos );
    float3 obj_normal   = ( obj_raypos - make_float3( q ) ) / q.w; //获取法线的单位向量
    float3 world_normal = normalize( optixTransformNormalFromObjectToWorldSpace( obj_normal ) );

    setPayload( world_normal * 0.5f + 0.5f );
}

image-20230902234740400

码字不易,点个赞吧

总结

生成圆的配置和生成三角形的配置很不一样,同时有许多特殊的函数可以调用,尝试了下生成多个圆,想要理解optixGetPrimitiveIndex函数和optixGetSbtGASIndex函数(评论区有懂哥的话希望指点下),但是失败了,配置管线的水平不行,等更强了之后再回头研究下。

参考资料

NVIDIA OptiX 8.0 - Programming Guide

NVIDIA OptiX 8.0 API

评论
收藏