Для вычисления текущих координат относительно центра дерева компоненты х и 2 возводятся в квадрат, а из полученных значений извлекается квадратный корень. Так вычисляется расстояние от центра дерева до текущего кольца. Затем оно умножается на RingFreq - коэффициент масштабирования, посредством которого можно задавать количество (большее или меньшее) колец на поверхности материала.
Затем создается функция, значение которой увеличивается от 0 до 1,0, а потом опять уменьшается до 0. К расстоянию прибавляются еще три октавы шума, чтобы материал выглядел волокнистым. Здесь можно вычислить и другие значения шума, но уже полученные тоже годятся. Получим дробную часть вычисленного значения, результат будет находиться в диапазоне [0, 1). Умножим это значение на 2,0 и получим функцию, значения которой будут входить в диапазон [0, 2). И наконец, вычтем 1,0 из тех значений, что больше 1,0, и получим искомую функцию, увеличивающуюся от 0 до 1,0, а потом уменьшающуюся обратно до нуля.
Эта «треугольная» функция понадобится для вычисления основного цвета фрагмента с помощью встроенной функции mix. Функция будет обеспечивать плавный линейный переход между цветами LightWood и DarkWood, основанный на вычисленном значении г.
Уже в результате этих вычислений получается неплохая функция, но попробуем еще улучшить ее имитацией незначительного эффекта зернистости распиленного дерева. (Читатель может и не разглядеть этот эффект на объектах, изображенных на цветном рис. 22.)
Нужно создать полоски, приблизительно параллельные оси у. Это делается сложением координат х и z, умножением результата на коэффициент GrainScale (еще одна uniform-переменная, значение которой можно изменять из приложения, чтобы контролировать частоту этого эффекта), добавлением 0,5 и отделением дробной части результата. Получается функция, значение которой находится в диапазоне [0, 1), но для значений по умолчанию GrainScale (27,0) и RingFreq (4,0) эта функция для г будет изменяться от 0 до 1,0 более часто, чем предыдущая. Можно было бы создать «волокна» просто линейным переходом от светлого цвета к темному, но попробуем применить более искусный способ. Значение г умножается на третью октаву шума - так оно увеличивается нелинейно - и сравнивается со значением GrainThreshold (по умолчанию 0,5). Если значение г меньше, чем GrainThreshold, текущий цвет меняется добавлением к нему значения, вычисленного перемножением значений LightWood, LightGrains и измененного значения шума. И наоборот, если значение г больше, чем GrainThreshold, текущий цвет меняется вычитанием из него произведения DarkWood, DarkGrains и измененного значения шума. (По умолчанию значение LightGrains 1,0, a DarkGrains 0, так что если г больше, чем GrainThreshold, цвет не изменится вообще.)
Можно поразвлечься и посмотреть, в результате чего изображение меняется. Возможно, есть простой способ добиться лучшего эффекта.
После того как цвет вычислен, остается умножить его на интерполированный коэффициент диффузного освещения и добавить значение прозрачности 1,0, чтобы получить окончательный цвет фрагмента. Результаты применения данного шейдера к трем различным объектам показаны на цветном рис. 22.