10.4.3. Фрагментный шейдер

В листинге 10.6 показан фрагментный шейдер, который используется для наложения карты среды.

Листинг 10.6. Фрагментный шейдер для наложения карты среды

const vec3 Xunitvec = vec3 (1.0. 0.0. O.Q); const vec3 Yunitvec = vec3 (0.0. 1.0, 0.0);

uniform vec3 BaseColor; uniform float MixRatio:

uniform sampler2D EnvMap; // = 4

varying vec3 Normal; varying vec3 EyeDir; varying float Lightlntensity;

void main (void)

{

// Вычислить вектор отражения

vec3 reflectDir = reflect (EyeDir. Normal):

// Вычислить углы возвышенности и азимута

vec2 index:

index.у = dot(norraalize(reflectDir). Yunitvec); reflectDir.y =0,0:

index.x = dot(noruialize(ref1ectDir), Xunitvec) * 0.5: // Привести значения index к правильному диапазону

if (reflectDir.z >= 0.0)

index = С index + 1,0) * 0.5; else {

index.t - (index.t + 1.0) * 0.5: index.s ” (-index.s) * 0.5 + 1.0:

}

// если reflectDir.z 2 0.0. s будет находиться в диапазоне от 0,25 // до 0.75

// если reflectDir.z < 0,0, s будет находиться в диапазоне от 0,75 до 1,25.

// и это нормально, так как установки текстуры позволяют это

// Выполнить поиск в карте среды.

vec3 envColor = vec3 (texture2D(EnvMap. index)):

// Добавить освещение в базовый цвет и смешать

vec3 base - Lightlntensity * BaseColor; envColor - mix(envColor. base. MixRatio);

gl^FragColor - vec4 (envColor, 1.0):

}

Varying-переменные Normal и EyeDi r - это значения, вычисленные вершинным шейдером и затем интерполированные в пределах примитива. Чтобы получить действительно точные результаты, нужно опять нормализовать значения во фрагментном шейдере, Исключение нормализации немного улучшит производительность, но ухудшит качество; для некоторых объектов это приемлемо.

Константы Xunitvec и Yunitvec установлены в значения, необходимые для вычисления углов возвышения и азимута. Сначала нужно вычислить угол возвышения путем нормализации вектора reflectionDi г и выполнения операции dot над Vunitvec. Так как оба вектора являются единичными, это дает значение косинуса для нужного угла, значение которого колеблется в пределах [-1,1]. Установка компонента у вектора отражения в 0 приведет к отображению этого вектора на плоскость XZ. Нормализация нового вектора дает косинус угла азимута, значение которого колеблется в пределах [-1,1]. Так как горизонтальное направление текстуры среды охватывает все 360°, умножаем это значение на 0,5, так что результат будет находиться в пределах половины карты среды. Теперь нужно определить, что же это за половина.

Если компонент г направления отражения является положительным, направление отражения - от передней стороны, и вычисленное значение будет использоваться непосредственно. Значения масштабируются и смещаются, так что при доступе к текстуре значения s будут находиться в диапазоне [0,25, 0,75], а значения £ - в диапазоне [0, 1].

Если компонент z отрицательный, расчеты будут несколько иные. Значение i вычисляется таким же образом, как и в предыдущем случае, но значение 5 масштабируется и сдвигается так, что оказывается в диапазоне [0,75, 1,25]. Впоследствии эти значения можно будет использовать непосредственно, так как для текстуры установлен режим GL REPEAT. Значения s, лежащие в промежутке от 1,0 до 1,25, будут отображаться на s, находящиеся в промежутке от 0 до 0,25 в настоящей текстуре (трюк, упомянутый ранее). Таким образом, доступ к текстуре в целом будет организован правильно, в зависимости от направления отражения. Можно сравнивать s с 1,0 и, если его значение больше 1,0, вычитать из него 1,0, но для этого нужно . будет выполнять дополнительные операции, что повлияет на производительность. Используя трюк режима повтора, можно оставить эти вычисления для аппаратного обеспечения.


⇐ вернуться назад | | далее ⇒