我正在传递具有以下布局的常量缓冲区:
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/