Nachdem ich eine Weile 'Standard'-Phong & Blinn-Shader geschrieben hatte, fing ich kürzlich an, mich mit physikalisch basierten Schattierungen zu beschäftigen. Eine Ressource, die mir sehr geholfen hat, sind diese Kursnotizen , insbesondere dieses Papier - es erklärt, wie man Blinn physikalisch plausibler macht.
Ich habe das in der Zeitung vorgeschlagene Blinn-Modell implementiert, und ich mag es wirklich, wie es aussieht. Die wichtigste vorgeschlagene Änderung (imo) ist die Einbeziehung des Fresnel-Reflexionsvermögens, und dies ist auch der Teil, der mir Probleme bereitet. Leider hat sich der Autor entschieden, sich nur auf den Spiegelteil zu konzentrieren und das diffuse Reflexionsvermögen wegzulassen. Angesichts einer diffusen Lambertschen Reflexion weiß ich einfach nicht, wie ich sie mit dem "verbesserten" Blinn kombinieren soll - denn nur das Hinzufügen diffuser und spiegelnder Teile scheint nicht mehr richtig zu sein.
Bei einigen Shadern wurde ein Gleitkomma-Fresnel-Term im Bereich von 0 bis 1 verwendet, der auf den Brechungsindizes der teilnehmenden Medien basiert. Schlicks Näherung wird jedes Mal verwendet:
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 );
}
Auf diese Weise kann man dann linear zwischen diffusem und spiegelndem Beitrag interpolieren, basierend auf dem Fresnel-Term, z
float fresnel = schlick( L, H, 1.0002926 /*air*/, 1.5191 /*other material*/ );
vec3 color = mix( diffuseContrib, specularContrib, fresnel );
In der Arbeit stellt der Autor fest, dass dieser Ansatz falsch ist - weil er die Spiegelfarbe grundsätzlich nur dann abdunkelt, wenn L parallel oder nahezu parallel zu H ist - und dass Sie anstelle eines f0 basierend auf den Brechungsindizes das Spiegelbild behandeln sollten färben Sie sich als f0 und lassen Sie Ihre Schlick-Näherung ein vec3 wie folgt berechnen:
vec3 schlick( in vec3 v0, in vec3 v1, in vec3 spec )
{
return spec + ( vec3( 1.0 ) - spec ) * pow( dot( v0, v1 ), 5 );
}
Dies führt dazu, dass die Spiegelfarbe unter Blickwinkeln in Richtung Weiß wechselt.
Nun ist meine Frage, wie würde ich eine diffuse Komponente in diese einführen? Bei 90 ° ist der Spiegelbeitrag vollständig weiß, was bedeutet, dass das gesamte einfallende Licht reflektiert wird, sodass kein diffuser Beitrag erfolgen kann. Kann ich bei Einfallswinkeln <90 ° einfach den gesamten diffusen Teil mit (vec3 (1) - schlick) multiplizieren, dh dem Anteil des Lichts, der nicht reflektiert wird?
vec3 diffuseContrib = max( dot( N, L ), 0.0 ) * kDiffuse * ( vec3( 1.0 ) - schlick( L, H, kSpec ) );
Oder brauche ich einen ganz anderen Ansatz?