我正在传递具有以下布局的常量缓冲区:

struct
{
    float spread;
    D2D1_POINT_2F dimension;
    D2D1_POINT_2F dimension2;
} m_constants;

为了调试起见,Dimension和Dimension2具有相同的值。

在着色器中,我有:
cbuffer constants
{
    float spread;
    float2 dimension;
    float2 dimension2;
};

float4 main(
    float4 pos      : SV_POSITION,
    float4 posScene : SCENE_POSITION,
    float4 uv0      : TEXCOORD0
    ) : SV_Target
{
    float width = dimension.x;
    float height = dimension.y;
    float2 uv2 = float2(posScene.x / width, posScene.y / height);
    color.rgb = float3(uv2.xy,  0);
    return color;
}

从理论上讲,这应该输出一个渐变,左下角为绿色,右上角为红色。确实如此。
但是,如果在着色器中我有宽度和高度,则可以使用Dimension2。我得到了从左侧的绿色到右侧的黄色的水平渐变。

这是为什么?当我将m_constants传递给着色器时,两个尺寸都具有相同的值

最佳答案

常量缓冲区数据默认情况下按16个字节对齐,因此这意味着:

cbuffer constants
{
    float spread;
    float2 dimension;
    float2 dimension2;
};

将会
cbuffer constants
{
    float spread; // 4 bytes
    float2 dimension; // 4 + 8 = 12 bytes
    float dummy; //12+8 = 20, which means we cross 16 for dimension 2, hence a dummy 4 bytes element is added
    float2 dimension2;
};

这是一个描述此情况的link

因此,安排结构的更好方法是:
struct
{
    D2D1_POINT_2F dimension;
    D2D1_POINT_2F dimension2;
    float spread;
} m_constants;

并相应地修改hlsl对应项:
cbuffer constants
{
    float2 dimension;
    float2 dimension2;
    float spread; // No more 16 bytes crossing problem
};

另一种方法,在c++端不修改初始布局,要么声明您的结构,如:
#pragma pack(push)
#pragma pack(16)
struct
{
    float spread;
    D2D1_POINT_2F dimension;
    D2D1_POINT_2F dimension2;
} m_constants;
#pragma pack(pop)

这将强制结构对齐16个字节。

您还可以使用/ Zp16编译器标志,但这将应用于您程序中的每个结构(并非总是如此)。在Visual Studio中,转到项目属性-> c / c++->代码生成,然后有“结构成员对齐”选项,您可以在其中进行设置。

您还可以在hlsl一侧使用packoffset,但是这意味着c++布局需要与打包的hlsl匹配(这意味着您在hlsl常量缓冲区中保持相同的顺序,但仍必须修改c++版本)。

关于c++ - HLSL:包装错误?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/14574061/

10-10 21:16