Добрый вечер. Делаю PathTracer и столкнулся с проблемой:
для расчета теней
прямого освещения я получаю для каждого пикселя его освещенность по формуле:
return emissionColor // RGB(255, 255, 255)
.scale(lightPower - rayLine.getLength() * (lightPower / fadeRadius)) // затухание с увеличением расстояния
.scale(lambertCos); // 0 - 1
В данном коде:
- lightPower - сила источника света (в примере - 2)
- rayLine.getLength() длина луча от точки, для которой рассчитываем освещенность до случайной точки на источнике света (для рассеянных теней)
- fadeRadius - расстояние с которого свет от источника света полностью затухает
lambertCos - рассчитывается по формуле
0 - Vector.dot( // 0 - специально, что бы было заметно отрицательное число
lightDirection, // вектор из точки, для которой рассчитываем освещенность, к источнику света, <b>нормализованный</b>
intersection.getNormal() - нормаль точки, для которой рассчитываем освещенность
);
Возьмем сцену - куб, верхняя плоскость куба - источник света.
С вышеприведенными формулами куб освещается корректно.
Затем возьмем верхнюю плоскость, сожмем её в 2 раза по ширине и длине и опустим, например, до середины куба.
Появится косяк, который виден на изображении - абсолютно резкий переход из тени в свет в точках, расположенных на близком расстоянии к плоскости источника света.
Что бы это устранить, будем умножать освещенность еще и на угол между направлением луча из точки, для которой рассчитываем освещенность, и нормалью на источнике света.
surfaceCost = Vector.dot(
lightDirection,
shadowRay.getNormal() // нормаль в точке пересечения луча в точке на источнике света
);
return emissionColor // RGB(255, 255, 255)
.scale(lightPower - rayLine.getLength() * (lightPower / fadeRadius)) // затухание с увеличением расстояния
.scale(lambertCos) // 0 - 1
.scale(surfaceCos); // 0 - 1
Результат станет таким, каким нужно, будет выглядеть процентов на 90, как на этой картинке
На картинке видно, что если источник света не занимает всю поверхность потолка, то он дает легкое затенение на стенах под потолком.
Ну а теперь проблема:
растянем источник света вновь до размеров всего потолка - как результат затенение под источником света все равно останется, т.к. лучи в затененных участках по прежнему будут находиться пол сильным углом к нормали источника света.
Вот как это выглядит (слева сверху)
Я пытался привязать surfaseCos к расстоянию между точкой на поверхности и точкой на источнике света:
surfaseCos = 1 - (surfaseCos * (rayline.getDist() * fadeRadius))
но почему то результат все равно не правильный. На последней картинке, теней на красной стене под ИС быть не должно, а на белой стене они должны появляться сначала резкими, затем становиться все более размытыми, как только ИС начинает удаляться от стены (сужаться), опускаться вниз.
Вообщем - есть у кого какие идеи по моей проблеме?