Depois de escrever shaders phong e blinn 'padrão' por um tempo, recentemente comecei a me envolver com sombreamentos fisicamente baseados. Um recurso que me ajudou muito são as notas do curso , especialmente este artigo - explica como tornar o blinn mais sombreado fisicamente plausível.
Eu implementei o modelo blinn apresentado no artigo e realmente gosto da aparência dele. A mudança mais significativa proposta (imo) é a inclusão da refletância de fresnel, e essa também é a parte que me causa problemas. Infelizmente, o autor optou por se concentrar apenas na parte especular, omitindo a refletância difusa. Dado, por exemplo, uma reflexão difusa lambertiana, simplesmente não sei como combiná-la com o blinn 'aprimorado' - porque apenas adicionar partes difusas e especulares parece não estar mais certa.
Em alguns shaders, vi um ponto flutuante 'termo fresnel' no intervalo de 0 a 1 sendo usado, com base nos índices de refração da mídia participante. A aproximação de Schlick é usada sempre:
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 );
}
Fazendo assim, é possível interpolar linearmente entre contribuição difusa e especular com base no termo fresnel, por exemplo
float fresnel = schlick( L, H, 1.0002926 /*air*/, 1.5191 /*other material*/ );
vec3 color = mix( diffuseContrib, specularContrib, fresnel );
No artigo, o autor afirma que essa abordagem é incorreta - porque basicamente escurece a cor especular sempre que L é paralela ou quase paralela a H - e que, em vez de calcular um f0 com base nos índices de refração, você deve tratar a especular colora-se como f0 e faça com que sua aproximação schlick calcule um vec3, assim:
vec3 schlick( in vec3 v0, in vec3 v1, in vec3 spec )
{
return spec + ( vec3( 1.0 ) - spec ) * pow( dot( v0, v1 ), 5 );
}
Isso resulta na cor especular indo para o branco em ângulos de visão.
Agora, minha pergunta é: como introduziria um componente difuso nisso? A 90 °, a contribuição especular é totalmente branca; isso significa que toda a luz que entra é refletida; portanto, não pode haver uma contribuição difusa. Para ângulos de incidência <90 °, posso multiplicar toda a parte difusa com (vec3 (1) - schlick), ou seja, a proporção de luz que não é refletida?
vec3 diffuseContrib = max( dot( N, L ), 0.0 ) * kDiffuse * ( vec3( 1.0 ) - schlick( L, H, kSpec ) );
Ou preciso de uma abordagem completamente diferente?