Hello,
Im working with the Source engine, and im wondering about the correct and best way of implementation of normalizing blinn phong
Here is the default implementation of the basic brdf in source.
All this code is publicly available on their source 2013 github page.
/////diffuse term is;
float3 DiffuseTerm(const bool bHalfLambert, const float3 worldNormal, const float3 lightDir,
const bool bDoLightingWarp, in sampler lightWarpSampler )
{
float fResult;
float NDotL = dot( worldNormal, lightDir ); // Unsaturated dot (-1 to 1 range)
fResult = saturate( NDotL ); // Saturate pure Lambertian term
float3 fOut = float3( fResult, fResult, fResult );
return fOut;
}
and main implementation is
diffuseLighting = vColor * fAtten * DiffuseTerm( bHalfLambert, worldNormal, lightDir, bDoLightingWarp, lightWarpSampler );
float3 vHalfAngle = normalize( vEyeDir.xyz + vLightDir.xyz );
float flNDotH = saturate( dot( vWorldNormal.xyz, vHalfAngle.xyz ) );
specularLighting = SourceBlinn(vWorldNormal,vEyeDir, vLightDir, fSpecularExponent);
specularLighting *= pow( saturate( dot( vWorldNormal, vLightDir ) ), 0.5 ); // Mask with N.L raised to a power
specularLighting *= color;
float3 diffuseComponent = albedo * diffuseLighting;
final = diffuseComponent + specularLighting
This is the default implementation of BlinnPhong ;
half SourceBlinn(half3 vWorldNormal, half3 vEyeDir, half3 vLightDir, half Expo)
{
float3 vHalfAngle = normalize( vEyeDir.xyz + vLightDir.xyz );
return pow( saturate(dot(vWorldNormal, vHalfAngle)), Expo);
}
and then Cryengine's Normalized.
#define ONE_OVER_PI 0.31831h
#define ONE_OVER_TWO_PI 0.159155h
half SourceBlinnCE(half3 vWorldNormal, half3 vEyeDir, half3 vLightDir, half Expo)
{
half fNormFactor = Expo * ONE_OVER_TWO_PI + ONE_OVER_PI;
float3 vHalfAngle = normalize( vEyeDir.xyz + vLightDir.xyz );
return fNormFactor * pow( saturate(dot(vWorldNormal, vHalfAngle)), Expo+1e-6); <-- cryengine also adds this modification
}
Would this be the correct way of doing it?
Similar to how its done in Cryengine I think.
Every engine that I have looked at so far has implemented it different.
Marmoset does;
half Marmo(half3 N, half3 V, half3 L, half Expo)
{
half3 H = normalize(V + L);
half fNormFactor = (Expo + 4.0)/(8.0*3.141592);
return fNormFactor * pow(saturate(dot(N, H)), Expo);
}
But I have also seen;
half fNormFactor = (Expo + 2.0) / 8.0; ... with seemingly no adjustment to the diffuse portion of the brdf.
Also half fNormFactor = (Expo+8.0) / 8.0;