Turn motion blur into camera space motion blur

This commit is contained in:
Vincent Lejeune 2014-07-07 18:44:25 +02:00
parent de7ceb0c2d
commit f23f7b05e5
5 changed files with 53 additions and 42 deletions

View File

@ -25,20 +25,17 @@ uniform float boost_amount;
// The color buffer to use.
uniform sampler2D color_buffer;
uniform sampler2D dtex;
// Center (in texture coordinates) at which the kart is. A small circle
// around this center is not blurred (see mask_radius below)
uniform vec2 center;
// The direction to which the blurring aims at
uniform vec2 direction;
// Radius of mask around the character in which no blurring happens
// so that the kart doesn't get blurred.
uniform float mask_radius;
// Maximum height of texture used
uniform float max_tex_height;
uniform mat4 previous_viewproj;
layout (std140) uniform MatrixesData
{
@ -55,42 +52,44 @@ out vec4 FragColor;
// Number of samples used for blurring
#define NB_SAMPLES 8
vec4 getPosFromUVDepth(vec3 uvDepth, mat4 InverseProjectionMatrix);
void main()
{
vec2 texcoords = gl_FragCoord.xy / screen;
vec2 texcoords = gl_FragCoord.xy / screen;
// Sample the color buffer
vec3 color = texture(color_buffer, texcoords).rgb;
// Sample the color buffer
vec3 color = texture(color_buffer, texcoords).rgb;
// Compute the blur direction.
// IMPORTANT: we don't normalize it so that it avoids a glitch around 'center',
// plus it naturally scales the motion blur in a cool way :)
vec2 blur_dir = direction - texcoords;
float z = texture(dtex, texcoords).x;
vec4 ViewPos = getPosFromUVDepth(vec3(texcoords, z), InverseProjectionMatrix);
vec4 OldScreenPos = previous_viewproj * InverseViewMatrix * ViewPos;
OldScreenPos /= OldScreenPos.w;
OldScreenPos = .5 * OldScreenPos + .5;
// Compute the blurring factor:
// - apply the mask, i.e. no blurring in a small circle around the kart
float blur_factor = max(0.0, length(texcoords - center) - mask_radius);
// Compute the blur direction.
// IMPORTANT: we don't normalize it so that it avoids a glitch around 'center',
// plus it naturally scales the motion blur in a cool way :)
vec2 blur_dir = texcoords - OldScreenPos.xy;
// - avoid blurring the top of the screen
blur_factor *= (max_tex_height - texcoords.t);
// Compute the blurring factor:
// - apply the mask, i.e. no blurring in a small circle around the kart
float blur_factor = max(0.0, length(texcoords - center) - mask_radius);
// - apply the boost amount
blur_factor *= boost_amount;
// - apply the boost amount
blur_factor *= boost_amount;
// Scale the blur direction
blur_dir *= blur_factor;
// Scale the blur direction
blur_dir *= blur_factor;
// Compute the blur
vec2 inc_vec = blur_dir / vec2(NB_SAMPLES);
vec2 blur_texcoords = texcoords + inc_vec;
for(int i=1 ; i < NB_SAMPLES ; i++)
{
color += texture(color_buffer, blur_texcoords).rgb;
blur_texcoords += inc_vec;
}
color /= vec3(NB_SAMPLES);
FragColor = vec4(color, 1.0);
// Keep this commented line for debugging:
//FragColor = vec4(blur_factor, blur_factor, blur_factor, 0.0);
// Compute the blur
vec2 inc_vec = blur_dir / vec2(NB_SAMPLES);
vec2 blur_texcoords = texcoords + inc_vec;
for(int i=1 ; i < NB_SAMPLES ; i++)
{
color += texture(color_buffer, blur_texcoords).rgb;
blur_texcoords += inc_vec;
}
color /= vec3(NB_SAMPLES);
FragColor = vec4(color, 1.0);
}

View File

@ -230,7 +230,7 @@ private:
core::array<video::IRenderTarget> m_mrt;
/** Matrixes used in several places stored here to avoid recomputation. */
core::matrix4 m_ViewMatrix, m_InvViewMatrix, m_ProjMatrix, m_InvProjMatrix, m_ProjViewMatrix, m_InvProjViewMatrix;
core::matrix4 m_ViewMatrix, m_InvViewMatrix, m_ProjMatrix, m_InvProjMatrix, m_ProjViewMatrix, m_previousProjViewMatrix, m_InvProjViewMatrix;
std::vector<video::ITexture *> SkyboxTextures;
std::vector<video::ITexture *> SphericalHarmonicsTextures;
@ -694,7 +694,8 @@ public:
void setProjMatrix(core::matrix4 matrix) { m_ProjMatrix = matrix; matrix.getInverse(m_InvProjMatrix); }
const core::matrix4 &getProjMatrix() const { return m_ProjMatrix; }
const core::matrix4 &getInvProjMatrix() const { return m_InvProjMatrix; }
void genProjViewMatrix() { m_ProjViewMatrix = m_ProjMatrix * m_ViewMatrix; m_InvProjViewMatrix = m_ProjViewMatrix; m_InvProjViewMatrix.makeInverse(); }
void genProjViewMatrix() { m_previousProjViewMatrix = m_ProjViewMatrix; m_ProjViewMatrix = m_ProjMatrix * m_ViewMatrix; m_InvProjViewMatrix = m_ProjViewMatrix; m_InvProjViewMatrix.makeInverse(); }
const core::matrix4 & getPreviousPVMatrix() { return m_previousProjViewMatrix; }
const core::matrix4 &getProjViewMatrix() const { return m_ProjViewMatrix; }
const core::matrix4 &getInvProjViewMatrix() const { return m_InvProjViewMatrix; }
#ifdef DEBUG

View File

@ -610,10 +610,14 @@ void PostProcessing::renderMotionBlur(unsigned cam, FrameBuffer &in_fbo, FrameBu
setTexture(0, in_fbo.getRTT()[0], GL_NEAREST, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
setTexture(1, irr_driver->getDepthStencilTexture(), GL_NEAREST, GL_NEAREST);
FullScreenShader::MotionBlurShader
::setUniforms(cb->getBoostTime(cam), cb->getCenter(cam),
::setUniforms(1., // Todo : should be framerate dependent
// Todo : use a previousPVMatrix per cam, not global
irr_driver->getPreviousPVMatrix(),
cb->getCenter(cam),
cb->getDirection(cam), 0.15f,
cb->getMaxHeight(cam) * 0.7f, 0);
cb->getMaxHeight(cam) * 0.7f, 0, 1);
glDrawArrays(GL_TRIANGLES, 0, 3);
}
@ -868,7 +872,7 @@ FrameBuffer *PostProcessing::render(scene::ICameraSceneNode * const camnode, boo
{
PROFILER_PUSH_CPU_MARKER("- Motion blur", 0xFF, 0x00, 0x00);
ScopedGPUTimer Timer(irr_driver->getGPUTimer(Q_MOTIONBLUR));
if (isRace && UserConfigParams::m_motionblur && m_any_boost && World::getWorld() != NULL) // motion blur
if (isRace && UserConfigParams::m_motionblur && World::getWorld() != NULL) // motion blur
{
renderMotionBlur(0, *in_fbo, *out_fbo);
std::swap(in_fbo, out_fbo);

View File

@ -2663,6 +2663,8 @@ namespace FullScreenShader
GLuint MotionBlurShader::uniform_boost_amount;
GLuint MotionBlurShader::uniform_center;
GLuint MotionBlurShader::uniform_color_buffer;
GLuint MotionBlurShader::uniform_dtex;
GLuint MotionBlurShader::uniform_previous_viewproj;
GLuint MotionBlurShader::uniform_direction;
GLuint MotionBlurShader::uniform_mask_radius;
GLuint MotionBlurShader::uniform_max_tex_height;
@ -2672,6 +2674,7 @@ namespace FullScreenShader
{
Program = LoadProgram(
GL_VERTEX_SHADER, file_manager->getAsset("shaders/screenquad.vert").c_str(),
GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/utils/getPosFromUVDepth.frag").c_str(),
GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/motion_blur.frag").c_str());
uniform_boost_amount = glGetUniformLocation(Program, "boost_amount");
uniform_center = glGetUniformLocation(Program, "center");
@ -2679,17 +2682,21 @@ namespace FullScreenShader
uniform_direction = glGetUniformLocation(Program, "direction");
uniform_mask_radius = glGetUniformLocation(Program, "mask_radius");
uniform_max_tex_height = glGetUniformLocation(Program, "max_tex_height");
uniform_dtex = glGetUniformLocation(Program, "dtex");
uniform_previous_viewproj = glGetUniformLocation(Program, "previous_viewproj");
vao = createFullScreenVAO(Program);
}
void MotionBlurShader::setUniforms(float boost_amount, const core::vector2df &center, const core::vector2df &direction, float mask_radius, float max_tex_height, unsigned TU_cb)
void MotionBlurShader::setUniforms(float boost_amount, const core::matrix4 &previousVP, const core::vector2df &center, const core::vector2df &direction, float mask_radius, float max_tex_height, unsigned TU_cb, unsigned TU_dtex)
{
glUniformMatrix4fv(uniform_previous_viewproj, 1, GL_FALSE, previousVP.pointer());
glUniform1f(uniform_boost_amount, boost_amount);
glUniform2f(uniform_center, center.X, center.Y);
glUniform2f(uniform_direction, direction.X, direction.Y);
glUniform1f(uniform_mask_radius, mask_radius);
glUniform1f(uniform_max_tex_height, max_tex_height);
glUniform1i(uniform_color_buffer, TU_cb);
glUniform1i(uniform_dtex, TU_dtex);
}
GLuint GodFadeShader::Program;

View File

@ -759,11 +759,11 @@ class MotionBlurShader
{
public:
static GLuint Program;
static GLuint uniform_boost_amount, uniform_color_buffer, uniform_center, uniform_direction, uniform_mask_radius, uniform_max_tex_height;
static GLuint uniform_boost_amount, uniform_color_buffer, uniform_dtex, uniform_previous_viewproj, uniform_center, uniform_direction, uniform_mask_radius, uniform_max_tex_height;
static GLuint vao;
static void init();
static void setUniforms(float boost_amount, const core::vector2df &center, const core::vector2df &direction, float mask_radius, float max_tex_height, unsigned TU_cb);
static void setUniforms(float boost_amount, const core::matrix4 &previousVP, const core::vector2df &center, const core::vector2df &direction, float mask_radius, float max_tex_height, unsigned TU_cb, unsigned TU_dtex);
};
class GodFadeShader