matrix - 如何在 DirectX 中将 float3x3 传递给 HLSL 着色器?
问题描述
我在将 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 文档:
HLSL 打包规则类似于
#pragma pack 4
使用 Visual Studio 执行,后者将数据打包到 4 字节边界中。此外,HLSL 对数据进行打包,使其不会跨越 16 字节边界。
还要记住,默认情况下,HLSL 使用“列优先”矩阵,而 DirectXMath 使用“行优先”。这就是为什么您会看到大量将矩阵转置为XMFLOAT?X?
HLSL 常量缓冲区结构的样本的原因。请参阅Microsoft 文档。
通常,您最好的选择是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];
}
推荐阅读
- vb.net - 将纬度/经度传递给距离函数时的类型转换问题
- prolog - 协同本体构建与Prolog
- asp.net-core - 使用 ntlm 在 Intranet 站点上进行混合身份验证,并可以更改登录用户
- python - Django Rest 返回 0 字节 zip 文件作为响应
- datetime - 将字符串转换为 xs:dateTime
- tsql - 写入具有基于它的索引和视图的表
- javascript - 调用方法时返回空数组
- java - 使用继承树模型简化数学表达式
- ios - UItableview 行未在 swift4 中与 mapkit 一起显示
- imagemagick - 如何将图像列表中的图像调整为相同大小