MathsAndConcepts

Тригонометрия


Тригонометрия это наука о взаимосвязи между расстояниями и углами. И начинается она с 



cos(Ø) = a/h


sin(Ø) = o/h


tan(Ø) = o/a



Угол измеряется в радианах, они по умолчанию являются единицами измерения углов в Shading Language. Взаимосвязь между радианами и градусами очень простая:


180 градусов = PI радиан = 3.141593 радиан


Знаете ли вы, что комбинируя функции sin и cos вы можете получить круг? Следующая пара уравнений делает именно это. Они называются параметрическими уравнениями круга:


x = radius * cos(Ø)
y = radius * sin(Ø)


где Ø это угол вращения вокруг круга. Используя эту пару уравнений, Вы можете легко вращать текстуру, например.



Вектора


Большинство людей знакомы с концепцией, в которой число обозначает «величину» или «множество». Математически, такие числа относят к типу объектов, названных скалярами. Скаляры очень удобны для подсчета расстояний, температур и т.д. Но есть много типов величин, которые не могут быть полностью отображены только скалярами. Сила, например, имеет величину и направление – она принадлежит к классу объектов, названных векторами. В основном, когда вы имеете дело с направлениями, вы должны о них думать как о векторах.



Вектора это 3D объекты, но у них нет определенных позиций. На иллюстрации все голубые вектора идентичны. Помните, что вектора описывают только свои длины и направления.


Как показано на иллюстрации, любой вектор может быть записан как (x, y, z), где, если вы поместите начало вектора в центр координат, три соответствующие координаты будут указывать на конец вектора.


Существует специальный тип вектора, называемый нормалью, который отображает перпендикуляр к поверхности в определенной точке. Особенность нормали заключается в том, что это не независимый вектор, он привязан к точке на поверхности.



Простая векторная арифметика






Если A = vector (a, b, c) и B = vector (x, y, z), тогда A + B равно vector (a+x, b+y, c+z), A – B равно vector (a-x, b-y, c-z), и 2*A + B равно vector (2*a+x, 2*b+y, 2*c+z)


существует специальная функция normalize(), которая возвращает вектор длиной в 1, но указывающий в том же направлении, что и исходный вектор.


Как умножать вектора


Существует два типа умножения векторов, первый, который называется скалярное произведение (dot product), возвращает скалярное значение, а второй, который называется называется векторное произведение (cross product), возвращает вектор. В SL скалярное произведение обозначается как . (точка), а векторное как ^ (крышка)



A. B = a*x + b*y + c*z = length(A) * length(B) * cos(Ø)


Скалярное произведение удобно использовать для вычисления угла между двумя векторами: если оба A и B единичной длины,
тогда A. B дает в результате cos(Ø). Таким образом угол между двумя векторами равен acos(normalize(A).normalize(B)).


A ^ B возвращает вектор который перпендикулярен к A и B, и длина которого равна
length(A)*length(B)*sin(Ø). В левостороннем пространстве (пространство, используемое по умолчанию в
Prman), используйте правило левой руки, чтобы определить направление вектора, полученного в результате векторного произведения.
Это значит, что A ^ B не равно B ^ A, потому что результатом будут вектора, направленные в противоположные стороны.
Векторное произведение обычно используется для нахождения нормали поверхности.



Почему вектора так важны для шейдинга?


Шейдинг, в основном, есть некоего рода игра с направлениями. Например, широко известный диффузный шейдинг – это просто
normalize(N).normalize(L), где N – нормаль в точке шейдинга, а L – направление луча от поверхности к источнику света.


Дальше приведены некоторые готовые примеры с использованием скалярного произведения:





Текстура, похожая на облака – это фрактал, аналогичный применённому в этом шейдере (bumpy shader), но примененный в данном случае к прозрачности поверхности сферы.


Скалярное произведение (в третьем снизу выражении) размывает границы сферы, как показано выше.
Так как Inm и Nnm оба являются векторами единичной длины, то Inm.Nnm? возвращает косинус угла между ними.
Это значение изменяется от 1 (в центре сферы) до 0 (на краю).


В следующем примере скалярное произведение позволяет определить видимую сторону патча; таким образом,
вы можете назначить различные текстуры на обе стороны.




Пространства



Для написания шейдеров вы должны знать, как использовать различные пространства в шейдинге.
Пространство – это координатная система, в которой измеряются 3Д точки. На изображении слева
координаты точек зависят от того, в каком пространстве (мировом или объекта) они измеряются.


Другой способ понять концепцию: пространство это нечто на подобие транформ ноды в Maya –
когда вы определяете переменные точку, вектор или нормаль, вы можете привязать их к пространству; когда пространство
перемещается, переменная будет двигаться вместе с ним. Это как парентинг точки/вектора/нормали к пространству.
Например, чтобы привязать точку к мировому пространству, вы можете сделать следующее:


point mypoint = point “world” (10.2, 2.3, 11.1);


В таблице ниже приведён список пространств, наиболее часто используемых в Renderman.


