本人初学者,如有错误和更好的表述,请指出
这次我们看optixSphere程序。
同样分为optixSphere.cpp、optixSphere.h、optixSphere.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。 -
input的type变成了OPTIX_BUILD_INPUT_TYPE_SPHERES,这个很好理解,因为这个程序目的是画圆,并只有一个圆心顶点 -
接下来构建加速结构时多出了
compact的内容,我试了试将其变为Traingle时的加速结构也同样能运行,应该只是性能优化
创建module时的pipeline_compile_options.usesPrimitiveTypeFlags和builtin_is_options.builtinISModuleType都变成了sphere相关。
其他的都大同小异。
optixSphere.cu文件
摄像机,raygen、miss函数都大同小异
主要看closesthit函数
首先调用的是optixGetRayTmax函数,这个在文档中可以找到,在closesthit中是最近交点的hitT。
optixGetWorldRayOrigin和optixGetWorldRayDirection函数顾名思义,分别获取光线起点和光线方向。
optixGetPrimitiveIndex获取的是碰撞图元的下标,如果是三角形,可以直接通过prim_idx*3+0、prim_idx*3+1、prim_idx*3+2获取三个顶点位置的下标(这个在optixPathTracer.cu及其他文件中可以看见)。
optixGetSbtGASIndex在这里获取的也是图元下标。
注意optixGetPrimitiveIndex和optixGetSbtGASIndex在不同的函数中的效果不一样,在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 );
}

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