如何将 float3x3 传递给 DirectX 中的 HLSL 着色器?
How to pass float3x3 to HLSL Shader in DirectX?
我在将 3x3 矩阵通过常量缓冲区传递到 DirectX 中的着色器时遇到了问题。这就是我定义常量缓冲区的方式:
在 .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 类型。
如何正确处理?
您遇到的问题是 HLSL 打包规则与 C++ 不同。见 Microsoft Docs:
HLSL packing rules are similar to performing a #pragma pack 4
with Visual Studio, which packs data into 4-byte boundaries. Additionally, HLSL packs data so that it does not cross a 16-byte boundary.
另请记住,默认情况下,HLSL 使用 'column-major' 矩阵,而 DirectXMath 使用 'row-major'。这就是为什么您会看到很多样本将矩阵从 XMFLOAT?X?
转置为 HLSL 常量缓冲区结构。参见 Microsoft Docs。
通常,您最好的选择是对 HLSL 矩阵使用 XMFLOAT4X4
。在 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];
}
我在将 3x3 矩阵通过常量缓冲区传递到 DirectX 中的着色器时遇到了问题。这就是我定义常量缓冲区的方式:
在 .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 类型。
如何正确处理?
您遇到的问题是 HLSL 打包规则与 C++ 不同。见 Microsoft Docs:
HLSL packing rules are similar to performing a
#pragma pack 4
with Visual Studio, which packs data into 4-byte boundaries. Additionally, HLSL packs data so that it does not cross a 16-byte boundary.
另请记住,默认情况下,HLSL 使用 'column-major' 矩阵,而 DirectXMath 使用 'row-major'。这就是为什么您会看到很多样本将矩阵从 XMFLOAT?X?
转置为 HLSL 常量缓冲区结构。参见 Microsoft Docs。
通常,您最好的选择是对 HLSL 矩阵使用 XMFLOAT4X4
。在 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];
}