Хочу прикрутить в квест шейдер с моделью освещения Орена-Наяра.
http://wiki.gamedev.net/index.php/D3DBook:%28Lighting%29_Oren-Nayar (http://wiki.gamedev.net/index.php/D3DBook:%28Lighting%29_Oren-Nayar)
Никак не могу победить косяки на объекте. Может у кого получалось реализовать под квест эту модель освещения?
на вскидку - нет добротного тангент спейса
наложи на бублик кубовый анврап 1*1*1
Решил проблему, вот такой вот должен быть пиксельный шейдер:
float3 N = normalize(IN.wnormal);
float3 L = normalize(IN.LightVector);
float3 V = normalize(IN.EyeVector);
float NdotL = dot(N,L);
float NdotV = dot(N,V);
float alpha = max(acos(NdotL), acos(NdotV));
float beta = min(acos(NdotL), acos(NdotV));
float gamma = dot(V - N * NdotV, L - N * NdotL);
float Roughness1 = 1.0;
float roug_sq = Roughness1 * Roughness1;
float A = 1.0 - 0.5 * (roug_sq / (roug_sq + 0.33));
float B = 0.45 * (roug_sq / (roug_sq + 0.09));
float3 diffuse = max (NdotL, 0.0) * DiffuseColor * (A + B * max(0.0, gamma) * sin(alpha) * tan(beta));
float3 result = diffuse;
return float4(result,1);
тангент и битангент не используем
а если потребуется выпонить рельефное текстурирование (нормал бамп/параллакс/ POM и т.д)? или анизотропное освещение (волосы например)?
лучше сделай хороший анврап
ибо
тангент спейс расчитывается по приращению тексурных
координат соседних точек и также их приращению позиции.
хороший анврап залог хорошего просчёта пространства касательных.(уж сколько людей на эти грабли наступали :D)
а вот и твой пример бублика из "0" поста с применённым кубовым анврапом.
Ну если требуется, то можно и с тангент/бинормал, суть не в этом.
Косяк крылся в формуле и я ее исправил, хотя она и сейчас далека от идеала.
Вот так будет выглядеть более-менее грамотная модель освещения Орен-Наяр:
const float PI = 3.14159f;
float3 N = normalize(IN.wnormal );
float3 L = normalize(IN.LightVector);
float3 V = normalize(IN.EyeVector);
float NdotL = dot(N,L);
float NdotV = dot(N,V);
// Compute the other aliases
float alpha = max(acos(NdotV), acos(NdotL));
float beta = min(acos(NdotV), acos(NdotL));
float gamma = dot(V - N * NdotV, L - N * NdotL);
float Roughness = 1.0;
float rough_sq = Roughness * Roughness;
float C1 = 1.0 - 0.5 * (rough_sq / (rough_sq + 0.33));
float C2 = 0.45 * (rough_sq / (rough_sq + 0.09));
if( gamma >= 0 )
{
C2 *= sin(alpha);
}
else
{
C2 *= (sin(alpha) - pow((2 * beta) / PI, 3));
}
float C3 = (1.0 / 8.0) ;
C3 *= (rough_sq / (rough_sq + 0.09));
C3 *= pow((4.0 * alpha * beta) / (PI * PI), 2);
float A = gamma * C2 * tan(beta);
float B = (1 - abs(gamma)) * C3 * tan((alpha + beta) / 2.0);
float3 final = DiffuseColor * max(0.0, NdotL) * (C1 + A + B);
return float4(final, 1.0);
ЦитироватьКосяк крылся в формуле и я ее исправил
и в анврапе также, я открыл твой пример с 0 поста, наложел кубовый анврап и всё исправилось.
Ну и одно замечание:
шейдер очень толстый при большом кол-ве ИС и если в добавок форвард рендеринг (с большим овердравом), то о высоком ФПС лучше не мечтать.
Лучше использовать старый Фонга или метод освещения из (Half-Life2) "Пол Ламберта". ::)
Вот тут много бумажек от Валв
про ПолЛамберта можно посмотреть пэпер за 2004 год.
http://www.valvesoftware.com/company/publications.html
Речь идет о диффузной модели освещения, причем тут фонг?
Пол-Ламберта это так:
float3 diffuse = max(dot(N,L), 0.0);
diffuse = diffuse*0.5+0.5;
diffuse *= diffuse;
правильно ли я понял?
ЦитироватьРечь идет о диффузной модели освещения, причем тут фонг?
http://ru.wikipedia.org/wiki/Затемнение_Фонга не?
вроде дифузнее некуда
Цитироватьправильно ли я понял?
ага
только зачем тут мах ??
float3 diffuse = max(dot(N,L), 0.0);
для гарантии от отрицательных значений
можно конечно и saturate(dot(N,L)) ну конечно можно и просто dot(N,L) раз ты оптимизируешь код дальше некуда
Цитироватьдля гарантии от отрицательных значений
:D
ПолЛамберта - это физически не коректная модель "мягкого" освещения.
И те грани , которые направлены в противоположенную сторону вектора направления ИС и надо чуть-чуть подсветить.
этими
max(dot(N,L), 0.0); или saturate(dot(N,L)) ты просто режешь результат по отрицательным значениям
и что дальше?
дальше мы отрезанное умножаем на 0,5, график функции сожмётся в 2 раза
далее мы прибавляем 0,5 и у нас этот график поднимется на половину по всему спектру...
это значит , что все что ты отрезал окрасится в половинный цвет (если ИС белый, то результат будет серым 127 127 127 )
затем мы это всё возводим в квадрат, немного смягчив результат
посчитаем , что при этом на задних поликах.. 0,5*0,5 = 0,25
Вобщем лажа получится!!
Надо так и только так:
Цитироватьfloat3 diffuse = dot(N,L);
diffuse = diffuse*0.5+0.5;
diffuse *= diffuse;
Ах да точно ;D
Немножко ступил, сенкс!