计算着色器:如何将不规则的结构作为参数传递?

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

我正在使用 Unity 进行 C# 工作。 我创建了一个计算着色器,想要将 C# 数据结构数组传递给它。 就在那时,我意识到我可能已经过度使用了奇特的数据结构,而不是坚持使用类似 C 的着色器结构。

更具体地说,我遇到了两个障碍:

1。我想要传递到着色器缓冲区的每个对象都包含一个链接列表,这意味着对象之间的大小不同。着色器缓冲区是否可以定义为除数组之外的任何其他值,其大小显式传递?

2。我想要传递给着色器的每个对象都是多态的。即它们都有一个字段“type”,但是如果 type==0 它们有一个字段 value0,而那些 type==1 的对象有一个字段 value1 。尝试用着色器语言实现这一点是否合理(可能使用类似 C 的联合)?

interface IObject {
   public int type { get; }
}

class Type0 : IObject {
   public int type => 0;
   public int field0;
}

class Type1 : IObject {
   public int type => 1;
   public float field1;
}

class ItemForShader {
   public List<IObject> objects { get; set; }
}
...

// Can I pass this to the shader?
var shaderParameters = new List<ItemForShader>() {
    new ItemForShader() {
       objects = new() { new Type0(), new Type1() }
    },
    new ItemForShader() {
       objects = new() { new Type1(), new Type0(), new Type0() }
    }
}

请注意:我不需要您详细说明任何解决方案(我已经可以看到您描述了如何传递链表节点的共享池,然后使用精美的索引系统在所有对象之间共享这些节点)。

我只是想知道什么是合理的以及通常如何完成(或不完成)。也许本质上描述了在该场景中什么C结构与什么C#结构相匹配?

编辑:正如我担心的那样,这不是好兆头: 具有动态长度的GLSL数组统一

制作多个着色器,一个用于每个数量的潜在项目 您想要支持的链接列表。 GLSL 不支持可变大小 数组。唯一的其他解决方案是创建具有最大的数组 您将使用的尺寸。

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

您问题的字面答案是:您不能。

GPU代码无法分配内存。 所有内存分配都是在着色器编译时计算出来的。 你不能有一个包含 N 个元素的数组。 您不能拥有多态数据类型。

但是您可以拥有预定大小的数据块,并从中构建这些概念。 在这种情况下,由于 int 和 float 的大小相同,因此您可以拥有紧密包装的联合结构。 一般来说,您只需计算出最大尺寸并让所有对象都使用该尺寸。 这是如何构建联合结构的示例:

C#:

[StructLayout(LayoutKind.Explicit)]
public struct IObject {
    [FieldOffset(0)]
    public uint type;
    [FieldOffset(1)]
    public int field0;
    [FieldOffset(1)]
    public float field1;

    public static IObject Type0(int field0) {
        return new IObject() {
            type = 0,
            field0 = field0,
        };
    }
    public static IObject Type1(float field1) {
        return new IObject() {
            type = 1,
            field1 = field1,
        };
    }
}

HLSL:

struct IObject {
    uint type;
    int unionMember;
};

int GetField0(IObject o) {
    return o.unionMember;
}
float GetField1(IObject o) {
    return asfloat(o.unionMember);
}

请注意,“asfloat”是 C 风格重新解释转换的 HLSL 等效项。 它不返回与 int 相同数字的浮点数,而是返回那些被解释为浮点数的字节。

我还将指出 GPU 着色器核心在遍历复杂数据结构时效率不高。 看一下这个问题,大致了解原因。

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