首页 > 解决方案 > 有没有一种特定的方法可以将数组作为常量缓冲区传递给着色器?

问题描述

在c++中,数组中有一个值,当我将它传递给shader时,数据都是0。有没有具体的方法将数组传递给shader?

这是我设置常量缓冲区的代码

    vector<XMFLOAT4X4> finalTransforms = Animator->GetTransforms(_timeDelta);

    BoneTransformBuffer.SetData(GraphicDev->GetDeviceContext(), finalTransforms);
    auto Transform = BoneTransformBuffer.GetBuffer();
    GraphicDev->GetDeviceContext()->VSSetConstantBuffers(1, 1, &Transform);

这是我在着色器中的常量缓冲区

cbuffer cbSkinned : register(b1)
{
    float4x4 BoneTransforms[96];
};

标签: shaderdirectxhlsl

解决方案


您的代码片段缺少有关您的类型和支持代码的大量信息,但我的第一个猜测是您应该使用:

BoneTransformBuffer.SetData(GraphicDev->GetDeviceContext(), finalTransforms.data());

此外,除非依赖返回优化,否则这条线vector<XMFLOAT4X4> finalTransforms = Animator->GetTransforms(_timeDelta); 会额外复制所有数据。GetTransforms

剥皮

请注意,对于蒙皮,您通常不需要为每个骨骼提供完整的 4x4 矩阵。蒙皮动画几乎总是使用仿射变换(平移、缩放和旋转),因此您浪费了常量缓冲区中 25% 的空间。

相反,使用:

struct SkinnedConstants
{
    XMVECTOR bones[96][3];
};
cbuffer cbSkinned : register(b1)
{
    float4x3 BoneTransforms[96];
};

然后你使用这样的东西来设置骨骼数据:

    for (size_t i = 0; i < count; i++)
    {
#if DIRECTX_MATH_VERSION >= 313
        XMStoreFloat3x4A(reinterpret_cast<XMFLOAT3X4A*>(&boneConstant[i]), value[i]);
#else
        // Xbox One XDK has an older version of DirectXMath
        XMMATRIX boneMatrix = XMMatrixTranspose(value[i]);

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

HLSL 代码类似于:

float3 Skin(inout VSInputNmTxWeights vin, float3 normal, uniform int boneCount)
{
    float4x3 skinning = 0;

    [unroll]
    for (int i = 0; i < boneCount; i++)
    {
        skinning += Bones[vin.Indices[i]] * vin.Weights[i];
    }

    vin.Position.xyz = mul(vin.Position, skinning);
    return mul(normal, (float3x3)skinning);
}

请参阅用于DX11 / DX12的XNA Game Studio Stock Effects和 DirectX Tool Kit 。


推荐阅读