Главная Статьи Ссылки Скачать Скриншоты Юмор Почитать Tools Проекты Обо мне Гостевая Форум |
Одним из эффектов, естественным образом получающихся при использовании камеры (но отсутствующих при рендеринге) является motion blur, т.е. размытие при движении.
Этот эффект естественным образом получается при съемке на камеру поскольку съемка одного кадра это не мгновенный процесс - он занимает некоторое время. Объекты, быстро двигающиеся на протяжении этого времени получаются размытыми.
Когда мы имеем дело с рендерингом в реальном времени, то имеет смысл разделить размытие, возникающее при движении/ повороте камеры, и размытие, возникающее при быстром движении объектов относительно камеры. Здесь мы рассмотрим только первый случай - размытие, возникающее при движении и повороте камеры - как можно реализовать данный эффект за счет постобработки результата рендеринга.
Будем считать что для текущего кадра у нас уже есть результаты рендеринга в виде изображения с освещением и G-буфера (на самом деле нам из него понадобится только значение zeye). В фрагментном шейдере постобработки мы по значению zeye восстановим трехмерные координаты Peye соответствующей точки в системе координат камеры.
Далее мы используем обратную модельную матрицу для того, чтобы перевести эту точку в мировую систему координат Pw. После этого мы берем модельную матрицу с предыдущего кадра Mprev и матрицу проектирования для того, чтобы определить положение этой точки на экране для предыдущего кадра.
Тем самым мы для точки имеем текущее положение на экране и предыдущее положение на экране. После этого мы просто берем несколько точек на отрезке соединяющем эти точки и находим среднее значение цвета в них. Это и будет требуемое размытие.
Ниже приводится соответствующий шейдер.
-- vertex
#version 330 core
layout(location = 0) in vec4 pos;
out vec2 tex;
void main(void)
{
tex = 0.5 * ( pos.xy + vec2 ( 1.0 ) );
gl_Position = vec4 ( pos.xy, 0.0, 1.0 );
}
-- fragment
#version 330 core
uniform mat4 proj; // we will need it in pos reconstruction
uniform mat4 mv;
uniform mat4 mvPrevInv; // inverted model-view matrix from previous frame
uniform sampler2D colorMap;
uniform sampler2D nzMap;
in vec2 tex;
out vec4 color;
const int samples = 7;
// Note: it assumes proj is classical projection matrix
// (not multiplied by smth else)
vec3 getViewPos ( in vec2 uv )
{
vec4 nz = texture ( nzMap, uv ); // eyeZ in w
vec2 a = vec2 ( -2.0 / proj [0][0], -2.0 / proj [1][1] );
vec2 b = vec2 ( 1.0 / proj [0][0], 1.0 / proj [1][1] );
return nz.w * vec3 ( a*uv + b, 1.0 );
}
void main ()
{
vec3 pos = getViewPos ( tex );
vec4 p0 = mvPrevInv * vec4 ( pos, 1.0 );
vec4 p = proj * mv * p0;
p.xyz /= p.w; // perspective division
p.xy = 0.5 * ( p.xy + vec2 ( 1.0 ) );
vec2 v = tex - p.xy;
vec2 uv = tex;
vec4 sum = texture ( colorMap, uv );
for ( int i = 1; i < samples; i++ )
{
uv += v / 3.0;
sum += texture ( colorMap, uv );
}
color = sum / samples;
}
Рис. Изображение в эффектом motion blur
Исходный код для этого примера на python можно скачать из репозитория.