Using shadows helps a little for the parts that should be occluded but I still need some help on the two problems above.

I'm using the following seperable gaussian blur function for the bloom (which is exactly like being used in MJPs recent samples):

cbuffer cbBlurProperties : register(b0)
{
float2 _ScreenSize;
float _BloomBlurSigma;
float _padding;
};
// Calculates the gaussian blur weight for a given distance and sigmas
float CalcGaussianWeight(int sampleDist, float sigma)
{
float g = 1.0f / sqrt(2.0f * 3.14159 * sigma * sigma);
return (g * exp(-(sampleDist * sampleDist) / (2 * sigma * sigma)));
}
// Performs a gaussian blur in one direction
float4 Blur(in float2 UV, float2 texScale, float sigma)
{
float4 color = 0;
for (int i = -3; i < 3; i++)
{
float weight = CalcGaussianWeight(i, sigma);
float2 texCoord = UV;
texCoord += (i / _ScreenSize) * texScale;
float4 sample = TargetTexture.Sample(TargetTextureSampler, texCoord);
color += sample * weight;
}
return color;
}
float4 PS(VSO input) : SV_TARGET0
{
return Blur(input.UV, float2(1, 0), _BloomBlurSigma);
}

I've tried different sigmas from 0.5 to 1.5 but at glancing angles the few pixels at the edge always lit up to extreme values and get expanded during the blur to the glowing ball (as seen in the video).

Do you think the problem might be my BRDF ?

Here's the one I'm using for the the head:

float3 N = Normal;
float3 L = normalize(LightDir);
float3 V = ViewDir;
float3 H = V + L;
float3 H_norm = normalize(H);
float4 Ls = float4(0, 0, 0, 1);
float4 Lr = float4(0, 0, 0, 1);
// Incident radiance
float3 Li = ToLinear(_LightColor.rgb) * _LightIntensity;
// Calculate cos(theta)
float NdotL = saturate(dot(N, L));
// Compute Fresnel Term (F) using Schlick's approximation
float base = 1.0f - saturate(dot(L, H_norm));
float exponential = pow(base, 5.0);
float3 F = 0.028f + (1.0f - 0.028f) * exponential;
// Add ambient light
Lr.rgb += ambient;
// Add diffuse light
Lr.rgb += NdotL * Li * shadowFactor;
Lr.rgb *= DiffuseAlbedo;
Lr.rgb *= (1.0f - F);
// Kelemen/Szirmay-Kalos (D) using a precomputed beckmann distribution
float NdotH = saturate(dot(N, H_norm));
float PH = pow(abs(2.0f * BeckmannTarget.SampleLevel(LinearSampler, float2(NdotH, SpecularPower), 0).r), 10.0f);
float ksk = max(PH / dot(H, H), 0.0f);
float D = ksk;
// Cook-Torrance approximation (G) by Kelemen and Szirmay-Kalos
float NdotV = saturate(dot(N, V)) + 0.00001f;
float LdotH = saturate(dot(L, H_norm)); + 0.00001f;
float G = 1.0f / (LdotH * LdotH);
float3 nominator = F * G * D;
float denominator = 4.0f;
Ls.rgb += nominator / denominator;
Ls.rgb *= NdotL * Li * shadowFactor; // multiply by cosine factor and incoming radiance
return Lr + Ls;