Pull to refresh

Comments 9

В качестве спектра, я так понимаю, взят Zucconi6, но ведь реальная спектральная картина зависит от цвета источника света. Если на диск светить светодиодом, то у нас будет дырявый спектр, в котором, в зависимости от цвета и качества, будут сильные пики красного, синего и зеленоватого цвета — и полностью отсутствовать все промежуточные значения. И картинка на диске, соответственно, тоже будет дырявой.

Иными словами, следующий шаг реализма — получить значение света (хотя бы RGB) в точке отражения и использовать его как вес для спектральной функции. Тогда можно будет увидеть зелёные блики от зелёного фонаря и красно-синие — от розового.
В общем случае нужно считать отдельно для как можно большего количества длин волн в видимом диапазоне, и после рассчётов переводить в XYZ численным интегрированием с учётом спектра источника. XYZ потом переводится в линейный sRGB умножением на матрицу. Подынтегральное выражение — чувствительность глаза (таблица значений CIE1931, которые полстатьи пытались аппроксимировать, cvrl.ioo.ucl.ac.uk/cmfs.htm), умноженное на спектр, получившийся после вычислений, которые в свою очередь зависят от спектра источника света (нет цвета в спектре источника — вычисления умножаются на ноль). Второй множитель дорого считать в шейдере для большого количества длин волн, и обычно обходятся тремя длинами волн, которые потом нужно интерполировать при интегрировании. У меня в шейдере выглядит как-то так:
float3 xyz = 0;
for (float j = 0; j < 64; j += 1) {
	float intensity = InterpolateLambdaNm(5.0*j+390, /*массив значений после рассчётов для нескольких длин волн*/);
	xyz += intensity * cie_colour_match_2012_2deg_390_705_5[j];
}
finalColor = mul(xyz_to_linear_srgb, xyz*5.0);

Нет, вы не поняли. Вопрос не в функции спектра, а в том, что источники света имеют, в общем случае, произвольную спектрограмму, которую, в добавок, аппроксимируют через свечение в значениях RGB. Из этого более реалистичной картинки без переписывания движка мы не получим.

Но я не об этом, я о том, что
color += gi.light.color * spectral_zucconi6(wavelength); 
// Стыдно, не знаю, нормирован ли вектор цвета, будем считать, что да

для получения таких картинок
image

Промахнулся, ответил отдельной веткой

Повторюсь, это верно для источников света со сложным спектром, а в юнити всё RGB. Так что даже если мы попытаемся биться головой об пол, в итоге получим то же самое RGB, либо с шумом, либо с мыльцом.
Хотя, если мы перейдём к одномерным текстурам спектра, то сможем и дёшево их пришивать к игровым объектам (как освещению, так и материалу), и достаточно дёшево их умножать, ведь для пары тип_освещения-тип_материала это нужно будет сделать единожды, и добавить перделок, как, например, эффект Доплера.
Но я этого, того, размечтался. Я, в конце концов, шейдеры не колупал и понятия не имею, как это делается.
Шейдеры можно писать как угодно, просчитывать процесс прохождения луча хоть с точностью в нанометр, главное в конце пиксельного шейдера выдать правильный цвет. Ну и данные о спектре источника хранить отдельно где-то конечно и передавать в шейдер, по умолчанию везде rgb.

дномерным текстурам спектра, то сможем и дёшево их пришивать к игровым объектам (как освещению, так и материалу), и достаточно дёшево их умножать

Дёшево не выйдет, так как вычисления придётся проводить отдельно для каждой моделируемой длины волны и в конце переводить в RGB. Хотя наверное можно предрассчитать всё для каждой длины волны и угла отражения и положить в 2D текстуру.

Я упоминал, но видимо слишком туманно :) Берем длины волн, для которых будем всё считать, и интенсивности излучения источника света на этих же длинах волн. Выйдет примерно так в цикле:
float[iLambda] result = getLightIntensity(iLambda)*calculateSomethingLikeCDreflectionAtWawelength(iLambda);
В статье всего три длины волны, и для сложного спектра понятно что этого слишком мало. result потом подставляется в InterpolateLambdaNm из моего предыдущего комментария. getLightIntensity() — возвращает значение спектрограммы источника света для данной длины волны. У автора там просто значения интенсивностей для rgb, что маловато для сложного спектра. tldr: нужно считать всё для большого количества длин волн, особенно если спектр источника сложный, но так как это дорого, то обычно считают для трёх длин волн примерно соответствующих rgb значениям, что "прокатывает" для равномерного спектра.

приблизительно 299 792 458 метров в секунду

точно 299 792 458 метров в секунду — см. определение метра.

Only those users with full accounts are able to leave comments. Log in, please.