После того, как я некоторое время писал «стандартные» шейдеры phong & blinn, я недавно начал заниматься физическим шейдингом. Ресурс, который мне очень помог, - это заметки о курсе , особенно эта статья, в которой объясняется, как сделать блины более правдоподобными.
Я реализовал модель blinn, изложенную в статье, и мне очень нравится, как она выглядит. Наиболее существенным предложенным изменением (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 и сделайте, чтобы ваше приближение schlick вычислило 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 ) );
Или мне нужен совершенно другой подход?