Skip to content

Instantly share code, notes, and snippets.

@ssube
Last active December 11, 2022 14:46
Show Gist options
  • Save ssube/a215efbb87d876c2b889c9b82a5e1913 to your computer and use it in GitHub Desktop.
Save ssube/a215efbb87d876c2b889c9b82a5e1913 to your computer and use it in GitHub Desktop.
phaser shader to texture
var myCustomCanvas = document.createElement('canvas');
myCustomCanvas.id = 'myCustomCanvas';
myCustomCanvas.style = 'border: 8px solid green';
document.body.appendChild(myCustomCanvas);
// It's important to set the WebGL context values that Phaser needs:
var contextCreationConfig = {
alpha: false,
depth: false,
antialias: true,
premultipliedAlpha: true,
stencil: true,
preserveDrawingBuffer: false,
failIfMajorPerformanceCaveat: false,
powerPreference: 'default'
};
var myCustomContext = myCustomCanvas.getContext('webgl2', contextCreationConfig);
const config = {
type: Phaser.WEBGL,
parent: 'phaser-example',
canvas: myCustomCanvas,
context: myCustomContext,
scene: {
preload: preload,
create: create,
update: update,
},
};
const InvertPipeline = new Phaser.Class({
Extends: Phaser.Renderer.WebGL.Pipelines.TextureTintPipeline,
initialize: function CustomPipeline (game) {
Phaser.Renderer.WebGL.Pipelines.TextureTintPipeline.call(this, {
game: game,
renderer: game.renderer,
fragShader: `
precision mediump float;
uniform sampler2D uMainSampler;
uniform vec2 uResolution;
uniform float uTime;
varying vec2 outTexCoord;
varying vec4 outTint;
void main()
{
vec2 uv = outTexCoord.xy;
uv.y = 1.0 - uv.y;
vec4 texel = vec4(1.0) - texture2D(uMainSampler, uv);
gl_FragColor = texel;
// gl_FragColor.xy = outTexCoord.xy;
}`,
});
},
});
const MipmapPipeline = new Phaser.Class({
Extends: Phaser.Renderer.WebGL.Pipelines.TextureTintPipeline,
onBind: function () {
Phaser.Renderer.WebGL.Pipelines.TextureTintPipeline.prototype.onBind.call(this);
const program = this.program;
const renderer = this.renderer;
const gl = this.renderer.gl;
// debugger;
renderer.setTexture2D(mips.glTexture, 7);
renderer.setInt1(program, 'uMipSampler', 7);
const active = gl.getParameter(gl.ACTIVE_TEXTURE);
gl.activeTexture(gl.TEXTURE7);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR);
gl.activeTexture(active);
return this;
},
initialize: function CustomPipeline (game) {
Phaser.Renderer.WebGL.Pipelines.TextureTintPipeline.call(this, {
game: game,
renderer: game.renderer,
fragShader: `#version 300 es
precision mediump float;
uniform sampler2D uMainSampler;
uniform sampler2D uMipSampler;
uniform vec2 uResolution;
uniform float uTime;
uniform float uLum;
in vec2 outTexCoord;
in vec4 outTint;
out vec4 outColor;
void main()
{
vec2 uv = outTexCoord.xy;
uv.y = 1.0 - uv.y;
float lod = max(0.0, (10.0 * uLum) + (10.0 * sin( uTime ))) * step( uv.x, 0.5 );
vec4 lum = textureLod(uMipSampler, outTexCoord, 5.0);
vec4 texel = texture(uMainSampler, uv);
outColor = lum + texel;
outColor.w = 1.0f;
}`,
vertShader: `#version 300 es
#define SHADER_NAME PHASER_TEXTURE_TINT_VS
precision mediump float;
uniform mat4 uProjectionMatrix;
uniform mat4 uViewMatrix;
uniform mat4 uModelMatrix;
in vec2 inPosition;
in vec2 inTexCoord;
in float inTintEffect;
in vec4 inTint;
out vec2 outTexCoord;
out float outTintEffect;
out vec4 outTint;
void main ()
{
gl_Position = uProjectionMatrix * uViewMatrix * uModelMatrix * vec4(inPosition, 1.0, 1.0);
outTexCoord = inTexCoord;
outTint = inTint;
outTintEffect = inTintEffect;
}
`
});
},
});
const GrayscalePipeline = new Phaser.Class({
Extends: Phaser.Renderer.WebGL.Pipelines.TextureTintPipeline,
initialize: function CustomPipeline (game) {
Phaser.Renderer.WebGL.Pipelines.TextureTintPipeline.call(this, {
game: game,
renderer: game.renderer,
fragShader: `
precision mediump float;
uniform sampler2D uMainSampler;
uniform sampler2D uMipSampler;
uniform vec2 uResolution;
uniform float uTime;
varying vec2 outTexCoord;
varying vec4 outTint;
void main()
{
vec2 uv = outTexCoord.xy;
uv.y = 1.0 - uv.y;
vec4 texel = texture2D(uMainSampler, uv);
float lum = (texel.x * 0.3) + (texel.y * 0.6) + (texel.z * 0.1);
texel.x = lum;
texel.y = lum;
texel.z = lum;
gl_FragColor = texel;
// gl_FragColor.xy = outTexCoord.xy;
}`,
});
},
});
const PlasmaPipeline = new Phaser.Class({
Extends: Phaser.Renderer.WebGL.Pipelines.TextureTintPipeline,
initialize: function CustomPipeline (game) {
Phaser.Renderer.WebGL.Pipelines.TextureTintPipeline.call(this, {
game: game,
renderer: game.renderer,
fragShader: `
precision mediump float;
uniform sampler2D uMainSampler;
uniform sampler2D uMipSampler;
uniform vec2 uResolution;
uniform float uTime;
varying vec2 outTexCoord;
varying vec4 outTint;
vec4 plasma()
{
vec2 pixelPos = gl_FragCoord.xy / uResolution * 20.0;
float freq = 0.8;
float value =
sin(uTime + pixelPos.x * freq) +
sin(uTime + pixelPos.y * freq) +
sin(uTime + (pixelPos.x + pixelPos.y) * freq) +
cos(uTime + sqrt(length(pixelPos - 0.5)) * freq * 2.0);
return vec4(
cos(value),
sin(value),
sin(value * 3.14 * 2.0),
cos(value)
);
}
void main()
{
vec2 uv = outTexCoord.xy;
uv.y = 1.0 - uv.y;
vec4 texel = texture2D(uMainSampler, uv);
texel *= vec4(outTint.rgb * outTint.a, outTint.a);
gl_FragColor = texel * plasma();
// gl_FragColor.xy = outTexCoord.xy;
}`,
});
},
});
const game = new Phaser.Game(config);
function preload() {
this.load.image('beball', 'assets/sprites/beball1.png');
this.load.image('atari', 'assets/sprites/atari400.png');
this.load.image('bikkuriman', 'assets/sprites/bikkuriman.png');
this.load.image('bunny', 'assets/sprites/bunny.png');
plasma = game.renderer.addPipeline('plasma', new PlasmaPipeline(game));
plasma.setFloat2('uResolution', game.config.width, game.config.height);
mipmapline = game.renderer.addPipeline('mipmap', new MipmapPipeline(game));
mipmapline.setFloat1('uTime', 0);
}
const sprites = [];
const layers = [];
const effects = [
'invert',
'mipmap',
];
var fillrect;
function create() {
sprites.push(this.add.sprite(300, 300, 'beball'));
sprites.push(this.add.sprite(800, 300, 'bikkuriman'));
sprites.push(this.add.sprite(0, 0, 'bunny'));
sprites.forEach((s) => s.setVisible(false));
fillrect = this.add.rectangle(0, 0, game.config.width, game.config.height, 0xFF000000, 1.0);
fillrect.setVisible(false);
mips = this.make.renderTexture({
x: 0,
y: 0,
width: game.config.width,
height: game.config.height,
});
updateMips(this.game.renderer.gl);
mips.setVisible(false);
for (const effect of effects) {
const rt = this.add.renderTexture(0, 0, game.config.width, game.config.height);
rt.setVisible(false);
rt.setPipeline(effect);
layers.push(rt);
}
layers[layers.length - 1].setVisible(true);
this.input.on('pointermove', function (pointer) {
sprites[2].x = pointer.x;
sprites[2].y = pointer.y;
}, this);
}
var time = 0.0;
function update(delta)
{
plasma.setFloat1('uTime', time);
mipmapline.setFloat1('uTime', time);
time += 0.05;
// sprites[2].rotation += 0.005;
layers[0].draw(fillrect, fillrect.displayWidth / 2, fillrect.displayHeight / 2);
layers[0].draw(sprites);
mips.draw(layers[0]);
const lum = updateMips(this.game.renderer.gl);
mipmapline.setFloat1('uLum', lum);
for (let i = 1; i < layers.length; ++i) {
const l = layers[i];
l.draw(fillrect, fillrect.displayWidth / 2, fillrect.displayHeight / 2);
l.draw(layers[i - 1]);
}
}
function updateMips(gl) {
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, mips.glTexture);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAX_LEVEL, 10);
gl.generateMipmap(gl.TEXTURE_2D);
const err = gl.getError();
if (err > 0) {
console.log(err);
debugger;
}
const pixels = new Uint8Array(4);
gl.bindFramebuffer(gl.READ_FRAMEBUFFER, mips.framebuffer);
gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixels);
return (pixels[0] + pixels[1] + pixels[2]) / 3.0 / 256.0;
}
const config = {
type: Phaser.WEBGL,
parent: 'phaser-example',
scene: {
preload: preload,
create: create,
update: update,
},
};
const BlurXPipeline = new Phaser.Class({
Extends: Phaser.Renderer.WebGL.Pipelines.TextureTintPipeline,
initialize: function CustomPipeline (game) {
Phaser.Renderer.WebGL.Pipelines.TextureTintPipeline.call(this, {
game: game,
renderer: game.renderer,
fragShader: `
precision mediump float;
uniform sampler2D uMainSampler;
uniform vec2 uResolution;
uniform float uTime;
varying vec2 outTexCoord;
varying vec4 outTint;
void main()
{
vec2 uv = outTexCoord.xy;
uv.y = 1.0 - uv.y;
vec2 pixel = vec2(1.0) / vec2(1024.0, 768.0);
vec4 texelU3 = texture2D(uMainSampler, vec2(uv.x, uv.y - pixel.y)) * 0.125;
vec4 texelU2 = texture2D(uMainSampler, vec2(uv.x, uv.y - pixel.y)) * 0.25;
vec4 texelU1 = texture2D(uMainSampler, vec2(uv.x, uv.y - pixel.y)) * 0.5;
vec4 texel00 = texture2D(uMainSampler, uv);
vec4 texelD1 = texture2D(uMainSampler, vec2(uv.x, uv.y + pixel.y)) * 0.5;
vec4 texelD2 = texture2D(uMainSampler, vec2(uv.x, uv.y + pixel.y)) * 0.25;
vec4 texelD3 = texture2D(uMainSampler, vec2(uv.x, uv.y + pixel.y)) * 0.125;
gl_FragColor = (texelU3 + texelU2 + texelU1 + texel00 + texelD1 + texelD2 + texelD3) / 2.75;
}`,
});
},
});
const BlurYPipeline = new Phaser.Class({
Extends: Phaser.Renderer.WebGL.Pipelines.TextureTintPipeline,
initialize: function CustomPipeline (game) {
Phaser.Renderer.WebGL.Pipelines.TextureTintPipeline.call(this, {
game: game,
renderer: game.renderer,
fragShader: `
precision mediump float;
uniform sampler2D uMainSampler;
uniform vec2 uResolution;
uniform float uTime;
varying vec2 outTexCoord;
varying vec4 outTint;
void main()
{
vec2 uv = outTexCoord.xy;
uv.y = 1.0 - uv.y;
vec2 pixel = vec2(1.0) / vec2(1024.0, 768.0);
vec4 texelU3 = texture2D(uMainSampler, vec2(uv.x - pixel.x, uv.y)) * 0.125;
vec4 texelU2 = texture2D(uMainSampler, vec2(uv.x - pixel.x, uv.y)) * 0.25;
vec4 texelU1 = texture2D(uMainSampler, vec2(uv.x - pixel.x, uv.y)) * 0.5;
vec4 texel00 = texture2D(uMainSampler, uv);
vec4 texelD1 = texture2D(uMainSampler, vec2(uv.x + pixel.x, uv.y)) * 0.5;
vec4 texelD2 = texture2D(uMainSampler, vec2(uv.x + pixel.x, uv.y)) * 0.25;
vec4 texelD3 = texture2D(uMainSampler, vec2(uv.x + pixel.x, uv.y)) * 0.125;
gl_FragColor = (texelU3 + texelU2 + texelU1 + texel00 + texelD1 + texelD2 + texelD3) / 2.75;
}`,
});
},
});
const InvertPipeline = new Phaser.Class({
Extends: Phaser.Renderer.WebGL.Pipelines.TextureTintPipeline,
initialize: function CustomPipeline (game) {
Phaser.Renderer.WebGL.Pipelines.TextureTintPipeline.call(this, {
game: game,
renderer: game.renderer,
fragShader: `
precision mediump float;
uniform sampler2D uMainSampler;
uniform vec2 uResolution;
uniform float uTime;
varying vec2 outTexCoord;
varying vec4 outTint;
void main()
{
vec2 uv = outTexCoord.xy;
uv.y = 1.0 - uv.y;
vec4 texel = vec4(1.0) - texture2D(uMainSampler, uv);
gl_FragColor = texel;
// gl_FragColor.xy = outTexCoord.xy;
}`,
});
},
});
const GrayscalePipeline = new Phaser.Class({
Extends: Phaser.Renderer.WebGL.Pipelines.TextureTintPipeline,
initialize: function CustomPipeline (game) {
Phaser.Renderer.WebGL.Pipelines.TextureTintPipeline.call(this, {
game: game,
renderer: game.renderer,
fragShader: `
precision mediump float;
uniform sampler2D uMainSampler;
uniform vec2 uResolution;
uniform float uTime;
varying vec2 outTexCoord;
varying vec4 outTint;
void main()
{
vec2 uv = outTexCoord.xy;
uv.y = 1.0 - uv.y;
vec4 texel = texture2D(uMainSampler, uv);
float lum = (texel.x * 0.3) + (texel.y * 0.6) + (texel.z * 0.1);
texel.x = lum;
texel.y = lum;
texel.z = lum;
gl_FragColor = texel;
// gl_FragColor.xy = outTexCoord.xy;
}`,
});
},
});
const PlasmaPipeline = new Phaser.Class({
Extends: Phaser.Renderer.WebGL.Pipelines.TextureTintPipeline,
initialize: function CustomPipeline (game) {
Phaser.Renderer.WebGL.Pipelines.TextureTintPipeline.call(this, {
game: game,
renderer: game.renderer,
fragShader: `
precision mediump float;
uniform sampler2D uMainSampler;
uniform vec2 uResolution;
uniform float uTime;
varying vec2 outTexCoord;
varying vec4 outTint;
vec4 plasma()
{
vec2 pixelPos = gl_FragCoord.xy / uResolution * 20.0;
float freq = 0.8;
float value =
sin(uTime + pixelPos.x * freq) +
sin(uTime + pixelPos.y * freq) +
sin(uTime + (pixelPos.x + pixelPos.y) * freq) +
cos(uTime + sqrt(length(pixelPos - 0.5)) * freq * 2.0);
return vec4(
cos(value),
sin(value),
sin(value * 3.14 * 2.0),
cos(value)
);
}
void main()
{
vec2 uv = outTexCoord.xy;
// uv.x = 0.5 - uv.x;
// uv.y = 0.5 + uv.y;
uv.y = 1.0 - uv.y;
vec4 texel = texture2D(uMainSampler, uv);
texel *= vec4(outTint.rgb * outTint.a, outTint.a);
gl_FragColor = texel * plasma();
// gl_FragColor.xy = outTexCoord.xy;
}`,
});
},
});
const game = new Phaser.Game(config);
function preload() {
this.load.image('beball', 'assets/sprites/beball1.png');
this.load.image('atari', 'assets/sprites/atari400.png');
this.load.image('bikkuriman', 'assets/sprites/bikkuriman.png');
this.load.image('bunny', 'assets/sprites/bunny.png');
plasma = game.renderer.addPipeline('plasma', new PlasmaPipeline(game));
plasma.setFloat2('uResolution', game.config.width, game.config.height);
game.renderer.addPipeline('grayscale', new GrayscalePipeline(game));
game.renderer.addPipeline('blurX', new BlurXPipeline(game));
game.renderer.addPipeline('blurY', new BlurYPipeline(game));
game.renderer.addPipeline('invert', new InvertPipeline(game));
}
const sprites = [];
const layers = [];
const effects = [
'blurX',
'blurY',
'grayscale',
'invert',
'blurX',
'blurY',
'blurX',
'blurY',
'plasma',
'invert',
//'blurX',
//'blurY',
];
var fillrect;
function create() {
sprites.push(this.add.sprite(300, 300, 'beball'));
sprites.push(this.add.sprite(800, 300, 'bikkuriman'));
sprites.push(this.add.sprite(0, 0, 'bunny'));
sprites.forEach((s) => s.setVisible(false));
fillrect = this.add.rectangle(0, 0, game.config.width, game.config.height, 0xFFFFFF00, 1.0);
fillrect.setVisible(false);
for (const effect of effects) {
const rt = this.add.renderTexture(0, 0, game.config.width, game.config.height);
rt.setVisible(false);
rt.setPipeline(effect);
layers.push(rt);
}
layers[layers.length - 1].setVisible(true);
this.input.on('pointermove', function (pointer) {
sprites[2].x = pointer.x;
sprites[2].y = pointer.y;
}, this);
}
var time = 0.0;
function update(delta)
{
plasma.setFloat1('uTime', time);
time += 0.05;
sprites[2].rotation += 0.005;
layers[0].draw(fillrect, fillrect.displayWidth / 2, fillrect.displayHeight / 2);
layers[0].draw(sprites);
for (let i = 1; i < layers.length; ++i) {
layers[i].draw(fillrect, fillrect.displayWidth / 2, fillrect.displayHeight / 2);
layers[i].draw(layers[i - 1]);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment