代码改变世界

hism的clusterBuilder

2023-01-12 22:09  kk20161206  阅读(74)  评论(0编辑  收藏  举报

clusterBuilder的构造函数

FClusterBuilder(TArray<FMatrix> InTransforms, TArray<float> InCustomDataFloats, int32 InNumCustomDataFloats, const FBox& InInstBox, int32 InMaxInstancesPerLeaf, float InDensityScaling, int32 InInstancingRandomSeed, bool InGenerateInstanceScalingRange)
        : OriginalNum(InTransforms.Num())
        , InstBox(InInstBox)
        , MaxInstancesPerLeaf(InMaxInstancesPerLeaf)
        , InstancingRandomSeed(InInstancingRandomSeed)
        , DensityScaling(InDensityScaling)
        , GenerateInstanceScalingRange(InGenerateInstanceScalingRange)
        , Transforms(MoveTemp(InTransforms))
        , CustomDataFloats(MoveTemp(InCustomDataFloats))
        , NumCustomDataFloats(InNumCustomDataFloats)
        , Result(nullptr)
    {
    }

调用是被

void UHierarchicalInstancedStaticMeshComponent::BuildTree()所调用。
FClusterBuilder Builder(InstanceTransforms, PerInstanceSMCustomData, NumCustomDataFloats, GetStaticMesh()->GetBounds().GetBox(), DesiredInstancesPerLeaf(), CurrentDensityScaling, InstancingRandomSeed, PerInstanceSMData.Num() > 0);
Builder.BuildTreeAndBuffer();

ApplyBuildTree(Builder);

BuildTree函数 里面调用了

Init函数

sortIndex是transform数据的数量*密度scale;

sortPoints数量是transform的数量。

sortPoints放transform的origin

sortIndex放符合条件的index。满足随机的,密度scale符合条件。

num是有效数据的数量,乘了密度。

occlusionLayerTarget:每个组件最大遮挡查询

minInstancesPerOcclusionQuery: 每个遮挡查询最小的实例数

if 总数量/每个查询最小实例数(最多的遮挡查询数) < occlusionLayerTarget

则occlusionLayerTarget = 总数量 / 每个查询最小实例数

  如果occlusionLayerTarget < minOcclusionQueriesPerComponent

    occlusionLayerTarget = 0;

 树枝数 internalNodeBranchingFactor = CVarFoliageSplitFactor

if 总数量 / 每个叶子最大实例数 (树枝最小数) < internalNodeBranchingFactor

则每个叶子最大实例数=总数量/树枝因子 internalNodeBranchingFactor

 

 继续看buildTree函数

result是FClusterTree类型

result的instanceReorderTable初始化为总共transform数,>= 实际的(乘了密度)。

如果树枝数 > 2, 遮挡层 >0, 总数量/树枝数 <= 遮挡查询数

则branchingFactor数 大概等于 每个查询最小实例数。

split(Num)  //有效的数量

 

 

这里我们看看split函数

里面调用了Split(0, num - 1);

是个递归函数

 

包围盒通过index转换为排序后的index,的originPosition 扩充的。

如果数量 < 遮挡查询数

则clusters里直接加入这个RunPair

否则,拿到最大的轴

这个轴的坐标排序

最终的sortIndex[index]的值是原来的没有排序的索引,sortIndex[index](sortIndex是transform数据的数量*密度scale;)。

递归遍历左半部分和右半部分。

 

如果当前是遮挡层,则result的outOcclusionLayerNum是clusters的数量

sortedInstances数组填入sortIndex数组

 

numRoots是clusters数

Result的nodes初始化为clusters的数目

每个是个FClusterNode,它的firstInstance是clusters的start,它的lastInstance是clusters的start+num-1;

对于从fistInstance到lastInstance,通过这个instanceIndex

拿到sortedInstances[instanceIndex],即最开始没有排序的index

transforms这个原来的index,拿到这个矩阵

拿到这个包围盒。

nodesPerLevel数组加入这个numroots

 

while(numRoot>1)

{

  对于每个簇sortIndex是原来簇的index,sortPoint是坐标

  如果树枝数目>2  遮挡层  簇数/树枝数 <= 遮挡层目标

  树枝数目 = max(2, 簇数目/遮挡层目标)  每个簇看成一个结点,除以遮挡目标数=簇又分为几个父。

  Split(numroots);

  

里面是split(start, end)

< 树枝数目,则直接形成一个FRunPair放到clusters里面

找到这个轴,排序

 

 

//得到倒数第二层的簇,它的RunPair放的是倒数第一层的(叶子层)的index;

 

RemapSortIndex初始化为num(实际数量个)
最终的sortIndex[index]的值是原来的没有排序的索引,
RemapSortIndex[index]对应排序前的instanceIndex
for (int32 Index = 0; Index < Num; Index++)
{
InverseInstanceIndex[RemapSortIndex[Index]] = Index;
}
//排序前的instanceIndex到有序的index的映射:inverseInstanceIndex数组

这一层的每个簇节点的fistInstance,lastinstance都弄成有序的index
for (int32 Index = 0; Index < Result->Nodes.Num(); Index++)
{
FClusterNode& Node = Result->Nodes[Index];
Node.FirstInstance = InverseInstanceIndex[Node.FirstInstance];
Node.LastInstance = InverseInstanceIndex[Node.LastInstance];
}
RemapSortIndex[index]对应排序前的instanceIndex,再sortedInstance拿到最初的transform的那个原始的index。

{
result->nodes是叶子节点的个数,cluster.num是这一层的簇的节点
新的节点数为二者之和
nodesPerLevel已经加入了一个元素:叶子节点的数
levelstarts放入当前层的簇数
对每个叶子节点
levelStarts放入上一层节点数(叶子节点数)+当前层的簇数

对于每个叶子
RemapSortIndex的索引是加上了上一层的index数量
加上孩子的索引
// InverseChildIndex[old index] == new index
InverseChildIndex.AddUninitialized(NewNum);
for (int32 Index = Clusters.Num(); Index < NewNum; Index++)
{
InverseChildIndex[RemapSortIndex[Index]] = Index;
}
for (int32 Index = 0; Index < Result->Nodes.Num(); Index++)
{
FClusterNode& Node = Result->Nodes[Index];
if (Node.FirstChild >= 0)
{
Node.FirstChild = InverseChildIndex[Node.FirstChild];
Node.LastChild = InverseChildIndex[Node.LastChild];
}
}


// Save inverse map
Result->InstanceReorderTable.Init(INDEX_NONE, OriginalNum);
for (int32 Index = 0; Index < Num; Index++)
{
Result->InstanceReorderTable[SortedInstances[Index]] = Index;
}
//
sortedInstance拿到最初的transform的那个原始的index。
InstanceReorderTable是反过来,输入原始,输出新的。

}

}