Как реализовать ламбертовское затенение

Я работаю над трассировкой лучей, используя C++ и OpenGL (glDrawPixels), и пока все идет хорошо. Тем не менее, мое затенение кажется немного неправильным. Я хочу, чтобы мои сферы выглядели более гладкими, без резких линий между уровнями интенсивности. На данный момент я просто пытаюсь реализовать ламбертовское затенение, то есть Intensity = Id * pd * (N dot L). Я знаю, как мне нужно рассчитать (N dot L) путем нормализации вектора нормали и вектора света, но как насчет Id и pd (диффузная интенсивность и коэффициент пропорциональности)? Я просто использую постоянное значение 2,5 для достижения следующего:

(Вот изображение того, как выглядит мое затенение)

Очевидно, что 2.5 совершенно произволен, и я использую его только потому, что другие мои попытки даже не напоминали правильное затенение. Уравнение выше, кажется, предполагает, что я должен умножить цвет на интенсивность. Это мой метод:

Color simpleIlluminate(Vector3D normal, Vector3D light, Color color) {
    float intensity = dotProduct(normal, light)*2.5f;
    color = Color((unsigned int)intensity*color.r, (unsigned int)intensity*color.g, (unsigned int)intensity*color.b);
    return color;
}

Предположим, что вектор нормали и вектор света верны. Color — это просто созданная мной цветовая структура, которая имеет целое число без знака для каждого из значений RGB. Параметр Color color — это цвет сферы, которую я хочу затенить, например. красный = цвет (255,0,0). Чтобы изменить интенсивность цвета, я просто умножаю каждое значение на вычисленную интенсивность, но при запуске это выглядит неправильно.

Может ли кто-нибудь объяснить, чего мне не хватает, и показать мне, как должна выглядеть правильная функция с учетом векторов и цвета сферы? Я искал везде, но я не могу найти хорошее решение. Возможно, я также неправильно выполняю преобразование float в unsigned int, но я не уверен. Любая помощь приветствуется.


person adamrob9    schedule 06.10.2016    source источник
comment
Возможно, вам потребуется внести поправку на гамму. Масштабируйте значения RGB в степени 2,2. Вычисленная интенсивность является линейной, но значения RGB регулируются так называемой гаммой. Проверьте sRGB в вики. Кроме того, убедитесь, что самые яркие значения RGB поверхности меньше 255, иначе они будут обрезаны.   -  person doug    schedule 07.10.2016


Ответы (2)


Я бы удалил этот коэффициент 2,5, так как он, вероятно, искажает результаты, и это вполне может привести к полосам, поскольку вы увеличиваете коэффициент за пределами диапазона 0 и 1.

Ламбертовское отражение также известно как косинусное отражение, и его очень просто понять. Рассмотрим плоскость, если бы свет был перпендикулярен плоскости, то весь свет падал бы на поверхность (100% или коэффициент 1,0). Если бы свет был направлен параллельно этой плоскости, то на поверхность упало бы 0 световых лучей (все лучи света параллельны и, следовательно, никогда не пересекают плоскость, поэтому коэффициент или 0).

Коэффициент отражения по Ламберту представляет собой просто косинус угла между направлением света и нормалью к поверхности и находится в диапазоне от 0 (свет не падает на плоскость) до 1,0 (весь свет падает на плоскость). Обратите внимание, что косинус (90) = 1. Косинус (0) = 0, поэтому он называется законом косинуса (отражательная способность Ламберта).

person lfgtm    schedule 10.10.2016

Я также мог бы неправильно выполнять преобразование float в unsigned int

Точно. (unsigned int)intensity*color.r эквивалентно ((unsigned int)intensity)*color.r. Таким образом, ваша интенсивность принимает дискретные уровни, прежде чем умножается на цвет, что приводит к появлению этих линий. Вместо этого попробуйте (unsigned int)(intensity*color.r).

person Quinchilion    schedule 10.10.2016