Après avoir écrit des shaders phong & blinn `` standard '' pendant un certain temps, j'ai récemment commencé à me familiariser avec l'ombrage à base physique. Une ressource qui m'a beaucoup aidé sont ces notes de cours , en particulier cet article - elles expliquent comment rendre le blinn plus physiquement plausible.
J'ai implémenté le modèle blinn proposé dans le document, et j'aime vraiment à quoi il ressemble. Le changement le plus important proposé (imo) est l'inclusion de la réflectance de Fresnel, et c'est aussi la partie qui me pose problème. Malheureusement, l'auteur a choisi de se concentrer uniquement sur la partie spéculaire, en omettant la réflectance diffuse. Étant donné, par exemple, une réflexion diffuse lambertienne, je ne sais tout simplement pas comment la combiner avec le blinn «amélioré» - parce que l'ajout de parties diffuses et spéculaires ne semble plus être correct.
Dans certains shaders, j'ai vu un «terme de Fresnel» à virgule flottante dans la plage 0 - 1 utilisé, basé sur les indices de réfraction des médias participants. L'approximation de Schlick est utilisée à chaque fois:
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 );
}
En procédant ainsi, on peut alors interpoler linéairement entre contribution diffuse et contribution spéculaire sur la base du terme de Fresnel, par exemple
float fresnel = schlick( L, H, 1.0002926 /*air*/, 1.5191 /*other material*/ );
vec3 color = mix( diffuseContrib, specularContrib, fresnel );
Dans l'article, l'auteur déclare que cette approche est incorrecte - car elle assombrit fondamentalement la couleur spéculaire chaque fois que L est parallèle ou presque parallèle à H - et qu'au lieu de calculer un f0 basé sur les indices de réfraction, vous devriez traiter le spéculaire se colorer comme f0 et avoir votre approximation schlick calculer un vec3, comme ceci:
vec3 schlick( in vec3 v0, in vec3 v1, in vec3 spec )
{
return spec + ( vec3( 1.0 ) - spec ) * pow( dot( v0, v1 ), 5 );
}
Il en résulte que la couleur spéculaire va vers le blanc à des angles de regard.
Maintenant ma question est, comment pourrais-je introduire un composant diffus dans ceci? À 90 °, la contribution spéculaire est entièrement blanche, ce qui signifie que toute la lumière entrante est réfléchie, il ne peut donc pas y avoir de contribution diffuse. Pour des angles d'incidence <90 °, puis-je simplement multiplier toute la partie diffuse avec (vec3 (1) - schlick), c'est-à-dire la proportion de lumière qui n'est pas réfléchie?
vec3 diffuseContrib = max( dot( N, L ), 0.0 ) * kDiffuse * ( vec3( 1.0 ) - schlick( L, H, kSpec ) );
Ou ai-je besoin d'une approche complètement différente?