Визуальные эффекты на GPU Стандартные модели освещения

advertisement
Визуальные эффекты на GPU
Стандартные модели освещения - Гуро
1. Падающий равномерно
рассеивается по всем направлением
верхней полусферы
2. Энергия, уходящая в заданном
направлении пропорциональна
только плотности световой энергии,
падающей в данную точку
l
P
Визуальные эффекты на GPU
Стандартные модели освещения - диффузная
n
v
l
n - вектор нормали в точке Р
v - вектор на наблюдателя
l - вектор на источник света

P
Уравнение освещенности:
Cres  Csurf  k a  k d  I light  max 0, n, l 
Визуальные эффекты на GPU
Стандартные модели - освещение по Блинну
n
h
v
h - бисектор векторов l и v
l
h
l v
l v
P
Уравнение освещенности:
Cres  Csurf  ka  kd  I light  max 0, n, l   ks  I light  max 0, n, h 
p
Визуальные эффекты на GPU
Стандартные модели - освещение по Блинну
C surf - цвет поверхности
I light - цвет источника света
ka - вклад фонового освещения
k d - вклад диффузной освещенности
k s - вклад бликовой освещенности
p - гладкость поверхности
Визуальные эффекты на 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,
OUT.n
OUT.l
OUT.v
OUT.h
OUT.pos
OUT.texCoord
return OUT;
}
=
=
=
=
=
=
IN.pos ).xyz;
mul ( mvi, float4 ( IN.n, 0 ) ).xyz;
normalize ( lightPos.xyz - p );
normalize ( eyePos.xyz
- p );
normalize ( OUT.l + OUT.v );
mul ( mvp, IN.pos );
IN.texCoord;
Визуальные эффекты на 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
float3
float3
float4
float4
n2
l2
h2
diff
spec
=
=
=
=
=
normalize
normalize
normalize
diffColor
specColor
return diff + spec;
}
(
(
(
*
*
IN.n );
IN.l );
IN.h );
max ( dot ( n2, l2 ), 0.0 );
pow ( max ( dot ( n2, h2 ), 0.0 ),
specPower );
Визуальные эффекты на GPU
Стандартные модели - освещение по Фонгу
n
r - отражение вектора v
относительно нормали n
r
v
l
P
Уравнение освещенности:
Cres  Csurf  ka  kd  I light  max 0, n, l   k s  I light  max 0, l , r 
p
Визуальные эффекты на 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,
OUT.n
OUT.l
OUT.v
OUT.pos
OUT.texCoord
return OUT;
}
=
=
=
=
=
IN.pos ).xyz;
mul ( mvi, float4 ( IN.n, 0 ) ).xyz;
normalize ( lightPos.xyz - p );
normalize ( eyePos.xyz
- p );
mul ( mvp, IN.pos );
IN.texCoord;
Визуальные эффекты на GPU
Освещение по Фонгу. Фрагментная программа
float4
main ( FragmentData
{
const float4 diffColor =
const float4 specColor =
const float specPower =
float3
float3
float3
float3
float4
float4
n2
l2
v2
r
diff
spec
=
=
=
=
=
=
float4 ( 0.5, 0.0, 0.0, 1.0 );
float4 ( 0.7, 0.7, 0.0, 1.0 );
30.0;
normalize
normalize
normalize
reflect (
diffColor
specColor
return diff + spec;
}
IN ) : COLOR
( IN.n );
( IN.l );
( IN.v );
-v2, n2 );
* max ( dot ( n2, l2 ), 0.0 );
* pow ( max ( dot ( l2, r ), 0.0 ),
specPower );
Визуальные эффекты на GPU
Bumpmapping
L
При использовании описанных моделей освещения
поверхности получаются слишком гладкими
Хочется добавить микрорельеф, не изменяя при этом
саму геометрию объектов
J
Попробуем просто в каждой точке отклонять вектор
нормали.
Тогда изменится освещенность в точке и создастся
иллюзия микрорельефа
Визуальные эффекты на GPU
Bumpmapping
n
n
n'
n'
n'
n
n - истинный вектор нормали
n’ - искаженный вектор нормали
Визуальные эффекты на GPU
Bumpmapping
Результат искажения
нормалей - при рендеринге
обычного тора было
произведено искажение
векторов нормали
Визуальные эффекты на GPU
Bumpmapping
? - в каком пространстве
n
задавать искажения вектора
нормали n
b
! - будем задавать в искажения
вектора (точнее, сам вектор
нормали n) в пространстве
“приклеенном” к выводимой
грани
t
Визуальные эффекты на GPU
Bumpmapping
Для каждой грани определим следующие
попарно ортогональных единичных вектора
n
b
t - касательный вектор к грани
n - нормаль грани
b - бинормаль (b = [n,t])
Эта тройка векторов образует
ортонормированный базис в пространстве
и, соответственно, систему координат,
называемую касательной (tangent space)
t
Визуальные эффекты на GPU
Bumpmapping
Как кодировать искажения нормали
- переведем единичный вектор нормали
(в касательном пространстве) в цвет и
поместим в текстуру
Неискаженная нормаль в касательном
пространстве всегда равна n=(0,01)
r  0.5  (nx  1),
g  0.5  (n y  1),
b  0.5  (nz  1)
Визуальные эффекты на GPU
Bumpmapping
Вершинная программа:
Фрагментная программа:
• вычислить вектора l, v, h (или r)
• перевести их в касательное
пространство
• передать фрагментной программе
вычисленные вектора и текстурные
координаты
• нормировать вектора l, v, h (или r)
• взять из карты нормалей нормаль
• перевести нормаль из RGBпредставления
• вычислить освещенность с
использованием полученного
вектора нормали и векторов l, v, h
(или r)
Визуальные эффекты на GPU
Bumpmapping - передаваемые данные
struct VertexData
{
float4 pos
float2 texCoord
float3 n
float3 t
float3 b
};
:
:
:
:
:
POSITION;
TEXCOORD0;
NORMAL;
TEXCOORD1;
TEXCOORD2;
struct FragmentData
{
float4 pos
: POSITION;
float2 texCoord : TEXCOORD0;
float3 lt;
float3 ht;
};
Визуальные эффекты на GPU
Bumpmapping - вершинная программа
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
OUT.texCoord
OUT.lt
OUT.ht
return OUT;
}
=
=
=
=
mul ( mvp, IN.pos );
IN.texCoord;
float3 ( dot ( l, t ), dot ( l, b ), dot ( l, n ) );
float3 ( dot ( h, t ), dot ( h, b ), dot ( h, n ) );
Визуальные эффекты на GPU
Bumpmapping - фрагментная программа
float4 main ( FragmentData IN,
uniform sampler2D bumpMap,
uniform sampler2D diffuseMap ) : COLOR
{
const
float4 specColor = float4 ( 1, 1, 1, 1 );
float3
float3
float3
float3
float
float
n
nt
l2
h2
diff
spec
=
=
=
=
=
=
tex2D ( bumpMap, IN.texCoord ).xyz;
normalize ( 2.0*n - 1.0 );
normalize ( IN.lt );
normalize ( IN.ht );
max ( dot ( nt, l2 ), 0.0 ) + 0.2;
pow ( max ( dot ( nt, h2 ), 0.0 ), 30.0 );
return diff * tex2D ( diffuseMap, IN.texCoord ) +
spec * specColor;
}
Визуальные эффекты на GPU
Анизотропные модели освещения
n
l
v
Поворот вокруг вектора нормали
не изменяет векторов l и v,
поэтому ранее рассмотренные
модели освещения не зависят от
подобных поворотов
Однако встречаются поверхности,
для это свойство не выполняется
(поверхность CD, полированный
металл).
Такие поверхности называются
анизотропными
Визуальные эффекты на GPU
Анизотропные модели освещения
n
t
n
n
t
t
Проще всего моделировать такие
поверхности, считая их состоящими
из множества ориентированных
бесконечно-тонких нитей.
Тогда в каждой точке поверхности
можно задать касательный t вектор к
такой нити, т.е. на поверхности
объекта возникает поле касательных
векторов t (P)
Визуальные эффекты на GPU
Анизотропные модели освещения
t
lt
ln
? - как освещать подобную нить, ведь
для нее неоднозначно определен вектор
нормали n
l
! - рассмотрим диффузную и бликовую
n
составляющие раздельно и для каждой
из них выберем такой вектор n
(ортогональный вектору t),
максимизирующий соответствующую
компоненту освещенности
Визуальные эффекты на GPU
Анизотропные модели освещения
Разложим вектор l на ортогональные части:
l    t  n* , n*t
Умножим скалярно на t и найдем параметры разложения
  l , t ,
