Revised FX pipeline. Added Glow, Shadow and Pixelate. Tested against multi-pass.

This commit is contained in:
Richard Davey 2023-02-13 18:50:27 +00:00
parent c09ce7b2e9
commit 532d5a9375
13 changed files with 558 additions and 168 deletions

View file

@ -4,6 +4,10 @@
* @license {@link https://opensource.org/licenses/MIT|MIT License} * @license {@link https://opensource.org/licenses/MIT|MIT License}
*/ */
var Glow = require('../fx/Glow');
var Shadow = require('../fx/Shadow');
var Pixelate = require('../fx/Pixelate');
/** /**
* Provides methods used for setting the FX values of a Game Object. * Provides methods used for setting the FX values of a Game Object.
* Should be applied as a mixin and not used directly. * Should be applied as a mixin and not used directly.
@ -93,28 +97,8 @@ var FX = {
{ {
}, },
enableFX: function () enableFX: function (padding)
{ {
this.fx = {
glow: {
quality: 0.1,
distance: 10,
outerStrength: 4,
innerStrength: 0,
knockout: false,
color: [ 1, 1, 1, 1 ]
},
shadow: {
x: 0,
y: 0,
decay: 0.1,
power: 1.0,
shadowColor: [ 0, 0, 0, 1 ],
samples: 12,
intensity: 1
}
};
var renderer = this.scene.sys.renderer; var renderer = this.scene.sys.renderer;
if (!renderer) if (!renderer)
@ -132,9 +116,66 @@ var FX = {
this.pipeline = pipeline; this.pipeline = pipeline;
if (!this.fx)
{
this.fx = [];
}
if (padding !== undefined)
{
this.fxPadding = padding;
}
return this; return this;
}, },
clearFX: function ()
{
// Remove them all
},
removeFX: function (fx)
{
// Remove specific fx
},
disableFX: function (clear)
{
this.resetPipeline();
if (clear)
{
this.clearFX();
}
},
addGlowFX: function ()
{
var fx = new Glow(this);
this.fx.push(fx);
return fx;
},
addShadowFX: function ()
{
var fx = new Shadow(this);
this.fx.push(fx);
return fx;
},
addPixelateFX: function ()
{
var fx = new Pixelate(this);
this.fx.push(fx);
return fx;
},
addBloom: function (r, g, b) addBloom: function (r, g, b)
{ {
} }

View file

@ -0,0 +1,73 @@
/**
* @author Richard Davey <rich@photonstorm.com>
* @copyright 2013-2023 Photon Storm Ltd.
* @license {@link https://opensource.org/licenses/MIT|MIT License}
*/
var Class = require('../../utils/Class');
var FX_CONST = require('./const');
/**
* @classdesc
*
* @class Glow
* @memberof Phaser.GameObjects.FX
* @constructor
* @since 3.60.0
*
* @param {Phaser.GameObjects.GameObject} gameObject - A reference to the Game Object that has this fx.
*/
var Glow = new Class({
initialize:
function Glow (gameObject)
{
this.type = FX_CONST.GLOW;
this.gameObject = gameObject;
this.active = true;
this.distance = 16;
this.outerStrength = 4;
this.innerStrength = 0;
this.knockout = false;
this._color = [ 1, 1, 1, 1 ];
},
/**
* The color of the glow.
*
* @name Phaser.GameObjects.FX.Glow#color
* @type {number}
* @since 3.60.0
*/
color: {
get: function ()
{
var color = this._color;
return (((color[0] * 255) << 16) + ((color[1] * 255) << 8) + (color[2] * 255 | 0));
},
set: function (value)
{
var color = this._color;
color[0] = ((value >> 16) & 0xFF) / 255;
color[1] = ((value >> 8) & 0xFF) / 255;
color[2] = (value & 0xFF) / 255;
}
},
destroy: function ()
{
this.gameObject = null;
}
});
module.exports = Glow;

View file

@ -0,0 +1,42 @@
/**
* @author Richard Davey <rich@photonstorm.com>
* @copyright 2013-2023 Photon Storm Ltd.
* @license {@link https://opensource.org/licenses/MIT|MIT License}
*/
var Class = require('../../utils/Class');
var FX_CONST = require('./const');
/**
* @classdesc
*
* @class Pixelate
* @memberof Phaser.GameObjects.FX
* @constructor
* @since 3.60.0
*
* @param {Phaser.GameObjects.GameObject} gameObject - A reference to the Game Object that has this fx.
*/
var Pixelate = new Class({
initialize:
function Pixelate (gameObject)
{
this.type = FX_CONST.PIXELATE;
this.gameObject = gameObject;
this.active = true;
this.amount = 1;
},
destroy: function ()
{
this.gameObject = null;
}
});
module.exports = Pixelate;

View file

@ -0,0 +1,75 @@
/**
* @author Richard Davey <rich@photonstorm.com>
* @copyright 2013-2023 Photon Storm Ltd.
* @license {@link https://opensource.org/licenses/MIT|MIT License}
*/
var Class = require('../../utils/Class');
var FX_CONST = require('./const');
/**
* @classdesc
*
* @class Shadow
* @memberof Phaser.GameObjects.FX
* @constructor
* @since 3.60.0
*
* @param {Phaser.GameObjects.GameObject} gameObject - A reference to the Game Object that has this fx.
*/
var Shadow = new Class({
initialize:
function Shadow (gameObject)
{
this.type = FX_CONST.SHADOW;
this.gameObject = gameObject;
this.active = true;
this.x = 0;
this.y = 0;
this.decay = 0.1;
this.power = 1.0;
this._color = [ 0, 0, 0, 1 ];
this.samples = 6; // max 12, min 1
this.intensity = 1;
},
/**
* The color of the shadow.
*
* @name Phaser.GameObjects.FX.Shadow#color
* @type {number}
* @since 3.60.0
*/
color: {
get: function ()
{
var color = this._color;
return (((color[0] * 255) << 16) + ((color[1] * 255) << 8) + (color[2] * 255 | 0));
},
set: function (value)
{
var color = this._color;
color[0] = ((value >> 16) & 0xFF) / 255;
color[1] = ((value >> 8) & 0xFF) / 255;
color[2] = (value & 0xFF) / 255;
}
},
destroy: function ()
{
this.gameObject = null;
}
});
module.exports = Shadow;

View file

@ -0,0 +1,41 @@
/**
* @author Richard Davey <rich@photonstorm.com>
* @copyright 2013-2023 Photon Storm Ltd.
* @license {@link https://opensource.org/licenses/MIT|MIT License}
*/
var FX_CONST = {
/**
* The Glow FX.
*
* @name Phaser.GameObjects.FX.GLOW
* @type {number}
* @const
* @since 3.60.0
*/
GLOW: 4,
/**
* The Shadow FX.
*
* @name Phaser.GameObjects.FX.SHADOW
* @type {number}
* @const
* @since 3.60.0
*/
SHADOW: 5,
/**
* The Pixelate FX.
*
* @name Phaser.GameObjects.FX.PIXELATE
* @type {number}
* @const
* @since 3.60.0
*/
PIXELATE: 6
};
module.exports = FX_CONST;

View file

@ -5,9 +5,10 @@
*/ */
var Class = require('../../../utils/Class'); var Class = require('../../../utils/Class');
var PreFXPipeline = require('./PreFXPipeline'); var FX_CONST = require('../../../gameobjects/fx/const');
var BloomFrag = require('../shaders/FXBloom-frag.js');
var GlowFrag = require('../shaders/FXGlow-frag.js'); var GlowFrag = require('../shaders/FXGlow-frag.js');
var PixelateFrag = require('../shaders/FXPixelate-frag.js');
var PreFXPipeline = require('./PreFXPipeline');
var ShadowFrag = require('../shaders/FXShadow-frag.js'); var ShadowFrag = require('../shaders/FXShadow-frag.js');
var SingleQuadVS = require('../shaders/Single-vert.js'); var SingleQuadVS = require('../shaders/Single-vert.js');
@ -30,54 +31,17 @@ var FXPipeline = new Class({
function FXPipeline (config) function FXPipeline (config)
{ {
var shaders = []; config.shaders = [
{ name: 'Glow', fragShader: GlowFrag, vertShader: SingleQuadVS },
var fragShader = GlowFrag; { name: 'Shadow', fragShader: ShadowFrag, vertShader: SingleQuadVS },
var quality = 0.1; { name: 'Pixelate', fragShader: PixelateFrag, vertShader: SingleQuadVS }
var distance = 10; ];
fragShader = fragShader.replace(/__SIZE__/gi, `${(1 / quality / distance).toFixed(7)}`);
fragShader = fragShader.replace(/__DIST__/gi, `${distance.toFixed(0)}.0`);
shaders.push({
name: 'Glow',
fragShader: fragShader,
vertShader: SingleQuadVS
});
fragShader = ShadowFrag;
var samples = 12;
fragShader = fragShader.replace(/__SAMPLES__/gi, samples.toFixed(0));
shaders.push({
name: 'Shadow',
fragShader: fragShader,
vertShader: SingleQuadVS
});
config.shaders = shaders;
PreFXPipeline.call(this, config); PreFXPipeline.call(this, config);
this.bloom = { this.source;
steps: 4, this.target;
offsetX: 2, this.swap;
offsetY: 3,
blurStrength: 1,
strength: 1.5,
color: [ 1, 1, 1 ]
};
this.glow = {
quality: 0.1,
distance: 10,
outerStrength: 4,
innerStrength: 0,
knockout: false,
color: [ 1, 1, 1, 1 ]
};
}, },
boot: function () boot: function ()
@ -85,60 +49,130 @@ var FXPipeline = new Class({
PreFXPipeline.prototype.boot.call(this); PreFXPipeline.prototype.boot.call(this);
console.log(this.shaders); console.log(this.shaders);
}, },
onDraw: function (target1, target2, target3) onDraw: function (target1, target2, target3)
{ {
// tempSprite = current sprite being drawn this.source = target1;
this.target = target2;
this.swap = target3;
this.setShader(this.shaders[4]); var drawn = false;
var sprite = this.tempSprite;
var glow = this.tempSprite.fx.glow; if (sprite && sprite.fx)
this.set1f('outerStrength', glow.outerStrength);
this.set1f('innerStrength', glow.innerStrength);
this.set4fv('glowColor', glow.color);
this.setBoolean('knockout', glow.knockout);
this.set2f('resolution', target1.width, target1.height);
this.copy(target1, target2);
this.setShader(this.shaders[5]);
var shadow = this.tempSprite.fx.shadow;
this.set1f('intensity', shadow.intensity);
this.set1f('decay', shadow.decay);
this.set1f('power', shadow.power / shadow.samples);
this.set2f('lightPosition', shadow.x, shadow.y);
this.set4fv('shadowColor', shadow.shadowColor);
this.copy(target2, target1);
this.drawToGame(target1);
},
onBloomDraw: function (target1, target2, target3)
{
this.manager.copyFrame(target1, target3);
var x = (2 / target1.width) * this.offsetX;
var y = (2 / target1.height) * this.offsetY;
for (var i = 0; i < this.steps; i++)
{ {
this.set2f('uOffset', x, 0); for (var i = 0; i < sprite.fx.length; i++)
this.copySprite(target1, target2); {
var fx = sprite.fx[i];
this.set2f('uOffset', 0, y); if (fx.active)
this.copySprite(target2, target1); {
switch (fx.type)
{
case FX_CONST.GLOW:
this.onGlowDraw(fx);
drawn = true;
break;
case FX_CONST.SHADOW:
this.onShadowDraw(fx);
drawn = true;
break;
case FX_CONST.PIXELATE:
this.onPixelateDraw(fx);
drawn = true;
break;
}
}
}
} }
this.blendFrames(target3, target1, target2, this.strength); if (!drawn)
{
this.source = target1;
}
this.copyToGame(target2); this.drawToGame(this.source);
} },
onGlowDraw: function (config)
{
var source = this.source;
var target = this.target;
this.setShader(this.shaders[FX_CONST.GLOW]);
this.set1f('distance', config.distance);
this.set1f('outerStrength', config.outerStrength);
this.set1f('innerStrength', config.innerStrength);
this.set4fv('glowColor', config._color);
this.setBoolean('knockout', config.knockout);
this.set2f('resolution', source.width, source.height);
this.copy(source, target);
this.source = target;
this.target = source;
},
onShadowDraw: function (config)
{
var source = this.source;
var target = this.target;
this.setShader(this.shaders[FX_CONST.SHADOW]);
this.set1i('samples', config.samples);
this.set1f('intensity', config.intensity);
this.set1f('decay', config.decay);
this.set1f('power', config.power / config.samples);
this.set2f('lightPosition', config.x, config.y);
this.set4fv('color', config._color);
this.copy(source, target);
this.source = target;
this.target = source;
},
onPixelateDraw: function (config)
{
var source = this.source;
var target = this.target;
this.setShader(this.shaders[FX_CONST.PIXELATE]);
this.set1f('amount', config.amount);
this.set2f('resolution', source.width, source.height);
this.copy(source, target);
this.source = target;
this.target = source;
},
// onBloomDraw: function (target1, target2, target3)
// {
// this.manager.copyFrame(target1, target3);
// var x = (2 / target1.width) * this.offsetX;
// var y = (2 / target1.height) * this.offsetY;
// for (var i = 0; i < this.steps; i++)
// {
// this.set2f('uOffset', x, 0);
// this.copySprite(target1, target2);
// this.set2f('uOffset', 0, y);
// this.copySprite(target2, target1);
// }
// this.blendFrames(target3, target1, target2, this.strength);
// this.copyToGame(target2);
// }
}); });

