510 likes | 714 Views
Визуальные эффекты на GPU Стандартные модели освещения - Гуро. 1. Падающий равномерно рассеивается по всем направлением верхней полусферы 2. Энергия, уходящая в заданном направлении пропорциональна только плотности световой энергии, падающей в данную точку.
E N D
Визуальные эффекты на GPUСтандартные модели освещения - Гуро 1. Падающий равномерно рассеивается по всем направлением верхней полусферы 2. Энергия, уходящая в заданном направлении пропорциональна только плотности световой энергии, падающей в данную точку
Визуальные эффекты на GPUСтандартные модели освещения - диффузная n - вектор нормали в точке Р v - вектор на наблюдателя l - вектор на источник света Уравнение освещенности:
Визуальные эффекты на GPUСтандартные модели - освещение по Блинну h - бисектор векторов l и v Уравнение освещенности:
Визуальные эффекты на GPUСтандартные модели - освещение по Блинну - цвет поверхности - цвет источника света - вклад фонового освещения - вклад диффузной освещенности - вклад бликовой освещенности - гладкость поверхности
Визуальные эффекты на GPUСтандартные модели - освещение по Блинну struct VertexData { float4 pos : POSITION; float2 texCoord : TEXCOORD0; float3 n : NORMAL; }; struct FragmentData { float4 pos : POSITION; float2 texCoord : TEXCOORD0; float3 n; float3 l; float3 h; float3 v; }; Вход вершинной программы Вход фрагментной программы
Визуальные эффекты на GPUОсвещение по Блинну. Вершинная программа FragmentData main ( VertexData IN, uniform float4 lightPos, uniform float4 eyePos, uniform float4x4 mvp, uniform float4x4 mv, uniform float4x4 mvi ) { FragmentData OUT; float3 p = mul ( mv, IN.pos ).xyz; OUT.n = mul ( mvi, float4 ( IN.n, 0 ) ).xyz; OUT.l = normalize ( lightPos.xyz - p ); OUT.v = normalize ( eyePos.xyz - p ); OUT.h = normalize ( OUT.l + OUT.v ); OUT.pos = mul ( mvp, IN.pos ); OUT.texCoord = IN.texCoord; return OUT; }
Визуальные эффекты на GPUОсвещение по Блинну. Фрагментная программа float4 main ( FragmentData IN ) : COLOR { const float4 diffColor = float4 ( 0.5, 0.0, 0.0, 1.0 ); const float4 specColor = float4 ( 0.7, 0.7, 0.0, 1.0 ); const float specPower = 30.0; float3 n2 = normalize ( IN.n ); float3 l2 = normalize ( IN.l ); float3 h2 = normalize ( IN.h ); float4 diff = diffColor * max ( dot ( n2, l2 ), 0.0 ); float4 spec = specColor * pow ( max ( dot ( n2, h2 ), 0.0 ), specPower ); return diff + spec; }
Визуальные эффекты на GPUСтандартные модели - освещение по Фонгу r - отражение вектораv относительно нормали n Уравнение освещенности:
Визуальные эффекты на GPUСтандартные модели - освещение по Фонгу
Визуальные эффекты на GPUОсвещение по Фонгу. Вершинная программа FragmentData main ( VertexData IN, uniform float4 lightPos, uniform float4 eyePos, uniform float4x4 mvp, uniform float4x4 mv, uniform float4x4 mvi ) { FragmentData OUT; float3 p = mul ( mv, IN.pos ).xyz; OUT.n = mul ( mvi, float4 ( IN.n, 0 ) ).xyz; OUT.l = normalize ( lightPos.xyz - p ); OUT.v = normalize ( eyePos.xyz - p ); OUT.pos = mul ( mvp, IN.pos ); OUT.texCoord = IN.texCoord; return OUT; }
Визуальные эффекты на GPUОсвещение по Фонгу. Фрагментная программа float4 main ( FragmentData IN ) : COLOR { const float4 diffColor = float4 ( 0.5, 0.0, 0.0, 1.0 ); const float4 specColor = float4 ( 0.7, 0.7, 0.0, 1.0 ); const float specPower = 30.0; float3 n2 = normalize ( IN.n ); float3 l2 = normalize ( IN.l ); float3 v2 = normalize ( IN.v ); float3 r = reflect ( -v2, n2 ); float4 diff = diffColor * max ( dot ( n2, l2 ), 0.0 ); float4 spec = specColor * pow ( max ( dot ( l2, r ), 0.0 ), specPower ); return diff + spec; }
Визуальные эффекты на GPUBumpmapping При использовании описанных моделей освещения поверхности получаются слишком гладкими Хочется добавить микрорельеф, не изменяя при этом саму геометрию объектов L Попробуем просто в каждой точке отклонять вектор нормали. Тогда изменится освещенность в точке и создастся иллюзия микрорельефа J
Визуальные эффекты на GPUBumpmapping n - истинный вектор нормали n’ - искаженный вектор нормали
Визуальные эффекты на GPUBumpmapping Результат искажения нормалей - при рендеринге обычного тора было произведено искажение векторов нормали
Визуальные эффекты на GPUBumpmapping ? - в каком пространстве задавать искажения вектора нормали n ! - будем задавать в искажения вектора (точнее, сам вектор нормали n) в пространстве “приклеенном” к выводимой грани
Визуальные эффекты на GPUBumpmapping Для каждой грани определим следующие попарно ортогональных единичных вектора t - касательный вектор к грани n - нормаль грани b - бинормаль (b = [n,t]) Эта тройка векторов образует ортонормированный базис в пространстве и, соответственно, систему координат, называемую касательной (tangent space)
Визуальные эффекты на GPUBumpmapping Как кодировать искажения нормали - переведем единичный вектор нормали (в касательном пространстве) в цвет и поместим в текстуру Неискаженная нормаль в касательном пространстве всегда равна n=(0,01)
Визуальные эффекты на GPUBumpmapping • Вершинная программа: • вычислить вектора l, v, h (или r) • перевести их в касательное пространство • передать фрагментной программе вычисленные вектора и текстурные координаты • Фрагментная программа: • нормировать вектора l, v, h (или r) • взять из карты нормалей нормаль • перевести нормаль из RGB-представления • вычислить освещенность с использованием полученного вектора нормали и векторов l, v, h (или r)
Визуальные эффекты на GPUBumpmapping - передаваемые данные struct VertexData { float4 pos : POSITION; float2 texCoord : TEXCOORD0; float3 n : NORMAL; float3 t : TEXCOORD1; float3 b : TEXCOORD2; }; struct FragmentData { float4 pos : POSITION; float2 texCoord : TEXCOORD0; float3 lt; float3 ht; };
Визуальные эффекты на GPUBumpmapping - вершинная программа FragmentData main ( VertexData IN, uniform float4 lightPos, uniform float4 eyePos, uniform float4x4 mvp, // modelview*projection uniform float4x4 mv, // modelview uniform float4x4 mvi ) { FragmentData OUT; float3 p = mul ( mv, IN.pos ).xyz; float3 l = normalize ( lightPos.xyz - p ); float3 v = normalize ( eyePos.xyz - p ); float3 h = l + v; float3 n = mul ( mvi, float4 ( IN.n, 0 ) ).xyz; float3 t = mul ( mvi, float4 ( IN.t, 0 ) ).xyz; float3 b = mul ( mvi, float4 ( IN.b, 0 ) ).xyz; OUT.pos = mul ( mvp, IN.pos ); OUT.texCoord = IN.texCoord; OUT.lt = float3 ( dot ( l, t ), dot ( l, b ), dot ( l, n ) ); OUT.ht = float3 ( dot ( h, t ), dot ( h, b ), dot ( h, n ) ); return OUT; }
Визуальные эффекты на GPUBumpmapping - фрагментная программа float4 main ( FragmentData IN, uniform sampler2D bumpMap, uniform sampler2D diffuseMap ) : COLOR { const float4 specColor = float4 ( 1, 1, 1, 1 ); float3 n = tex2D ( bumpMap, IN.texCoord ).xyz; float3 nt = normalize ( 2.0*n - 1.0 ); float3 l2 = normalize ( IN.lt ); float3 h2 = normalize ( IN.ht ); float diff = max ( dot ( nt, l2 ), 0.0 ) + 0.2; float spec = pow ( max ( dot ( nt, h2 ), 0.0 ), 30.0 ); return diff * tex2D ( diffuseMap, IN.texCoord ) + spec * specColor; }
Визуальные эффекты на GPUАнизотропные модели освещения Поворот вокруг вектора нормали не изменяет векторов l и v, поэтому ранее рассмотренные модели освещения не зависят от подобных поворотов Однако встречаются поверхности, для это свойство не выполняется (поверхность CD, полированный металл). Такие поверхности называются анизотропными
Визуальные эффекты на GPUАнизотропные модели освещения Проще всего моделировать такие поверхности, считая их состоящими из множества ориентированных бесконечно-тонких нитей. Тогда в каждой точке поверхности можно задать касательный tвектор к такой нити, т.е. на поверхности объекта возникает поле касательных векторов t (P)
Визуальные эффекты на GPUАнизотропные модели освещения ? - как освещать подобную нить, ведь для нее неоднозначно определен вектор нормали n ! - рассмотрим диффузную и бликовую составляющие раздельно и для каждой из них выберем такой вектор n(ортогональный вектору t), максимизирующий соответствующую компоненту освещенности
Визуальные эффекты на GPUАнизотропные модели освещения Разложим вектор lна ортогональные части: Умножим скалярно на tи найдем параметры разложения Легко убедиться, что максимум (l,n)достигается на следующем векторе:
Визуальные эффекты на GPUАнизотропные модели освещения Таким образом получаем следующее уравнение освещенности для анизотропной поверхности:
Визуальные эффекты на GPUАнизотропные модели освещенияПередаваемые данные struct VertexData { float4 pos : POSITION; float2 texCoord : TEXCOORD0; float3 n : NORMAL; float3 t : TEXCOORD1; float3 b : TEXCOORD2; }; struct FragmentData { float4 pos : POSITION; float2 texCoord : TEXCOORD0; float3 lt; float3 ht; };
Визуальные эффекты на GPUАнизотропные модели освещения. Вершинная программа FragmentData main ( VertexData IN, uniform float4 lightPos, uniform float4 eyePos, uniform float4x4 mvp, uniform float4x4 mv, uniform float4x4 mvi ) { FragmentData OUT; float3 p = mul ( mv, IN.pos ).xyz; float3 l = normalize ( lightPos.xyz - p ); float3 v = normalize ( eyePos.xyz - p ); float3 h = normalize ( l + v ); float3 n = mul ( mvi, float4 ( IN.n, 0 ) ).xyz; float3 t = mul ( mvi, float4 ( IN.t, 0 ) ).xzy; float3 b = mul ( mvi, float4 ( IN.b, 0 ) ).xyz; OUT.lt = float3 ( dot ( l, t ), dot ( l, b ), dot ( l, n ) ); OUT.ht = float3 ( dot ( h, t ), dot ( h, b ), dot ( h, n ) ); OUT.pos = mul ( mvp, IN.pos ); OUT.texCoord = IN.texCoord; return OUT; }
Визуальные эффекты на GPUАнизотропные модели освещенияФрагментная программа float4 main ( FragmentData IN, uniform sampler2D tangentMap, uniform sampler2D decalMap, uniform sampler2D anisoMap ) : COLOR { const float3 specColor = float3 ( 0, 0, 1 ); float3 tang = normalize ( 2*tex2D( tangentMap, IN.texCoord ).xyz-1); float dot1 = dot ( normalize ( IN.lt ), tang ); float dot2 = dot ( normalize ( IN.ht ), tang ); float2 arg = float2 ( dot1, dot2 ); float2 ds = tex2D ( anisoMap, arg*arg ).xy; float3 color = tex2D ( decalMap, IN.texCoord ).xyz; return float4 ( color * ds.x + specColor * ds.y, 1.0 ); }
Визуальные эффекты на GPUМодель Уорда (Ward) Простейший вид модели освещения Уорда: - гладкость поверхности - касательный вектор - бисектор векторов l и v
Визуальные эффекты на GPUМодель Уорда (Ward)Фрагментная программа float4 main ( FragmentData IN, uniform sampler2D tangentMap, uniform sampler2D decalMap ) : COLOR { const float4 specColor = float4 ( 0, 0, 1, 0 ); const float3 n = float3 ( 0, 0, 1 ); const float roughness = 5.0; float4 color = tex2D ( decalMap, IN.texCoord ); float3 tang = normalize ( 2*tex2D ( tangentMap, IN.texCoord ).xyz-1 ); float dot1 = dot ( IN.ht, tang ) * roughness; float dot2 = dot ( IN.ht, n ); float p = dot1 / dot2; return float4 ( color.rgb + specColor.rgb * exp ( -p*p ), 1 ); }
Визуальные эффекты на GPUМоделирование преломления
Визуальные эффекты на GPUМоделирование преломления ! - используем встроенную функцию refractдля нахождения преломленного вектора и по этому вектору возьмем значение из кубической карты отражения. const float eta = 0.9; // Find reflection/refraction vectors float3 en = normalize ( IN.e ); float3 nn = normalize ( IN.n ); float3 r = reflect ( en, nn ); float3 t = refract ( en, nn, eta ); // Do a lookup into the environment map float3 envColor = texCUBE ( envMap, r ).xyz; float3 refractionColor = texCUBE ( envMap, t ).xyz;
Визуальные эффекты на GPUМоделирование преломления - учет длины волны
Визуальные эффекты на GPUМоделирование преломления - учет длины волны ! - функция refractзависит также и от коэффициента преломления eta. Данный коэффициент зависит от длины волны. Поэтому возьмем три коэффициента преломления (по одному для каждой цветовой компоненты), найдем преломленный вектор и соответствующий цвет. Из каждого из трех полученных цветов возьмем по одной цветовой компоненте (соответствующей длине волны) и построим из них новый цвет.
Визуальные эффекты на GPUСвечение (glow) Нарисовать светящийся объект в текстуру Применить «размытие» к этой текстуре Нарисовать всю сцену Наложить на изображение сцены размытую текстуру
Визуальные эффекты на GPUДифракция
Визуальные эффекты на GPUДифракция Разность фаз можно приближенно записать как du, где u=sin1 - sin2. Если эта разница кратна длине волны, то происходит усиление света, в противном случае - ослабевание.
Визуальные эффекты на GPUДифракция. Вершинная программа. FragmentData main ( VertexData IN, uniform float4 lightPos, uniform float4 eyePos, uniform float4x4 mvp, uniform float4x4 mv, uniform float4x4 mvi ) { FragmentData OUT; float3 p = mul ( mv, IN.pos ); float3 l = normalize ( lightPos.xyz - p ); float3 v = normalize ( eyePos.xyz - p ); float3 h = normalize ( l + v ); float3 n = mul ( mvi, float4 ( IN.n, 0 ) ).xyz; float3 t = mul ( mvi, float4 ( IN.t, 0 ) ).xzy; float3 b = mul ( mvi, float4 ( IN.b, 0 ) ).xyz; OUT.lt = float3 ( dot ( l, t ), dot ( l, b ), dot ( l, n ) ); OUT.ht = float3 ( dot ( h, t ), dot ( h, b ), dot ( h, n ) ); OUT.vt = float3 ( dot ( v, t ), dot ( v, b ), dot ( v, n ) ); OUT.pos = mul ( mvp, IN.pos ); OUT.texCoord = IN.texCoord; return OUT; }
Визуальные эффекты на GPUДифракция. Фрагментная программа. float4 main ( FragmentData IN, uniform sampler2D tangentMap, uniform sampler2D decalMap, uniform sampler1D rainbowMap ) : COLOR { const float3 specColor = float3 ( 0, 0, 1 ); const float3 n = float3 ( 0, 0, 1 ); const float roughness = 30.0; const float d = 40.0; float3 tang = normalize ( 2*tex2D(tangentMap, IN.texCoord).xyz-1); float u = dot ( IN.ht, tang ); float w = dot ( IN.ht, n ); float e = roughness * u / w; float3 color = float3 ( 0, 0, 0 ); float u1 = d * abs ( u ); for ( int n = 1; n <= 8; n++ ) color += tex1D ( rainbowMap, u1 / float ( n ) ).rgb; return float4 ( specColor * exp ( -e*e ) + color * 0.25, alpha ); }
Визуальные эффекты на GPUРендеринг меха
Визуальные эффекты на GPUРендеринг меха Текстура Слои 1, 2, 3 и т.д.
Визуальные эффекты на GPUРендеринг меха
Визуальные эффекты на GPUРендеринг меха Модель освещения - анизотропная (для волосков) Вершинный шейдер - сдвинуть вершины для слоя и подготовить все величины для расчета освещенности Фрагментный шейдер - непосредственно расчет освещенности Вершинная программа также обеспечивает перенос вершин для очередного слоя и анимацию меха путем изменения текстурных координат в зависимости от времени
Визуальные эффекты на GPUРендеринг меха. Вершинная программа FragmentData main ( VertexData IN, uniform float tl, uniform float time, uniform float4 lightPos, uniform float4 eyePos, uniform float4x4 mvp, uniform float4x4 mv, uniform float4x4 mvi ) { FragmentData OUT; float4 pp = IN.pos + tl * float4 ( IN.n, 0 ); float3 p = mul ( mv, pp ).xyz; float3 l = normalize ( lightPos.xyz - p ); float3 v = normalize ( eyePos.xyz - p ); float3 h = l + v; float3 n = mul ( mvi, float4 ( IN.n, 0 ) ).xyz; float3 t = mul ( mvi, float4 ( IN.t, 0 ) ).xyz; float3 b = mul ( mvi, float4 ( IN.b, 0 ) ).xyz; OUT.pos = mul ( mvp, pp ); OUT.texCoord = IN.texCoord + float2 ( 0, 0.02 * sin ( time ) * tl ); OUT.color = IN.color; OUT.lt = float3 ( dot ( l, t ), dot ( l, b ), dot ( l, n ) ); OUT.ht = float3 ( dot ( h, t ), dot ( h, b ), dot ( h, n ) ); return OUT; }
Визуальные эффекты на GPUРендеринг меха. Фрагментная программа float4 main ( FragmentData IN, uniform sampler2D furMap, uniform sampler2D anisoMap ) : COLOR { const float3 specColor = float3 ( 1, 1, 1 ); float3 tang = normalize ( IN.furDir ); float dot1 = dot ( normalize ( IN.lt ), tang ); float dot2 = dot ( normalize ( IN.ht ), tang ); float2 arg = float2 ( dot1, dot2 ); float2 ds = tex2D ( anisoMap, arg*arg ).xy; float4 color = tex2D ( furMap, IN.texCoord * float2 ( 6, 12 ) ); return IN.color * float4 ( color.xyz + specColor * ds.y*0.5, color.w*color.w ); }
Визуальные эффекты на GPUРендеринг меха. Главная программа // draw shells from innermost to outermost glEnable ( GL_BLEND ); glBlendFunc ( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); // draw every layer for ( int i = 0; i < numLayers; i++ ) { float t = (float) i / MAX_LAYERS; float shadow = 0.7*(shadowMin * (1 - t) + shadowMax * t); glColor4f ( shadow, shadow, shadow, shadow ); vertexProgram.setParameter ( "tl", t * scale ); object -> render (); } // restore state glDisable ( GL_BLEND );
Визуальные эффекты на GPUСгорание как в DooM III
Визуальные эффекты на GPUСгорание как в DooM III. Вершинная программа FragmentData main ( VertexData IN, uniform float4 lightPos, uniform float4 eyePos, uniform float4x4 mvp, uniform float4x4 mv, uniform float4x4 mvi ) { FragmentData OUT; OUT.p = mul ( mv, IN.pos ).xyz; OUT.n = mul ( mvi, float4 ( IN.n, 0 ) ).xyz; OUT.l = normalize ( lightPos.xyz - OUT.p ); OUT.v = normalize ( eyePos.xyz - OUT.p ); OUT.h = normalize ( OUT.l + OUT.v ); OUT.pos = mul ( mvp, IN.pos ); OUT.texCoord = IN.texCoord; return OUT; }