After writing 'standard' phong & blinn shaders for a while, I recently started to dabble in physically based shading. A resource that helped me a lot are these course notes, especially this paper - it explains how to make blinn more shading physically plausible.
I implemted the blinn model propsed in the paper, and I really like how it looks. The most significant change proposed ( imo ) is the inclusion of the fresnel reflectance, and this is also the part that gives me problems. Unfortunately, the author chose to focus on the specular part only, omitting diffuse reflectance. Given e.g. a lambertian diffuse reflection, I just don't know how to combine it with the 'improved' blinn - because just adding diffuse & specular parts does not seem to be right any more.
In some shaders I've seen a floating point 'fresnel term' in range 0 - 1 being used, based on the indices of refraction of the participating media. Schlick's approximation is used every time:
float schlick( in vec3 v0, in vec3 v1, in float n1, in float n2 ) { float f0 = ( n1 - n2 ) / ( n1 + n2 ); f0 *= f0; return f0 + ( 1 - f0 ) * pow( dot( v0, v1 ), 5 ); } Doing it like this, one can then linearly interpolate between diffuse and specular contribution based on the fresnel term, e.g.
float fresnel = schlick( L, H, 1.0002926 /*air*/, 1.5191 /*other material*/ ); vec3 color = mix( diffuseContrib, specularContrib, fresnel ); In the paper, the author states that this approach is incorrect - because it basically just darkens the specular color whenever L is parallel or nearly parallel to H - and that instead of computing a f0 based on the indices of refraction, you should treat the specular color itself as f0 and have your schlick approximation compute a vec3, like this:
vec3 schlick( in vec3 v0, in vec3 v1, in vec3 spec ) { return spec + ( vec3( 1.0 ) - spec ) * pow( dot( v0, v1 ), 5 ); } This results in the specular color going towards white at glancing angles.
Now my question is, how would I introduce a diffuse component into this? At 90° the specular contribution is fully white, this means all incoming light is reflected, so there can't be a diffuse contribution. For incidence angles < 90°, can I just multiply the whole diffuse part with ( vec3( 1 ) - schlick ), i.e. the proportion of light that isn't reflected?
vec3 diffuseContrib = max( dot( N, L ), 0.0 ) * kDiffuse * ( vec3( 1.0 ) - schlick( L, H, kSpec ) ); Or do I need a completely different approach?