View file

@ -566,25 +566,22 @@ var PreFXPipeline = new Class({
gl.bindFramebuffer(gl.FRAMEBUFFER, null); gl.bindFramebuffer(gl.FRAMEBUFFER, null);
}, },
// cls: function (target1, target2, target3) /**
// { * Draws the `source` Render Target to the `target` Render Target.
// var gl = this.gl; *
* This is done using whatever the currently bound shader is. This method does
// gl.clearColor(0, 0, 0, 0); * not set a shader. All it does is bind the source texture, set the viewport and UVs
// gl.viewport(0, 0, target1.width, target1.height); * then bind the target framebuffer, clears it and draws the source to it.
*
// gl.bindFramebuffer(gl.FRAMEBUFFER, target1.framebuffer); * At the end a null framebuffer is bound. No other clearing-up takes place, so
// gl.clear(gl.COLOR_BUFFER_BIT); * use this method carefully.
*
// gl.bindFramebuffer(gl.FRAMEBUFFER, target2.framebuffer); * @method Phaser.Renderer.WebGL.Pipelines.PreFXPipeline#copy
// gl.clear(gl.COLOR_BUFFER_BIT); * @since 3.60.0
*
// gl.bindFramebuffer(gl.FRAMEBUFFER, target3.framebuffer); * @param {Phaser.Renderer.WebGL.RenderTarget} source - The source Render Target.
// gl.clear(gl.COLOR_BUFFER_BIT); * @param {Phaser.Renderer.WebGL.RenderTarget} target - The target Render Target.
*/
// gl.bindFramebuffer(gl.FRAMEBUFFER, null);
// },
copy: function (source, target) copy: function (source, target)
{ {
var gl = this.gl; var gl = this.gl;

View file

@ -7,6 +7,7 @@ module.exports = [
'', '',
'varying vec2 outTexCoord;', 'varying vec2 outTexCoord;',
'', '',
'uniform float distance;',
'uniform float outerStrength;', 'uniform float outerStrength;',
'uniform float innerStrength;', 'uniform float innerStrength;',
'uniform vec2 resolution;', 'uniform vec2 resolution;',
@ -14,12 +15,8 @@ module.exports = [
'uniform bool knockout;', 'uniform bool knockout;',
'', '',
'const float PI = 3.14159265358979323846264;', 'const float PI = 3.14159265358979323846264;',
'', 'const float MAX_DIST = 128.0;',
'const float DIST = __DIST__;', 'const float SIZE = 0.15;',
'const float SIZE = min(__SIZE__, PI * 2.0);',
'const float NUM = ceil(PI * 2.0 / SIZE);',
'',
'const float MAX_TOTAL_ALPHA = NUM * DIST * (DIST + 1.0) / 2.0;',
'', '',
'void main ()', 'void main ()',
'{', '{',
@ -34,24 +31,30 @@ module.exports = [
' {', ' {',
' direction = vec2(cos(angle), sin(angle)) * px;', ' direction = vec2(cos(angle), sin(angle)) * px;',
'', '',
' for (float curDistance = 0.0; curDistance < DIST; curDistance++)', ' for (float curDistance = 0.0; curDistance < MAX_DIST; curDistance++)',
' {', ' {',
' if (curDistance >= distance)',
' {',
' break;',
' }',
'',
' displaced = outTexCoord + direction * (curDistance + 1.0);', ' displaced = outTexCoord + direction * (curDistance + 1.0);',
'', '',
' totalAlpha += (DIST - curDistance) * texture2D(uMainSampler, displaced).a;', ' totalAlpha += (distance - curDistance) * texture2D(uMainSampler, displaced).a;',
' }', ' }',
' }', ' }',
'', '',
' vec4 curColor = texture2D(uMainSampler, outTexCoord);', ' vec4 curColor = texture2D(uMainSampler, outTexCoord);',
'', '',
' float alphaRatio = (totalAlpha / MAX_TOTAL_ALPHA);', ' float maxAlpha = 42.0 * distance * (distance + 1.0) / 2.0;',
' float alphaRatio = (totalAlpha / maxAlpha);',
'', '',
' float innerGlowAlpha = (1.0 - alphaRatio) * innerStrength * curColor.a;', ' float innerGlowAlpha = (1.0 - alphaRatio) * innerStrength * curColor.a;',
' float innerGlowStrength = min(1.0, innerGlowAlpha);', ' float innerGlowStrength = min(1.0, innerGlowAlpha);',
'', '',
' vec4 innerColor = mix(curColor, glowColor, innerGlowStrength);', ' vec4 innerColor = mix(curColor, glowColor, innerGlowStrength);',
'', '',
' float outerGlowAlpha = alphaRatio * outerStrength * (1. - curColor.a);', ' float outerGlowAlpha = alphaRatio * outerStrength * (1.0 - curColor.a);',
' float outerGlowStrength = min(1.0 - innerColor.a, outerGlowAlpha);', ' float outerGlowStrength = min(1.0 - innerColor.a, outerGlowAlpha);',
'', '',
' vec4 outerGlowColor = outerGlowStrength * glowColor.rgba;', ' vec4 outerGlowColor = outerGlowStrength * glowColor.rgba;',
@ -59,6 +62,7 @@ module.exports = [
' if (knockout)', ' if (knockout)',
' {', ' {',
' float resultAlpha = outerGlowAlpha + innerGlowAlpha;', ' float resultAlpha = outerGlowAlpha + innerGlowAlpha;',
'',
' gl_FragColor = vec4(glowColor.rgb * resultAlpha, resultAlpha);', ' gl_FragColor = vec4(glowColor.rgb * resultAlpha, resultAlpha);',
' }', ' }',
' else', ' else',

View file

@ -0,0 +1,33 @@
module.exports = [
'#define SHADER_NAME PIXELATE_FS',
'',
'precision mediump float;',
'',
'uniform sampler2D uMainSampler;',
'uniform vec2 resolution;',
'uniform float amount;',
'',
'varying vec2 outTexCoord;',
'',
'void main ()',
'{',
' float pixelSize = floor(2.0 + amount);',
'',
' vec2 center = pixelSize * floor(outTexCoord * resolution / pixelSize) + pixelSize * vec2(0.5, 0.5);',
'',
' vec2 corner1 = center + pixelSize * vec2(-0.5, -0.5);',
' vec2 corner2 = center + pixelSize * vec2(+0.5, -0.5);',
' vec2 corner3 = center + pixelSize * vec2(+0.5, +0.5);',
' vec2 corner4 = center + pixelSize * vec2(-0.5, +0.5);',
'',
' vec4 pixel = 0.4 * texture2D(uMainSampler, center / resolution);',
'',
' pixel += 0.15 * texture2D(uMainSampler, corner1 / resolution);',
' pixel += 0.15 * texture2D(uMainSampler, corner2 / resolution);',
' pixel += 0.15 * texture2D(uMainSampler, corner3 / resolution);',
' pixel += 0.15 * texture2D(uMainSampler, corner4 / resolution);',
'',
' gl_FragColor = pixel;',
'}',
''
].join('\n');

View file

@ -4,15 +4,17 @@ module.exports = [
'precision mediump float;', 'precision mediump float;',
'', '',
'uniform sampler2D uMainSampler;', 'uniform sampler2D uMainSampler;',
'uniform vec2 lightPosition;',
'uniform vec4 shadowColor;',
'uniform float decay;',
'uniform float power;',
'uniform float intensity;',
'', '',
'varying vec2 outTexCoord;', 'varying vec2 outTexCoord;',
'', '',
'const int SAMPLES = __SAMPLES__;', 'uniform vec2 lightPosition;',
'uniform vec4 color;',
'uniform float decay;',
'uniform float power;',
'uniform float intensity;',
'uniform int samples;',
'',
'const int MAX = 12;',
'', '',
'void main ()', 'void main ()',
'{', '{',
@ -21,15 +23,21 @@ module.exports = [
' vec2 pc = (lightPosition - outTexCoord) * intensity;', ' vec2 pc = (lightPosition - outTexCoord) * intensity;',
'', '',
' float shadow = 0.0;', ' float shadow = 0.0;',
' float limit = max(float(MAX), float(samples));',
'', '',
' for (int i = 0; i < SAMPLES; ++i)', ' for (int i = 0; i < MAX; ++i)',
' {', ' {',
' shadow += texture2D(uMainSampler, outTexCoord + float(i) * decay / float(SAMPLES) * pc).a * power;', ' if (i >= samples)',
' {',
' break;',
' }',
'',
' shadow += texture2D(uMainSampler, outTexCoord + float(i) * decay / limit * pc).a * power;',
' }', ' }',
'', '',
' float mask = 1.0 - texture.a;', ' float mask = 1.0 - texture.a;',
'', '',
' gl_FragColor = mix(texture, shadowColor, shadow * mask);', ' gl_FragColor = mix(texture, color, shadow * mask);',
'}', '}',
'' ''
].join('\n'); ].join('\n');

View file

@ -6,6 +6,7 @@ uniform sampler2D uMainSampler;
varying vec2 outTexCoord; varying vec2 outTexCoord;
uniform float distance;
uniform float outerStrength; uniform float outerStrength;
uniform float innerStrength; uniform float innerStrength;
uniform vec2 resolution; uniform vec2 resolution;
@ -13,12 +14,8 @@ uniform vec4 glowColor;
uniform bool knockout; uniform bool knockout;
const float PI = 3.14159265358979323846264; const float PI = 3.14159265358979323846264;
const float MAX_DIST = 128.0;
const float DIST = __DIST__; const float SIZE = 0.15;
const float SIZE = min(__SIZE__, PI * 2.0);
const float NUM = ceil(PI * 2.0 / SIZE);
const float MAX_TOTAL_ALPHA = NUM * DIST * (DIST + 1.0) / 2.0;
void main () void main ()
{ {
@ -33,24 +30,30 @@ void main ()
{ {
direction = vec2(cos(angle), sin(angle)) * px; direction = vec2(cos(angle), sin(angle)) * px;
for (float curDistance = 0.0; curDistance < DIST; curDistance++) for (float curDistance = 0.0; curDistance < MAX_DIST; curDistance++)
{ {
if (curDistance >= distance)
{
break;
}
displaced = outTexCoord + direction * (curDistance + 1.0); displaced = outTexCoord + direction * (curDistance + 1.0);
totalAlpha += (DIST - curDistance) * texture2D(uMainSampler, displaced).a; totalAlpha += (distance - curDistance) * texture2D(uMainSampler, displaced).a;
} }
} }
vec4 curColor = texture2D(uMainSampler, outTexCoord); vec4 curColor = texture2D(uMainSampler, outTexCoord);
float alphaRatio = (totalAlpha / MAX_TOTAL_ALPHA); float maxAlpha = 42.0 * distance * (distance + 1.0) / 2.0;
float alphaRatio = (totalAlpha / maxAlpha);
float innerGlowAlpha = (1.0 - alphaRatio) * innerStrength * curColor.a; float innerGlowAlpha = (1.0 - alphaRatio) * innerStrength * curColor.a;
float innerGlowStrength = min(1.0, innerGlowAlpha); float innerGlowStrength = min(1.0, innerGlowAlpha);
vec4 innerColor = mix(curColor, glowColor, innerGlowStrength); vec4 innerColor = mix(curColor, glowColor, innerGlowStrength);
float outerGlowAlpha = alphaRatio * outerStrength * (1. - curColor.a); float outerGlowAlpha = alphaRatio * outerStrength * (1.0 - curColor.a);
float outerGlowStrength = min(1.0 - innerColor.a, outerGlowAlpha); float outerGlowStrength = min(1.0 - innerColor.a, outerGlowAlpha);
vec4 outerGlowColor = outerGlowStrength * glowColor.rgba; vec4 outerGlowColor = outerGlowStrength * glowColor.rgba;
@ -58,6 +61,7 @@ void main ()
if (knockout) if (knockout)
{ {
float resultAlpha = outerGlowAlpha + innerGlowAlpha; float resultAlpha = outerGlowAlpha + innerGlowAlpha;
gl_FragColor = vec4(glowColor.rgb * resultAlpha, resultAlpha); gl_FragColor = vec4(glowColor.rgb * resultAlpha, resultAlpha);
} }
else else

View file

@ -0,0 +1,30 @@
#define SHADER_NAME PIXELATE_FS
precision mediump float;
uniform sampler2D uMainSampler;
uniform vec2 resolution;
uniform float amount;
varying vec2 outTexCoord;
void main ()
{
float pixelSize = floor(2.0 + amount);
vec2 center = pixelSize * floor(outTexCoord * resolution / pixelSize) + pixelSize * vec2(0.5, 0.5);
vec2 corner1 = center + pixelSize * vec2(-0.5, -0.5);
vec2 corner2 = center + pixelSize * vec2(+0.5, -0.5);
vec2 corner3 = center + pixelSize * vec2(+0.5, +0.5);
vec2 corner4 = center + pixelSize * vec2(-0.5, +0.5);
vec4 pixel = 0.4 * texture2D(uMainSampler, center / resolution);
pixel += 0.15 * texture2D(uMainSampler, corner1 / resolution);
pixel += 0.15 * texture2D(uMainSampler, corner2 / resolution);
pixel += 0.15 * texture2D(uMainSampler, corner3 / resolution);
pixel += 0.15 * texture2D(uMainSampler, corner4 / resolution);
gl_FragColor = pixel;
}

View file

@ -3,15 +3,17 @@
precision mediump float; precision mediump float;
uniform sampler2D uMainSampler; uniform sampler2D uMainSampler;
uniform vec2 lightPosition;
uniform vec4 shadowColor;
uniform float decay;
uniform float power;
uniform float intensity;
varying vec2 outTexCoord; varying vec2 outTexCoord;
const int SAMPLES = __SAMPLES__; uniform vec2 lightPosition;
uniform vec4 color;
uniform float decay;
uniform float power;
uniform float intensity;
uniform int samples;
const int MAX = 12;
void main () void main ()
{ {
@ -20,13 +22,19 @@ void main ()
vec2 pc = (lightPosition - outTexCoord) * intensity; vec2 pc = (lightPosition - outTexCoord) * intensity;
float shadow = 0.0; float shadow = 0.0;
float limit = max(float(MAX), float(samples));
for (int i = 0; i < SAMPLES; ++i) for (int i = 0; i < MAX; ++i)
{ {
shadow += texture2D(uMainSampler, outTexCoord + float(i) * decay / float(SAMPLES) * pc).a * power; if (i >= samples)
{
break;
}
shadow += texture2D(uMainSampler, outTexCoord + float(i) * decay / limit * pc).a * power;
} }
float mask = 1.0 - texture.a; float mask = 1.0 - texture.a;
gl_FragColor = mix(texture, shadowColor, shadow * mask); gl_FragColor = mix(texture, color, shadow * mask);
} }