Finally make the bloody blur effect work properly.
This fixes the artefacts appearing when only part of the screen is updated. This version also brings ton of optimizations which might well increase performance 2 or 3 times on slower cards: - Windows are not drawn twice anymore. Now they're drawn only to render target and later changed parts of the render target are copied back onto screen. - Shaders have been optimized. Some calculations moved from pixel shader to vertex shader. - For ARGB windows, if window's opacity is 0 then it will stay transparent instead of being replaced by blurred background. - Blur effect should now play nicer with other effects, e.g. shadows. svn path=/trunk/KDE/kdebase/workspace/; revision=748502icc-effect-5.14.5
parent
eba221d0a3
commit
213833fc7f
188
effects/blur.cpp
188
effects/blur.cpp
|
@ -47,12 +47,17 @@ BlurEffect::BlurEffect() : Effect()
|
||||||
mWindowShader = 0;
|
mWindowShader = 0;
|
||||||
|
|
||||||
mBlurRadius = 4;
|
mBlurRadius = 4;
|
||||||
mTime = 0;
|
|
||||||
mValid = loadData();
|
mValid = loadData();
|
||||||
|
if( !mValid )
|
||||||
|
{
|
||||||
|
kWarning() << "Loading failed";
|
||||||
|
}
|
||||||
|
effects->addRepaintFull();
|
||||||
}
|
}
|
||||||
|
|
||||||
BlurEffect::~BlurEffect()
|
BlurEffect::~BlurEffect()
|
||||||
{
|
{
|
||||||
|
effects->addRepaintFull();
|
||||||
delete mSceneTexture;
|
delete mSceneTexture;
|
||||||
delete mTmpTexture;
|
delete mTmpTexture;
|
||||||
delete mBlurTexture;
|
delete mBlurTexture;
|
||||||
|
@ -61,7 +66,7 @@ BlurEffect::~BlurEffect()
|
||||||
delete mBlurTarget;
|
delete mBlurTarget;
|
||||||
delete mBlurShader;
|
delete mBlurShader;
|
||||||
delete mWindowShader;
|
delete mWindowShader;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool BlurEffect::loadData()
|
bool BlurEffect::loadData()
|
||||||
|
@ -140,44 +145,123 @@ bool BlurEffect::supported()
|
||||||
(effects->compositingType() == OpenGLCompositing);
|
(effects->compositingType() == OpenGLCompositing);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QRegion BlurEffect::expandedRegion( const QRegion& region ) const
|
||||||
|
{
|
||||||
|
QRegion expandedregion;
|
||||||
|
foreach( QRect r, region.rects() )
|
||||||
|
{
|
||||||
|
r.adjust( -mBlurRadius, -mBlurRadius, mBlurRadius, mBlurRadius );
|
||||||
|
expandedregion += r;
|
||||||
|
}
|
||||||
|
return expandedregion;
|
||||||
|
}
|
||||||
|
|
||||||
void BlurEffect::prePaintScreen( ScreenPrePaintData& data, int time )
|
void BlurEffect::prePaintScreen( ScreenPrePaintData& data, int time )
|
||||||
{
|
{
|
||||||
mTransparentWindows = 0;
|
mTransparentWindows = 0;
|
||||||
mTime += time;
|
mScreenDirty = QRegion();
|
||||||
|
mBlurDirty = QRegion();
|
||||||
|
mBlurMask = QRegion();
|
||||||
|
|
||||||
effects->prePaintScreen(data, time);
|
effects->prePaintScreen(data, time);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BlurEffect::prePaintWindow( EffectWindow* w, WindowPrePaintData& data, int time )
|
void BlurEffect::prePaintWindow( EffectWindow* w, WindowPrePaintData& data, int time )
|
||||||
{
|
{
|
||||||
|
// Expand the painted area
|
||||||
|
mBlurMask |= expandedRegion( data.paint );
|
||||||
|
data.paint |= expandedRegion( mBlurMask );
|
||||||
effects->prePaintWindow( w, data, time );
|
effects->prePaintWindow( w, data, time );
|
||||||
|
|
||||||
if( w->isPaintingEnabled() && ( data.mask & PAINT_WINDOW_TRANSLUCENT ))
|
if( w->isPaintingEnabled() && ( data.mask & PAINT_WINDOW_TRANSLUCENT ))
|
||||||
mTransparentWindows++;
|
mTransparentWindows++;
|
||||||
}
|
data.setTranslucent();
|
||||||
|
}
|
||||||
|
|
||||||
void BlurEffect::paintWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data )
|
void BlurEffect::paintScreen( int mask, QRegion region, ScreenPaintData& data )
|
||||||
{
|
|
||||||
if( mValid && mTransparentWindows )
|
|
||||||
{
|
{
|
||||||
if( mask & PAINT_WINDOW_TRANSLUCENT )
|
// TODO: prePaintWindow() gets called _after_ paintScreen(), so we have no
|
||||||
|
// way of knowing here whether there will be any translucent windows or
|
||||||
|
// not. If we'd know that there's no translucent windows then we could
|
||||||
|
// render straight onto screen, saving some time.
|
||||||
|
if( mValid /*&& mTransparentWindows*/ )
|
||||||
{
|
{
|
||||||
|
// rendering everything onto render target
|
||||||
|
effects->pushRenderTarget(mSceneTarget);
|
||||||
|
effects->paintScreen( mask, region, data );
|
||||||
|
effects->popRenderTarget();
|
||||||
|
|
||||||
|
// Copy changed areas back onto screen
|
||||||
|
mScreenDirty &= mBlurMask;
|
||||||
|
if( !mScreenDirty.isEmpty() )
|
||||||
|
{
|
||||||
|
if( mask & PAINT_SCREEN_TRANSFORMED )
|
||||||
|
{
|
||||||
|
// We don't want any transformations when working with our own
|
||||||
|
// textures, so load an identity matrix
|
||||||
|
glMatrixMode( GL_MODELVIEW );
|
||||||
|
glPushMatrix();
|
||||||
|
glLoadIdentity();
|
||||||
|
}
|
||||||
|
|
||||||
|
GLTexture* tex = mSceneTexture;
|
||||||
|
int pixels = 0;
|
||||||
|
tex->bind();
|
||||||
|
tex->enableUnnormalizedTexCoords();
|
||||||
|
foreach( QRect r, mScreenDirty.rects() )
|
||||||
|
{
|
||||||
|
r.adjust(0, -1, 0, -1);
|
||||||
|
int rx2 = r.x() + r.width();
|
||||||
|
int ry2 = r.y() + r.height();
|
||||||
|
glBegin(GL_QUADS);
|
||||||
|
glTexCoord2f( r.x(), ry2 ); glVertex2f( r.x(), ry2 );
|
||||||
|
glTexCoord2f( rx2 , ry2 ); glVertex2f( rx2 , ry2 );
|
||||||
|
glTexCoord2f( rx2 , r.y() ); glVertex2f( rx2 , r.y() );
|
||||||
|
glTexCoord2f( r.x(), r.y() ); glVertex2f( r.x(), r.y() );
|
||||||
|
glEnd();
|
||||||
|
pixels += r.width()*r.height();
|
||||||
|
}
|
||||||
|
tex->disableUnnormalizedTexCoords();
|
||||||
|
tex->unbind();
|
||||||
|
|
||||||
|
if( mask & PAINT_SCREEN_TRANSFORMED )
|
||||||
|
{
|
||||||
|
// Restore the original matrix
|
||||||
|
glPopMatrix();
|
||||||
|
}
|
||||||
|
// kDebug() << "Copied" << mScreenDirty.rects().count() << "rects, pixels:" << pixels;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
effects->paintScreen( mask, region, data );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BlurEffect::drawWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data )
|
||||||
|
{
|
||||||
|
if( mValid /*&& mTransparentWindows*/ )
|
||||||
|
{
|
||||||
|
if( mask & PAINT_WINDOW_TRANSLUCENT &&
|
||||||
|
(data.opacity != 1.0 || data.contents_opacity != 1.0 || data.decoration_opacity != 1.0 ))
|
||||||
|
{
|
||||||
// Make sure the blur texture is up to date
|
// Make sure the blur texture is up to date
|
||||||
if( mask & PAINT_SCREEN_TRANSFORMED )
|
if( mask & PAINT_SCREEN_TRANSFORMED )
|
||||||
{
|
{
|
||||||
// We don't want any transformations when working with our own
|
// We don't want any transformations when working with our own
|
||||||
// textures, so load an identity matrix
|
// textures, so load an identity matrix
|
||||||
glPushMatrix();
|
glPushMatrix();
|
||||||
glLoadIdentity();
|
glLoadIdentity();
|
||||||
}
|
}
|
||||||
// If we're having transformations, we don't know the window's
|
// If we're having transformations, we don't know the window's
|
||||||
// transformed position on the screen and thus have to update the
|
// transformed position on the screen and thus have to update the
|
||||||
// entire screen
|
// entire screen
|
||||||
if( mask & ( PAINT_WINDOW_TRANSFORMED | PAINT_SCREEN_TRANSFORMED | PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS ) )
|
if( mask & ( PAINT_WINDOW_TRANSFORMED | PAINT_SCREEN_TRANSFORMED | PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS ) )
|
||||||
updateBlurTexture( QRegion(0, 0, displayWidth(), displayHeight()) );
|
updateBlurTexture( QRegion(0, 0, displayWidth(), displayHeight()) );
|
||||||
else
|
else
|
||||||
updateBlurTexture(region);
|
updateBlurTexture( mBlurDirty );
|
||||||
|
mBlurDirty = QRegion();
|
||||||
if( mask & PAINT_SCREEN_TRANSFORMED )
|
if( mask & PAINT_SCREEN_TRANSFORMED )
|
||||||
// Restore the original matrix
|
// Restore the original matrix
|
||||||
glPopMatrix();
|
glPopMatrix();
|
||||||
|
@ -191,97 +275,87 @@ void BlurEffect::paintWindow( EffectWindow* w, int mask, QRegion region, WindowP
|
||||||
glActiveTexture(GL_TEXTURE0);
|
glActiveTexture(GL_TEXTURE0);
|
||||||
|
|
||||||
// Paint
|
// Paint
|
||||||
effects->paintWindow( w, mask, region, data );
|
effects->drawWindow( w, mask, region, data );
|
||||||
if(mTransparentWindows > 1)
|
|
||||||
{
|
|
||||||
// If we have multiple translucent windows on top of each
|
|
||||||
// other, we need to paint those onto the scene rendertarget
|
|
||||||
// as well
|
|
||||||
effects->pushRenderTarget(mSceneTarget);
|
|
||||||
effects->paintWindow( w, mask, region, data );
|
|
||||||
effects->popRenderTarget();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Disable blur texture and shader
|
// Disable blur texture and shader
|
||||||
glActiveTexture(GL_TEXTURE4);
|
glActiveTexture(GL_TEXTURE4);
|
||||||
mBlurTexture->unbind();
|
mBlurTexture->unbind();
|
||||||
glActiveTexture(GL_TEXTURE0);
|
glActiveTexture(GL_TEXTURE0);
|
||||||
mWindowShader->unbind();
|
mWindowShader->unbind();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Opaque window
|
// Opaque window
|
||||||
// Paint to the screen...
|
// Paint to the rendertarget (which is already being used)
|
||||||
effects->paintWindow( w, mask, region, data );
|
effects->drawWindow( w, mask, region, data );
|
||||||
// ...and to the rendertarget as well
|
}
|
||||||
effects->pushRenderTarget(mSceneTarget);
|
// Mark the window's region as dirty
|
||||||
effects->paintWindow( w, mask, region, data );
|
mScreenDirty += region;
|
||||||
effects->popRenderTarget();
|
mBlurDirty += region & mBlurMask;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else
|
else
|
||||||
// If there are no translucent windows then paint as usual
|
// If there are no translucent windows then paint as usual
|
||||||
effects->paintWindow( w, mask, region, data );
|
effects->drawWindow( w, mask, region, data );
|
||||||
}
|
}
|
||||||
|
|
||||||
void BlurEffect::updateBlurTexture(const QRegion& region)
|
void BlurEffect::updateBlurTexture(const QRegion& region)
|
||||||
{
|
{
|
||||||
QRect bounding = region.boundingRect();
|
QRect bounding = region.boundingRect();
|
||||||
QVector<QRect> rects = region.rects();
|
QVector<QRect> rects = region.rects();
|
||||||
int totalarea = 0;
|
int totalarea = 0;
|
||||||
foreach( QRect r, rects )
|
foreach( QRect r, rects )
|
||||||
totalarea += r.width() * r.height();
|
totalarea += r.width() * r.height();
|
||||||
if( (int)(totalarea * 1.33 + 100 ) < bounding.width() * bounding.height() )
|
if( (int)(totalarea * 1.33 + 100 ) < bounding.width() * bounding.height() )
|
||||||
{
|
{
|
||||||
// Use small rects
|
// Use small rects
|
||||||
updateBlurTexture(rects);
|
updateBlurTexture(rects);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Bounding rect is probably cheaper
|
// Bounding rect is probably cheaper
|
||||||
QVector<QRect> tmp( 1, bounding );
|
QVector<QRect> tmp( 1, bounding );
|
||||||
updateBlurTexture( tmp );
|
updateBlurTexture( tmp );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void BlurEffect::updateBlurTexture(const QVector<QRect>& rects)
|
void BlurEffect::updateBlurTexture(const QVector<QRect>& rects)
|
||||||
{
|
{
|
||||||
// Blur
|
// Blur
|
||||||
// First pass (vertical)
|
// First pass (vertical)
|
||||||
effects->pushRenderTarget(mTmpTarget);
|
|
||||||
mBlurShader->bind();
|
mBlurShader->bind();
|
||||||
mSceneTexture->bind();
|
effects->pushRenderTarget(mTmpTarget);
|
||||||
|
mBlurShader->setAttribute("xBlur", 0.0f);
|
||||||
|
mBlurShader->setAttribute("yBlur", 1.0f);
|
||||||
|
|
||||||
mBlurShader->setAttribute("xBlur", 0);
|
mSceneTexture->bind();
|
||||||
mBlurShader->setAttribute("yBlur", 1);
|
|
||||||
|
|
||||||
foreach( QRect r, rects )
|
foreach( QRect r, rects )
|
||||||
{
|
{
|
||||||
r.adjust(-mBlurRadius, -mBlurRadius, mBlurRadius, mBlurRadius);
|
// We change x coordinates here because horizontal blur pass (which
|
||||||
|
// comes after this one) also uses pixels that are horizontally edging
|
||||||
|
// the blurred area. Thus we need to make sure that those pixels are
|
||||||
|
// also updated.
|
||||||
glBegin(GL_QUADS);
|
glBegin(GL_QUADS);
|
||||||
glVertex2f( r.x() , r.y() + r.height() );
|
glVertex2f( r.x()-mBlurRadius , r.y() + r.height() );
|
||||||
glVertex2f( r.x() + r.width(), r.y() + r.height() );
|
glVertex2f( r.x() + r.width()+mBlurRadius, r.y() + r.height() );
|
||||||
glVertex2f( r.x() + r.width(), r.y() );
|
glVertex2f( r.x() + r.width()+mBlurRadius, r.y() );
|
||||||
glVertex2f( r.x() , r.y() );
|
glVertex2f( r.x()-mBlurRadius , r.y() );
|
||||||
glEnd();
|
glEnd();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
mSceneTexture->unbind();
|
mSceneTexture->unbind();
|
||||||
mBlurShader->unbind();
|
|
||||||
effects->popRenderTarget();
|
effects->popRenderTarget();
|
||||||
|
|
||||||
// Second pass (horizontal)
|
// Second pass (horizontal)
|
||||||
effects->pushRenderTarget(mBlurTarget);
|
effects->pushRenderTarget(mBlurTarget);
|
||||||
mBlurShader->bind();
|
mBlurShader->setAttribute("xBlur", 1.0f);
|
||||||
mTmpTexture->bind();
|
mBlurShader->setAttribute("yBlur", 0.0f);
|
||||||
|
|
||||||
mBlurShader->setAttribute("xBlur", 1);
|
mTmpTexture->bind();
|
||||||
mBlurShader->setAttribute("yBlur", 0);
|
|
||||||
|
|
||||||
foreach( QRect r, rects )
|
foreach( QRect r, rects )
|
||||||
{
|
{
|
||||||
r.adjust(-mBlurRadius, -mBlurRadius, mBlurRadius, mBlurRadius);
|
|
||||||
glBegin(GL_QUADS);
|
glBegin(GL_QUADS);
|
||||||
glVertex2f( r.x() , r.y() + r.height() );
|
glVertex2f( r.x() , r.y() + r.height() );
|
||||||
glVertex2f( r.x() + r.width(), r.y() + r.height() );
|
glVertex2f( r.x() + r.width(), r.y() + r.height() );
|
||||||
|
@ -292,9 +366,9 @@ void BlurEffect::updateBlurTexture(const QVector<QRect>& rects)
|
||||||
|
|
||||||
|
|
||||||
mTmpTexture->unbind();
|
mTmpTexture->unbind();
|
||||||
mBlurShader->unbind();
|
|
||||||
effects->popRenderTarget();
|
effects->popRenderTarget();
|
||||||
}
|
mBlurShader->unbind();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
|
|
@ -75,9 +75,10 @@ X-KDE-ServiceTypes=KWin/Effect
|
||||||
X-KDE-PluginInfo-Author=Rivo Laks
|
X-KDE-PluginInfo-Author=Rivo Laks
|
||||||
X-KDE-PluginInfo-Email=rivolaks@hot.ee
|
X-KDE-PluginInfo-Email=rivolaks@hot.ee
|
||||||
X-KDE-PluginInfo-Name=kwin4_effect_blur
|
X-KDE-PluginInfo-Name=kwin4_effect_blur
|
||||||
X-KDE-PluginInfo-Version=0.1.0
|
X-KDE-PluginInfo-Version=0.2.0
|
||||||
X-KDE-PluginInfo-Category=Appearance
|
X-KDE-PluginInfo-Category=Appearance
|
||||||
X-KDE-PluginInfo-Depends=
|
X-KDE-PluginInfo-Depends=
|
||||||
X-KDE-PluginInfo-License=GPL
|
X-KDE-PluginInfo-License=GPL
|
||||||
X-KDE-PluginInfo-EnabledByDefault=false
|
X-KDE-PluginInfo-EnabledByDefault=false
|
||||||
X-KDE-Library=kwin4_effect_builtins
|
X-KDE-Library=kwin4_effect_builtins
|
||||||
|
X-Ordering=85
|
||||||
|
|
|
@ -24,6 +24,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
// Include with base class for effects.
|
// Include with base class for effects.
|
||||||
#include <kwineffects.h>
|
#include <kwineffects.h>
|
||||||
|
|
||||||
|
#include <QRegion>
|
||||||
|
|
||||||
template< class T > class QVector;
|
template< class T > class QVector;
|
||||||
|
|
||||||
|
|
||||||
|
@ -44,9 +46,10 @@ class BlurEffect : public Effect
|
||||||
~BlurEffect();
|
~BlurEffect();
|
||||||
|
|
||||||
virtual void prePaintScreen( ScreenPrePaintData& data, int time );
|
virtual void prePaintScreen( ScreenPrePaintData& data, int time );
|
||||||
|
virtual void paintScreen( int mask, QRegion region, ScreenPaintData& data );
|
||||||
|
|
||||||
virtual void prePaintWindow( EffectWindow* w, WindowPrePaintData& data, int time );
|
virtual void prePaintWindow( EffectWindow* w, WindowPrePaintData& data, int time );
|
||||||
virtual void paintWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data );
|
virtual void drawWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data );
|
||||||
|
|
||||||
static bool supported();
|
static bool supported();
|
||||||
|
|
||||||
|
@ -56,6 +59,8 @@ class BlurEffect : public Effect
|
||||||
void updateBlurTexture(const QVector<QRect>& rects);
|
void updateBlurTexture(const QVector<QRect>& rects);
|
||||||
void updateBlurTexture(const QRegion& region);
|
void updateBlurTexture(const QRegion& region);
|
||||||
|
|
||||||
|
QRegion expandedRegion( const QRegion& r ) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
GLTexture* mSceneTexture;
|
GLTexture* mSceneTexture;
|
||||||
GLTexture* mTmpTexture;
|
GLTexture* mTmpTexture;
|
||||||
|
@ -69,7 +74,11 @@ class BlurEffect : public Effect
|
||||||
int mBlurRadius;
|
int mBlurRadius;
|
||||||
|
|
||||||
int mTransparentWindows;
|
int mTransparentWindows;
|
||||||
int mTime;
|
|
||||||
|
QRegion mBlurDirty;
|
||||||
|
QRegion mScreenDirty;
|
||||||
|
|
||||||
|
QRegion mBlurMask;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
|
@ -14,7 +14,7 @@ vec2 pix2tex(vec2 pix)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns color of the window at given texture coordinate, taking into
|
// Returns color of the window at given texture coordinate, taking into
|
||||||
// account opacity, brightness and saturation
|
// account brightness and saturation, but not opacity
|
||||||
vec4 windowColor(vec2 texcoord)
|
vec4 windowColor(vec2 texcoord)
|
||||||
{
|
{
|
||||||
vec4 color = texture2D(windowTex, texcoord);
|
vec4 color = texture2D(windowTex, texcoord);
|
||||||
|
@ -23,21 +23,18 @@ vec4 windowColor(vec2 texcoord)
|
||||||
color.rgb = mix(vec3(grayscale), color.rgb, saturation);
|
color.rgb = mix(vec3(grayscale), color.rgb, saturation);
|
||||||
// Apply brightness
|
// Apply brightness
|
||||||
color.rgb = color.rgb * brightness;
|
color.rgb = color.rgb * brightness;
|
||||||
// Apply opacity
|
|
||||||
color.a = color.a * opacity;
|
|
||||||
// and return
|
// and return
|
||||||
return color;
|
return color;
|
||||||
}
|
}
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
vec2 texcoord = (gl_TexCoord[0] * gl_TextureMatrix[0]).xy;
|
vec2 blurtexcoord = pix2tex(gl_FragCoord.xy);
|
||||||
vec2 blurtexcoord = pix2tex(gl_FragCoord.xy); //(gl_FragCoord * gl_TextureMatrix[4]).xy;
|
|
||||||
|
|
||||||
vec4 winColor = windowColor(texcoord);
|
vec4 winColor = windowColor(gl_TexCoord[0].xy);
|
||||||
vec3 tex = mix(texture2D(backgroundTex, blurtexcoord).rgb,
|
vec3 tex = mix(texture2D(backgroundTex, blurtexcoord).rgb,
|
||||||
winColor.rgb, winColor.a * opacity);
|
winColor.rgb, winColor.a * opacity);
|
||||||
|
|
||||||
gl_FragColor = vec4(tex, 1.0);
|
gl_FragColor = vec4(tex, pow(winColor.a, 0.2));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
gl_TexCoord[0] = gl_MultiTexCoord0;
|
gl_TexCoord[0] = gl_MultiTexCoord0 * gl_TextureMatrix[0];
|
||||||
gl_Position = ftransform();
|
gl_Position = ftransform();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,20 +1,19 @@
|
||||||
uniform sampler2D inputTex;
|
uniform sampler2D inputTex;
|
||||||
uniform float textureWidth;
|
|
||||||
uniform float textureHeight;
|
|
||||||
|
|
||||||
varying vec2 pos;
|
varying vec2 samplePos1;
|
||||||
varying vec2 blurDirection;
|
varying vec2 samplePos2;
|
||||||
|
varying vec2 samplePos3;
|
||||||
|
varying vec2 samplePos4;
|
||||||
|
varying vec2 samplePos5;
|
||||||
|
|
||||||
|
|
||||||
// Converts pixel coordinates to texture coordinates
|
// If defined, use five samples (blur radius = 5), otherwise 3 samples (radius = 3)
|
||||||
vec2 pix2tex(vec2 pix)
|
#define FIVE_SAMPLES
|
||||||
|
|
||||||
|
|
||||||
|
vec3 blurTex(vec2 pos, float strength)
|
||||||
{
|
{
|
||||||
return vec2(pix.x / textureWidth, 1.0 - pix.y / textureHeight);
|
return texture2D(inputTex, pos).rgb * strength;
|
||||||
}
|
|
||||||
|
|
||||||
vec3 blurTex(float offset, float strength)
|
|
||||||
{
|
|
||||||
return texture2D(inputTex, pix2tex(pos + blurDirection * offset)).rgb * strength;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
|
@ -23,11 +22,17 @@ void main()
|
||||||
// This blur actually has a radius of 4, but we take advantage of gpu's
|
// This blur actually has a radius of 4, but we take advantage of gpu's
|
||||||
// linear texture filtering, so e.g. 1.5 actually gives us both texels
|
// linear texture filtering, so e.g. 1.5 actually gives us both texels
|
||||||
// 1 and 2
|
// 1 and 2
|
||||||
vec3 tex = blurTex(0.0, 0.20);
|
#ifdef FIVE_SAMPLES
|
||||||
tex += blurTex(-1.5, 0.30);
|
vec3 tex = blurTex(samplePos1, 0.30);
|
||||||
tex += blurTex( 1.5, 0.30);
|
tex += blurTex(samplePos2, 0.25);
|
||||||
tex += blurTex(-3.5, 0.10);
|
tex += blurTex(samplePos3, 0.25);
|
||||||
tex += blurTex( 3.5, 0.10);
|
tex += blurTex(samplePos4, 0.1);
|
||||||
|
tex += blurTex(samplePos5, 0.1);
|
||||||
|
#else
|
||||||
|
vec3 tex = blurTex(samplePos1, 0.40);
|
||||||
|
tex += blurTex(samplePos2, 0.30);
|
||||||
|
tex += blurTex(samplePos3, 0.30);
|
||||||
|
#endif
|
||||||
|
|
||||||
gl_FragColor = vec4(tex, 1.0);
|
gl_FragColor = vec4(tex, 1.0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,28 @@
|
||||||
varying vec2 pos;
|
varying vec2 samplePos1;
|
||||||
varying vec2 blurDirection;
|
varying vec2 samplePos2;
|
||||||
|
varying vec2 samplePos3;
|
||||||
|
varying vec2 samplePos4;
|
||||||
|
varying vec2 samplePos5;
|
||||||
|
|
||||||
|
uniform float textureWidth;
|
||||||
|
uniform float textureHeight;
|
||||||
attribute float xBlur;
|
attribute float xBlur;
|
||||||
attribute float yBlur;
|
attribute float yBlur;
|
||||||
|
|
||||||
|
|
||||||
|
vec2 mkSamplePos(vec2 origin, float offset)
|
||||||
|
{
|
||||||
|
vec2 foo = origin + vec2(xBlur, yBlur) * offset;
|
||||||
|
return vec2(foo.x / textureWidth, 1.0 - foo.y / textureHeight);
|
||||||
|
}
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
blurDirection = vec2(xBlur, yBlur);
|
samplePos1 = mkSamplePos(gl_Vertex.xy, 0.0);
|
||||||
pos = gl_Vertex.xy;
|
samplePos2 = mkSamplePos(gl_Vertex.xy, -1.5);
|
||||||
|
samplePos3 = mkSamplePos(gl_Vertex.xy, 1.5);
|
||||||
|
samplePos4 = mkSamplePos(gl_Vertex.xy, 3.5);
|
||||||
|
samplePos5 = mkSamplePos(gl_Vertex.xy, -3.5);
|
||||||
|
|
||||||
gl_Position = ftransform();
|
gl_Position = ftransform();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue