在Unity / C#中的树结构中,如何使用ComputeShaders对从根到叶的计算值求和?

问题描述 投票:0回答:1

如果这不是混合多个世界的话,这不会太难:算法世界、C# 世界和计算着色器世界(在 Unity 中)。

编辑:有些相关。我的情况更糟糕,因为每个节点不仅有一个值,还有一个值列表。

================

这是我在 C# 中的结构(为了解释而简化):

class Function {
   public int type; // 0 or 1
   public int param1;
   public int param2;
}

class Node {
   public string Id;
   public List<Function> Functions;
   public List<Node> Children;
}

一旦加载,你可以像这样想象它,如果它是 json 风格渲染的:

{
   "id": "node0",
   "functions": [ 
       { "type": 0, "param1": 5, "param2" : 6}, 
       { "type": 1, "param1": 7, "param2" : 8}
   ],
   "children": [
      {
         "id": "node00",
         "functions": [
            { "type": 0, "param1": 9, "param2" : 10}, 
            { "type": 1, "param1": 11, "param2" : 12}
         ],
         "children": [
            { 
               "id" : "node000", 
               "functions": [
                  { "type": 0, "param1": 13, "param2" : 14},
                  { "type": 1, "param1": 15, "param2" : 16},
               ], 
               "children": [] //this one's a leaf
            } 
         ]
      },
      {
         "id": "node01",
         "functions": [{ "type": 0, "param1": 15, "param2" : 16}],
         "children": [] // also a leaf
      }
   ]
}
     

我想使用计算着色器来计算每个节点的“该”值(不仅仅是叶子!) 每个节点的值是这样计算的:

  1. 计算其每个函数
  2. 将这些相同函数的所有结果相加
  3. 将所有父项的所有函数相加,一直到根。

例如,node000 将计算如下:

int result0 = computeFunction(type: 0, param1: 13, param2: 14);
int result1 = computeFunction(type: 1, param1: 15, param2: 16);
int node000Sum = result0 + result1 // there can be as many terms as there are functions in the node.
// (not detailed) : repeat with parent, node00
// (not detailed) : repeat with grandparent, node0, which is also root.
int finalResult = node000Sum + node00Sum + node0Sum

我们不只是想要叶子的最终总和。我们还将在需要的地方使用node00Sum和node0Sum(换句话说:每个节点的计算结果都在某个地方使用)。

====================

这就是设置。现在我的问题是:我无法想象如何组织该数据以使其由计算着色器有效地处理。

我认为最简单的第一步是将all节点的函数存储在一个大平面数组中(伪json): 所有功能:[ {“类型”:0,“参数1”:5,“参数2”:6}, {“类型”:1,“参数1”:7,“参数2”:8}, {“类型”:0,“参数1”:9,“参数2”:10}, {“类型”:1,“参数1”:11,“参数2”:12}, {“类型”:0,“参数1”:13,“参数2”:14}, {“类型”:1,“参数1”:15,“参数2”:16}, {“类型”:0,“参数1”:15,“参数2”:16} ] ...然后让着色器计算每个函数(并且仅计算它)。

...然后(也许)有第二个着色器通道来进行求和...(否则,如果太复杂,则在 C# 中进行)。 ...然后将这些总和与它们所属的原始节点相匹配。

但无论我尝试什么,数据结构很快就会变得令人头疼。

创建所有函数的数组并计算它们很容易,但求和并将它们匹配回节点却很困难。为了提高效率,我必须使用数组(着色器不处理链接列表),但我还需要以某种方式“记住”树结构。结果,我很快就陷入了一些穷人的链表(和整个树)中,试图处理数组中项目的索引。

即使我做到了,也很难将总和与原始节点相匹配。

你将如何实现这一目标? (即一般方法需要改变什么)?文学中有类似的问题吗?

(我打赌有,但我不想需要博士学位才能理解它。)

c# unity-game-engine compute-shader
1个回答
0
投票

struct Node { public int parentNodeId public int[] functionIds }

您还将把 id 存储到函数中(它看起来像函数的参数,而不是函数本身)。每个节点的 functionId 数组的大小必须是恒定的(如果您不想创建更多间接,则无法动态表示它)。

现在算法应该如何工作了。您将有一个带有节点的平面数组,一个带有函数的平面数组(它们的数据?),一个带有 int 的平面数组(每个深度的节点数),以及某种结果数组。您需要计算每个节点的总和。数组中的节点应按深度排序,父节点在开头,叶子在末尾。您还将有另一个数组,其中包含每个深度的节点数(从根到叶排序,就像节点数组本身一样)。之后,您可以启动计算机着色器。

我们从数组中取出索引为 0 的元素,其中包含深度节点数(最有可能有一个,即根)- N0,计算带有节点的数组中 N0 个元素的结果(我们将这些结果写入一些结果数组),取索引1处的元素(深度的下一层),从从N0开始的节点数组中取出N1个元素,计算它们自己的函数值,添加父级的值(节点中的父级索引),写入结果到我们某种数组,取索引 2 处的元素...

在每个深度/层执行结束时,您需要调用“barrier”函数(Unity中很可能有一个,或其类似物;一般来说,这在GLSL中使用),以便执行对于该层的所有元素,对于尚未计算父母的孩子,该函数不会开始执行。

很抱歉,答案和描述太抽象了

© www.soinside.com 2019 - 2024. All rights reserved.