ПространствоЗначение
shaderТочка в RIB где описан шейдер.
worldСразу после описания WorldBegin.
cameraМежду описанием Display и WorldBegin в RIB.
objectТочка в RIB, где описан объект.
currentПространство, в котором проводится большинство 3D вычислений. Когда Вы определяете точку/вектор/нормаль без указания определенного пространства, она оказывается в этом пространстве. Пространством current для PRman является пространство camera, а в BMRT это пространство world.
NDCНормализованое пространство координат устройства, где x и y лежат в пределах от (0, 0) в левом верхнем углу экрана до (1, 1) в нижнем правом углу.

Вы также можете определить свою собственную систему координат в RIB, написав следующее:


CoordinateSystem «имя_пространства»


где имя_пространства это любая строка. Будьте осторожны, чтобы случайно не переназначить одно из пространств, описанных в таблице. После того, как вы назвали пространство, вы можете использовать его так же, как и любое другое. Например, вы можете инициализировать им точку в вашем шейдере:


point mypoint = point “spacename” (10.2, 2.3, 11.1);


В Shading Language вы можете перемещать точки, вектора и нормали из одного пространства в другое, используя функции transform, vtransform или ntransform. Следующий пример показывает, как эти три функции должны быть использованы.


point newpoint = transform( “current”, “object”, oldpoint );
/* перейти в пространство “object”. Это же действие может быть записано как point newpoint = transform(«object”, oldpoint);
пропущенное первое пространство будет установлено в “current” */


vector newvector = vtransform( “object”, “world”, oldvector );


normal newnormal = ntransform( “NDC”, oldnormal );
/* также, как и выше, перемещаемся из “current” */


Важно держать в уме пространства, в которых находятся Ваши точки и вектора. Обычно Вы не должны смешивать в вычислениях точки/вектора из разных пространств, и Shading Language помогает Вам в этом, трансформируя Ваши точки/вектора в пространство “current”. Например, если вы присвоили point “object” (0,0,1) переменной, PRMan немедленно трансформирует точку в пространство “camera”, и переменная не будет больше содержать значения (0,0,1), но это будет другая тройка xyz, которые вычислены относительно положения камеры. Так что


point mypoint = point “object” (0, 0, 1);
color mycolor = color mypoint;


не сделает mycolor синим, но


point mypoint = transform(«object», point “object” (0,0,1));
color mycolor = color mypoint;


сделает.


Шум





Шум это одна из наиболее часто используемых функций в Shading Language. Она может быть записана в одной из следующих форм, которые генерируют одно-, двух-, трех- и четырехмерный шум соответственно:


[float|color|point] noise( float u )
[float|color|point] noise( float u, v )
[float|color|point] noise( point pt )
[float|color|point] noise( point pt, float t )


Существует также несколько специальных функций шума, названных cellnoise() и pnoise() – мы поговорим о них чуть позже, после того, как мы усвоим основную концепцию шума.


Во-первых, вы должны заметить, это то что кривая шума представляет собой синусоидальную кривую с неповторяющейся частотой и амплитудой на всей длине. Во-вторых, амплитуда кривой равна 0.5 на целых значениях чисел. И наконец, амплитуда кривой в основном варьируется в пределах 0.3 – 0.7, и никогда не уходит ниже 0 или больше чем 1. Итак, шум может генерировать плавное изменение между числами и является хорошей основой для построения многих хаотических шумов в природе.


Применяя к функции простые арифметические операции, вы можете получить интересные вариации шума:









Функция cellnoise имеет такой же синтаксис, как и noise, но возвращает не плавно изменяющееся
значение, а случайные числа (от 0 до 1), когда ее аргумент изменяется шагом в целое число (integer).


Pnoise (periodic noise) – просто шум, который повторяется в интервале period. Его синтаксис:


[float|color|point] pnoise( float u, uniform float period )
[float|color|point] pnoise( float u, float v, uniform float uperiod, uniform float vperiod )
[float|color|point] pnoise( point pt, uniform point pperiod )
[float|color|point] pnoise( point pt, float t, uniform point pperiod, uniform float tperiod )


Повторяющиеся функции


Предположим, у вас есть функция fn(x); вы можете сделать ее периодической, повторяя x. Стандартный метод
повторения числа состоит в применении к нему функции mod(a,b), которая возвращает остаток от деления a на b.





Пример использования данного метода можно увидеть в checker shader.


Различные функции




step( a, b ) возвращает 0, если b меньше чем a, или 1, если b больше чем a.
Используется как замена конструкции if.


smoothstep( a, b, c ) возвращает 0, если c меньше чем a, 1, если c больше чем b,
или плавно изменяет значение между 0 и 1 если c между a и b. Это простая функция может быть использована
для генерации сглаженных текстур. Например, она используется для создания мягких краев в [http://cade.scope.edu/courseware/notes/renderman_blk/light.html#spot spotlight shader]].


mix( color1, color2, index ) возвращает color1, если index равен 0, color2, если index
равен 1, и смешивает два цвета, если index между 0 и 1. На самом деле вы также можете смешивать
пару флоатов, точек, нормалей или векторов. В любом случае, index должен быть величиной типа float от 0 до 1.
Функцию mix можно использовать для окрашивания результатов функций step или smoothstep.


Полный список функций Shading Language можно найти в спецификации Renderman.