しばらくの間、「標準的な」フォン&ブリンシェーダーを書いた後、最近、物理ベースのシェーディングに手を出し始めました。私を大いに助けたリソースは、これらのコースノート、特にこのペーパーです。これは、ブリンを物理的にもっともらしいシェーディングにする方法を説明しています。
私はこの論文で提案されているブリンモデルを実装しました。提案されている最も重要な変更(imo)は、フレネル反射率を含めることであり、これも問題を引き起こす部分です。残念ながら、著者は拡散反射率を省略して鏡面部分のみに焦点を合わせることにしました。たとえば、ランバート拡散反射を考えると、それを「改善された」ブリンと組み合わせる方法がわからないだけです-拡散部分と鏡面部分を追加するだけではもはや正しくないように思えるからです。
一部のシェーダーでは、関与するメディアの屈折率に基づいて、範囲0〜1の浮動小数点「フレネル項」が使用されているのを見ました。シュリックの近似が毎回使用されます:
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 );
}
このようにすると、フレネル項に基づいて拡散と鏡面反射の寄与を線形補間できます。たとえば、
float fresnel = schlick( L, H, 1.0002926 /*air*/, 1.5191 /*other material*/ );
vec3 color = mix( diffuseContrib, specularContrib, fresnel );
この論文では、著者はこのアプローチが正しくないことを述べています。これは、基本的にLがHに平行またはほぼ平行な場合に鏡面反射光の色を暗くするためです。屈折率に基づいてf0を計算する代わりに、鏡面反射光を扱う必要があります。それ自体をf0として色付けし、次のようにシュリック近似でvec3を計算します。
vec3 schlick( in vec3 v0, in vec3 v1, in vec3 spec )
{
return spec + ( vec3( 1.0 ) - spec ) * pow( dot( v0, v1 ), 5 );
}
その結果、鏡面反射光の色は、少し見ると白に近づきます。
私の質問は、これに拡散コンポーネントをどのように導入するのですか?90°では、鏡面反射の寄与は完全に白です。つまり、すべての入射光が反射されるため、拡散の寄与はありません。入射角が90°未満の場合、拡散部分全体に(vec3(1)-schlick)を乗算するだけでよいのですか?つまり、反射されない光の割合ですか?
vec3 diffuseContrib = max( dot( N, L ), 0.0 ) * kDiffuse * ( vec3( 1.0 ) - schlick( L, H, kSpec ) );
それとも完全に異なるアプローチが必要ですか?