Repository: google/filament
File: filament/src/materials/ssao/gtaoImpl.fs (F#)

Code before:
        : 1.0;
    vec3 deltaPosBackface = deltaPos - viewDir * materialParams.constThickness * linearThicknessMultiplier;

    // Project sample onto the unit circle and compute the angle relative to V
    frontBackHorizon.x = dot(normalize(deltaPos), viewDir);
    frontBackHorizon.y = dot(normalize(deltaPosBackface), viewDir);

    frontBackHorizon.x = acosFast(frontBackHorizon.x);
    frontBackHorizon.y = acosFast(frontBackHorizon.y);

    // Shift sample from V to normal, clamp in [0..1]
    frontBackHorizon = clamp(((samplingDirection * -frontBackHorizon) + n + HALF_PI) / PI, 0.0, 1.0);

    // Sampling direction inverts min/max angles
    frontBackHorizon = samplingDirection >= 0.0 ? frontBackHorizon.yx : frontBackHorizon.xy;

    return updateSectors(frontBackHorizon.x, frontBackHorizon.y, globalOccludedBitfield);
}

// https://graphics.stanford.edu/%7Eseander/bithacks.html
highp uint countBits(highp uint value) {
    value = value - ((value >> 1u) & 0x55555555u);
    value = (value & 0x33333333u) + ((value >> 2u) & 0x33333333u);
    return ((value + (value >> 4u) & 0xF0F0F0Fu) * 0x1010101u) >> 24u;
}

void groundTruthAmbientOcclusion(out float obscurance, out vec3 bentNormal,
        highp vec2 uv, highp vec3 origin, vec3 normal) {
    vec2 uvSamplePos = uv;
    highp vec3 viewDir = normalize(-origin);
    highp float ssRadius = -(materialParams.projectionScaleRadius / origin.z);

    float noiseOffset = spatialOffsetsNoise(uv);
    float noiseDirection = spatialDirectionNoise(uv);

    float initialRayStep = fract(noiseOffset);

    // The distance we want to move forward for each step
    float stepRadius = ssRadius / (materialParams.stepsPerSlice + 1.0);

    float visibility = 0.0;
    for (float i = 0.0; i < materialParams.sliceCount.x; i += 1.0) {
        float slice = (i + noiseDirection) * materialParams.sliceCount.y;
        float phi = slice * PI;
        float cosPhi = cos(phi);
        float sinPhi = sin(phi);
        vec2 omega = vec2(cosPhi, sinPhi);

        // Calculate the direction of the current slice
        vec3 direction = vec3(cosPhi, sinPhi, 0.0);
        // Project direction onto the plane orthogonal to viewDir.

Review comment (refactor):
I think the better way to fix this is to do what we do for things like `packUnorm4x8`.

Have a look at ShaderCompilerService.cpp around lines 1094. We inject the missing functions based on the current version. I suggest you split this PR, the highp stuff only, and then the bitCount change.

Code after:
        : 1.0;
    vec3 deltaPosBackface = deltaPos - viewDir * materialParams.constThickness * linearThicknessMultiplier;

    // Project sample onto the unit circle and compute the angle relative to V
    frontBackHorizon.x = dot(normalize(deltaPos), viewDir);
    frontBackHorizon.y = dot(normalize(deltaPosBackface), viewDir);

    frontBackHorizon.x = acosFast(frontBackHorizon.x);
    frontBackHorizon.y = acosFast(frontBackHorizon.y);

    // Shift sample from V to normal, clamp in [0..1]
    frontBackHorizon = clamp(((samplingDirection * -frontBackHorizon) + n + HALF_PI) / PI, 0.0, 1.0);

    // Sampling direction inverts min/max angles
    frontBackHorizon = samplingDirection >= 0.0 ? frontBackHorizon.yx : frontBackHorizon.xy;

    return updateSectors(frontBackHorizon.x, frontBackHorizon.y, globalOccludedBitfield);
}

void groundTruthAmbientOcclusion(out float obscurance, out vec3 bentNormal,
        highp vec2 uv, highp vec3 origin, vec3 normal) {
    vec2 uvSamplePos = uv;
    highp vec3 viewDir = normalize(-origin);
    highp float ssRadius = -(materialParams.projectionScaleRadius / origin.z);

    float noiseOffset = spatialOffsetsNoise(uv);
    float noiseDirection = spatialDirectionNoise(uv);

    float initialRayStep = fract(noiseOffset);

    // The distance we want to move forward for each step
    float stepRadius = ssRadius / (materialParams.stepsPerSlice + 1.0);

    float visibility = 0.0;
    for (float i = 0.0; i < materialParams.sliceCount.x; i += 1.0) {
        float slice = (i + noiseDirection) * materialParams.sliceCount.y;
        float phi = slice * PI;
        float cosPhi = cos(phi);
        float sinPhi = sin(phi);
        vec2 omega = vec2(cosPhi, sinPhi);

        // Calculate the direction of the current slice
        vec3 direction = vec3(cosPhi, sinPhi, 0.0);
        // Project direction onto the plane orthogonal to viewDir.
        vec3 orthoDirection = normalize(direction - (dot(direction, viewDir)*viewDir));
        // `axis` is orthogonal to direction and viewDir (basically the normal of the slice plane)
        // Used to define projectedNormal
        vec3 axis = cross(orthoDirection, viewDir);
        // `projNormal` is the normal projected onto the slice plane
        vec3 projNormal = normal - axis * dot(normal, axis);