在 HLSL 计算着色器中解包/打包 SNorm16

问题描述 投票:0回答:1

我正在尝试在 HLSL 计算着色器中解压 SNorm16 值。由于 SNorm16x4 = 总共 8 个字节,并且加载/存储函数只能读/写 4 个字节,我试图将两个 4 字节值打包为 1 个 8 字节值,将其解包为 4 个值,处理结果,然后打包它打包并存储为 1 个 8 字节的打包值。

代码是:

float2 UnpackFromSNorm16x2(uint v)
{
    uint2 tempU = asuint(uint2(v, v >> 16) & 0xFFFF);
    int2 tempI = int2(tempU.x - 32767, tempU.y - 32767);
    return float2( tempI * float(1.0 / 32767.0));
}

int FloatToSNorm16(float v)
{
    //According to D3D10 rules, the value "-1.0f" has two representations:
    //  0x1000 and 0x10001
    //This allows everyone to convert by just multiplying by 32767 instead
    //of multiplying the negative values by 32768 and 32767 for positive.
    return int(clamp(v >= 0.0f ? (v * 32767.0f + 0.5f) : (v * 32767.0f - 0.5f), -32768.0f, 32767.0f));
}

uint PackToSNorm16x2(float2 v)
{
    int intX = int(FloatToSNorm16(v.x));
    int intY = int(FloatToSNorm16(v.y));
    uint2 uintXY = uint2(clamp(intX + 32767, 0, 65535), clamp(intY + 32767, 0, 65535));
    uint x = (uintXY.x << 0) & 0x0000FFFF;
    uint y = (uintXY.y << 16) & 0xFFFF0000;
    return x | y;
}

uint2 inputTangentUInt = asuint(vertices.Load2(baseOffset + tangentOffset));
float4 qTangentUnpacked = float4(UnpackFromSNorm16x2(inputTangentUInt.x), UnpackFromSNorm16x2(inputTangentUInt.y));

//Do some work with qTangentUnpacked

uint2 qTangentPacked = uint2(PackTwoSNORM16(qTangentUnpacked.xy), PackTwoSNORM16(qTangentUnpacked.zw));
vertices.Store2(baseOffset + tangentOffset, asuint(qTangentPacked));

但是最终结果是错误的,看起来有些数据丢失了。 我做错了什么?

unity-game-engine hlsl compute-shader
1个回答
0
投票

有一组用于执行此类转换的 HLSL 例程,称为

D3DX_DXGIFormatConvert.inl
。它记录在 Microsoft Learn 上,并用于在旧版 DirectX SDK 中提供。

最新版本位于 GitHub

请参阅此博文了解更多信息。

© www.soinside.com 2019 - 2024. All rights reserved.