如何在DirectX中将float3x3传递给HLSL着色器?

3
我在 DirectX 中通过常量缓冲区将 3x3 矩阵传递给着色器时遇到了问题。这是我定义常量缓冲区的方式:
在 .cpp 文件中:
struct PostProcessConvolutionCB {
    float screenWidth;
    float screenHeight;
    float sum;
    XMFLOAT3X3 kernel;
};

在.hlsl文件中:
struct PostProcessConvolutionCB {
    float screenWidth;
    float screenHeight;
    float sum;
    float3x3 kernel;
};
ConstantBuffer<PostProcessConvolutionCB> cb : register(b0);

struct PixelShaderInput {
    float4 Position : SV_Position;
};

float4 main(PixelShaderInput IN) : SV_Target {
    return float4(cb.kernel[1][1], 0.f, 0.f, 1.f);
}

看起来访问某些元素出了问题。为了测试这个问题,我像这样在常量缓冲区中初始化矩阵:XMFLOAT3X3(0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f, 0.9f); 并尝试通过在着色器中硬编码矩阵索引来显示每个元素的值,就像上面的 hlsl 片段中一样(cb.kernel[1][1])。经过 9 次运行后,我得到了以下结果:

kernel[0][0] = 0.1
kernel[1][0] = 0.2
kernel[2][0] = 0.3

kernel[0][1] = 0.5
kernel[1][1] = 0.6
kernel[2][1] = 0.7

kernel[0][2] = 0.9
kernel[1][2] = 1.0
kernel[2][2] = 1.0

似乎每一行都对齐到4个浮点数。将矩阵更改为4x4有所帮助,但我想肯定有一种方法可以使用float3x3类型。

如何正确处理这个问题?

1个回答

3
您遇到的问题是HLSL打包规则与C ++不同。请参阅Microsoft Docs

HLSL打包规则类似于使用Visual Studio的#pragma pack 4,它将数据打包到4字节边界中。此外,HLSL对数据进行打包,以使其不跨越16字节边界。

还要记住,默认情况下,HLSL使用“列主”矩阵,而DirectXMath使用“行主”矩阵。这就是为什么您会看到许多示例从XMFLOAT?X?转置矩阵到HLSL常量缓冲区结构体。请参阅Microsoft Docs

通常,最好使用XMFLOAT4X4作为HLSL矩阵。在HLSL中节省一些常量缓冲区内存的选项之一(特别适用于皮肤,其中有许多不包括投影变换的骨骼)是使用:

struct SkinnedEffectConstants
{
…
    XMVECTOR bones[MaxBones][3];
};

然后在 C++ 中使用:
for (size_t i = 0; i < count; i++)
{
    XMMATRIX boneMatrix = XMMatrixTranspose(XMLoadFloat4x3(…));

    boneConstant[i][0] = boneMatrix.r[0];
    boneConstant[i][1] = boneMatrix.r[1];
    boneConstant[i][2] = boneMatrix.r[2];
}

1
好的,那很有道理。我采用了float4x3的方法,它起作用了。谢谢! - Maciej Dziuban

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接