Después de escribir los sombreadores de phong y blinn 'estándar' por un tiempo, recientemente comencé a incursionar en el sombreado de base física. Un recurso que me ayudó mucho son estas notas del curso , especialmente este documento : explica cómo hacer que el sombreado sea más plausible físicamente.
Implementé el modelo blinn que aparece en el documento, y realmente me gusta cómo se ve. El cambio más significativo propuesto (imo) es la inclusión de la reflectancia de fresnel, y esta es también la parte que me da problemas. Desafortunadamente, el autor eligió enfocarse solo en la parte especular, omitiendo la reflectancia difusa. Dado, por ejemplo, un reflejo difuso lambertiano, simplemente no sé cómo combinarlo con el blinn 'mejorado', porque simplemente agregar partes difusas y especulares ya no parece ser correcto.
En algunos sombreadores, he visto un 'término fresnel' de coma flotante en el rango 0-1 que se usa, basado en los índices de refracción de los medios participantes. La aproximación de Schlick se usa siempre:
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 );
}
Haciéndolo así, se puede interpolar linealmente entre la contribución difusa y especular en función del término fresnel, p. Ej.
float fresnel = schlick( L, H, 1.0002926 /*air*/, 1.5191 /*other material*/ );
vec3 color = mix( diffuseContrib, specularContrib, fresnel );
En el documento, el autor afirma que este enfoque es incorrecto, porque básicamente solo oscurece el color especular siempre que L es paralelo o casi paralelo a H, y que en lugar de calcular un f0 basado en los índices de refracción, debe tratar el especular colorearse como f0 y hacer que su aproximación schlick calcule un vec3, así:
vec3 schlick( in vec3 v0, in vec3 v1, in vec3 spec )
{
return spec + ( vec3( 1.0 ) - spec ) * pow( dot( v0, v1 ), 5 );
}
Esto da como resultado que el color especular vaya hacia el blanco en ángulos de mirada.
Ahora mi pregunta es, ¿cómo introduciría un componente difuso en esto? A 90 °, la contribución especular es completamente blanca, esto significa que toda la luz entrante se refleja, por lo que no puede haber una contribución difusa. Para ángulos de incidencia <90 °, ¿puedo simplemente multiplicar toda la parte difusa con (vec3 (1) - schlick), es decir, la proporción de luz que no se refleja?
vec3 diffuseContrib = max( dot( N, L ), 0.0 ) * kDiffuse * ( vec3( 1.0 ) - schlick( L, H, kSpec ) );
¿O necesito un enfoque completamente diferente?