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

View File

@ -230,7 +230,7 @@ private:
core::array<video::IRenderTarget> m_mrt; core::array<video::IRenderTarget> m_mrt;
/** Matrixes used in several places stored here to avoid recomputation. */ /** 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 *> SkyboxTextures;
std::vector<video::ITexture *> SphericalHarmonicsTextures; std::vector<video::ITexture *> SphericalHarmonicsTextures;
@ -694,7 +694,8 @@ public:
void setProjMatrix(core::matrix4 matrix) { m_ProjMatrix = matrix; matrix.getInverse(m_InvProjMatrix); } void setProjMatrix(core::matrix4 matrix) { m_ProjMatrix = matrix; matrix.getInverse(m_InvProjMatrix); }
const core::matrix4 &getProjMatrix() const { return m_ProjMatrix; } const core::matrix4 &getProjMatrix() const { return m_ProjMatrix; }
const core::matrix4 &getInvProjMatrix() const { return m_InvProjMatrix; } 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 &getProjViewMatrix() const { return m_ProjViewMatrix; }
const core::matrix4 &getInvProjViewMatrix() const { return m_InvProjViewMatrix; } const core::matrix4 &getInvProjViewMatrix() const { return m_InvProjViewMatrix; }
#ifdef DEBUG #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); 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_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, 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 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->getDirection(cam), 0.15f,
cb->getMaxHeight(cam) * 0.7f, 0); cb->getMaxHeight(cam) * 0.7f, 0, 1);
glDrawArrays(GL_TRIANGLES, 0, 3); 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); PROFILER_PUSH_CPU_MARKER("- Motion blur", 0xFF, 0x00, 0x00);
ScopedGPUTimer Timer(irr_driver->getGPUTimer(Q_MOTIONBLUR)); 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); renderMotionBlur(0, *in_fbo, *out_fbo);
std::swap(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_boost_amount;
GLuint MotionBlurShader::uniform_center; GLuint MotionBlurShader::uniform_center;
GLuint MotionBlurShader::uniform_color_buffer; GLuint MotionBlurShader::uniform_color_buffer;
GLuint MotionBlurShader::uniform_dtex;
GLuint MotionBlurShader::uniform_previous_viewproj;
GLuint MotionBlurShader::uniform_direction; GLuint MotionBlurShader::uniform_direction;
GLuint MotionBlurShader::uniform_mask_radius; GLuint MotionBlurShader::uniform_mask_radius;
GLuint MotionBlurShader::uniform_max_tex_height; GLuint MotionBlurShader::uniform_max_tex_height;
@ -2672,6 +2674,7 @@ namespace FullScreenShader
{ {
Program = LoadProgram( Program = LoadProgram(
GL_VERTEX_SHADER, file_manager->getAsset("shaders/screenquad.vert").c_str(), 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()); GL_FRAGMENT_SHADER, file_manager->getAsset("shaders/motion_blur.frag").c_str());
uniform_boost_amount = glGetUniformLocation(Program, "boost_amount"); uniform_boost_amount = glGetUniformLocation(Program, "boost_amount");
uniform_center = glGetUniformLocation(Program, "center"); uniform_center = glGetUniformLocation(Program, "center");
@ -2679,17 +2682,21 @@ namespace FullScreenShader
uniform_direction = glGetUniformLocation(Program, "direction"); uniform_direction = glGetUniformLocation(Program, "direction");
uniform_mask_radius = glGetUniformLocation(Program, "mask_radius"); uniform_mask_radius = glGetUniformLocation(Program, "mask_radius");
uniform_max_tex_height = glGetUniformLocation(Program, "max_tex_height"); uniform_max_tex_height = glGetUniformLocation(Program, "max_tex_height");
uniform_dtex = glGetUniformLocation(Program, "dtex");
uniform_previous_viewproj = glGetUniformLocation(Program, "previous_viewproj");
vao = createFullScreenVAO(Program); 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); glUniform1f(uniform_boost_amount, boost_amount);
glUniform2f(uniform_center, center.X, center.Y); glUniform2f(uniform_center, center.X, center.Y);
glUniform2f(uniform_direction, direction.X, direction.Y); glUniform2f(uniform_direction, direction.X, direction.Y);
glUniform1f(uniform_mask_radius, mask_radius); glUniform1f(uniform_mask_radius, mask_radius);
glUniform1f(uniform_max_tex_height, max_tex_height); glUniform1f(uniform_max_tex_height, max_tex_height);
glUniform1i(uniform_color_buffer, TU_cb); glUniform1i(uniform_color_buffer, TU_cb);
glUniform1i(uniform_dtex, TU_dtex);
} }
GLuint GodFadeShader::Program; GLuint GodFadeShader::Program;

View File

@ -759,11 +759,11 @@ class MotionBlurShader
{ {
public: public:
static GLuint Program; 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 GLuint vao;
static void init(); 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 class GodFadeShader