Dopo aver scritto shader phong e blinn "standard" per un po ', di recente ho iniziato a dilettarmi con l'ombreggiatura basata fisicamente. Una risorsa che mi ha aiutato molto sono queste note del corso , in particolare questo documento - spiega come rendere fisicamente plausibili i blinn.
Ho implementato il modello Blinn proposto nel documento e mi piace molto come appare. Il cambiamento più significativo proposto (imo) è l'inclusione della riflessione di Fresnel, e questa è anche la parte che mi dà problemi. Sfortunatamente, l'autore ha scelto di concentrarsi solo sulla parte speculare, omettendo la riflessione diffusa. Dato ad esempio un riflesso diffuso lambertiano, non so proprio come combinarlo con il blinn "migliorato", perché l'aggiunta di parti diffuse e speculari non sembra più essere corretta.
In alcuni shader ho visto un 'termine di fresnel' in virgola mobile nell'intervallo 0 - 1, basato sugli indici di rifrazione dei media partecipanti. L'approssimazione di Schlick viene utilizzata ogni volta:
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 );
}
In questo modo, si può quindi interpolare linearmente tra contributo diffuso e speculare in base al termine di Fresnel, ad es.
float fresnel = schlick( L, H, 1.0002926 /*air*/, 1.5191 /*other material*/ );
vec3 color = mix( diffuseContrib, specularContrib, fresnel );
Nel documento, l'autore afferma che questo approccio non è corretto - perché fondamentalmente scurisce il colore speculare ogni volta che L è parallelo o quasi parallelo a H - e che invece di calcolare un f0 basato sugli indici di rifrazione, dovresti trattare il speculare colora se stesso come f0 e fai calcolare la tua approssimazione schlick a vec3, in questo modo:
vec3 schlick( in vec3 v0, in vec3 v1, in vec3 spec )
{
return spec + ( vec3( 1.0 ) - spec ) * pow( dot( v0, v1 ), 5 );
}
Ciò si traduce nel colore speculare che va verso il bianco ad angoli di occhiata.
Ora la mia domanda è: come potrei introdurre un componente diffuso in questo? A 90 ° il contributo speculare è completamente bianco, questo significa che tutta la luce in entrata viene riflessa, quindi non può esserci un contributo diffuso. Per angoli di incidenza <90 °, posso semplicemente moltiplicare l'intera parte diffusa con (vec3 (1) - schlick), ovvero la proporzione di luce che non viene riflessa?
vec3 diffuseContrib = max( dot( N, L ), 0.0 ) * kDiffuse * ( vec3( 1.0 ) - schlick( L, H, kSpec ) );
O ho bisogno di un approccio completamente diverso?