HLSL 如何将常量缓冲区作为一个整体传递给函数,而不是每个成员

HLSL how to pass constant buffer as a whole to functions, instead of per member

假设我有多个使用相同功能的着色器,我想将它移到一个单独的函数中。例如,我有多个共享相同矩阵乘法的顶点着色器:

PS_INPUT main(VERTEX_INPUT vertex)
{
    PS_INPUT output = (PS_INPUT)0;

    output.Position = mul(vertex.Position, World);
    output.Position = mul(output.Position, View);
    output.Position = mul(output.Position, Projection);

    // other uncommon functionality...
   
    return output;
}

并且数据来自常量缓冲区。

cbuffer Object : register(b0)
{
    float4x4 World;
}

cbuffer Camera : register(b1)
{
    float4x4 View;
    float4x4 Projection;
}

如果我想将矩阵乘法移动到单独的函数中,我通常会这样写:

float4 process_position(float4 inputPosition, float4x4 world, float4x4 view, float4x4 projection)
{
    float4 outPosition = mul(inputPosition, world);
    outPosition = mul(outPosition, view);
    outPosition = mul(outPosition, projection);
    return outPosition;
}

这很容易失控,并随着更多的争论变得异常混乱。参数可以分组在一个结构中,但如果我更改常量缓冲区中的某些内容,仍然需要维护。 有没有办法自动将绑定到当前着色器的整个 cbuffer 传递给一个函数,而不是它的单个成员?像这样的东西会很棒:

float4 process_position(float4 inputPosition, Object objBuf, Camera camBuf) // errors...
{
    float4 outPosition = mul(inputPosition, objBuf.World);
    outPosition = mul(outPosition, camBuf.View);
    outPosition = mul(outPosition, camBuf.Projection);
    return outPosition;
}

PS_INPUT main(VERTEX_INPUT vertex)
{
    PS_INPUT output = (PS_INPUT)0;

    output.Position = process_output(vertex.Position, Object, Camera); // errors...

    // other uncommon functionality...

    return output;
}

注意:使用着色器模型5_0

在着色器模型 5 中,常量缓冲区不是对象或变量,因此不能将 then 作为参数传递给函数。

最接近的方法确实是使用结构(并确保在 cbuffer 声明和函数输入中都使用结构。

struct sObjectData
{
    float4x4 World;
};

struct sCameraData
{
    float4x4 View;
    float4x4 Projection;
};

cbuffer cbObject : register(b0)
{
    sObjectData objectData;
}

cbuffer Camera : register(b1)
{
    sCameraData cameraData;
}

float4 process_position(float4 inputPosition, sObjectData objBuf, sCameraData 
camBuf)
{
    float4 outPosition = mul(inputPosition, objBuf.World);
    outPosition = mul(outPosition, camBuf.View);
    outPosition = mul(outPosition, camBuf.Projection);
    return outPosition;
}

float4 test = process_position(input.pos, objectData, cameraData);

当然可以进行一些维护(如果您重命名一个字段或删除一个字段,但如果无论如何都允许传递整个 cbuffer 也会出现这种情况),但至少添加新字段或重新排序字段会成功不受影响。