如何将 float3 打包成一个 float

How can I pack a float3 into one float

我正在做一些动画工作。我需要将一些枢轴打包到 UV 中,然后我的着色器才能读取它们。

我需要将4个float3打包成一个float4。因此,我需要将每个float3打包成一个float。

这4个float3分别是(modelspaceposition1,direction1,modelspaceposition2,direction2)。我知道如何处理这些指示,因为它们是标准化的。我可以使用类似的东西:

 #define f3_f(c) (dot(round((c) * 255), float3(65536, 256, 1)))
 #define f_f3(f) (frac((f) / float3(16777216, 65536, 256)))

但是我该如何处理仓位呢?我用的是SM3.0,不能按位运算

你真的需要把它打包成一个浮点数(4字节),还是可以把它打包成一个32位无符号整数(即4字节)?

如果,那么看看DirectXMath for converting to/from various formats as done in DirectXTex中的代码如DXGI_FORMAT_R11G11B10_FLOAT。由于此格式仅为正数,因此您必须对格式进行缩放和偏置 to/from 以处理 [-1,+1] 范围,但这很容易做到 (0.5*value + 0.5 <-> 2*value - 1).

// 3D vector: 11/11/10 floating-point components
// The 3D vector is packed into 32 bits as follows: a 5-bit biased exponent
// and 6-bit mantissa for x component, a 5-bit biased exponent and
// 6-bit mantissa for y component, a 5-bit biased exponent and a 5-bit
// mantissa for z. The z component is stored in the most significant bits
// and the x component in the least significant bits. No sign bits so
// all partial-precision numbers are positive.
// (Z10Y11X11): [32] ZZZZZzzz zzzYYYYY yyyyyyXX XXXxxxxx [0]
struct XMFLOAT3PK
{
    union
    {
        struct
        {
            uint32_t xm : 6; // x-mantissa
            uint32_t xe : 5; // x-exponent
            uint32_t ym : 6; // y-mantissa
            uint32_t ye : 5; // y-exponent
            uint32_t zm : 5; // z-mantissa
            uint32_t ze : 5; // z-exponent
        };
        uint32_t v;
    };

    XMFLOAT3PK() = default;

    XMFLOAT3PK(const XMFLOAT3PK&) = default;
    XMFLOAT3PK& operator=(const XMFLOAT3PK&) = default;

    XMFLOAT3PK(XMFLOAT3PK&&) = default;
    XMFLOAT3PK& operator=(XMFLOAT3PK&&) = default;

    explicit XM_CONSTEXPR XMFLOAT3PK(uint32_t Packed) : v(Packed) {}
    XMFLOAT3PK(float _x, float _y, float _z);
    explicit XMFLOAT3PK(_In_reads_(3) const float *pArray);

    operator uint32_t () const { return v; }

    XMFLOAT3PK& operator= (uint32_t Packed) { v = Packed; return *this; }
};

// Converts float3 to the 11/11/10 format
inline void XM_CALLCONV XMStoreFloat3PK
(
    XMFLOAT3PK* pDestination,
    FXMVECTOR V
)
{
    assert(pDestination);

    __declspec(align(16)) uint32_t IValue[4];
    XMStoreFloat3A( reinterpret_cast<XMFLOAT3A*>(&IValue), V );

    uint32_t Result[3];

    // X & Y Channels (5-bit exponent, 6-bit mantissa)
    for(uint32_t j=0; j < 2; ++j)
    {
        uint32_t Sign = IValue[j] & 0x80000000;
        uint32_t I = IValue[j] & 0x7FFFFFFF;

        if ((I & 0x7F800000) == 0x7F800000)
        {
            // INF or NAN
            Result[j] = 0x7c0;
            if (( I & 0x7FFFFF ) != 0)
            {
                Result[j] = 0x7c0 | (((I>>17)|(I>>11)|(I>>6)|(I))&0x3f);
            }
            else if ( Sign )
            {
                // -INF is clamped to 0 since 3PK is positive only
                Result[j] = 0;
            }
        }
        else if ( Sign )
        {
            // 3PK is positive only, so clamp to zero
            Result[j] = 0;
        }
        else if (I > 0x477E0000U)
        {
            // The number is too large to be represented as a float11, set to max
            Result[j] = 0x7BF;
        }
        else
        {
            if (I < 0x38800000U)
            {
                // The number is too small to be represented as a normalized float11
                // Convert it to a denormalized value.
                uint32_t Shift = 113U - (I >> 23U);
                I = (0x800000U | (I & 0x7FFFFFU)) >> Shift;
            }
            else
            {
                // Rebias the exponent to represent the value as a normalized float11
                I += 0xC8000000U;
            }

            Result[j] = ((I + 0xFFFFU + ((I >> 17U) & 1U)) >> 17U)&0x7ffU;
        }
    }

    // Z Channel (5-bit exponent, 5-bit mantissa)
    uint32_t Sign = IValue[2] & 0x80000000;
    uint32_t I = IValue[2] & 0x7FFFFFFF;

    if ((I & 0x7F800000) == 0x7F800000)
    {
        // INF or NAN
        Result[2] = 0x3e0;
        if ( I & 0x7FFFFF )
        {
            Result[2] = 0x3e0 | (((I>>18)|(I>>13)|(I>>3)|(I))&0x1f);
        }
        else if ( Sign )
        {
            // -INF is clamped to 0 since 3PK is positive only
            Result[2] = 0;
        }
    }
    else if ( Sign )
    {
        // 3PK is positive only, so clamp to zero
        Result[2] = 0;
    }
    else if (I > 0x477C0000U)
    {
        // The number is too large to be represented as a float10, set to max
        Result[2] = 0x3df;
    }
    else
    {
        if (I < 0x38800000U)
        {
            // The number is too small to be represented as a normalized float10
            // Convert it to a denormalized value.
            uint32_t Shift = 113U - (I >> 23U);
            I = (0x800000U | (I & 0x7FFFFFU)) >> Shift;
        }
        else
        {
            // Rebias the exponent to represent the value as a normalized float10
            I += 0xC8000000U;
        }

        Result[2] = ((I + 0x1FFFFU + ((I >> 18U) & 1U)) >> 18U)&0x3ffU;
    }

    // Pack Result into memory
    pDestination->v = (Result[0] & 0x7ff)
                      | ( (Result[1] & 0x7ff) << 11 )
                      | ( (Result[2] & 0x3ff) << 22 );
}


