Search code examples
mathfloating-pointnumbersshaderhlsl

Efficient conditional ceiling and floor in HLSL


I was trying to figure this out for quite some time already, but I can't get it quite right. What I want to do is to round a float towards the nearest integer, based on a different float.

I basically need a function that should work like this:

float roundParam(float val, float dir)
{
    if (dir >= 0)
        return ceil(val);
    else
        return floor(val);
}

This is of course VERY inefficient, as it requires a branch per vector component. I figured this out, but it breaks for integers:

float roundParam(float val, float dir)
{
    return round(val + 0.5 * sign(dir));
}

Solution

  • Thanks to @wim and his observation that floor(x) = -ceil(-x) and ceil(x) = -floor(-x) I was able to create this function that solved the problem:

    float3 roundParam(float3 val, float3 dir)
    {
        float3 dirSign = sign(dir);
        return dirSign * floor(dirSign * val) + dirSign;
    }