n*  l  l , t   t
n
* 2
 n , n   1  l , t 
*
*
2
Легко убедиться, что максимум (l,n) достигается на
следующем векторе:
n*
n*

*
2
n
1  l , t 
Визуальные эффекты на GPU
Анизотропные модели освещения
Таким образом получаем следующее уравнение освещенности
для анизотропной поверхности:

Cres  Csurf  k a  k d  I light  1  l , t 
k s  I light  1  h, t 
0.5
p
2

Визуальные эффекты на GPU
Анизотропные модели освещения
Передаваемые данные
struct VertexData
{
float4 pos
float2 texCoord
float3 n
float3 t
float3 b
};
:
:
:
:
:
POSITION;
TEXCOORD0;
NORMAL;
TEXCOORD1;
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
OUT.ht
OUT.pos
OUT.texCoord
return OUT;
}
=
=
=
=
float3 ( dot ( l, t ), dot ( l, b ), dot ( l, n ) );
float3 ( dot ( h, t ), dot ( h, b ), dot ( h, n ) );
mul ( mvp, IN.pos );
IN.texCoord;
Визуальные эффекты на GPU
Анизотропные модели освещения
Фрагментная программа
float4 main ( FragmentData IN,
uniform sampler2D tangentMap,
uniform sampler2D decalMap,
uniform sampler2D anisoMap ) : COLOR
{
const float3 specColor = float3 ( 0, 0, 1 );
float3
float
float
float2
float2
float3
tang
dot1
dot2
arg
ds
color
=
=
=
=
=
=
normalize
dot
dot
float2
tex2D
tex2D
(
(
(
(
(
(
2*tex2D( tangentMap, IN.texCoord ).xyz-1);
normalize ( IN.lt ), tang );
normalize ( IN.ht ), tang );
dot1, dot2 );
anisoMap, arg*arg ).xy;
decalMap, IN.texCoord ).xyz;
return float4 ( color * ds.x + specColor * ds.y, 1.0 );
}
Визуальные эффекты на GPU
Модель Уорда (Ward)
Простейший вид модели освещения Уорда:
Cres


