Advertisement

DirectXMath conditional assignment

Started by October 26, 2017 10:42 AM
3 comments, last by matt77hias 7 years, 3 months ago

I am using Frostbite's sRGB <-> linear color space conversion on the CPU with DirectXMath which does not have a conditional assignment (? : construct) :(

Any way to improve this:


const XMVECTOR comp = XMVectorLessOrEqual(srgb, XMVectorReplicate(0.04045f));

return XMVectorSet(
            XMVectorGetX(comp) ? XMVectorGetX(low) : XMVectorGetX(high),
            XMVectorGetY(comp) ? XMVectorGetY(low) : XMVectorGetY(high),
            XMVectorGetZ(comp) ? XMVectorGetZ(low) : XMVectorGetZ(high),
            XMVectorGetW(srgb)
        );

Full code:


/**
     Converts the given spectrum from linear to sRGB space.

     @param[in]   linear
                  The spectrum in linear space.
     @return      The spectrum in sRGB space.
     @note        The alpha channel of the given spectrum is preserved.
     */
    inline const XMVECTOR XM_CALLCONV LinearToSRGB(FXMVECTOR linear) noexcept {
        // Frostbite's conversion
        static const float exp = 1.0f / 2.4f;
        
        const XMVECTOR low  = linear * 12.92f;
        const XMVECTOR high = 1.055f * XMVectorPow(linear, XMVectorReplicate(exp))
                            - XMVectorReplicate(0.055f);
        const XMVECTOR comp = XMVectorLessOrEqual(linear, XMVectorReplicate(0.0031308f));

        return XMVectorSet(
            XMVectorGetX(comp) ? XMVectorGetX(low) : XMVectorGetX(high),
            XMVectorGetY(comp) ? XMVectorGetY(low) : XMVectorGetY(high),
            XMVectorGetZ(comp) ? XMVectorGetZ(low) : XMVectorGetZ(high),
            XMVectorGetW(linear)
        );
    }

    /**
     Converts the given spectrum from sRGB to linear space.

     @param[in]     srgb
                    The spectrum in sRGB space.
     @return        The spectrum in linear space.
     @note          The alpha channel of the given spectrum is preserved.
     */
    inline const XMVECTOR XM_CALLCONV SRGBToLinear(FXMVECTOR srgb) noexcept {
        // Frostbite's conversion
        static const float mlow  = 1.0f / 12.92f;
        static const float mhigh = 1.0f / 1.055f;

        const XMVECTOR low  = srgb * mlow;
        const XMVECTOR high = XMVectorPow(
                                  mhigh * (srgb + XMVectorReplicate(0.055f)),
                                  XMVectorReplicate(2.4f)
                              );
        const XMVECTOR comp = XMVectorLessOrEqual(srgb, XMVectorReplicate(0.04045f));

        return XMVectorSet(
            XMVectorGetX(comp) ? XMVectorGetX(low) : XMVectorGetX(high),
            XMVectorGetY(comp) ? XMVectorGetY(low) : XMVectorGetY(high),
            XMVectorGetZ(comp) ? XMVectorGetZ(low) : XMVectorGetZ(high),
            XMVectorGetW(srgb)
        );
    }

 

🧙

XMVectorLessOrEqual returns 0xFFFFFFFF on true and 0x00000000 on false, therefore you can play with bitwise operations:

Quote

const XMVECTOR lowhigh = XMVectorOrInt(XMVectorAndInt(low, comp), XMVectorAndCInt(high, comp));

// set W component

Edit: ajmiles suggestion is better - XMVectorSelect does exactly same thing as I suggested above.

Advertisement

XMVectorSelect is what you're looking for. It takes the masks output by functions such as LessOrEqual and each bit in the mask is used to select between A or B.

Adam Miles - Principal Software Development Engineer - Microsoft Xbox Advanced Technology Group

2 hours ago, ajmiles said:

XMVectorSelect is what you're looking for. It takes the masks output by functions such as LessOrEqual and each bit in the mask is used to select between A or B.

Thanks that is exactly the functionality I was looking for :)

🧙

This topic is closed to new replies.

Advertisement