// Converts the 11/11/10 format to float3
inline XMVECTOR XM_CALLCONV XMLoadFloat3PK
(
    const XMFLOAT3PK* pSource
)
{
    assert(pSource);

    __declspec(align(16)) uint32_t Result[4];
    uint32_t Mantissa;
    uint32_t Exponent;

    // X Channel (6-bit mantissa)
    Mantissa = pSource->xm;

    if ( pSource->xe == 0x1f ) // INF or NAN
    {
        Result[0] = static_cast<uint32_t>(0x7f800000 | (static_cast<int>(pSource->xm) << 17));
    }
    else
    {
        if ( pSource->xe != 0 ) // The value is normalized
        {
            Exponent = pSource->xe;
        }
        else if (Mantissa != 0) // The value is denormalized
        {
            // Normalize the value in the resulting float
            Exponent = 1;

            do
            {
                Exponent--;
                Mantissa <<= 1;
            } while ((Mantissa & 0x40) == 0);

            Mantissa &= 0x3F;
        }
        else // The value is zero
        {
            Exponent = static_cast<uint32_t>(-112);
        }

        Result[0] = ((Exponent + 112) << 23) | (Mantissa << 17);
    }

    // Y Channel (6-bit mantissa)
    Mantissa = pSource->ym;

    if ( pSource->ye == 0x1f ) // INF or NAN
    {
        Result[1] = static_cast<uint32_t>(0x7f800000 | (static_cast<int>(pSource->ym) << 17));
    }
    else
    {
        if ( pSource->ye != 0 ) // The value is normalized
        {
            Exponent = pSource->ye;
        }
        else if (Mantissa != 0) // The value is denormalized
        {
            // Normalize the value in the resulting float
            Exponent = 1;

            do
            {
                Exponent--;
                Mantissa <<= 1;
            } while ((Mantissa & 0x40) == 0);

            Mantissa &= 0x3F;
        }
        else // The value is zero
        {
            Exponent = static_cast<uint32_t>(-112);
        }

        Result[1] = ((Exponent + 112) << 23) | (Mantissa << 17);
    }

    // Z Channel (5-bit mantissa)
    Mantissa = pSource->zm;

    if ( pSource->ze == 0x1f ) // INF or NAN
    {
        Result[2] = static_cast<uint32_t>(0x7f800000 | (static_cast<int>(pSource->zm) << 17));
    }
    else
    {
        if ( pSource->ze != 0 ) // The value is normalized
        {
            Exponent = pSource->ze;
        }
        else if (Mantissa != 0) // The value is denormalized
        {
            // Normalize the value in the resulting float
            Exponent = 1;

            do
            {
                Exponent--;
                Mantissa <<= 1;
            } while ((Mantissa & 0x20) == 0);

            Mantissa &= 0x1F;
        }
        else // The value is zero
        {
            Exponent = static_cast<uint32_t>(-112);
        }

        Result[2] = ((Exponent + 112) << 23) | (Mantissa << 18);
    }

    return XMLoadFloat3A( reinterpret_cast<const XMFLOAT3A*>(&Result) );
}