本人初学者,如有错误和更好的表述,请指出
这次我们看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
函数(评论区有懂哥的话希望指点下),但是失败了,配置管线的水平不行,等更强了之后再回头研究下。
参考资料