本发明涉及一种层次包围盒构建方法,属于计算机图形处理技术领域,具体是涉及一种基于动态任务调度的层次包围盒构建方法。
背景技术:
光线跟踪(raytracing)是一种在平面图像中通过跟踪视点与像素平面上的像素连线形成的射线,并计算该射线与场景中物体的交点来设置像素属性的技术,由appe在1968年提出。该技术通常生成比典型的扫描线渲染方法质量更高的图片,但需要更高的计算成本。这使得光线跟踪更适用于如电影和电视视觉效果、静止图像等离线渲染方面而不适合在如游戏等实时渲染领域。此外,光线跟踪还可用于模拟诸如反射、折射、闪射和色散等光学效果。
bvh是一种以几何物体为对象的树结构,该树的叶子结点为与轴平行的可包围几何物体的最小立方体盒子。这些叶子结点被组合为一些集合并被更大的立方体盒子即内部结点所包围,直到最后的根结点。bvh可以有效地支持几何对象的一些操作如碰撞检测、光线跟踪加速等。
技术实现要素:
本发明的目的是优化原有的基于gpu的计算方法,调整其并行架构使之并行效率更高,设计出一套改进的cuda并行架构方式,利用gpu加速执行使得bvh构建速度在单个主机上的并行度进一步提高,相比当前通用方法bvh构建速度大约提升25%。
本发明的上述技术问题主要是通过下述技术方案得以解决的:
一种基于动态任务调度的层次包围盒构建方法,包括以下步骤:
步骤1:初始化gpu中的全局变量g_optimizecounter,所述g_optimizecounter用于表示当前已处理任务数目;
步骤2:根据全局变量g_optimizecounter值和场景三角元片数目为线程分配任务;
步骤3:结合任务id自顶向上遍历bvh,并读取幼树重构所需数据到局部变量;
步骤4:当warp中有符合预定条件的线程时使用warp级编程用聚类方法进行幼树重构;
步骤5:重复执行步骤2-4直到达到设定的结束条件,gpu输出计算结果。
优选的,上述的基于动态任务调度的层次包围盒构建方法,所述步骤4中所述的预定条件为warp中存在的至少一个线程的内部结点下有9个叶子结点。
优选的,上述的基于动态任务调度的层次包围盒构建方法,所述步骤2具体包括:
步骤2.1:计算当前warp中空闲的线程数目;
步骤2.2:在warp第一个空闲线程中通过获取g_optimizecounter值得到当前已处理的任务数,并放入共享变量中;若所有任务都已完成则结束循环;
步骤2.3:结合共享变量中的任务数目和当前线程在warp中空闲线程的序号,进行任务分配。
优选的,上述的基于动态任务调度的层次包围盒构建方法,所述步骤3中,终止第一个到达父结点的线程以保证处理内部结点时该结点下的所有子结点都已经处理完毕。
优选的,上述的基于动态任务调度的层次包围盒构建方法,所述步骤4中,具体包括以下子步骤:
步骤4.1:判断当前warp中是否有9个及以上线程满足条件,若没有则跳转到步骤2,若有则执行步骤4.2;
步骤4.2:从当前结点开始向下寻找9个叶子结点形成幼树;
步骤4.3:计算4.2中幼树下9个叶子结点之间的距离并存储在距离矩阵中;
步骤4.4:使用聚类方法进行幼树重构;每次使用16个线程的并行规约选取距离矩阵中距离最小的两个结点作为聚类对象形成新的内部结点,以该结点代替上述两个结点并更新距离矩阵,一直到幼树的根结点;
步骤4.5:将bvh树结点拓扑变更情况写入到全局内存中,若warp中还有剩余任务,则转到步骤4.2,否则转到步骤2。
优选的,上述的基于动态任务调度的层次包围盒构建方法,所述步骤4.2中,初始时只有一个内部结点和两个叶子结点,并且每次从叶子结点中寻找包围盒表面积最小的作为内部结点,并将该结点的直接子节点作为叶子结点。
优选的,上述的基于动态任务调度的层次包围盒构建方法,在每一步的寻找表面积最小过程使用16个线程的并行规约找最小值,并在16个线程中编号为0的线程汇总更新当前内结点和叶子结点属性。
优选的,上述的基于动态任务调度的层次包围盒构建方法,所述步骤4.3中,使用16个线程计算36个距离值经过三轮计算即可完成任务。
通过以上描述可知,采用上述结构后,本发明遍历bvh时将一个线程对应叶子结点,在聚类幼树重构时一个warp对应2个内部结点,使得bvh构建算法在单个主机上的并行度进一步的提高,相比当前通用的方法bvh构建速度提升了大约25%。
因此,本发明具有如下优点:
1.使用本发明提供的方法可以大幅度提升bvh的构建速度,使得光线跟踪的帧率更高;
2.用本发明提供的方法可以针对不同的场景规模用不同的策略以提高gpu的利用率。
附图说明
附图1是本发明实施例的bvh构建算法流程图。
具体实施方式
下面通过实施例,并结合附图,对本发明的技术方案作进一步具体的说明。
实施例1:
本发明所采用的技术方案是:基于动态任务调度的层次包围盒构建算法,其特征包括以下步骤:
步骤1:初始化gpu中的全局变量g_optimizecounter,该值表示当前已完成和在运行的任务数目,分配共享内存;
步骤2:根据g_optimizecounter值和场景三角元片数目为线程分配任务;
步骤3:结合任务id自顶向上遍历bvh,并读取幼树重构所需数据到局部变量;
步骤4:当warp中存在至少一个线程,该线程中的内部结点下有9个叶子结点,使用warp级编程用聚类方法进行幼树重构;
步骤5:重复执行步骤2直到达到设定的结束条件,gpu输出计算结果;
步骤2的具体实现包括以下子步骤:
步骤2.1:计算当前warp中空闲的线程数目;
步骤2.2:在warp第一个空闲线程中通过获取g_optimizecounter值得到当前已处理的任务数,并放入共享变量中;若所有任务都已完成则结束循环;
步骤2.3:结合共享变量中的任务数目和当前线程在warp中空闲线程的序号,进行任务分配。
步骤3的具体实现包括以下子步骤:
步骤3.1:读取任务id对应的全局变量值,判断是否为第一次遍历该结点,若为首次遍历则将当前任务id设置为-1,意味着终止该任务对应的线程,并转到步骤2.2。
步骤3.2:根据任务id从全局变量中读取相应数据。
步骤4的具体实现包括以下子步骤:
步骤4.1:判断当前warp中是否有9个及以上线程满足条件,若没有则跳转到步骤2。
步骤4.2:从当前结点开始向下寻找9个叶子结点形成幼树。初始时只有一个内部结点和两个叶子结点,每次从叶子结点中寻找包围盒表表面积最小的作为内部结点,将该结点的直接子节点作为叶子结点。
步骤4.3:计算4.2中幼树下9个叶子结点之间的距离并存储在距离矩阵中。
步骤4.4:使用聚类方法进行幼树重构;每次选取距离矩阵中距离最小的两个结点作为聚类对象形成新的内部结点,以该结点代替上述两个结点并更新距离矩阵,一直到幼树的根结点。
步骤4.5:将bvh树结点拓扑变更情况写入到全局内存中。
步骤4.6:若warp中还有剩余任务,则转到步骤4.2,否则转到步骤2.1。
实施例2
下面结合实施例2进一步阐述本发明的原理。请见图1,本发明所采用的技术方案是:基于动态任务调度的i包围盒构建算法,包括以下步骤:
步骤1:初始化gpu中的全局变量,g_optimizecounter表示当前已完成和在运行的任务数目,分配共享内存;其中分配共享内存即根据幼树叶子结点数目确定幼树内部结点、幼树叶子结点、幼树叶子结点包围盒表面积和距离矩阵分别占用的共享内存大小。
步骤2:根据g_optimizecounter值和场景三角元片数目为线程分配任务;通过gpu内置的数值函数统计出warp中满足某种条件的线程数目nums,将g_optimizecounter更新为g_optimizecounter加上nums并为每个空闲线程分配任务id;若任务已分配完则结束循环。
其具体实现包括以下子步骤:
步骤2.1:计算当前warp中空闲的线程数目;在程序中用currentnodeindex表示当前任务id,当其值为-1是表示线程空闲,可用下列函数得知warp中空闲线程数目以及当前线程是否空闲:
constboolterminated=currentnodeindex==-1;
constunsignedintmaskterminated=__ballot(terminated);
constintnumterminated=__popc(maskterminated);
上述代码中terminated用来标识当前线程是否空闲,__ballot函数换回一个32位无符号整形,当warp中某线程中的值为真时将32位数中对应的位数设置为1。__popc则返回参数的二进制表示中1出现的次数,即warp中空闲线程数目。
步骤2.2:在warp第一个空闲线程中通过获取g_optimizecounter值得到当前已处理的任务数,并放入共享变量中同时用原子操作更新g_optimizecounter以防止并发操作时的数据写入错误;若所有任务都已完成则结束循环。
步骤3:结合任务id自顶向上遍历bvh,由bvh树性质可知:分别处理两个叶子结点的线程在向上遍历是会发生冲突,故应在此时终止一个线程。在本发明中终止第一个到达父结点的线程以保证处理内部结点时该结点下的所有子结点都已经处理完毕。在判断是否第一次访问内部结点2可通过原子操作实现:
counter=atomicadd(&counters[currentnodeindex],1);
atomicadd将参数1和参数2相加并存入参数1,返回值为原参数1的值。则第一读取时返回值为0且将参数1置为1,可用于判断访问顺序。若为第二次访问则读取幼树重构所需数据到局部变量。
步骤4:当warp中有符合条件的线程时使用warp级编程用聚类方法进行幼树重构:先找到满足条件的幼树根结点再从该根结点向下找到9个叶子结点并进行重构;
其具体实现包括以下子步骤:
步骤4.1:判断当前warp中是否有9个及以上线程满足条件:
unsignedintvote=__ballot(trianglecount>=gamma);
若vote不等于0则说明有满足条件的结点,若没有则跳转到步骤2。
步骤4.2:从当前结点开始向下寻找9个叶子结点形成幼树。初始时只有一个内部结点和两个叶子结点,每次从叶子结点中寻找包围盒表面积最小的作为内部结点,并将该结点的直接子节点作为叶子结点。在每一步的寻找表面积最小过程使用16个线程的并行规约找最小值,并在16个线程中编号为0的线程汇总更新当前内结点和叶子结点属性。
步骤4.3:计算4.2中幼树下9个叶子结点之间的距离并存储在距离矩阵中,这里用16个线程计算36个距离值经过三轮计算极乐完成任务。
步骤4.4:使用聚类方法进行幼树重构;每次使用16个线程的并行规约选取距离矩阵中距离最小的两个结点作为聚类对象形成新的内部结点,以该结点代替上述两个结点并更新距离矩阵,一直到幼树的根结点。在幼树聚类重构过程中需要warp中各个线程之间互相读取局部变量:
floatsah=__shfl(threadsah,joinrow,calculate_size);
其中参数1为需要读取的局部变量值,参数2为变量所在线程序号,参数3为指定的快大小,在本发明中以16个线程为单位,即calculate_size为16。聚类一步后将相应变化写入到全局变量中。
步骤4.5:将bvh树结点拓扑变更情况写入到全局内存中,若warp中还有剩余任务,则转到步骤4.2,否则转到步骤2。
应当理解的是,上述针对较佳实施例的描述较为详细,并不能因此而认为是对本发明专利保护范围的限制,本领域的普通技术人员在本发明的启示下,在不脱离本发明权利要求所保护的范围情况下,还可以做出替换或变形,均落入本发明的保护范围之内,本发明的请求保护范围应以所附权利要求为准。