h, t  

 Csurf  ka  k s  I light  exp   k 
h, n 

k
- гладкость поверхности
t
- касательный вектор
h - бисектор векторов l и v
Визуальные эффекты на GPU
Модель Уорда (Ward)
Фрагментная программа
float4 main ( FragmentData IN,
uniform sampler2D
uniform sampler2D
{
const float4
specColor
const float3
n
const float roughness = 5.0;
float4
float3
float
float
float
color
tang
dot1
dot2
p
=
=
=
=
=
tangentMap,
decalMap ) : COLOR
= float4 ( 0, 0, 1, 0 );
= float3 ( 0, 0, 1 );
tex2D ( decalMap, IN.texCoord );
normalize ( 2*tex2D ( tangentMap, IN.texCoord ).xyz-1 );
dot ( IN.ht, tang ) * roughness;
dot ( IN.ht, n );
dot1 / dot2;
return float4 ( color.rgb + specColor.rgb * exp ( -p*p ), 1 );
}
Визуальные эффекты на GPU
Моделирование преломления
n
r
v
t
Визуальные эффекты на GPU
Моделирование преломления
! - используем встроенную функцию
refract для нахождения преломленного
вектора и по этому вектору возьмем
значение из кубической карты
отражения.
const float
float3
float3
float3
float3
en
nn
r
t
=
=
=
=
eta = 0.9;
// Find reflection/refraction vectors
normalize ( IN.e );
normalize ( IN.n );
reflect
( en, nn );
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.
Данный коэффициент зависит от
длины волны. Поэтому возьмем три
коэффициента преломления (по
одному для каждой цветовой
компоненты), найдем преломленный
вектор и соответствующий цвет.
Из каждого из трех полученных
цветов возьмем по одной цветовой
компоненте (соответствующей длине
волны) и построим из них новый цвет.
n
r
v
tred
t green
tblue
Визуальные эффекты на GPU
Свечение (glow)
Визуальные эффекты на GPU
Свечение (glow)
Нарисовать светящийся объект в текстуру
Применить «размытие» к этой текстуре
Нарисовать всю сцену
Наложить на изображение сцены размытую текстуру
Визуальные эффекты на GPU
Дифракция
Визуальные эффекты на GPU
Дифракция
n
n
v
v
l
l
C
A
d
B
Разность фаз можно приближенно записать как du,
где u= sin 1 - sin 2.
Если эта разница кратна длине волны, то происходит усиление
света, в противном случае - ослабевание.
Визуальные эффекты на 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
OUT.ht
OUT.vt
OUT.pos
OUT.texCoord
return OUT;
}
=
=
=
=
=
float3 ( dot ( l,
float3 ( dot ( h,
float3 ( dot ( v,
mul ( mvp, IN.pos
IN.texCoord;
t ), dot ( l, b ), dot ( l, n ) );
t ), dot ( h, b ), dot ( h, n ) );
t ), dot ( v, b ), dot ( v, n ) );
);
Визуальные эффекты на 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
Рендеринг меха
Модель освещения - анизотропная (для волосков)
Вершинный шейдер - сдвинуть вершины для слоя и подготовить
все величины для расчета освещенности
Фрагментный шейдер - непосредственно расчет освещенности
n
pos+n*3*d
pos+n*2*d
pos+n*d
pos
Вершинная программа также
обеспечивает перенос вершин для
очередного слоя и анимацию меха
путем изменения текстурных
координат в зависимости от времени
Визуальные эффекты на 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
float3
float
float
float2
float2
float4
tang
dot1
dot2
arg
ds
color
specColor = float3 ( 1, 1, 1 );
=
=
=
=
=
=
normalize
dot
dot
float2
tex2D
tex2D
(
(
(
(
(
(
IN.furDir );
normalize ( IN.lt ), tang );
normalize ( IN.ht ), tang );
dot1, dot2 );
anisoMap, arg*arg ).xy;
furMap, IN.texCoord * float2 ( 6, 12 ) );
return IN.color * float4 ( color.xyz + specColor * ds.y*0.5,
color.w*color.w );
}
Визуальные эффекты на GPU
Рендеринг меха. Главная программа
glEnable
glBlendFunc
// draw shells from innermost to outermost
( GL_BLEND );
( 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
OUT.n
OUT.l
OUT.v
OUT.h
OUT.pos
OUT.texCoord
return OUT;
}
=
=
=
=
=
=
=
mul ( mv, IN.pos ).xyz;
mul ( mvi, float4 ( IN.n, 0 ) ).xyz;
normalize ( lightPos.xyz - OUT.p );
normalize ( eyePos.xyz
- OUT.p );
normalize ( OUT.l + OUT.v );
mul ( mvp, IN.pos );
IN.texCoord;
Визуальные эффекты на GPU
Сгорание как в DooM III. Фрагментная программа
float4
main ( FragmentData IN,
uniform float time, uniform sampler3D noiseMap ) : COLOR
{
float3
float
float3
float3
float3
float4
float4
float4
noise
t
n2
l2
h2
diff
spec
color
=
=
=
=
=
=
=
=
turbulence ( noiseMap, 0.1 * IN.p );
-0.3 - noise.x + fmod ( time, 15 ) / 15;
normalize ( IN.n );
normalize ( IN.l );
normalize ( IN.h );
diffColor * max ( dot ( n2, l2 ), 0.5 );
specColor * pow ( max ( dot ( n2, h2 ), 0 ), 30 );
diff + spec;
if ( t > 0 )
if ( t > 0.02 )
color = float4 ( 0, 0, 0, 0 );
else
color = lerp ( darkRed, brightRed, t * 50 );
return color;
}
Download