Turn motion blur into camera space motion blur
This commit is contained in:
parent
de7ceb0c2d
commit
f23f7b05e5
@ -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);
|
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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);
|
||||||
|
@ -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 ¢er, 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 ¢er, 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;
|
||||||
|
@ -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 ¢er, 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 ¢er, const core::vector2df &direction, float mask_radius, float max_tex_height, unsigned TU_cb, unsigned TU_dtex);
|
||||||
};
|
};
|
||||||
|
|
||||||
class GodFadeShader
|
class GodFadeShader
|
||||||
|
Loading…
Reference in New Issue
Block a user